From 750fd917f70fa8ea0653188e5fb49828cd29efa6 Mon Sep 17 00:00:00 2001 From: wanghuai <748928840@qq.com> Date: Fri, 2 Feb 2024 19:05:26 +0000 Subject: [PATCH 11/22] ethernet: bundle module for Motorcomm YT6801 - The Asus XC-LS3A6M motherboard (Loongson 3A6000) comes with two Ethernet ports, which uses a yt6801 controller. - This patch introduces an out of tree module to provide support for this NIC. [^1] - Refactor module tree to make it work with Kconfig. [^2] - Drop unneeded installation script (yt_nic_install.sh). - Trim README to remove useless installation instructions. [^1]: Ref: https://www.motor-comm.com/Public/Uploads/uploadfile/files/20240104/yt6801-linux-driver-1.0.27.zip [^2]: CONFIG_NET_VENDOR_MOTORCOMM =(y)=> CONFIG_YT8601 (tristate). Co-authored-by: Mingcong Bai Signed-off-by: Shi Pujin --- drivers/net/ethernet/Kconfig | 1 + drivers/net/ethernet/Makefile | 2 + drivers/net/ethernet/motorcomm/Kconfig | 29 + drivers/net/ethernet/motorcomm/Makefile | 23 + drivers/net/ethernet/motorcomm/Notice.txt | 30 + drivers/net/ethernet/motorcomm/README | 89 + drivers/net/ethernet/motorcomm/fuxi-dbg.c | 510 ++ drivers/net/ethernet/motorcomm/fuxi-dbg.h | 24 + drivers/net/ethernet/motorcomm/fuxi-efuse.c | 968 +++ drivers/net/ethernet/motorcomm/fuxi-efuse.h | 33 + .../net/ethernet/motorcomm/fuxi-gmac-common.c | 1014 +++ .../ethernet/motorcomm/fuxi-gmac-debugfs.c | 760 ++ .../net/ethernet/motorcomm/fuxi-gmac-desc.c | 1254 +++ .../ethernet/motorcomm/fuxi-gmac-ethtool.c | 1177 +++ drivers/net/ethernet/motorcomm/fuxi-gmac-hw.c | 6714 +++++++++++++++++ .../net/ethernet/motorcomm/fuxi-gmac-net.c | 2366 ++++++ .../net/ethernet/motorcomm/fuxi-gmac-pci.c | 365 + .../net/ethernet/motorcomm/fuxi-gmac-phy.c | 422 ++ .../net/ethernet/motorcomm/fuxi-gmac-reg.h | 1876 +++++ drivers/net/ethernet/motorcomm/fuxi-gmac.h | 924 +++ drivers/net/ethernet/motorcomm/fuxi-os.h | 560 ++ 21 files changed, 19141 insertions(+) create mode 100644 drivers/net/ethernet/motorcomm/Kconfig create mode 100644 drivers/net/ethernet/motorcomm/Makefile create mode 100644 drivers/net/ethernet/motorcomm/Notice.txt create mode 100644 drivers/net/ethernet/motorcomm/README create mode 100644 drivers/net/ethernet/motorcomm/fuxi-dbg.c create mode 100644 drivers/net/ethernet/motorcomm/fuxi-dbg.h create mode 100644 drivers/net/ethernet/motorcomm/fuxi-efuse.c create mode 100644 drivers/net/ethernet/motorcomm/fuxi-efuse.h create mode 100644 drivers/net/ethernet/motorcomm/fuxi-gmac-common.c create mode 100644 drivers/net/ethernet/motorcomm/fuxi-gmac-debugfs.c create mode 100644 drivers/net/ethernet/motorcomm/fuxi-gmac-desc.c create mode 100644 drivers/net/ethernet/motorcomm/fuxi-gmac-ethtool.c create mode 100644 drivers/net/ethernet/motorcomm/fuxi-gmac-hw.c create mode 100644 drivers/net/ethernet/motorcomm/fuxi-gmac-net.c create mode 100644 drivers/net/ethernet/motorcomm/fuxi-gmac-pci.c create mode 100644 drivers/net/ethernet/motorcomm/fuxi-gmac-phy.c create mode 100644 drivers/net/ethernet/motorcomm/fuxi-gmac-reg.h create mode 100644 drivers/net/ethernet/motorcomm/fuxi-gmac.h create mode 100644 drivers/net/ethernet/motorcomm/fuxi-os.h diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig index 5a274b99f299..88a1f8a07e10 100644 --- a/drivers/net/ethernet/Kconfig +++ b/drivers/net/ethernet/Kconfig @@ -127,6 +127,7 @@ source "drivers/net/ethernet/mediatek/Kconfig" source "drivers/net/ethernet/mellanox/Kconfig" source "drivers/net/ethernet/micrel/Kconfig" source "drivers/net/ethernet/microchip/Kconfig" +source "drivers/net/ethernet/motorcomm/Kconfig" source "drivers/net/ethernet/mscc/Kconfig" source "drivers/net/ethernet/microsoft/Kconfig" source "drivers/net/ethernet/moxa/Kconfig" diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile index 0d872d4efcd1..3e3d90f93697 100644 --- a/drivers/net/ethernet/Makefile +++ b/drivers/net/ethernet/Makefile @@ -61,6 +61,7 @@ obj-$(CONFIG_NET_VENDOR_MEDIATEK) += mediatek/ obj-$(CONFIG_NET_VENDOR_MELLANOX) += mellanox/ obj-$(CONFIG_NET_VENDOR_MICREL) += micrel/ obj-$(CONFIG_NET_VENDOR_MICROCHIP) += microchip/ +obj-$(CONFIG_NET_VENDOR_MOTORCOMM) += motorcomm/ obj-$(CONFIG_NET_VENDOR_MICROSEMI) += mscc/ obj-$(CONFIG_NET_VENDOR_MOXART) += moxa/ obj-$(CONFIG_NET_VENDOR_MYRI) += myricom/ @@ -104,3 +105,4 @@ obj-$(CONFIG_NET_VENDOR_XILINX) += xilinx/ obj-$(CONFIG_NET_VENDOR_XIRCOM) += xircom/ obj-$(CONFIG_NET_VENDOR_SYNOPSYS) += synopsys/ obj-$(CONFIG_NET_VENDOR_PENSANDO) += pensando/ +obj-m += motorcomm/ diff --git a/drivers/net/ethernet/motorcomm/Kconfig b/drivers/net/ethernet/motorcomm/Kconfig new file mode 100644 index 000000000000..30fc2eabd2be --- /dev/null +++ b/drivers/net/ethernet/motorcomm/Kconfig @@ -0,0 +1,29 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Motorcomm network device configuration +# + +config NET_VENDOR_MOTORCOMM + bool "Motorcomm devices" + default y + depends on PCI + help + If you have a network (Ethernet) card belonging to this class, say Y. + + Note that the answer to this question doesn't directly affect the + kernel: saying N will just cause the configurator to skip all + the questions about Motorcomm cards. If you say Y, you will be asked + for your specific card in the following questions. + +if NET_VENDOR_MOTORCOMM + +config YT6801 + tristate "Motorcomm YT6801 Ethernet support" + depends on PCI + help + If you have a network (Ethernet) controller of this type, say Y here. + + To compile this driver as a module, choose M here. The module + will be called forcedeth. + +endif # NET_VENDOR_MOTORCOMM diff --git a/drivers/net/ethernet/motorcomm/Makefile b/drivers/net/ethernet/motorcomm/Makefile new file mode 100644 index 000000000000..5f25a4eda63c --- /dev/null +++ b/drivers/net/ethernet/motorcomm/Makefile @@ -0,0 +1,23 @@ +# SPDX-License-Identifier: GPL-2.0-only +################################################################################ +# +# Copyright (c) 2023 Motorcomm, Inc. +# Motorcomm Confidential and Proprietary. +# +# This is Motorcomm NIC driver relevant files. Please don't copy, modify, +# distribute without commercial permission. +# +################################################################################ + +obj-$(CONFIG_YT6801) += yt6801.o + +yt6801-objs := fuxi-gmac-common.o \ + fuxi-gmac-desc.o \ + fuxi-gmac-ethtool.o \ + fuxi-gmac-hw.o \ + fuxi-gmac-net.o \ + fuxi-gmac-pci.o \ + fuxi-gmac-phy.o \ + fuxi-efuse.o \ + fuxi-dbg.o \ + fuxi-gmac-debugfs.o diff --git a/drivers/net/ethernet/motorcomm/Notice.txt b/drivers/net/ethernet/motorcomm/Notice.txt new file mode 100644 index 000000000000..230978a18635 --- /dev/null +++ b/drivers/net/ethernet/motorcomm/Notice.txt @@ -0,0 +1,30 @@ +============================================================================= + +This file contains certain notices of software components included with +the software that Motorcomm, Inc. ("Motorcomm") is required to +provide you. Except where prohibited by the open source license, the +content of this file is provided solely to satisfy Motorcomm's attribution +and notice requirement; your use of these software components +together with the Motorcomm software ("Software") is subject to the terms +of your license from Motorcomm. Compliance with all copyright laws and +software license agreements included in the notice section of this +file are the responsibility of the user. Except as may be granted by +separate express written agreement, this file provides no license to +any patents, trademarks, copyrights, or other intellectual property +of Motorcomm or any of its subsidiaries. + +Software provided with this notice is NOT A CONTRIBUTION to any open +source project. If alternative licensing is available for any of the +components with licenses or attributions provided below, a license +choice is made for receiving such code by Motorcomm. + +Copyright (c) 2021 Motorcomm, Inc. All rights reserved. + +Motorcomm is a trademark of Motorcomm Incorporated, registered in China +and other countries. All Motorcomm Incorporated trademarks +are used with permission. Other products and brand names may be +trademarks or registered trademarks of their respective owners. + +============================================================================= + + diff --git a/drivers/net/ethernet/motorcomm/README b/drivers/net/ethernet/motorcomm/README new file mode 100644 index 000000000000..fb76cff20c1c --- /dev/null +++ b/drivers/net/ethernet/motorcomm/README @@ -0,0 +1,89 @@ + + + This is the Linux device driver released for Motorcomm YT6801 Gigabit + Ethernet controllers with PCI-Express interface. + + + 1. Set manually + a. Set the IP address of your machine. + + # ifconfig ethX "the IP address of your machine" + + b. Set the IP address of DNS. + + Insert the following configuration in /etc/resolv.conf. + + nameserver "the IP address of DNS" + + c. Set the IP address of gateway. + + # route add default gw "the IP address of gateway" + + 2. Set by doing configurations in /etc/sysconfig/network-scripts + /ifcfg-ethX for Redhat and Fedora, or /etc/sysconfig/network + /ifcfg-ethX for SuSE. There are two examples to set network + configurations. + + a. Fixed IP address: + DEVICE=eth0 + BOOTPROTO=static + ONBOOT=yes + TYPE=ethernet + NETMASK=255.255.255.0 + IPADDR=192.168.1.1 + GATEWAY=192.168.1.254 + BROADCAST=192.168.1.255 + + b. DHCP: + DEVICE=eth0 + BOOTPROTO=dhcp + ONBOOT=yes + + + There are two ways to modify the MAC address of the NIC. + 1. Use ifconfig: + + # ifconfig ethX hw ether YY:YY:YY:YY:YY:YY + + ,where X is the device number assigned by Linux kernel, and + YY:YY:YY:YY:YY:YY is the MAC address assigned by the user. + + 2. Use ip: + + # ip link set ethX address YY:YY:YY:YY:YY:YY + + ,where X is the device number assigned by Linux kernel, and + YY:YY:YY:YY:YY:YY is the MAC address assigned by the user. + + + + Force the link status by using ethtool. + a. Insert the driver first. + b. Make sure that ethtool exists in /sbin. + c. Force the link status as the following command. + + # ethtool -s ethX speed SPEED_MODE duplex DUPLEX_MODE autoneg NWAY_OPTION + + ,where + SPEED_MODE = 1000 for 1000Mbps + = 100 for 100Mbps + = 10 for 10Mbps + DUPLEX_MODE = half for half-duplex + = full for full-duplex + NWAY_OPTION = off for auto-negotiation off (true force) + = on for auto-negotiation on (nway force) + + For example: + + # ethtool -s eth0 speed 100 duplex full autoneg on + + will force PHY to operate in 100Mpbs Full-duplex(nway force). + + + Transmitting Jumbo Frames, whose packet size is bigger than 1500 bytes, please change mtu by the following command. + + # ifconfig ethX mtu MTU + + , where X=0,1,2,..., and MTU is configured by user. + + YT6801 supports Jumbo Frame size up to 9 kBytes. diff --git a/drivers/net/ethernet/motorcomm/fuxi-dbg.c b/drivers/net/ethernet/motorcomm/fuxi-dbg.c new file mode 100644 index 000000000000..5deddef39242 --- /dev/null +++ b/drivers/net/ethernet/motorcomm/fuxi-dbg.c @@ -0,0 +1,510 @@ +/*++ + +Copyright (c) 2021 Motorcomm Corporation. +Confidential and Proprietary. All rights reserved. + +This is Motorcomm Corporation NIC driver relevant files. Please don't copy, modify, +distribute without commercial permission. + + +Module Name: + mp_dbg.c + +Abstract: + This module contains all debug-related code. + +Revision History: + +Notes: + +--*/ + +#include "fuxi-gmac.h" + +#if defined(UEFI) +#include + + +UINT32 MPDebugLevel = MP_LOUD; + +void DbgPrintAddress(unsigned char* Address) +{ + // If your MAC address has a different size, adjust the printf accordingly. + //{ASSERT(ETH_LENGTH_OF_ADDRESS == 6); } + + DbgPrintF(MP_LOUD, "%02x-%02x-%02x-%02x-%02x-%02x.", \ + Address[0], Address[1], Address[2], \ + Address[3], Address[4], Address[5]); +} + +void fxgmac_dump_buffer(unsigned char *skb, unsigned int len, int tx_rx) +{ +#define ZDbgPrintF(Level, ...) AsciiPrint("fx-pat " __VA_ARGS__); \ + + //unsigned char buffer[128]; + unsigned int i, j; + char * caption[3] = { "Tx", + "Rx", + "Buffer"}; + + if(tx_rx > 2) tx_rx = 2; + + ZDbgPrintF(MP_TRACE, " ************** Data dump start ****************\n"); + ZDbgPrintF(MP_TRACE, " %a data of %d bytes\n", caption[tx_rx], len); + + for (i = 0; i < len; i += 32) { + unsigned int len_line = min(len - i, 32U); + + for(j = 0; j < len_line; j++) + { + AsciiPrint("%02x ", (u8)skb[i + j]); + } + AsciiPrint("\n"); + } + + ZDbgPrintF(MP_TRACE, " ************** Data dump end ****************\n"); +} + +#elif defined(_WIN64) || defined(_WIN32) +#include "fuxi-gmac-reg.h" +#include "fuxi-mp.h" +#if DBG + +/** +Constants +**/ + +#define _FILENUMBER 'GBED' + +// Bytes to appear on each line of dump output. +// +#define DUMP_BytesPerLine 16 + +ULONG MPDebugLevel = MP_LOUD; +ULONG MPAllocCount = 0; // the number of outstanding allocs +NDIS_SPIN_LOCK MPMemoryLock; // spinlock for the debug mem list +LIST_ENTRY MPMemoryList; +BOOLEAN MPInitDone = FALSE; // debug mem list init flag + +PVOID +MPAuditAllocMemTag( + UINT Size, + CHAR* FileNumber, + ULONG LineNumber, + NDIS_HANDLE MiniportAdapterHandle + ) +{ + PMP_ALLOCATION pAllocInfo; + PVOID Pointer; + + if (!MPInitDone) + { + NdisAllocateSpinLock(&MPMemoryLock); + InitializeListHead(&MPMemoryList); + MPInitDone = TRUE; + } + + pAllocInfo = NdisAllocateMemoryWithTagPriority( + MiniportAdapterHandle, + (UINT)(Size + sizeof(MP_ALLOCATION)), + NIC_TAG, + LowPoolPriority);//leileiz + + if (pAllocInfo == (PMP_ALLOCATION)NULL) + { + Pointer = NULL; + + DbgPrintF(MP_LOUD, "%s - file %s, line %d, Size %d failed!", __FUNCTION__, FileNumber, LineNumber, Size); + } + else + { + Pointer = (PVOID)&(pAllocInfo->UserData); + MP_MEMSET(Pointer, Size, 0xc); + + pAllocInfo->Signature = 'DOOG'; + pAllocInfo->FileNumber = FileNumber; + pAllocInfo->LineNumber = LineNumber; + pAllocInfo->Size = Size; + + NdisAcquireSpinLock(&MPMemoryLock); + InsertTailList(&MPMemoryList, &pAllocInfo->List); + MPAllocCount++; + NdisReleaseSpinLock(&MPMemoryLock); + } + + DbgPrintF(MP_LOUD, + "%s - file %s, line %d, %d bytes, [0x"PTR_FORMAT"].", __FUNCTION__, + FileNumber, LineNumber, Size, Pointer); + + return(Pointer); +} + +VOID MPAuditFreeMem( + IN PVOID Pointer + ) +{ + PMP_ALLOCATION pAllocInfo; + + pAllocInfo = CONTAINING_RECORD(Pointer, MP_ALLOCATION, UserData); + + ASSERT(pAllocInfo->Signature == (ULONG)'DOOG'); + + NdisAcquireSpinLock(&MPMemoryLock); + pAllocInfo->Signature = (ULONG)'DEAD'; + RemoveEntryList(&pAllocInfo->List); + MPAllocCount--; + NdisReleaseSpinLock(&MPMemoryLock); + + NdisFreeMemory(pAllocInfo, 0, 0); +} + +VOID mpDbgPrintUnicodeString( + IN PUNICODE_STRING UnicodeString + ) +{ + UCHAR Buffer[256]; + + USHORT i; + + for (i = 0; (i < UnicodeString->Length / 2) && (i < 255); i++) + { + Buffer[i] = (UCHAR)UnicodeString->Buffer[i]; + } + +#pragma prefast(suppress: __WARNING_POTENTIAL_BUFFER_OVERFLOW, "i is bounded by 255"); + Buffer[i] = '\0'; + + DbgPrint("%s", Buffer); +} + + + +// Hex dump 'cb' bytes starting at 'p' grouping 'ulGroup' bytes together. +// For example, with 'ulGroup' of 1, 2, and 4: +// +// 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +// 0000 0000 0000 0000 0000 0000 0000 0000 |................| +// 00000000 00000000 00000000 00000000 |................| +// +// If 'fAddress' is true, the memory address dumped is prepended to each +// line. +// +VOID +Dump( + __in_bcount(cb) IN CHAR* p, + IN ULONG cb, + IN BOOLEAN fAddress, + IN ULONG ulGroup + ) +{ + INT cbLine; + + while (cb) + { + cbLine = (cb < DUMP_BytesPerLine) ? cb : DUMP_BytesPerLine; +#pragma prefast(suppress: __WARNING_POTENTIAL_BUFFER_OVERFLOW, "p is bounded by cb bytes"); + DumpLine( p, cbLine, fAddress, ulGroup ); + cb -= cbLine; + p += cbLine; + } +} + + +VOID +DumpLine( + __in_bcount(cb) IN CHAR* p, + IN ULONG cb, + IN BOOLEAN fAddress, + IN ULONG ulGroup + ) +{ + + CHAR* pszDigits = "0123456789ABCDEF"; + CHAR szHex[ ((2 + 1) * DUMP_BytesPerLine) + 1 ]; + CHAR* pszHex = szHex; + CHAR szAscii[ DUMP_BytesPerLine + 1 ]; + CHAR* pszAscii = szAscii; + ULONG ulGrouped = 0; + + if (fAddress) + { + DbgPrint( "RLTK: %p: ", p ); + } + else + { + DbgPrint( "RLTK: " ); + } + + while (cb) + { +#pragma prefast(suppress: __WARNING_POTENTIAL_BUFFER_OVERFLOW, "pszHex accessed is always within bounds"); + *pszHex++ = pszDigits[ ((UCHAR )*p) / 16 ]; + *pszHex++ = pszDigits[ ((UCHAR )*p) % 16 ]; + + if (++ulGrouped >= ulGroup) + { + *pszHex++ = ' '; + ulGrouped = 0; + } + +#pragma prefast(suppress: __WARNING_POTENTIAL_BUFFER_OVERFLOW, "pszAscii is bounded by cb bytes"); + *pszAscii++ = (*p >= 32 && *p < 128) ? *p : '.'; + + ++p; + --cb; + } + + *pszHex = '\0'; + *pszAscii = '\0'; + + DbgPrint( + "%-*s|%-*s|\n", + (2 * DUMP_BytesPerLine) + (DUMP_BytesPerLine / ulGroup), szHex, + DUMP_BytesPerLine, szAscii ); +} + +void fxgmac_dump_buffer(unsigned char *skb, unsigned int len, int tx_rx) +{ + #define ZDbgPrintF(Level, ...) DbgPrint("fx-pat " ##__VA_ARGS__); + + unsigned char buffer[128]; + unsigned int i, j; + char * caption[3] = { "Tx", + "Rx", + "Buffer"}; + + if(tx_rx > 2) tx_rx = 2; + + ZDbgPrintF(MP_TRACE, " ************** Data dump start ****************\n"); + ZDbgPrintF(MP_TRACE, " %s data of %d bytes\n", caption[tx_rx], len); + + for (i = 0; i < len; i += 32) { + unsigned int len_line = min(len - i, 32U); + + for(j = 0; j < len_line; j++) + { + sprintf((char *)&buffer[j * 3], " %02x", (u8)skb[i + j]); + } + buffer[j * 3] = '\0'; + ZDbgPrintF(MP_TRACE, " %#06x: %s\n", i, buffer); + } + + ZDbgPrintF(MP_TRACE, " ************** Data dump end ****************\n"); + +} + +VOID +DbgPrintOidName( + _In_ NDIS_OID Oid) +{ + PCHAR oidName = NULL; + + switch (Oid) { + +#undef MAKECASE +#define MAKECASE(oidx) case oidx: oidName = NIC_DBG_STRING #oidx "\n"; break; + + /* Operational OIDs */ + MAKECASE(OID_GEN_SUPPORTED_LIST) + MAKECASE(OID_GEN_HARDWARE_STATUS) + MAKECASE(OID_GEN_MEDIA_SUPPORTED) + MAKECASE(OID_GEN_MEDIA_IN_USE) + MAKECASE(OID_GEN_MAXIMUM_LOOKAHEAD) + MAKECASE(OID_GEN_MAXIMUM_FRAME_SIZE) + MAKECASE(OID_GEN_LINK_SPEED) + MAKECASE(OID_GEN_TRANSMIT_BUFFER_SPACE) + MAKECASE(OID_GEN_RECEIVE_BUFFER_SPACE) + MAKECASE(OID_GEN_TRANSMIT_BLOCK_SIZE) + MAKECASE(OID_GEN_RECEIVE_BLOCK_SIZE) + MAKECASE(OID_GEN_VENDOR_ID) + MAKECASE(OID_GEN_VENDOR_DESCRIPTION) + MAKECASE(OID_GEN_VENDOR_DRIVER_VERSION) + MAKECASE(OID_GEN_CURRENT_PACKET_FILTER) + MAKECASE(OID_GEN_CURRENT_LOOKAHEAD) + MAKECASE(OID_GEN_DRIVER_VERSION) + MAKECASE(OID_GEN_MAXIMUM_TOTAL_SIZE) + MAKECASE(OID_GEN_PROTOCOL_OPTIONS) + MAKECASE(OID_GEN_MAC_OPTIONS) + MAKECASE(OID_GEN_MEDIA_CONNECT_STATUS) + MAKECASE(OID_GEN_MAXIMUM_SEND_PACKETS) + MAKECASE(OID_GEN_SUPPORTED_GUIDS) + MAKECASE(OID_GEN_NETWORK_LAYER_ADDRESSES) + MAKECASE(OID_GEN_TRANSPORT_HEADER_OFFSET) + MAKECASE(OID_GEN_MEDIA_CAPABILITIES) + MAKECASE(OID_GEN_PHYSICAL_MEDIUM) + MAKECASE(OID_GEN_MACHINE_NAME) + MAKECASE(OID_GEN_VLAN_ID) + MAKECASE(OID_GEN_RECEIVE_SCALE_PARAMETERS) + MAKECASE(OID_GEN_RECEIVE_SCALE_CAPABILITIES) + MAKECASE(OID_GEN_RECEIVE_HASH) +#if (NTDDI_VERSION >= NTDDI_WINBLUE) ||(NDIS_SUPPORT_NDIS640) + MAKECASE(OID_GEN_ISOLATION_PARAMETERS) // query only +#endif + MAKECASE(OID_GEN_RNDIS_CONFIG_PARAMETER) + + /* Operational OIDs for NDIS 6.0 */ + MAKECASE(OID_GEN_MAX_LINK_SPEED) + MAKECASE(OID_GEN_LINK_STATE) + MAKECASE(OID_GEN_LINK_PARAMETERS) + MAKECASE(OID_GEN_MINIPORT_RESTART_ATTRIBUTES) + MAKECASE(OID_GEN_ENUMERATE_PORTS) + MAKECASE(OID_GEN_PORT_STATE) + MAKECASE(OID_GEN_PORT_AUTHENTICATION_PARAMETERS) + MAKECASE(OID_GEN_INTERRUPT_MODERATION) + MAKECASE(OID_GEN_PHYSICAL_MEDIUM_EX) + + /* Statistical OIDs */ + MAKECASE(OID_GEN_XMIT_OK) + MAKECASE(OID_GEN_RCV_OK) + MAKECASE(OID_GEN_XMIT_ERROR) + MAKECASE(OID_GEN_RCV_ERROR) + MAKECASE(OID_GEN_RCV_NO_BUFFER) + MAKECASE(OID_GEN_DIRECTED_BYTES_XMIT) + MAKECASE(OID_GEN_DIRECTED_FRAMES_XMIT) + MAKECASE(OID_GEN_MULTICAST_BYTES_XMIT) + MAKECASE(OID_GEN_MULTICAST_FRAMES_XMIT) + MAKECASE(OID_GEN_BROADCAST_BYTES_XMIT) + MAKECASE(OID_GEN_BROADCAST_FRAMES_XMIT) + MAKECASE(OID_GEN_DIRECTED_BYTES_RCV) + MAKECASE(OID_GEN_DIRECTED_FRAMES_RCV) + MAKECASE(OID_GEN_MULTICAST_BYTES_RCV) + MAKECASE(OID_GEN_MULTICAST_FRAMES_RCV) + MAKECASE(OID_GEN_BROADCAST_BYTES_RCV) + MAKECASE(OID_GEN_BROADCAST_FRAMES_RCV) + MAKECASE(OID_GEN_RCV_CRC_ERROR) + MAKECASE(OID_GEN_TRANSMIT_QUEUE_LENGTH) + + /* Statistical OIDs for NDIS 6.0 */ + MAKECASE(OID_GEN_STATISTICS) + MAKECASE(OID_GEN_BYTES_RCV) + MAKECASE(OID_GEN_BYTES_XMIT) + MAKECASE(OID_GEN_RCV_DISCARDS) + MAKECASE(OID_GEN_XMIT_DISCARDS) + + /* Misc OIDs */ + MAKECASE(OID_GEN_GET_TIME_CAPS) + MAKECASE(OID_GEN_GET_NETCARD_TIME) + MAKECASE(OID_GEN_NETCARD_LOAD) + MAKECASE(OID_GEN_DEVICE_PROFILE) + MAKECASE(OID_GEN_INIT_TIME_MS) + MAKECASE(OID_GEN_RESET_COUNTS) + MAKECASE(OID_GEN_MEDIA_SENSE_COUNTS) + + /* PnP power management operational OIDs */ + MAKECASE(OID_PNP_SET_POWER) + MAKECASE(OID_PNP_QUERY_POWER) + MAKECASE(OID_PNP_CAPABILITIES) + MAKECASE(OID_PNP_ADD_WAKE_UP_PATTERN) + MAKECASE(OID_PNP_REMOVE_WAKE_UP_PATTERN) + MAKECASE(OID_PNP_ENABLE_WAKE_UP) + MAKECASE(OID_PM_HARDWARE_CAPABILITIES) + MAKECASE(OID_PM_ADD_WOL_PATTERN) + MAKECASE(OID_PM_REMOVE_WOL_PATTERN) + MAKECASE(OID_PM_PARAMETERS) + MAKECASE(OID_PM_WOL_PATTERN_LIST) + MAKECASE(OID_PM_ADD_PROTOCOL_OFFLOAD) + MAKECASE(OID_PM_REMOVE_PROTOCOL_OFFLOAD) + MAKECASE(OID_PM_PROTOCOL_OFFLOAD_LIST) + + MAKECASE(OID_PNP_WAKE_UP_PATTERN_LIST) + /* PnP power management statistical OIDs */ + MAKECASE(OID_PNP_WAKE_UP_ERROR) + MAKECASE(OID_PNP_WAKE_UP_OK) + + /* Ethernet operational OIDs */ + MAKECASE(OID_802_3_PERMANENT_ADDRESS) + MAKECASE(OID_802_3_CURRENT_ADDRESS) + MAKECASE(OID_802_3_MULTICAST_LIST) + MAKECASE(OID_802_3_MAXIMUM_LIST_SIZE) + MAKECASE(OID_802_3_MAC_OPTIONS) + + /* Ethernet operational OIDs for NDIS 6.0 */ + MAKECASE(OID_802_3_ADD_MULTICAST_ADDRESS) + MAKECASE(OID_802_3_DELETE_MULTICAST_ADDRESS) + + /* Ethernet statistical OIDs */ + MAKECASE(OID_802_3_RCV_ERROR_ALIGNMENT) + MAKECASE(OID_802_3_XMIT_ONE_COLLISION) + MAKECASE(OID_802_3_XMIT_MORE_COLLISIONS) + MAKECASE(OID_802_3_XMIT_DEFERRED) + MAKECASE(OID_802_3_XMIT_MAX_COLLISIONS) + MAKECASE(OID_802_3_RCV_OVERRUN) + MAKECASE(OID_802_3_XMIT_UNDERRUN) + MAKECASE(OID_802_3_XMIT_HEARTBEAT_FAILURE) + MAKECASE(OID_802_3_XMIT_TIMES_CRS_LOST) + MAKECASE(OID_802_3_XMIT_LATE_COLLISIONS) + + /* TCP/IP OIDs */ + MAKECASE(OID_TCP_TASK_OFFLOAD) + MAKECASE(OID_TCP_TASK_IPSEC_ADD_SA) + MAKECASE(OID_TCP_TASK_IPSEC_DELETE_SA) + MAKECASE(OID_TCP_SAN_SUPPORT) + MAKECASE(OID_TCP_TASK_IPSEC_ADD_UDPESP_SA) + MAKECASE(OID_TCP_TASK_IPSEC_DELETE_UDPESP_SA) + MAKECASE(OID_TCP4_OFFLOAD_STATS) + MAKECASE(OID_TCP6_OFFLOAD_STATS) + MAKECASE(OID_IP4_OFFLOAD_STATS) + MAKECASE(OID_IP6_OFFLOAD_STATS) + + /* TCP offload OIDs for NDIS 6 */ + MAKECASE(OID_TCP_OFFLOAD_CURRENT_CONFIG) + MAKECASE(OID_TCP_OFFLOAD_PARAMETERS) + MAKECASE(OID_TCP_OFFLOAD_HARDWARE_CAPABILITIES) + MAKECASE(OID_TCP_CONNECTION_OFFLOAD_CURRENT_CONFIG) + MAKECASE(OID_TCP_CONNECTION_OFFLOAD_HARDWARE_CAPABILITIES) + MAKECASE(OID_OFFLOAD_ENCAPSULATION) + +#if (NDIS_SUPPORT_NDIS620) + /* VMQ OIDs for NDIS 6.20 */ + MAKECASE(OID_RECEIVE_FILTER_FREE_QUEUE) + MAKECASE(OID_RECEIVE_FILTER_CLEAR_FILTER) + MAKECASE(OID_RECEIVE_FILTER_ALLOCATE_QUEUE) + MAKECASE(OID_RECEIVE_FILTER_QUEUE_ALLOCATION_COMPLETE) + MAKECASE(OID_RECEIVE_FILTER_SET_FILTER) +#endif + +#if (NDIS_SUPPORT_NDIS630 || NDIS_SUPPORT_NDIS680) + /* NDIS QoS OIDs for NDIS 6.30 */ + MAKECASE(OID_QOS_PARAMETERS) +#endif + +#if (NDIS_SUPPORT_NDIS680) + /* RSSv2 OIDS*/ + MAKECASE(OID_GEN_RSS_SET_INDIRECTION_TABLE_ENTRIES) + MAKECASE(OID_GEN_RECEIVE_SCALE_PARAMETERS_V2) +#endif + } + + if (oidName) + { + DbgPrintF(MP_LOUD, "%s", oidName); + } + else + { + DbgPrintF(MP_LOUD, "<** Unknown OID 0x%08x **>.", Oid); + } +} + +VOID +DbgPrintAddress( + _In_reads_bytes_(ETH_LENGTH_OF_ADDRESS) PUCHAR Address) +{ + // If your MAC address has a different size, adjust the printf accordingly. + //{ASSERT(ETH_LENGTH_OF_ADDRESS == 6); } + + DbgPrintF(MP_LOUD, "%02x-%02x-%02x-%02x-%02x-%02x.", + Address[0], Address[1], Address[2], + Address[3], Address[4], Address[5]); +} +#endif + +#elif defined(LINUX) + +#elif defined(UBOOT) +#ifdef DBG +u32 MPDebugLevel = MP_LOUD; +#endif +#else + +#endif + diff --git a/drivers/net/ethernet/motorcomm/fuxi-dbg.h b/drivers/net/ethernet/motorcomm/fuxi-dbg.h new file mode 100644 index 000000000000..a8c42369e783 --- /dev/null +++ b/drivers/net/ethernet/motorcomm/fuxi-dbg.h @@ -0,0 +1,24 @@ +/*++ + +Copyright (c) 2021 Motorcomm Corporation. +Confidential and Proprietary. All rights reserved. + +This is Motorcomm Corporation NIC driver relevant files. Please don't copy, modify, +distribute without commercial permission. + +--*/ + +#ifndef _MP_DBG_H +#define _MP_DBG_H + +// +// Message verbosity: lower values indicate higher urgency +// +#define MP_OFF 0 +#define MP_ERROR 1 +#define MP_WARN 2 +#define MP_TRACE 3 +#define MP_INFO 4 +#define MP_LOUD 5 + +#endif // _MP_DBG_H \ No newline at end of file diff --git a/drivers/net/ethernet/motorcomm/fuxi-efuse.c b/drivers/net/ethernet/motorcomm/fuxi-efuse.c new file mode 100644 index 000000000000..a91734fd84d7 --- /dev/null +++ b/drivers/net/ethernet/motorcomm/fuxi-efuse.c @@ -0,0 +1,968 @@ + +/*++ + +Copyright (c) 2021 Motorcomm Corporation. +Confidential and Proprietary. All rights reserved. + +This is Motorcomm Corporation 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" + +#ifdef UEFI +#include "nic_sw.h" +#endif + +bool fxgmac_read_patch_from_efuse_per_index(struct fxgmac_pdata* pdata, u8 index, u32* offset, u32* value) /* read patch per index. */ +{ + unsigned int wait, i; + u32 regval = 0; + bool succeed = false; + + if (index >= FUXI_EFUSE_MAX_ENTRY) { + FXGMAC_PR("Reading efuse out of range, index %d\n", index); + return false; + } + + if (offset) { + *offset = 0; + } + for (i = EFUSE_PATCH_ADDR_START_BYTE; i < EFUSE_PATCH_DATA_START_BYTE; i++) { + regval = 0; + regval = FXGMAC_SET_REG_BITS(regval, EFUSE_OP_ADDR_POS, EFUSE_OP_ADDR_LEN, EFUSE_REGION_A_B_LENGTH + index * EFUSE_EACH_PATH_SIZE + i); + regval = FXGMAC_SET_REG_BITS(regval, EFUSE_OP_START_POS, EFUSE_OP_START_LEN, 1); + regval = FXGMAC_SET_REG_BITS(regval, EFUSE_OP_MODE_POS, EFUSE_OP_MODE_LEN, EFUSE_OP_MODE_ROW_READ); + writereg(pdata->pAdapter, regval, pdata->base_mem + EFUSE_OP_CTRL_0); + wait = 1000; + while (wait--) { + usleep_range_ex(pdata->pAdapter, 20, 50); + regval = readreg(pdata->pAdapter, pdata->base_mem + EFUSE_OP_CTRL_1); + if (FXGMAC_GET_REG_BITS(regval, EFUSE_OP_DONE_POS, EFUSE_OP_DONE_LEN)) { + succeed = true; + break; + } + } + if (succeed) { + if (offset) { + *offset |= (FXGMAC_GET_REG_BITS(regval, EFUSE_OP_RD_DATA_POS, EFUSE_OP_RD_DATA_LEN) << (i << 3)); + } + } + else { + FXGMAC_PR("Fail to reading efuse Byte%d\n", index * EFUSE_EACH_PATH_SIZE + i); + return succeed; + } + } + + if (value) { + *value = 0; + } + for (i = EFUSE_PATCH_DATA_START_BYTE; i < EFUSE_EACH_PATH_SIZE; i++) { + regval = 0; + regval = FXGMAC_SET_REG_BITS(regval, EFUSE_OP_ADDR_POS, EFUSE_OP_ADDR_LEN, EFUSE_REGION_A_B_LENGTH + index * EFUSE_EACH_PATH_SIZE + i); + regval = FXGMAC_SET_REG_BITS(regval, EFUSE_OP_START_POS, EFUSE_OP_START_LEN, 1); + regval = FXGMAC_SET_REG_BITS(regval, EFUSE_OP_MODE_POS, EFUSE_OP_MODE_LEN, EFUSE_OP_MODE_ROW_READ); + writereg(pdata->pAdapter, regval, pdata->base_mem + EFUSE_OP_CTRL_0); + wait = 1000; + while (wait--) { + usleep_range_ex(pdata->pAdapter, 20, 50); + regval = readreg(pdata->pAdapter, pdata->base_mem + EFUSE_OP_CTRL_1); + if (FXGMAC_GET_REG_BITS(regval, EFUSE_OP_DONE_POS, EFUSE_OP_DONE_LEN)) { + succeed = true; + break; + } + } + if (succeed) { + if (value) { + *value |= (FXGMAC_GET_REG_BITS(regval, EFUSE_OP_RD_DATA_POS, EFUSE_OP_RD_DATA_LEN) << ((i - 2) << 3)); + } + } + else { + FXGMAC_PR("Fail to reading efuse Byte%d\n", index * EFUSE_EACH_PATH_SIZE + i); + return succeed; + } + } + + return succeed; +} + +bool fxgmac_read_patch_from_efuse(struct fxgmac_pdata* pdata, u32 offset, u32* value) /* read patch per index. */ +{ + u32 reg_offset, reg_val; + u32 cur_val = 0; + bool succeed = true; + u8 index = 0; + + if(offset >> 16){ + FXGMAC_PR("Reading efuse out of range, reg %d. reg must be 2bytes.\n", index); + return false; + } + + for (index = 0; index < FUXI_EFUSE_MAX_ENTRY; index++) { + if (!fxgmac_read_patch_from_efuse_per_index(pdata, index, ®_offset, ®_val)) { + succeed = false; + break; + } else if (reg_offset == offset) { + cur_val = reg_val; + } else if (0 == reg_offset && 0 == reg_val) { + break; // first blank. We should write here. + } + } + + if (value) { + *value = cur_val; + } + + return succeed; +} + +bool fxgmac_write_patch_to_efuse_per_index(struct fxgmac_pdata* pdata, u8 index, u32 offset, u32 value) +{ + unsigned int wait, i; + u32 reg_val; + bool succeed = false; + u32 cur_reg, cur_val; + u8 max_index = FUXI_EFUSE_MAX_ENTRY; + + if(offset >> 16){ + FXGMAC_PR("Reading efuse out of range, reg %d. reg must be 2bytes.\n", index); + return false; + } + + fxgmac_efuse_read_data(pdata, EFUSE_LED_ADDR, ®_val); + if (EFUSE_LED_COMMON_SOLUTION == reg_val) { + max_index = FUXI_EFUSE_MAX_ENTRY_UNDER_LED_COMMON; + } + + if (index >= max_index) { + FXGMAC_PR("Writing efuse out of range, index %d max index %d\n", index, max_index); + return false; + } + + if (fxgmac_read_patch_from_efuse_per_index(pdata, index, &cur_reg, &cur_val)) { + if(cur_reg != 0 || cur_val != 0){ + FXGMAC_PR(" The index %d has writed value, cannot rewrite it.\n", index); + return false; + } + }else{ + FXGMAC_PR("Cannot read index %d.\n", index); + return false; + } + + for (i = EFUSE_PATCH_ADDR_START_BYTE; i < EFUSE_PATCH_DATA_START_BYTE; i++) { + reg_val = 0; + reg_val = FXGMAC_SET_REG_BITS(reg_val, EFUSE_OP_ADDR_POS, EFUSE_OP_ADDR_LEN, EFUSE_REGION_A_B_LENGTH + index * EFUSE_EACH_PATH_SIZE + i); + reg_val = FXGMAC_SET_REG_BITS(reg_val, EFUSE_OP_WR_DATA_POS, EFUSE_OP_WR_DATA_LEN, (offset >> (i << 3)) & 0xFF); + reg_val = FXGMAC_SET_REG_BITS(reg_val, EFUSE_OP_START_POS, EFUSE_OP_START_LEN, 1); + reg_val = FXGMAC_SET_REG_BITS(reg_val, EFUSE_OP_MODE_POS, EFUSE_OP_MODE_LEN, EFUSE_OP_MODE_ROW_WRITE); + writereg(pdata->pAdapter, reg_val, pdata->base_mem + EFUSE_OP_CTRL_0); + + succeed = false; + wait = 1000; + while (wait--) { + usleep_range_ex(pdata->pAdapter, 20, 50); + reg_val = readreg(pdata->pAdapter, pdata->base_mem + EFUSE_OP_CTRL_1); + if (FXGMAC_GET_REG_BITS(reg_val, EFUSE_OP_DONE_POS, EFUSE_OP_DONE_LEN)) { + succeed = true; + break; + } + } + if (!succeed) { + FXGMAC_PR("Fail to writing efuse Byte%d\n", index * EFUSE_EACH_PATH_SIZE + i); + return succeed; + } + } + + for (i = 2; i < 6; i++) { + reg_val = 0; + reg_val = FXGMAC_SET_REG_BITS(reg_val, EFUSE_OP_ADDR_POS, EFUSE_OP_ADDR_LEN, 18 + index * 6 + i); + reg_val = FXGMAC_SET_REG_BITS(reg_val, EFUSE_OP_WR_DATA_POS, EFUSE_OP_WR_DATA_LEN, (value >> ((i - 2) << 3)) & 0xFF); + reg_val = FXGMAC_SET_REG_BITS(reg_val, EFUSE_OP_START_POS, EFUSE_OP_START_LEN, 1); + reg_val = FXGMAC_SET_REG_BITS(reg_val, EFUSE_OP_MODE_POS, EFUSE_OP_MODE_LEN, EFUSE_OP_MODE_ROW_WRITE); + writereg(pdata->pAdapter, reg_val, pdata->base_mem + EFUSE_OP_CTRL_0); + + succeed = false; + wait = 1000; + while (wait--) { + usleep_range_ex(pdata->pAdapter, 20, 50); + reg_val = readreg(pdata->pAdapter, pdata->base_mem + EFUSE_OP_CTRL_1); + if (FXGMAC_GET_REG_BITS(reg_val, EFUSE_OP_DONE_POS, EFUSE_OP_DONE_LEN)) { + succeed = true; + break; + } + } + if (!succeed) { + FXGMAC_PR("Fail to writing efuse Byte%d\n", index * EFUSE_EACH_PATH_SIZE + i); + return succeed; + } + } + + return succeed; +} + +bool fxgmac_write_patch_to_efuse(struct fxgmac_pdata* pdata, u32 offset, u32 value) +{ + unsigned int wait, i; + u32 reg_offset, reg_val; + u32 cur_offset = 0, cur_val = 0; + bool succeed = false; + u8 index = 0; + + if(offset >> 16){ + FXGMAC_PR("Reading efuse out of range, reg %d. reg must be 2bytes.\n", index); + return false; + } + + for (index = 0; ; index++) { + if (!fxgmac_read_patch_from_efuse_per_index(pdata, index, ®_offset, ®_val)) { + return false; + } else if (reg_offset == offset) { + cur_offset = reg_offset; + cur_val = reg_val; + } else if (0 == reg_offset && 0 == reg_val) { + break; // first blank. We should write here. + } + } + + if (cur_offset == offset) { + if (cur_val == value) { + FXGMAC_PR("0x%x -> Reg0x%x already exists, ignore.\n", value, offset); + return true; + } else { + FXGMAC_PR("Reg0x%x entry current value 0x%x, reprogram.\n", offset, value); + } + } + + for (i = EFUSE_PATCH_ADDR_START_BYTE; i < EFUSE_PATCH_DATA_START_BYTE; i++) { + reg_val = 0; + reg_val = FXGMAC_SET_REG_BITS(reg_val, EFUSE_OP_ADDR_POS, EFUSE_OP_ADDR_LEN, EFUSE_REGION_A_B_LENGTH + index * EFUSE_EACH_PATH_SIZE + i); + reg_val = FXGMAC_SET_REG_BITS(reg_val, EFUSE_OP_WR_DATA_POS, EFUSE_OP_WR_DATA_LEN, (offset >> (i << 3)) & 0xFF ); + reg_val = FXGMAC_SET_REG_BITS(reg_val, EFUSE_OP_START_POS, EFUSE_OP_START_LEN, 1); + reg_val = FXGMAC_SET_REG_BITS(reg_val, EFUSE_OP_MODE_POS, EFUSE_OP_MODE_LEN, EFUSE_OP_MODE_ROW_WRITE); + writereg(pdata->pAdapter, reg_val, pdata->base_mem + EFUSE_OP_CTRL_0); + + succeed = false; + wait = 1000; + while (wait--) { + usleep_range_ex(pdata->pAdapter, 20, 50); + reg_val = readreg(pdata->pAdapter, pdata->base_mem + EFUSE_OP_CTRL_1); + if (FXGMAC_GET_REG_BITS(reg_val, EFUSE_OP_DONE_POS, EFUSE_OP_DONE_LEN)) { + succeed = true; + break; + } + } + if (!succeed) { + FXGMAC_PR("Fail to writing efuse Byte%d\n", index * EFUSE_EACH_PATH_SIZE + i); + return succeed; + } + } + + for (i = EFUSE_PATCH_DATA_START_BYTE; i < EFUSE_EACH_PATH_SIZE; i++) { + reg_val = 0; + reg_val = FXGMAC_SET_REG_BITS(reg_val, EFUSE_OP_ADDR_POS, EFUSE_OP_ADDR_LEN, EFUSE_REGION_A_B_LENGTH + index * EFUSE_EACH_PATH_SIZE + i); + reg_val = FXGMAC_SET_REG_BITS(reg_val, EFUSE_OP_WR_DATA_POS, EFUSE_OP_WR_DATA_LEN, (value >> ((i - 2) << 3)) & 0xFF); + reg_val = FXGMAC_SET_REG_BITS(reg_val, EFUSE_OP_START_POS, EFUSE_OP_START_LEN, 1); + reg_val = FXGMAC_SET_REG_BITS(reg_val, EFUSE_OP_MODE_POS, EFUSE_OP_MODE_LEN, EFUSE_OP_MODE_ROW_WRITE); + writereg(pdata->pAdapter, reg_val, pdata->base_mem + EFUSE_OP_CTRL_0); + + succeed = false; + wait = 1000; + while (wait--) { + usleep_range_ex(pdata->pAdapter, 20, 50); + reg_val = readreg(pdata->pAdapter, pdata->base_mem + EFUSE_OP_CTRL_1); + if (FXGMAC_GET_REG_BITS(reg_val, EFUSE_OP_DONE_POS, EFUSE_OP_DONE_LEN)) { + succeed = true; + break; + } + } + if (!succeed) { + FXGMAC_PR("Fail to writing efuse Byte%d\n", index * EFUSE_EACH_PATH_SIZE + i); + return succeed; + } + } + + return succeed; +} + +bool fxgmac_read_mac_subsys_from_efuse(struct fxgmac_pdata* pdata, u8* mac_addr, u32* subsys, u32* revid) +{ + u32 offset = 0, value = 0; + u32 machr = 0, maclr = 0; + bool succeed = true; + u8 index = 0; + + for (index = 0; ; index++) { + if (!fxgmac_read_patch_from_efuse_per_index(pdata, index, &offset, &value)) { + succeed = false; + break; // reach the last item. + } + if (0x00 == offset) { + break; // reach the blank. + } + if (MACA0LR_FROM_EFUSE == offset) { + maclr = value; + } + if (MACA0HR_FROM_EFUSE == offset) { + machr = value; + } + + if ((0x08 == offset) && revid) { + *revid = value; + } + if ((0x2C == offset) && subsys) { + *subsys = value; + } + } + if (mac_addr) { + mac_addr[5] = (u8)(maclr & 0xFF); + mac_addr[4] = (u8)((maclr >> 8) & 0xFF); + mac_addr[3] = (u8)((maclr >> 16) & 0xFF); + mac_addr[2] = (u8)((maclr >> 24) & 0xFF); + mac_addr[1] = (u8)(machr & 0xFF); + mac_addr[0] = (u8)((machr >> 8) & 0xFF); + } + + return succeed; +} + +bool fxgmac_write_mac_subsys_to_efuse(struct fxgmac_pdata* pdata, u8* mac_addr, u32* subsys, u32* revid) +{ + u32 machr = 0, maclr = 0,pcie_cfg_ctrl= PCIE_CFG_CTRL_DEFAULT_VAL; + bool succeed = true; + if (mac_addr) { + machr = readreg(pdata->pAdapter, pdata->base_mem + MACA0HR_FROM_EFUSE); + maclr = readreg(pdata->pAdapter, pdata->base_mem + MACA0LR_FROM_EFUSE); + DPRINTK("Current mac address from efuse is %02x-%02x-%02x-%02x-%02x-%02x.\n", + (machr >> 8) & 0xFF, machr & 0xFF, (maclr >> 24) & 0xFF, (maclr >> 16) & 0xFF, (maclr >> 8) & 0xFF, maclr & 0xFF); + + if(!fxgmac_write_patch_to_efuse(pdata, MACA0HR_FROM_EFUSE, (((u32)mac_addr[0]) << 8) | mac_addr[1])){ + succeed = false; + } + if(!fxgmac_write_patch_to_efuse(pdata, MACA0LR_FROM_EFUSE, (((u32)mac_addr[2]) << 24) | (((u32)mac_addr[3]) << 16) | (((u32)mac_addr[4]) << 8) | mac_addr[5])){ + succeed = false; + } + } + + if (revid) { + if(!fxgmac_write_patch_to_efuse(pdata, EFUSE_REVID_REGISTER, *revid)){ + succeed = false; + } + } + if (subsys) { + pcie_cfg_ctrl = FXGMAC_SET_REG_BITS(pcie_cfg_ctrl, MGMT_PCIE_CFG_CTRL_CS_EN_POS, MGMT_PCIE_CFG_CTRL_CS_EN_LEN, 1); + if (!fxgmac_write_patch_to_efuse(pdata, MGMT_PCIE_CFG_CTRL, pcie_cfg_ctrl)){ + succeed = false; + } + if(!fxgmac_write_patch_to_efuse(pdata, EFUSE_SUBSYS_REGISTER, *subsys)){ + succeed = false; + } + pcie_cfg_ctrl = FXGMAC_SET_REG_BITS(pcie_cfg_ctrl, MGMT_PCIE_CFG_CTRL_CS_EN_POS, MGMT_PCIE_CFG_CTRL_CS_EN_LEN, 0); + if (!fxgmac_write_patch_to_efuse(pdata, MGMT_PCIE_CFG_CTRL, pcie_cfg_ctrl)){ + succeed = false; + } + } + return succeed; +} + +bool fxgmac_write_mac_addr_to_efuse(struct fxgmac_pdata* pdata, u8* mac_addr) +{ + u32 machr = 0, maclr = 0; + bool succeed = true; + + if (mac_addr) { + machr = readreg(pdata->pAdapter, pdata->base_mem + MACA0HR_FROM_EFUSE); + maclr = readreg(pdata->pAdapter, pdata->base_mem + MACA0LR_FROM_EFUSE); + DPRINTK("Current mac address from efuse is %02x-%02x-%02x-%02x-%02x-%02x.\n", + (machr >> 8) & 0xFF, machr & 0xFF, (maclr >> 24) & 0xFF, (maclr >> 16) & 0xFF, (maclr >> 8) & 0xFF, maclr & 0xFF); + + if(!fxgmac_write_patch_to_efuse(pdata, MACA0HR_FROM_EFUSE, (((u32)mac_addr[0]) << 8) | mac_addr[1])){ + succeed = false; + } + if(!fxgmac_write_patch_to_efuse(pdata, MACA0LR_FROM_EFUSE, (((u32)mac_addr[2]) << 24) | (((u32)mac_addr[3]) << 16) | (((u32)mac_addr[4]) << 8) | mac_addr[5])){ + succeed = false; + } + } + + return succeed; +} + +bool fxgmac_read_subsys_from_efuse(struct fxgmac_pdata* pdata, u32* subsys, u32* revid) +{ + u32 offset = 0, value = 0; + u8 index; + bool succeed = true; + + for (index = 0; ; index++) { + if (!fxgmac_read_patch_from_efuse_per_index(pdata, index, &offset, &value)) { + succeed = false; + break; // reach the last item. + } + if (0x00 == offset) { + break; // reach the blank. + } + + if ((EFUSE_REVID_REGISTER == offset) && revid) { + *revid = value; + }else{ + succeed = false; + } + if ((EFUSE_SUBSYS_REGISTER == offset) && subsys) { + *subsys = value; + }else{ + succeed = false; + } + } + + return succeed; +} + +bool fxgmac_write_subsys_to_efuse(struct fxgmac_pdata* pdata, u32* subsys, u32* revid) +{ + bool succeed = true; + + /* write subsys info */ + if (revid) { + if(!fxgmac_write_patch_to_efuse(pdata, EFUSE_REVID_REGISTER, *revid)){ + succeed = false; + } + } + if (subsys) { + if(!fxgmac_write_patch_to_efuse(pdata, EFUSE_SUBSYS_REGISTER, *subsys)){ + succeed = false; + } + } + return succeed; +} + +bool fxgmac_efuse_load(struct fxgmac_pdata* pdata) +{ + bool succeed = false; + unsigned int wait; + u32 reg_val = 0; + reg_val = FXGMAC_SET_REG_BITS(reg_val, EFUSE_OP_START_POS, EFUSE_OP_START_LEN, 1); + reg_val = FXGMAC_SET_REG_BITS(reg_val, EFUSE_OP_MODE_POS, EFUSE_OP_MODE_LEN, EFUSE_OP_MODE_AUTO_LOAD); + writereg(pdata->pAdapter, reg_val, pdata->base_mem + EFUSE_OP_CTRL_0); + + wait = 1000; + while (wait--) { + usleep_range_ex(pdata->pAdapter, 20, 50); + reg_val = readreg(pdata->pAdapter, pdata->base_mem + EFUSE_OP_CTRL_1); + if (FXGMAC_GET_REG_BITS(reg_val, EFUSE_OP_DONE_POS, EFUSE_OP_DONE_LEN)) { + succeed = true; + break; + } + } + if (!succeed) { + FXGMAC_PR("Fail to loading efuse, ctrl_1 0x%08x\n", reg_val); + } + return succeed; +} + +bool fxgmac_efuse_read_data(struct fxgmac_pdata* pdata, u32 offset, u32* value) +{ + bool succeed = false; + unsigned int wait; + u32 reg_val = 0; + + //if (reg >= EFUSE_REGION_A_B_LENGTH) { + // FXGMAC_PR("Read addr out of range %d", reg); + // return succeed; + //} + + if (value) { + *value = 0; + } + + reg_val = FXGMAC_SET_REG_BITS(reg_val, EFUSE_OP_ADDR_POS, EFUSE_OP_ADDR_LEN, offset); + reg_val = FXGMAC_SET_REG_BITS(reg_val, EFUSE_OP_START_POS, EFUSE_OP_START_LEN, 1); + reg_val = FXGMAC_SET_REG_BITS(reg_val, EFUSE_OP_MODE_POS, EFUSE_OP_MODE_LEN, EFUSE_OP_MODE_ROW_READ); + writereg(pdata->pAdapter, reg_val, pdata->base_mem + EFUSE_OP_CTRL_0); + wait = 1000; + while (wait--) { + usleep_range_ex(pdata->pAdapter, 20, 50); + reg_val = readreg(pdata->pAdapter, pdata->base_mem + EFUSE_OP_CTRL_1); + if (FXGMAC_GET_REG_BITS(reg_val, EFUSE_OP_DONE_POS, EFUSE_OP_DONE_LEN)) { + succeed = true; + break; + } + } + + if (succeed) { + if (value) { + *value = FXGMAC_GET_REG_BITS(reg_val, EFUSE_OP_RD_DATA_POS, EFUSE_OP_RD_DATA_LEN); + } + } + else { + FXGMAC_PR("Fail to reading efuse Byte%d\n", offset); + } + + return succeed; +} + +bool fxgmac_efuse_write_oob(struct fxgmac_pdata* pdata) +{ + bool succeed = false; + unsigned int wait; + u32 reg_val, value; + + if (!fxgmac_efuse_read_data(pdata, EFUSE_OOB_ADDR, ®_val)) { + return succeed; + } + + if (FXGMAC_GET_REG_BITS(reg_val, EFUSE_OOB_POS, EFUSE_OOB_LEN)) { + FXGMAC_PR("OOB Ctrl bit already exists"); + return true; + } + + value = 0; + value = FXGMAC_SET_REG_BITS(value, EFUSE_OOB_POS, EFUSE_OOB_LEN, 1); + + reg_val = 0; + reg_val = FXGMAC_SET_REG_BITS(reg_val, EFUSE_OP_ADDR_POS, EFUSE_OP_ADDR_LEN, EFUSE_OOB_ADDR); + reg_val = FXGMAC_SET_REG_BITS(reg_val, EFUSE_OP_WR_DATA_POS, EFUSE_OP_WR_DATA_LEN, value & 0xFF); + reg_val = FXGMAC_SET_REG_BITS(reg_val, EFUSE_OP_START_POS, EFUSE_OP_START_LEN, 1); + reg_val = FXGMAC_SET_REG_BITS(reg_val, EFUSE_OP_MODE_POS, EFUSE_OP_MODE_LEN, EFUSE_OP_MODE_ROW_WRITE); + writereg(pdata->pAdapter, reg_val, pdata->base_mem + EFUSE_OP_CTRL_0); + + wait = 1000; + while (wait--) { + usleep_range_ex(pdata->pAdapter, 20, 50); + reg_val = readreg(pdata->pAdapter, pdata->base_mem + EFUSE_OP_CTRL_1); + if (FXGMAC_GET_REG_BITS(reg_val, EFUSE_OP_DONE_POS, EFUSE_OP_DONE_LEN)) { + succeed = true; + break; + } + } + + if (!succeed) { + FXGMAC_PR("Fail to writing efuse Byte OOB"); + } + + return succeed; +} + +bool fxgmac_efuse_write_led(struct fxgmac_pdata* pdata, u32 value) +{ + bool succeed = false; + unsigned int wait; + u32 reg_val; + + if (!fxgmac_efuse_read_data(pdata, EFUSE_LED_ADDR, ®_val)) { + return succeed; + } + + if (reg_val == value) { + FXGMAC_PR("Led Ctrl option already exists"); + return true; + } + + reg_val = 0; + reg_val = FXGMAC_SET_REG_BITS(reg_val, EFUSE_OP_ADDR_POS, EFUSE_OP_ADDR_LEN, EFUSE_LED_ADDR); + reg_val = FXGMAC_SET_REG_BITS(reg_val, EFUSE_OP_WR_DATA_POS, EFUSE_OP_WR_DATA_LEN, value & 0xFF); + reg_val = FXGMAC_SET_REG_BITS(reg_val, EFUSE_OP_START_POS, EFUSE_OP_START_LEN, 1); + reg_val = FXGMAC_SET_REG_BITS(reg_val, EFUSE_OP_MODE_POS, EFUSE_OP_MODE_LEN, EFUSE_OP_MODE_ROW_WRITE); + writereg(pdata->pAdapter, reg_val, pdata->base_mem + EFUSE_OP_CTRL_0); + + wait = 1000; + while (wait--) { + usleep_range_ex(pdata->pAdapter, 20, 50); + reg_val = readreg(pdata->pAdapter, pdata->base_mem + EFUSE_OP_CTRL_1); + if (FXGMAC_GET_REG_BITS(reg_val, EFUSE_OP_DONE_POS, EFUSE_OP_DONE_LEN)) { + succeed = true; + break; + } + } + + if (!succeed) { + FXGMAC_PR("Fail to writing efuse Byte LED"); + } + + return succeed; +} + +bool fxgmac_efuse_write_data(struct fxgmac_pdata* pdata, u32 offset, u32 value) +{ + bool succeed = false; + unsigned int wait; + u32 reg_val; + + if (!fxgmac_efuse_read_data(pdata, offset, ®_val)) { + return succeed; + } + + if (reg_val == value) { + FXGMAC_PR("offset 0x%x already exists", offset); + return true; + } + + reg_val = 0; + reg_val = FXGMAC_SET_REG_BITS(reg_val, EFUSE_OP_ADDR_POS, EFUSE_OP_ADDR_LEN, offset & 0xFF); + reg_val = FXGMAC_SET_REG_BITS(reg_val, EFUSE_OP_WR_DATA_POS, EFUSE_OP_WR_DATA_LEN, value & 0xFF); + reg_val = FXGMAC_SET_REG_BITS(reg_val, EFUSE_OP_START_POS, EFUSE_OP_START_LEN, 1); + reg_val = FXGMAC_SET_REG_BITS(reg_val, EFUSE_OP_MODE_POS, EFUSE_OP_MODE_LEN, EFUSE_OP_MODE_ROW_WRITE); + writereg(pdata->pAdapter, reg_val, pdata->base_mem + EFUSE_OP_CTRL_0); + + wait = 1000; + while (wait--) { + usleep_range_ex(pdata->pAdapter, 20, 50); + reg_val = readreg(pdata->pAdapter, pdata->base_mem + EFUSE_OP_CTRL_1); + if (FXGMAC_GET_REG_BITS(reg_val, EFUSE_OP_DONE_POS, EFUSE_OP_DONE_LEN)) { + succeed = true; + break; + } + } + + if (!succeed) { + FXGMAC_PR("Fail to writing efuse 0x%x Byte LED", offset); + } + + return succeed; +} + +static void fxgmac_read_led_efuse_config(struct fxgmac_pdata* pdata, struct led_setting* pfirst, struct led_setting* psecond) +{ + u32 val_high = 0, val_low = 0; + + //read first area + fxgmac_efuse_read_data(pdata, EFUSE_FISRT_UPDATE_ADDR, &val_high); + fxgmac_efuse_read_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 1), &val_low); + pfirst->disable_led_setting[4] = ((val_high << 8) + val_low); + + fxgmac_efuse_read_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 2), &val_high); + fxgmac_efuse_read_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 3), &val_low); + pfirst->disable_led_setting[3] = ((val_high << 8) + val_low); + + fxgmac_efuse_read_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 4), &val_high); + fxgmac_efuse_read_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 5), &val_low); + pfirst->disable_led_setting[2] = ((val_high << 8) + val_low); + + fxgmac_efuse_read_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 6), &val_high); + fxgmac_efuse_read_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 7), &val_low); + pfirst->disable_led_setting[1] = ((val_high << 8) + val_low); + + fxgmac_efuse_read_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 8), &val_high); + fxgmac_efuse_read_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 9), &val_low); + pfirst->disable_led_setting[0] = ((val_high << 8) + val_low); + + fxgmac_efuse_read_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 10), &val_high); + fxgmac_efuse_read_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 11), &val_low); + pfirst->s5_led_setting[4] = ((val_high << 8) + val_low); + + fxgmac_efuse_read_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 12), &val_high); + fxgmac_efuse_read_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 13), &val_low); + pfirst->s5_led_setting[3] = ((val_high << 8) + val_low); + + fxgmac_efuse_read_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 14), &val_high); + fxgmac_efuse_read_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 15), &val_low); + pfirst->s5_led_setting[2] = ((val_high << 8) + val_low); + + fxgmac_efuse_read_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 16), &val_high); + fxgmac_efuse_read_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 17), &val_low); + pfirst->s5_led_setting[1] = ((val_high << 8) + val_low); + + fxgmac_efuse_read_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 18), &val_high); + fxgmac_efuse_read_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 19), &val_low); + pfirst->s5_led_setting[0] = ((val_high << 8) + val_low); + + fxgmac_efuse_read_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 20), &val_high); + fxgmac_efuse_read_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 21), &val_low); + pfirst->s3_led_setting[4] = ((val_high << 8) + val_low); + + fxgmac_efuse_read_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 22), &val_high); + fxgmac_efuse_read_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 23), &val_low); + pfirst->s3_led_setting[3] = ((val_high << 8) + val_low); + + fxgmac_efuse_read_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 24), &val_high); + fxgmac_efuse_read_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 25), &val_low); + pfirst->s3_led_setting[2] = ((val_high << 8) + val_low); + + fxgmac_efuse_read_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 26), &val_high); + fxgmac_efuse_read_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 27), &val_low); + pfirst->s3_led_setting[1] = ((val_high << 8) + val_low); + + fxgmac_efuse_read_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 28), &val_high); + fxgmac_efuse_read_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 29), &val_low); + pfirst->s3_led_setting[0] = ((val_high << 8) + val_low); + + fxgmac_efuse_read_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 30), &val_high); + fxgmac_efuse_read_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 31), &val_low); + pfirst->s0_led_setting[4] = ((val_high << 8) + val_low); + + fxgmac_efuse_read_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 32), &val_high); + fxgmac_efuse_read_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 33), &val_low); + pfirst->s0_led_setting[3] = ((val_high << 8) + val_low); + + fxgmac_efuse_read_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 34), &val_high); + fxgmac_efuse_read_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 35), &val_low); + pfirst->s0_led_setting[2] = ((val_high << 8) + val_low); + + fxgmac_efuse_read_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 36), &val_high); + fxgmac_efuse_read_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 37), &val_low); + pfirst->s0_led_setting[1] = ((val_high << 8) + val_low); + + fxgmac_efuse_read_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 38), &val_high); + fxgmac_efuse_read_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 39), &val_low); + pfirst->s0_led_setting[0] = ((val_high << 8) + val_low); + + //read second area + fxgmac_efuse_read_data(pdata, EFUSE_SECOND_UPDATE_ADDR, &val_high); + fxgmac_efuse_read_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 1), &val_low); + psecond->disable_led_setting[4] = ((val_high << 8) + val_low); + + fxgmac_efuse_read_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 2), &val_high); + fxgmac_efuse_read_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 3), &val_low); + psecond->disable_led_setting[3] = ((val_high << 8) + val_low); + + fxgmac_efuse_read_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 4), &val_high); + fxgmac_efuse_read_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 5), &val_low); + psecond->disable_led_setting[2] = ((val_high << 8) + val_low); + + fxgmac_efuse_read_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 6), &val_high); + fxgmac_efuse_read_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 7), &val_low); + psecond->disable_led_setting[1] = ((val_high << 8) + val_low); + + fxgmac_efuse_read_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 8), &val_high); + fxgmac_efuse_read_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 9), &val_low); + psecond->disable_led_setting[0] = ((val_high << 8) + val_low); + + fxgmac_efuse_read_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 10), &val_high); + fxgmac_efuse_read_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 11), &val_low); + psecond->s5_led_setting[4] = ((val_high << 8) + val_low); + + fxgmac_efuse_read_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 12), &val_high); + fxgmac_efuse_read_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 13), &val_low); + psecond->s5_led_setting[3] = ((val_high << 8) + val_low); + + fxgmac_efuse_read_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 14), &val_high); + fxgmac_efuse_read_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 15), &val_low); + psecond->s5_led_setting[2] = ((val_high << 8) + val_low); + + fxgmac_efuse_read_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 16), &val_high); + fxgmac_efuse_read_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 17), &val_low); + psecond->s5_led_setting[1] = ((val_high << 8) + val_low); + + fxgmac_efuse_read_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 18), &val_high); + fxgmac_efuse_read_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 19), &val_low); + psecond->s5_led_setting[0] = ((val_high << 8) + val_low); + + fxgmac_efuse_read_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 20), &val_high); + fxgmac_efuse_read_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 21), &val_low); + psecond->s3_led_setting[4] = ((val_high << 8) + val_low); + + fxgmac_efuse_read_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 22), &val_high); + fxgmac_efuse_read_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 23), &val_low); + psecond->s3_led_setting[3] = ((val_high << 8) + val_low); + + fxgmac_efuse_read_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 24), &val_high); + fxgmac_efuse_read_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 25), &val_low); + psecond->s3_led_setting[2] = ((val_high << 8) + val_low); + + fxgmac_efuse_read_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 26), &val_high); + fxgmac_efuse_read_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 27), &val_low); + psecond->s3_led_setting[1] = ((val_high << 8) + val_low); + + fxgmac_efuse_read_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 28), &val_high); + fxgmac_efuse_read_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 29), &val_low); + psecond->s3_led_setting[0] = ((val_high << 8) + val_low); + + fxgmac_efuse_read_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 30), &val_high); + fxgmac_efuse_read_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 31), &val_low); + psecond->s0_led_setting[4] = ((val_high << 8) + val_low); + + fxgmac_efuse_read_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 32), &val_high); + fxgmac_efuse_read_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 33), &val_low); + psecond->s0_led_setting[3] = ((val_high << 8) + val_low); + + fxgmac_efuse_read_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 34), &val_high); + fxgmac_efuse_read_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 35), &val_low); + psecond->s0_led_setting[2] = ((val_high << 8) + val_low); + + fxgmac_efuse_read_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 36), &val_high); + fxgmac_efuse_read_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 37), &val_low); + psecond->s0_led_setting[1] = ((val_high << 8) + val_low); + + fxgmac_efuse_read_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 38), &val_high); + fxgmac_efuse_read_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 39), &val_low); + psecond->s0_led_setting[0] = ((val_high << 8) + val_low); +} + +bool fxgmac_write_led_setting_to_efuse(struct fxgmac_pdata* pdata) +{ + struct led_setting led_config_first; + struct led_setting led_config_second; + bool bfirstflag = false, bsecondflag = false; + bool bsucceed = false; + + fxgmac_read_led_efuse_config(pdata, &led_config_first, &led_config_second); + + if (0x00 == led_config_first.s0_led_setting[0] && 0x00 == led_config_first.s0_led_setting[1] && 0x00 == led_config_first.s0_led_setting[2] && 0x00 == led_config_first.s0_led_setting[3] && 0x00 == led_config_first.s0_led_setting[4] + && 0x00 == led_config_first.s3_led_setting[0] && 0x00 == led_config_first.s3_led_setting[1] && 0x00 == led_config_first.s3_led_setting[2] && 0x00 == led_config_first.s3_led_setting[3] && 0x00 == led_config_first.s3_led_setting[4] + && 0x00 == led_config_first.s5_led_setting[0] && 0x00 == led_config_first.s5_led_setting[1] && 0x00 == led_config_first.s5_led_setting[2] && 0x00 == led_config_first.s5_led_setting[3] && 0x00 == led_config_first.s5_led_setting[4] + && 0x00 == led_config_first.disable_led_setting[0] && 0x00 == led_config_first.disable_led_setting[1] && 0x00 == led_config_first.disable_led_setting[2] && 0x00 == led_config_first.disable_led_setting[3] && 0x00 == led_config_first.disable_led_setting[4] + ) { + bfirstflag = true; + } + + if (0x00 == led_config_second.s0_led_setting[0] && 0x00 == led_config_second.s0_led_setting[1] && 0x00 == led_config_second.s0_led_setting[2] && 0x00 == led_config_second.s0_led_setting[3] && 0x00 == led_config_second.s0_led_setting[4] + && 0x00 == led_config_second.s3_led_setting[0] && 0x00 == led_config_second.s3_led_setting[1] && 0x00 == led_config_second.s3_led_setting[2] && 0x00 == led_config_second.s3_led_setting[3] && 0x00 == led_config_second.s3_led_setting[4] + && 0x00 == led_config_second.s5_led_setting[0] && 0x00 == led_config_second.s5_led_setting[1] && 0x00 == led_config_second.s5_led_setting[2] && 0x00 == led_config_second.s5_led_setting[3] && 0x00 == led_config_second.s5_led_setting[4] + && 0x00 == led_config_second.disable_led_setting[0] && 0x00 == led_config_second.disable_led_setting[1] && 0x00 == led_config_second.disable_led_setting[2] && 0x00 == led_config_second.disable_led_setting[3] && 0x00 == led_config_second.disable_led_setting[4] + ) { + bsecondflag = true; + } + +#ifndef LINUX + DbgPrintF(MP_TRACE, "%s s0 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x", __FUNCTION__, pdata->ledconfig.s0_led_setting[0], pdata->ledconfig.s0_led_setting[1], pdata->ledconfig.s0_led_setting[2], pdata->ledconfig.s0_led_setting[3], pdata->ledconfig.s0_led_setting[4]); + DbgPrintF(MP_TRACE, "%s s3 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x", __FUNCTION__, pdata->ledconfig.s3_led_setting[0], pdata->ledconfig.s3_led_setting[1], pdata->ledconfig.s3_led_setting[2], pdata->ledconfig.s3_led_setting[3], pdata->ledconfig.s3_led_setting[4]); + DbgPrintF(MP_TRACE, "%s s5 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x", __FUNCTION__, pdata->ledconfig.s5_led_setting[0], pdata->ledconfig.s5_led_setting[1], pdata->ledconfig.s5_led_setting[2], pdata->ledconfig.s5_led_setting[3], pdata->ledconfig.s5_led_setting[4]); + DbgPrintF(MP_TRACE, "%s disable 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x", __FUNCTION__, pdata->ledconfig.disable_led_setting[0], pdata->ledconfig.disable_led_setting[1], pdata->ledconfig.disable_led_setting[2], pdata->ledconfig.disable_led_setting[3], pdata->ledconfig.disable_led_setting[4]); +#endif + + if (bfirstflag && bsecondflag) { + //update first area + fxgmac_efuse_write_data(pdata, EFUSE_FISRT_UPDATE_ADDR, (pdata->ledconfig.disable_led_setting[4]>>8)&0xFF); + fxgmac_efuse_write_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 1), pdata->ledconfig.disable_led_setting[4]); + fxgmac_efuse_write_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 2), (pdata->ledconfig.disable_led_setting[3] >> 8) & 0xFF); + fxgmac_efuse_write_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 3), pdata->ledconfig.disable_led_setting[3]); + fxgmac_efuse_write_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 4), (pdata->ledconfig.disable_led_setting[2] >> 8) & 0xFF); + fxgmac_efuse_write_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 5), pdata->ledconfig.disable_led_setting[2]); + fxgmac_efuse_write_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 6), (pdata->ledconfig.disable_led_setting[1] >> 8) & 0xFF); + fxgmac_efuse_write_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 7), pdata->ledconfig.disable_led_setting[1]); + fxgmac_efuse_write_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 8), (pdata->ledconfig.disable_led_setting[0] >> 8) & 0xFF); + fxgmac_efuse_write_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 9), pdata->ledconfig.disable_led_setting[0]); + + fxgmac_efuse_write_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 10), (pdata->ledconfig.s5_led_setting[4] >> 8) & 0xFF); + fxgmac_efuse_write_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 11), pdata->ledconfig.s5_led_setting[4]); + fxgmac_efuse_write_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 12), (pdata->ledconfig.s5_led_setting[3] >> 8) & 0xFF); + fxgmac_efuse_write_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 13), pdata->ledconfig.s5_led_setting[3]); + fxgmac_efuse_write_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 14), (pdata->ledconfig.s5_led_setting[2] >> 8) & 0xFF); + fxgmac_efuse_write_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 15), pdata->ledconfig.s5_led_setting[2]); + fxgmac_efuse_write_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 16), (pdata->ledconfig.s5_led_setting[1] >> 8) & 0xFF); + fxgmac_efuse_write_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 17), pdata->ledconfig.s5_led_setting[1]); + fxgmac_efuse_write_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 18), (pdata->ledconfig.s5_led_setting[0] >> 8) & 0xFF); + fxgmac_efuse_write_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 19), pdata->ledconfig.s5_led_setting[0]); + + fxgmac_efuse_write_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 20), (pdata->ledconfig.s3_led_setting[4] >> 8) & 0xFF); + fxgmac_efuse_write_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 21), pdata->ledconfig.s3_led_setting[4]); + fxgmac_efuse_write_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 22), (pdata->ledconfig.s3_led_setting[3] >> 8) & 0xFF); + fxgmac_efuse_write_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 23), pdata->ledconfig.s3_led_setting[3]); + fxgmac_efuse_write_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 24), (pdata->ledconfig.s3_led_setting[2] >> 8) & 0xFF); + fxgmac_efuse_write_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 25), pdata->ledconfig.s3_led_setting[2]); + fxgmac_efuse_write_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 26), (pdata->ledconfig.s3_led_setting[1] >> 8) & 0xFF); + fxgmac_efuse_write_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 27), pdata->ledconfig.s3_led_setting[1]); + fxgmac_efuse_write_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 28), (pdata->ledconfig.s3_led_setting[0] >> 8) & 0xFF); + fxgmac_efuse_write_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 29), pdata->ledconfig.s3_led_setting[0]); + + fxgmac_efuse_write_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 30), (pdata->ledconfig.s0_led_setting[4] >> 8) & 0xFF); + fxgmac_efuse_write_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 31), pdata->ledconfig.s0_led_setting[4]); + fxgmac_efuse_write_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 32), (pdata->ledconfig.s0_led_setting[3] >> 8) & 0xFF); + fxgmac_efuse_write_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 33), pdata->ledconfig.s0_led_setting[3]); + fxgmac_efuse_write_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 34), (pdata->ledconfig.s0_led_setting[2] >> 8) & 0xFF); + fxgmac_efuse_write_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 35), pdata->ledconfig.s0_led_setting[2]); + fxgmac_efuse_write_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 36), (pdata->ledconfig.s0_led_setting[1] >> 8) & 0xFF); + fxgmac_efuse_write_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 37), pdata->ledconfig.s0_led_setting[1]); + fxgmac_efuse_write_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 38), (pdata->ledconfig.s0_led_setting[0] >> 8) & 0xFF); + fxgmac_efuse_write_data(pdata, (EFUSE_FISRT_UPDATE_ADDR - 39), pdata->ledconfig.s0_led_setting[0]); + + bsucceed = true; + } + else if (!bfirstflag && bsecondflag) { + //update second area + fxgmac_efuse_write_data(pdata, EFUSE_SECOND_UPDATE_ADDR, (pdata->ledconfig.disable_led_setting[4] >> 8) & 0xFF); + fxgmac_efuse_write_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 1), pdata->ledconfig.disable_led_setting[4]); + fxgmac_efuse_write_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 2), (pdata->ledconfig.disable_led_setting[3] >> 8) & 0xFF); + fxgmac_efuse_write_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 3), pdata->ledconfig.disable_led_setting[3]); + fxgmac_efuse_write_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 4), (pdata->ledconfig.disable_led_setting[2] >> 8) & 0xFF); + fxgmac_efuse_write_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 5), pdata->ledconfig.disable_led_setting[2]); + fxgmac_efuse_write_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 6), (pdata->ledconfig.disable_led_setting[1] >> 8) & 0xFF); + fxgmac_efuse_write_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 7), pdata->ledconfig.disable_led_setting[1]); + fxgmac_efuse_write_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 8), (pdata->ledconfig.disable_led_setting[0] >> 8) & 0xFF); + fxgmac_efuse_write_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 9), pdata->ledconfig.disable_led_setting[0]); + + fxgmac_efuse_write_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 10), (pdata->ledconfig.s5_led_setting[4] >> 8) & 0xFF); + fxgmac_efuse_write_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 11), pdata->ledconfig.s5_led_setting[4]); + fxgmac_efuse_write_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 12), (pdata->ledconfig.s5_led_setting[3] >> 8) & 0xFF); + fxgmac_efuse_write_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 13), pdata->ledconfig.s5_led_setting[3]); + fxgmac_efuse_write_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 14), (pdata->ledconfig.s5_led_setting[2] >> 8) & 0xFF); + fxgmac_efuse_write_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 15), pdata->ledconfig.s5_led_setting[2]); + fxgmac_efuse_write_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 16), (pdata->ledconfig.s5_led_setting[1] >> 8) & 0xFF); + fxgmac_efuse_write_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 17), pdata->ledconfig.s5_led_setting[1]); + fxgmac_efuse_write_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 18), (pdata->ledconfig.s5_led_setting[0] >> 8) & 0xFF); + fxgmac_efuse_write_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 19), pdata->ledconfig.s5_led_setting[0]); + + fxgmac_efuse_write_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 20), (pdata->ledconfig.s3_led_setting[4] >> 8) & 0xFF); + fxgmac_efuse_write_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 21), pdata->ledconfig.s3_led_setting[4]); + fxgmac_efuse_write_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 22), (pdata->ledconfig.s3_led_setting[3] >> 8) & 0xFF); + fxgmac_efuse_write_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 23), pdata->ledconfig.s3_led_setting[3]); + fxgmac_efuse_write_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 24), (pdata->ledconfig.s3_led_setting[2] >> 8) & 0xFF); + fxgmac_efuse_write_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 25), pdata->ledconfig.s3_led_setting[2]); + fxgmac_efuse_write_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 26), (pdata->ledconfig.s3_led_setting[1] >> 8) & 0xFF); + fxgmac_efuse_write_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 27), pdata->ledconfig.s3_led_setting[1]); + fxgmac_efuse_write_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 28), (pdata->ledconfig.s3_led_setting[0] >> 8) & 0xFF); + fxgmac_efuse_write_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 29), pdata->ledconfig.s3_led_setting[0]); + + fxgmac_efuse_write_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 30), (pdata->ledconfig.s0_led_setting[4] >> 8) & 0xFF); + fxgmac_efuse_write_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 31), pdata->ledconfig.s0_led_setting[4]); + fxgmac_efuse_write_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 32), (pdata->ledconfig.s0_led_setting[3] >> 8) & 0xFF); + fxgmac_efuse_write_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 33), pdata->ledconfig.s0_led_setting[3]); + fxgmac_efuse_write_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 34), (pdata->ledconfig.s0_led_setting[2] >> 8) & 0xFF); + fxgmac_efuse_write_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 35), pdata->ledconfig.s0_led_setting[2]); + fxgmac_efuse_write_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 36), (pdata->ledconfig.s0_led_setting[1] >> 8) & 0xFF); + fxgmac_efuse_write_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 37), pdata->ledconfig.s0_led_setting[1]); + fxgmac_efuse_write_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 38), (pdata->ledconfig.s0_led_setting[0] >> 8) & 0xFF); + fxgmac_efuse_write_data(pdata, (EFUSE_SECOND_UPDATE_ADDR - 39), pdata->ledconfig.s0_led_setting[0]); + + bsucceed = true; + } + + return bsucceed; +} + +bool fxgmac_read_led_setting_from_efuse(struct fxgmac_pdata* pdata) +{ + struct led_setting led_config_first; + struct led_setting led_config_second; + bool bfirstflag = false, bsecondflag = false; + bool bsucceed = false; + + fxgmac_read_led_efuse_config(pdata, &led_config_first, &led_config_second); + + if (0x00 == led_config_first.s0_led_setting[0] && 0x00 == led_config_first.s0_led_setting[1] && 0x00 == led_config_first.s0_led_setting[2] && 0x00 == led_config_first.s0_led_setting[3] && 0x00 == led_config_first.s0_led_setting[4] + && 0x00 == led_config_first.s3_led_setting[0] && 0x00 == led_config_first.s3_led_setting[1] && 0x00 == led_config_first.s3_led_setting[2] && 0x00 == led_config_first.s3_led_setting[3] && 0x00 == led_config_first.s3_led_setting[4] + && 0x00 == led_config_first.s5_led_setting[0] && 0x00 == led_config_first.s5_led_setting[1] && 0x00 == led_config_first.s5_led_setting[2] && 0x00 == led_config_first.s5_led_setting[3] && 0x00 == led_config_first.s5_led_setting[4] + && 0x00 == led_config_first.disable_led_setting[0] && 0x00 == led_config_first.disable_led_setting[1] && 0x00 == led_config_first.disable_led_setting[2] && 0x00 == led_config_first.disable_led_setting[3] && 0x00 == led_config_first.disable_led_setting[4] + ) { + bfirstflag = true; + } + + if (0x00 == led_config_second.s0_led_setting[0] && 0x00 == led_config_second.s0_led_setting[1] && 0x00 == led_config_second.s0_led_setting[2] && 0x00 == led_config_second.s0_led_setting[3] && 0x00 == led_config_second.s0_led_setting[4] + && 0x00 == led_config_second.s3_led_setting[0] && 0x00 == led_config_second.s3_led_setting[1] && 0x00 == led_config_second.s3_led_setting[2] && 0x00 == led_config_second.s3_led_setting[3] && 0x00 == led_config_second.s3_led_setting[4] + && 0x00 == led_config_second.s5_led_setting[0] && 0x00 == led_config_second.s5_led_setting[1] && 0x00 == led_config_second.s5_led_setting[2] && 0x00 == led_config_second.s5_led_setting[3] && 0x00 == led_config_second.s5_led_setting[4] + && 0x00 == led_config_second.disable_led_setting[0] && 0x00 == led_config_second.disable_led_setting[1] && 0x00 == led_config_second.disable_led_setting[2] && 0x00 == led_config_second.disable_led_setting[3] && 0x00 == led_config_second.disable_led_setting[4] + ) { + bsecondflag = true; + } + + if (!bfirstflag && bsecondflag) { + //read first area + memcpy(&pdata->led, &led_config_first, sizeof(struct led_setting)); + bsucceed = true; + } + else if (!bfirstflag && !bsecondflag) { + //read second area + memcpy(&pdata->led, &led_config_second, sizeof(struct led_setting)); + bsucceed = true; + } + +#ifndef LINUX + DbgPrintF(MP_TRACE, "%s s0 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x", __FUNCTION__, pdata->led.s0_led_setting[0], pdata->led.s0_led_setting[1], pdata->led.s0_led_setting[2], pdata->led.s0_led_setting[3], pdata->led.s0_led_setting[4]); + DbgPrintF(MP_TRACE, "%s s3 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x", __FUNCTION__, pdata->led.s3_led_setting[0], pdata->led.s3_led_setting[1], pdata->led.s3_led_setting[2], pdata->led.s3_led_setting[3], pdata->led.s3_led_setting[4]); + DbgPrintF(MP_TRACE, "%s s5 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x", __FUNCTION__, pdata->led.s5_led_setting[0], pdata->led.s5_led_setting[1], pdata->led.s5_led_setting[2], pdata->led.s5_led_setting[3], pdata->led.s5_led_setting[4]); + DbgPrintF(MP_TRACE, "%s disable 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x", __FUNCTION__, pdata->led.disable_led_setting[0], pdata->led.disable_led_setting[1], pdata->led.disable_led_setting[2], pdata->led.disable_led_setting[3], pdata->led.disable_led_setting[4]); +#endif + + return bsucceed; +} \ No newline at end of file diff --git a/drivers/net/ethernet/motorcomm/fuxi-efuse.h b/drivers/net/ethernet/motorcomm/fuxi-efuse.h new file mode 100644 index 000000000000..7832028e5168 --- /dev/null +++ b/drivers/net/ethernet/motorcomm/fuxi-efuse.h @@ -0,0 +1,33 @@ + +/*++ + +Copyright (c) 2021 Motorcomm Corporation. +Confidential and Proprietary. All rights reserved. + +This is Motorcomm Corporation NIC driver relevant files. Please don't copy, modify, +distribute without commercial permission. + +--*/ + +#ifndef __FUXI_EFUSE_H__ +#define __FUXI_EFUSE_H__ + + +bool fxgmac_read_patch_from_efuse(struct fxgmac_pdata* pdata, u32 offset, u32* value); /* read patch per register offset. */ +bool fxgmac_read_patch_from_efuse_per_index(struct fxgmac_pdata* pdata, u8 index, u32* offset, u32* value); /* read patch per 0-based index. */ +bool fxgmac_write_patch_to_efuse(struct fxgmac_pdata* pdata, u32 offset, u32 value); +bool fxgmac_write_patch_to_efuse_per_index(struct fxgmac_pdata* pdata, u8 index, u32 offset, u32 value); +bool fxgmac_read_mac_subsys_from_efuse(struct fxgmac_pdata* pdata, u8* mac_addr, u32* subsys, u32* revid); +bool fxgmac_write_mac_subsys_to_efuse(struct fxgmac_pdata* pdata, u8* mac_addr, u32* subsys, u32* revid); +bool fxgmac_write_mac_addr_to_efuse(struct fxgmac_pdata* pdata, u8* mac_addr); +bool fxgmac_read_subsys_from_efuse(struct fxgmac_pdata* pdata, u32* subsys, u32* revid); +bool fxgmac_write_subsys_to_efuse(struct fxgmac_pdata* pdata, u32* subsys, u32* revid); +bool fxgmac_efuse_load(struct fxgmac_pdata* pdata); +bool fxgmac_efuse_read_data(struct fxgmac_pdata* pdata, u32 offset, u32* value); +bool fxgmac_efuse_write_data(struct fxgmac_pdata* pdata, u32 offset, u32 value); +bool fxgmac_efuse_write_oob(struct fxgmac_pdata* pdata); +bool fxgmac_efuse_write_led(struct fxgmac_pdata* pdata, u32 value); +bool fxgmac_read_led_setting_from_efuse(struct fxgmac_pdata* pdata); +bool fxgmac_write_led_setting_to_efuse(struct fxgmac_pdata* pdata); + +#endif // __FUXI_EFUSE_H__ \ No newline at end of file diff --git a/drivers/net/ethernet/motorcomm/fuxi-gmac-common.c b/drivers/net/ethernet/motorcomm/fuxi-gmac-common.c new file mode 100644 index 000000000000..4b625f8425d6 --- /dev/null +++ b/drivers/net/ethernet/motorcomm/fuxi-gmac-common.c @@ -0,0 +1,1014 @@ +/*++ + +Copyright (c) 2021 Motor-comm Corporation. +Confidential and Proprietary. All rights reserved. + +This is Motor-comm Corporation NIC driver relevant files. Please don't copy, modify, +distribute without commercial permission. + +--*/ + + +#include +#include + +#include "fuxi-os.h" +#include "fuxi-gmac.h" +#include "fuxi-gmac-reg.h" + + +MODULE_LICENSE("Dual BSD/GPL"); + +static int debug = 16; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "FUXI ethernet debug level (0=none,...,16=all)"); + + +static unsigned char dev_addr[6] = {0, 0x55, 0x7b, 0xb5, 0x7d, 0xf7}; + +static void fxgmac_read_mac_addr(struct fxgmac_pdata *pdata) +{ + struct net_device *netdev = pdata->netdev; + struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops; + DPRINTK("read mac from eFuse\n"); + + // if efuse have mac addr,use it.if not,use static mac address. + hw_ops->read_mac_subsys_from_efuse(pdata, pdata->mac_addr, NULL, NULL); + if (ETH_IS_ZEROADDRESS(pdata->mac_addr)) { + /* Currently it uses a static mac address for test */ + memcpy(pdata->mac_addr, dev_addr, netdev->addr_len); + } +} + +static void fxgmac_default_config(struct fxgmac_pdata *pdata) +{ + pdata->tx_osp_mode = DMA_OSP_ENABLE; + pdata->tx_sf_mode = MTL_TSF_ENABLE; + pdata->rx_sf_mode = MTL_RSF_DISABLE;//MTL_RSF_DISABLE 20210514 + pdata->pblx8 = DMA_PBL_X8_ENABLE;//DMA_PBL_X8_ENABLE 20210514 + pdata->tx_pbl = DMA_PBL_32; + pdata->rx_pbl = DMA_PBL_32;//DMA_PBL_32 20210514 + pdata->tx_threshold = MTL_TX_THRESHOLD_128; + pdata->rx_threshold = MTL_RX_THRESHOLD_128; +#if 1 + pdata->tx_pause = 1; + pdata->rx_pause = 1; +#else + pdata->tx_pause = 0; + pdata->rx_pause = 0; +#endif +#if FXGMAC_RSS_FEATURE_ENABLED + pdata->rss = 1; +#else + pdata->rss = 0; +#endif + // open interrupt moderation default + pdata->intr_mod = 1; + pdata->crc_check = 1; + + //yzhang, set based on phy status. pdata->phy_speed = SPEED_1000; + pdata->sysclk_rate = FXGMAC_SYSCLOCK; + pdata->phy_autoeng = AUTONEG_ENABLE; // default to autoneg + pdata->phy_duplex = DUPLEX_FULL; + pdata->expansion.phy_link = false; + pdata->phy_speed = SPEED_1000; + + // default to magic + pdata->expansion.wol = WAKE_MAGIC; + + strlcpy(pdata->drv_name, FXGMAC_DRV_NAME, sizeof(pdata->drv_name)); + strlcpy(pdata->drv_ver, FXGMAC_DRV_VERSION, sizeof(pdata->drv_ver)); + + printk("FXGMAC_DRV_NAME:%s, FXGMAC_DRV_VERSION:%s\n", FXGMAC_DRV_NAME, FXGMAC_DRV_VERSION); +} + +static void fxgmac_init_all_ops(struct fxgmac_pdata *pdata) +{ + fxgmac_init_desc_ops(&pdata->desc_ops); + fxgmac_init_hw_ops(&pdata->hw_ops); + + DPRINTK("register desc_ops and hw ops\n"); +} + +int fxgmac_init(struct fxgmac_pdata *pdata, bool save_private_reg) +{ + struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops; + struct net_device *netdev = pdata->netdev; + unsigned int i,dma_width; + int ret; + + /* Set all the function pointers */ + fxgmac_init_all_ops(pdata); + + /* Set default configuration data */ + fxgmac_default_config(pdata); + + /* Set irq, base_addr, MAC address, */ + netdev->irq = pdata->dev_irq; + netdev->base_addr = (unsigned long)pdata->base_mem; + fxgmac_read_mac_addr(pdata); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,17,0)) + eth_hw_addr_set(netdev, pdata->mac_addr); +#else + memcpy(netdev->dev_addr, pdata->mac_addr, netdev->addr_len); +#endif + + if (save_private_reg) { + hw_ops->save_nonstick_reg(pdata); + } + + // reset here to get hw features correctly + hw_ops->exit(pdata); + + /* Populate the hardware features */ + fxgmac_get_all_hw_features(pdata); + fxgmac_print_all_hw_features(pdata); + + /* TODO: Set the PHY mode to XLGMII */ + + /* Set the DMA mask */ +#ifdef CONFIG_ARM64 + dma_width = FUXI_DMA_BIT_MASK; +#else + dma_width = pdata->hw_feat.dma_width; +#endif + ret = dma_set_mask_and_coherent(pdata->dev, + DMA_BIT_MASK(dma_width)); + if (ret) { + dev_err(pdata->dev, "dma_set_mask_and_coherent failed\n"); + return ret; + } + + /* Channel and ring params initializtion + * pdata->channel_count; + * pdata->tx_ring_count; + * pdata->rx_ring_count; + * pdata->tx_desc_count; + * pdata->rx_desc_count; + */ + BUILD_BUG_ON_NOT_POWER_OF_2(FXGMAC_TX_DESC_CNT); + pdata->tx_desc_count = FXGMAC_TX_DESC_CNT; + if (pdata->tx_desc_count & (pdata->tx_desc_count - 1)) { + dev_err(pdata->dev, "tx descriptor count (%d) is not valid\n", + pdata->tx_desc_count); + ret = -EINVAL; + return ret; + } + BUILD_BUG_ON_NOT_POWER_OF_2(FXGMAC_RX_DESC_CNT); + pdata->rx_desc_count = FXGMAC_RX_DESC_CNT; + if (pdata->rx_desc_count & (pdata->rx_desc_count - 1)) { + dev_err(pdata->dev, "rx descriptor count (%d) is not valid\n", + pdata->rx_desc_count); + ret = -EINVAL; + return ret; + } + + pdata->tx_ring_count = min_t(unsigned int, num_online_cpus(), + pdata->hw_feat.tx_ch_cnt); + pdata->tx_ring_count = min_t(unsigned int, pdata->tx_ring_count, + pdata->hw_feat.tx_q_cnt); + pdata->tx_q_count = pdata->tx_ring_count; + +#if !(FXGMAC_NUM_OF_TX_Q_USED) + ret = netif_set_real_num_tx_queues(netdev, pdata->tx_q_count); +#else + ret = netif_set_real_num_tx_queues(netdev, FXGMAC_NUM_OF_TX_Q_USED /*pdata->tx_q_count*/); +#endif + + DPRINTK("num_online_cpus:%u, tx_ch_cnt:%u, tx_q_cnt:%u, tx_ring_count:%u\n", + num_online_cpus(), pdata->hw_feat.tx_ch_cnt, pdata->hw_feat.tx_q_cnt, + pdata->tx_ring_count); + + if (ret) { + dev_err(pdata->dev, "error setting real tx queue count\n"); + return ret; + } +#if 0 + DPRINTK("num_online_cpus:%u, tx_ch_cnt:%u, tx_q_cnt:%u, tx_ring_count:%u\n", + num_online_cpus(), pdata->hw_feat.tx_ch_cnt, pdata->hw_feat.tx_q_cnt, + pdata->tx_ring_count); +#endif + + pdata->rx_ring_count = min_t(unsigned int, + netif_get_num_default_rss_queues(), + pdata->hw_feat.rx_ch_cnt); +#ifdef FXGMAC_ONE_CHANNEL + pdata->rx_ring_count = 1; + pdata->hw_feat.rx_q_cnt = pdata->rx_ring_count; +#else + pdata->rx_ring_count = min_t(unsigned int, pdata->rx_ring_count, + pdata->hw_feat.rx_q_cnt); +#endif + pdata->rx_q_count = pdata->rx_ring_count; + ret = netif_set_real_num_rx_queues(netdev, pdata->rx_q_count); + if (ret) { + dev_err(pdata->dev, "error setting real rx queue count\n"); + return ret; + } + + pdata->channel_count = + max_t(unsigned int, pdata->tx_ring_count, pdata->rx_ring_count); + + DPRINTK("default rss queues:%u, rx_ch_cnt:%u, rx_q_cnt:%u, rx_ring_count:%u\n", + netif_get_num_default_rss_queues(), pdata->hw_feat.rx_ch_cnt, pdata->hw_feat.rx_q_cnt, + pdata->rx_ring_count); + DPRINTK("channel_count:%u, netdev tx channel_num=%u\n", pdata->channel_count, netdev->num_tx_queues); + + /* Initialize RSS hash key and lookup table */ +#if FXGMAC_RSS_HASH_KEY_LINUX + netdev_rss_key_fill(pdata->rss_key, sizeof(pdata->rss_key)); +#else + //this is for test only. HW does not want to change Hash key, 20210617 + hw_ops->get_rss_hash_key(pdata, (u8 *)pdata->rss_key); +#endif + +#if FXGMAC_MSIX_CH0RXDIS_EN + for (i = 0; i < FXGMAC_RSS_MAX_TABLE_SIZE; i++) { + pdata->rss_table[i] = FXGMAC_SET_REG_BITS( + pdata->rss_table[i], + MAC_RSSDR_DMCH_POS, + MAC_RSSDR_DMCH_LEN, + (i % 3) + 1); //eliminate ch0 + } +#else + for (i = 0; i < FXGMAC_RSS_MAX_TABLE_SIZE; i++) { + pdata->rss_table[i] = FXGMAC_SET_REG_BITS( + pdata->rss_table[i], + MAC_RSSDR_DMCH_POS, + MAC_RSSDR_DMCH_LEN, + i % pdata->rx_ring_count); //note, rx_ring_count should be equal to IRQ requsted for MSIx, 4 + } +#endif + + pdata->rss_options = FXGMAC_SET_REG_BITS( + pdata->rss_options, + MAC_RSSCR_IP4TE_POS, + MAC_RSSCR_IP4TE_LEN, 1); + pdata->rss_options = FXGMAC_SET_REG_BITS( + pdata->rss_options, + MAC_RSSCR_TCP4TE_POS, + MAC_RSSCR_TCP4TE_LEN, 1); + pdata->rss_options = FXGMAC_SET_REG_BITS( + pdata->rss_options, + MAC_RSSCR_UDP4TE_POS, + MAC_RSSCR_UDP4TE_LEN, 1); + + /* config MTU supported, 20210726 */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0)) + netdev->min_mtu = ETH_MIN_MTU; + netdev->max_mtu = FXGMAC_JUMBO_PACKET_MTU + (ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN); +#endif + /* + netdev->extended->min_mtu = netdev->min_mtu; + netdev->extended->max_mtu = netdev->max_mtu; + */ + + DPRINTK("rss_options:0x%x\n", pdata->rss_options); + + /* Set device operations */ + netdev->netdev_ops = fxgmac_get_netdev_ops(); + netdev->ethtool_ops = fxgmac_get_ethtool_ops(); + + /* Set device features */ + if (pdata->hw_feat.tso) { + netdev->hw_features = NETIF_F_TSO; + netdev->hw_features |= NETIF_F_TSO6; + netdev->hw_features |= NETIF_F_SG; + netdev->hw_features |= NETIF_F_IP_CSUM; + netdev->hw_features |= NETIF_F_IPV6_CSUM; + } else if (pdata->hw_feat.tx_coe) { + netdev->hw_features = NETIF_F_IP_CSUM; + netdev->hw_features |= NETIF_F_IPV6_CSUM; + } + + if (pdata->hw_feat.rx_coe) { + netdev->hw_features |= NETIF_F_RXCSUM; + netdev->hw_features |= NETIF_F_GRO; + } + + if (pdata->hw_feat.rss) { + netdev->hw_features |= NETIF_F_RXHASH; //it is NETIF_F_RXHASH_BIT finally + } + + netdev->vlan_features |= netdev->hw_features; + + netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_RX; + pdata->vlan_strip = 1; + if (pdata->hw_feat.sa_vlan_ins) { + netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_TX; + } +#if FXGMAC_FILTER_SINGLE_VLAN_ENABLED + /* only can filter one vlan id */ + pdata->hw_feat.vlhash = 1 ; +#else + pdata->hw_feat.vlhash = 0 ; +#endif + + if (pdata->hw_feat.vlhash) { + netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER; + pdata->vlan_filter = 1; + } + + netdev->features |= netdev->hw_features; + pdata->expansion.netdev_features = netdev->features; + + netdev->priv_flags |= IFF_UNICAST_FLT; + + /* Use default watchdog timeout */ + netdev->watchdog_timeo = msecs_to_jiffies(5000);//refer to sunxi-gmac, 5s + netdev->gso_max_size = NIC_MAX_TCP_OFFLOAD_SIZE; + + /* Tx coalesce parameters initialization */ + pdata->tx_usecs = FXGMAC_INIT_DMA_TX_USECS; + pdata->tx_frames = FXGMAC_INIT_DMA_TX_FRAMES; + + /* Rx coalesce parameters initialization */ + pdata->rx_riwt = hw_ops->usec_to_riwt(pdata, FXGMAC_INIT_DMA_RX_USECS); + + pdata->rx_usecs = FXGMAC_INIT_DMA_RX_USECS; + pdata->rx_frames = FXGMAC_INIT_DMA_RX_FRAMES; + + DPRINTK("fxgmac_init callout,ok.\n"); + + return 0; +} + +static void fxgmac_init_interrupt_scheme(struct fxgmac_pdata *pdata) +{ +#ifdef CONFIG_PCI_MSI + int vectors, rc, i, req_vectors; + /* check cpu core number. + * since we have 4 channels, we must ensure the number of cpu core > 4 + * otherwise, just roll back to legacy + */ + vectors = num_online_cpus(); + DPRINTK("num of cpu=%d\n", vectors); + if(vectors >= FXGMAC_MAX_DMA_CHANNELS) { + // 0-3 for rx, 4 for tx, 5 for phy + req_vectors = FXGMAC_MSIX_INT_NUMS; + pdata->expansion.msix_entries = kcalloc(req_vectors, + sizeof(struct msix_entry), + GFP_KERNEL); + if (!pdata->expansion.msix_entries) { + DPRINTK("MSIx, kcalloc err for msix entries, rollback to MSI..\n"); + goto enable_msi_interrupt; + }else { + for (i = 0; i < req_vectors; i++) + pdata->expansion.msix_entries[i].entry = i; + + rc = pci_enable_msix_range(pdata->pdev, + pdata->expansion.msix_entries, + req_vectors, + req_vectors); + if (rc < 0) { + DPRINTK("enable MSIx failed,%d.\n", rc); + req_vectors = 0; //indicate failure + } else { + req_vectors = rc; + } + + if(req_vectors >= FXGMAC_MAX_DMA_CHANNELS_PLUS_1TX) { + DPRINTK("enable MSIx ok, cpu=%d,vectors=%d.\n", + vectors, req_vectors); + pdata->expansion.int_flags = FXGMAC_SET_REG_BITS(pdata->expansion.int_flags, + FXGMAC_FLAG_INTERRUPT_POS, + FXGMAC_FLAG_INTERRUPT_LEN, + FXGMAC_FLAG_MSIX_ENABLED); + pdata->per_channel_irq = 1; + pdata->expansion.phy_irq = + pdata->expansion.msix_entries[MSI_ID_PHY_OTHER].vector; + return; + }else if (req_vectors){ + DPRINTK("enable MSIx with only %d vector, while we need %d, rollback to MSI.\n", req_vectors, vectors); + //roll back to msi + pci_disable_msix(pdata->pdev); + kfree(pdata->expansion.msix_entries); + pdata->expansion.msix_entries = NULL; + req_vectors = 0; + }else { + DPRINTK("enable MSIx failure and clear msix entries.\n"); + //roll back to msi + kfree(pdata->expansion.msix_entries); + pdata->expansion.msix_entries = NULL; + req_vectors = 0; + } + } + } + +enable_msi_interrupt: + rc = pci_enable_msi(pdata->pdev); + if (rc < 0) { + pdata->expansion.int_flags = FXGMAC_SET_REG_BITS(pdata->expansion.int_flags, + FXGMAC_FLAG_INTERRUPT_POS, + FXGMAC_FLAG_INTERRUPT_LEN, + FXGMAC_FLAG_LEGACY_ENABLED); + DPRINTK("enable MSI failure, rollback to LEGACY.\n"); + } else { + pdata->expansion.int_flags = FXGMAC_SET_REG_BITS(pdata->expansion.int_flags, + FXGMAC_FLAG_INTERRUPT_POS, + FXGMAC_FLAG_INTERRUPT_LEN, + FXGMAC_FLAG_MSI_ENABLED); + pdata->dev_irq = pdata->pdev->irq; + DPRINTK("enable MSI ok, irq=%d.\n", pdata->pdev->irq); + } +#else + pdata = pdata; +#endif +} + +int fxgmac_drv_probe(struct device *dev, struct fxgmac_resources *res) +{ + struct fxgmac_pdata *pdata; + struct net_device *netdev; + int ret; + + netdev = alloc_etherdev_mq(sizeof(struct fxgmac_pdata), + FXGMAC_MAX_DMA_CHANNELS); + + if (!netdev) { + dev_err(dev, "alloc_etherdev failed\n"); + return -ENOMEM; + } + + SET_NETDEV_DEV(netdev, dev); + dev_set_drvdata(dev, netdev); + pdata = netdev_priv(netdev); + pdata->dev = dev; + pdata->pdev = to_pci_dev(dev); + pdata->netdev = netdev; + + pdata->dev_irq = res->irq; + + // default to legacy interrupt + pdata->expansion.int_flags = FXGMAC_SET_REG_BITS(pdata->expansion.int_flags, + FXGMAC_FLAG_INTERRUPT_POS, + FXGMAC_FLAG_INTERRUPT_LEN, + FXGMAC_FLAG_LEGACY_ENABLED); + pdata->expansion.phy_irq = pdata->dev_irq; + + fxgmac_init_interrupt_scheme(pdata); + + pdata->expansion.current_state = CURRENT_STATE_INIT; + + pdata->msg_enable = NETIF_MSG_DRV; + DPRINTK("netif msg_enable init to %08x\n", pdata->msg_enable); + + pdata->mac_regs = res->addr; + pdata->base_mem = res->addr; + pdata->mac_regs = pdata->mac_regs + FUXI_MAC_REGS_OFFSET; + + ret = fxgmac_init(pdata, true); + if (ret) { + dev_err(dev, "fxgmac init failed\n"); + goto err_free_netdev; + } + + pdata->hw_ops.read_led_config(pdata); + + netif_carrier_off(netdev); + ret = register_netdev(netdev); + if (ret) { + dev_err(dev, "net device registration failed\n"); + goto err_free_netdev; + } + if(netif_msg_drv(pdata)) DPRINTK("fxgamc_drv_prob callout, netdev num_tx_q=%u\n", netdev->num_tx_queues); + +#ifdef HAVE_FXGMAC_DEBUG_FS + fxgmac_dbg_init(pdata); + fxgmac_dbg_adapter_init(pdata); +#endif /* HAVE_FXGMAC_DEBUG_FS */ + + return 0; + +err_free_netdev: + free_netdev(netdev); + DPRINTK("fxgamc_drv_prob callout with err \n"); + + return ret; +} + +int fxgmac_drv_remove(struct device *dev) +{ + struct net_device *netdev = dev_get_drvdata(dev); + struct fxgmac_pdata * pdata = netdev_priv(netdev); + struct fxgmac_hw_ops* hw_ops = &pdata->hw_ops; + +#ifdef HAVE_FXGMAC_DEBUG_FS + fxgmac_dbg_adapter_exit(pdata); +#endif /*HAVE_FXGMAC_DEBUG_FS */ + hw_ops->led_under_shutdown(pdata); + + unregister_netdev(netdev); + free_netdev(netdev); + + return 0; +} + +void fxgmac_dump_tx_desc(struct fxgmac_pdata *pdata, + struct fxgmac_ring *ring, + unsigned int idx, + unsigned int count, + unsigned int flag) +{ + struct fxgmac_desc_data *desc_data; + struct fxgmac_dma_desc *dma_desc; + + while (count--) { + desc_data = FXGMAC_GET_DESC_DATA(ring, idx); + dma_desc = desc_data->dma_desc; + + netdev_dbg(pdata->netdev, "TX: dma_desc=%p, dma_desc_addr=%pad\n", + desc_data->dma_desc, &desc_data->dma_desc_addr); + netdev_dbg(pdata->netdev, + "TX_NORMAL_DESC[%d %s] = %08x:%08x:%08x:%08x\n", idx, + (flag == 1) ? "QUEUED FOR TX" : "TX BY DEVICE", + le32_to_cpu(dma_desc->desc0), + le32_to_cpu(dma_desc->desc1), + le32_to_cpu(dma_desc->desc2), + le32_to_cpu(dma_desc->desc3)); + + idx++; + } +} + +void fxgmac_dump_rx_desc(struct fxgmac_pdata *pdata, + struct fxgmac_ring *ring, + unsigned int idx) +{ + struct fxgmac_desc_data *desc_data; + struct fxgmac_dma_desc *dma_desc; + + desc_data = FXGMAC_GET_DESC_DATA(ring, idx); + dma_desc = desc_data->dma_desc; + + netdev_dbg(pdata->netdev, "RX: dma_desc=%p, dma_desc_addr=%pad\n", + desc_data->dma_desc, &desc_data->dma_desc_addr); + netdev_dbg(pdata->netdev, + "RX_NORMAL_DESC[%d RX BY DEVICE] = %08x:%08x:%08x:%08x\n", + idx, + le32_to_cpu(dma_desc->desc0), + le32_to_cpu(dma_desc->desc1), + le32_to_cpu(dma_desc->desc2), + le32_to_cpu(dma_desc->desc3)); +} + +void fxgmac_dbg_pkt(struct net_device *netdev, + struct sk_buff *skb, bool tx_rx) +{ + struct ethhdr *eth = (struct ethhdr *)skb->data; + unsigned char buffer[128]; + unsigned int i; + + netdev_dbg(netdev, "\n************** SKB dump ****************\n"); + + netdev_dbg(netdev, "%s packet of %d bytes\n", + (tx_rx ? "TX" : "RX"), skb->len); + + netdev_dbg(netdev, "Dst MAC addr: %pM\n", eth->h_dest); + netdev_dbg(netdev, "Src MAC addr: %pM\n", eth->h_source); + netdev_dbg(netdev, "Protocol: %#06hx\n", ntohs(eth->h_proto)); + + for (i = 0; i < skb->len; i += 32) { + unsigned int len = min(skb->len - i, 32U); + + hex_dump_to_buffer(&skb->data[i], len, 32, 1, + buffer, sizeof(buffer), false); + netdev_dbg(netdev, " %#06x: %s\n", i, buffer); + } + + netdev_dbg(netdev, "\n************** SKB dump ****************\n"); +} + +void fxgmac_print_pkt(struct net_device *netdev, + struct sk_buff *skb, bool tx_rx) +{ +#ifdef FXGMAC_DEBUG + struct ethhdr *eth = (struct ethhdr *)skb->data; +#endif + unsigned char buffer[128]; + unsigned int i; + + DPRINTK("\n************** SKB dump ****************\n"); + DPRINTK("%s packet of %d bytes\n", + (tx_rx ? "TX" : "RX"), skb->len); + +#ifdef FXGMAC_DEBUG + DPRINTK("Dst MAC addr: %pM\n", eth->h_dest); + DPRINTK("Src MAC addr: %pM\n", eth->h_source); + DPRINTK("Protocol: %#06hx\n", ntohs(eth->h_proto)); +#endif + for (i = 0; i < skb->len; i += 32) { + unsigned int len = min(skb->len - i, 32U); + + hex_dump_to_buffer(&skb->data[i], len, 32, 1, + buffer, sizeof(buffer), false); + DPRINTK(" %#06x: %s\n", i, buffer); + } + + DPRINTK("\n************** SKB dump ****************\n"); +} + +void fxgmac_get_all_hw_features(struct fxgmac_pdata *pdata) +{ + struct fxgmac_hw_features *hw_feat = &pdata->hw_feat; + unsigned int mac_hfr0, mac_hfr1, mac_hfr2, mac_hfr3; + + mac_hfr0 = readl(pdata->mac_regs + MAC_HWF0R); + mac_hfr1 = readl(pdata->mac_regs + MAC_HWF1R); + mac_hfr2 = readl(pdata->mac_regs + MAC_HWF2R); + mac_hfr3 = readl(pdata->mac_regs + MAC_HWF3R); + + memset(hw_feat, 0, sizeof(*hw_feat)); + + hw_feat->version = readl(pdata->mac_regs + MAC_VR); + if(netif_msg_drv(pdata)) DPRINTK ("get offset 0x110,ver=%#x\n", readl(pdata->mac_regs + 0x110)); + + /* Hardware feature register 0 */ + hw_feat->phyifsel = FXGMAC_GET_REG_BITS(mac_hfr0, + MAC_HWF0R_ACTPHYIFSEL_POS, + MAC_HWF0R_ACTPHYIFSEL_LEN); + hw_feat->vlhash = FXGMAC_GET_REG_BITS(mac_hfr0, + MAC_HWF0R_VLHASH_POS, + MAC_HWF0R_VLHASH_LEN); + hw_feat->sma = FXGMAC_GET_REG_BITS(mac_hfr0, + MAC_HWF0R_SMASEL_POS, + MAC_HWF0R_SMASEL_LEN); + hw_feat->rwk = FXGMAC_GET_REG_BITS(mac_hfr0, + MAC_HWF0R_RWKSEL_POS, + MAC_HWF0R_RWKSEL_LEN); + hw_feat->mgk = FXGMAC_GET_REG_BITS(mac_hfr0, + MAC_HWF0R_MGKSEL_POS, + MAC_HWF0R_MGKSEL_LEN); + hw_feat->mmc = FXGMAC_GET_REG_BITS(mac_hfr0, + MAC_HWF0R_MMCSEL_POS, + MAC_HWF0R_MMCSEL_LEN); + hw_feat->aoe = FXGMAC_GET_REG_BITS(mac_hfr0, + MAC_HWF0R_ARPOFFSEL_POS, + MAC_HWF0R_ARPOFFSEL_LEN); + hw_feat->ts = FXGMAC_GET_REG_BITS(mac_hfr0, + MAC_HWF0R_TSSEL_POS, + MAC_HWF0R_TSSEL_LEN); + hw_feat->eee = FXGMAC_GET_REG_BITS(mac_hfr0, + MAC_HWF0R_EEESEL_POS, + MAC_HWF0R_EEESEL_LEN); + hw_feat->tx_coe = FXGMAC_GET_REG_BITS(mac_hfr0, + MAC_HWF0R_TXCOESEL_POS, + MAC_HWF0R_TXCOESEL_LEN); + hw_feat->rx_coe = FXGMAC_GET_REG_BITS(mac_hfr0, + MAC_HWF0R_RXCOESEL_POS, + MAC_HWF0R_RXCOESEL_LEN); + hw_feat->addn_mac = FXGMAC_GET_REG_BITS(mac_hfr0, + MAC_HWF0R_ADDMACADRSEL_POS, + MAC_HWF0R_ADDMACADRSEL_LEN); + hw_feat->ts_src = FXGMAC_GET_REG_BITS(mac_hfr0, + MAC_HWF0R_TSSTSSEL_POS, + MAC_HWF0R_TSSTSSEL_LEN); + hw_feat->sa_vlan_ins = FXGMAC_GET_REG_BITS(mac_hfr0, + MAC_HWF0R_SAVLANINS_POS, + MAC_HWF0R_SAVLANINS_LEN); + + /* Hardware feature register 1 */ + hw_feat->rx_fifo_size = FXGMAC_GET_REG_BITS(mac_hfr1, + MAC_HWF1R_RXFIFOSIZE_POS, + MAC_HWF1R_RXFIFOSIZE_LEN); + hw_feat->tx_fifo_size = FXGMAC_GET_REG_BITS(mac_hfr1, + MAC_HWF1R_TXFIFOSIZE_POS, + MAC_HWF1R_TXFIFOSIZE_LEN); + hw_feat->adv_ts_hi = FXGMAC_GET_REG_BITS(mac_hfr1, + MAC_HWF1R_ADVTHWORD_POS, + MAC_HWF1R_ADVTHWORD_LEN); + hw_feat->dma_width = FXGMAC_GET_REG_BITS(mac_hfr1, + MAC_HWF1R_ADDR64_POS, + MAC_HWF1R_ADDR64_LEN); + hw_feat->dcb = FXGMAC_GET_REG_BITS(mac_hfr1, + MAC_HWF1R_DCBEN_POS, + MAC_HWF1R_DCBEN_LEN); + hw_feat->sph = FXGMAC_GET_REG_BITS(mac_hfr1, + MAC_HWF1R_SPHEN_POS, + MAC_HWF1R_SPHEN_LEN); +#if (0 /*LINUX_VERSION_CODE >= KERNEL_VERSION(5,0,0)*/) + hw_feat->tso = 0; //bypass tso +#else + hw_feat->tso = FXGMAC_GET_REG_BITS(mac_hfr1, + MAC_HWF1R_TSOEN_POS, + MAC_HWF1R_TSOEN_LEN); +#endif + hw_feat->dma_debug = FXGMAC_GET_REG_BITS(mac_hfr1, + MAC_HWF1R_DBGMEMA_POS, + MAC_HWF1R_DBGMEMA_LEN); +#if (FXGMAC_RSS_FEATURE_ENABLED) + hw_feat->rss = 1; +#else + hw_feat->rss = 0; /* = FXGMAC_GET_REG_BITS(mac_hfr1, + MAC_HWF1R_RSSEN_POS, + MAC_HWF1R_RSSEN_LEN);*/ +#endif + hw_feat->tc_cnt = 3/*1, yzhang try,0412*/; /* FXGMAC_GET_REG_BITS(mac_hfr1, + MAC_HWF1R_NUMTC_POS, + MAC_HWF1R_NUMTC_LEN); */ + hw_feat->avsel = FXGMAC_GET_REG_BITS(mac_hfr1, + MAC_HWF1R_AVSEL_POS, + MAC_HWF1R_AVSEL_LEN); + hw_feat->ravsel = FXGMAC_GET_REG_BITS(mac_hfr1, + MAC_HWF1R_RAVSEL_POS, + MAC_HWF1R_RAVSEL_LEN); + hw_feat->hash_table_size = FXGMAC_GET_REG_BITS(mac_hfr1, + MAC_HWF1R_HASHTBLSZ_POS, + MAC_HWF1R_HASHTBLSZ_LEN); + hw_feat->l3l4_filter_num = FXGMAC_GET_REG_BITS(mac_hfr1, + MAC_HWF1R_L3L4FNUM_POS, + MAC_HWF1R_L3L4FNUM_LEN); + + /* Hardware feature register 2 */ +#if 1 /* hw implement only 1 Q, but from software we see 4 logical Qs. hardcode to 4 Qs. */ + hw_feat->rx_q_cnt = 3/*FXGMAC_GET_REG_BITS(mac_hfr2, + MAC_HWF2R_RXQCNT_POS, + MAC_HWF2R_RXQCNT_LEN)*/; +#else + hw_feat->rx_q_cnt = FXGMAC_GET_REG_BITS(mac_hfr2, + MAC_HWF2R_RXQCNT_POS, + MAC_HWF2R_RXQCNT_LEN); +#endif + hw_feat->tx_q_cnt = FXGMAC_GET_REG_BITS(mac_hfr2, + MAC_HWF2R_TXQCNT_POS, + MAC_HWF2R_TXQCNT_LEN); +#if 0 /*yzhang for debug. only 1 rx channl and q*/ + hw_feat->rx_ch_cnt = 0 /*FXGMAC_GET_REG_BITS(mac_hfr2, + MAC_HWF2R_RXCHCNT_POS, + MAC_HWF2R_RXCHCNT_LEN)*/; +#else + hw_feat->rx_ch_cnt = FXGMAC_GET_REG_BITS(mac_hfr2, + MAC_HWF2R_RXCHCNT_POS, + MAC_HWF2R_RXCHCNT_LEN); +#endif + hw_feat->tx_ch_cnt = FXGMAC_GET_REG_BITS(mac_hfr2, + MAC_HWF2R_TXCHCNT_POS, + MAC_HWF2R_TXCHCNT_LEN); + hw_feat->pps_out_num = FXGMAC_GET_REG_BITS(mac_hfr2, + MAC_HWF2R_PPSOUTNUM_POS, + MAC_HWF2R_PPSOUTNUM_LEN); + hw_feat->aux_snap_num = FXGMAC_GET_REG_BITS(mac_hfr2, + MAC_HWF2R_AUXSNAPNUM_POS, + MAC_HWF2R_AUXSNAPNUM_LEN); + + /* Translate the Hash Table size into actual number */ + switch (hw_feat->hash_table_size) { + case 0: + break; + case 1: + hw_feat->hash_table_size = 64; + break; + case 2: + hw_feat->hash_table_size = 128; + break; + case 3: + hw_feat->hash_table_size = 256; + break; + } + + /* Translate the address width setting into actual number */ + switch (hw_feat->dma_width) { + case 0: + hw_feat->dma_width = 32; + break; + case 1: + hw_feat->dma_width = 40; + break; + case 2: + hw_feat->dma_width = 48; + break; + default: + hw_feat->dma_width = 32; + } + + /* The Queue, Channel and TC counts are zero based so increment them + * to get the actual number + */ + hw_feat->rx_q_cnt++; + hw_feat->tx_q_cnt++; + hw_feat->rx_ch_cnt++; + hw_feat->tx_ch_cnt++; + hw_feat->tc_cnt++; + + hw_feat->hwfr3 = mac_hfr3; + DPRINTK("HWFR3: %u\n", mac_hfr3); +} + +void fxgmac_print_all_hw_features(struct fxgmac_pdata *pdata) +{ + char *str = NULL; + + DPRINTK("\n"); + DPRINTK("=====================================================\n"); + DPRINTK("\n"); + DPRINTK("HW support following features,ver=%#x\n",pdata->hw_feat.version); + DPRINTK("\n"); + /* HW Feature Register0 */ + DPRINTK("VLAN Hash Filter Selected : %s\n", + pdata->hw_feat.vlhash ? "YES" : "NO"); + DPRINTK("SMA (MDIO) Interface : %s\n", + pdata->hw_feat.sma ? "YES" : "NO"); + DPRINTK("PMT Remote Wake-up Packet Enable : %s\n", + pdata->hw_feat.rwk ? "YES" : "NO"); + DPRINTK("PMT Magic Packet Enable : %s\n", + pdata->hw_feat.mgk ? "YES" : "NO"); + DPRINTK("RMON/MMC Module Enable : %s\n", + pdata->hw_feat.mmc ? "YES" : "NO"); + DPRINTK("ARP Offload Enabled : %s\n", + pdata->hw_feat.aoe ? "YES" : "NO"); + DPRINTK("IEEE 1588-2008 Timestamp Enabled : %s\n", + pdata->hw_feat.ts ? "YES" : "NO"); + DPRINTK("Energy Efficient Ethernet Enabled : %s\n", + pdata->hw_feat.eee ? "YES" : "NO"); + DPRINTK("Transmit Checksum Offload Enabled : %s\n", + pdata->hw_feat.tx_coe ? "YES" : "NO"); + DPRINTK("Receive Checksum Offload Enabled : %s\n", + pdata->hw_feat.rx_coe ? "YES" : "NO"); + DPRINTK("Additional MAC Addresses 1-31 Selected : %s\n", + pdata->hw_feat.addn_mac ? "YES" : "NO"); + + switch (pdata->hw_feat.ts_src) { + case 0: + str = "RESERVED"; + break; + case 1: + str = "INTERNAL"; + break; + case 2: + str = "EXTERNAL"; + break; + case 3: + str = "BOTH"; + break; + } + DPRINTK("Timestamp System Time Source : %s\n", str); + + DPRINTK("Source Address or VLAN Insertion Enable : %s\n", + pdata->hw_feat.sa_vlan_ins ? "YES" : "NO"); + + /* HW Feature Register1 */ + switch (pdata->hw_feat.rx_fifo_size) { + case 0: + str = "128 bytes"; + break; + case 1: + str = "256 bytes"; + break; + case 2: + str = "512 bytes"; + break; + case 3: + str = "1 KBytes"; + break; + case 4: + str = "2 KBytes"; + break; + case 5: + str = "4 KBytes"; + break; + case 6: + str = "8 KBytes"; + break; + case 7: + str = "16 KBytes"; + break; + case 8: + str = "32 kBytes"; + break; + case 9: + str = "64 KBytes"; + break; + case 10: + str = "128 KBytes"; + break; + case 11: + str = "256 KBytes"; + break; + default: + str = "RESERVED"; + } + DPRINTK("MTL Receive FIFO Size : %s\n", str); + + switch (pdata->hw_feat.tx_fifo_size) { + case 0: + str = "128 bytes"; + break; + case 1: + str = "256 bytes"; + break; + case 2: + str = "512 bytes"; + break; + case 3: + str = "1 KBytes"; + break; + case 4: + str = "2 KBytes"; + break; + case 5: + str = "4 KBytes"; + break; + case 6: + str = "8 KBytes"; + break; + case 7: + str = "16 KBytes"; + break; + case 8: + str = "32 kBytes"; + break; + case 9: + str = "64 KBytes"; + break; + case 10: + str = "128 KBytes"; + break; + case 11: + str = "256 KBytes"; + break; + default: + str = "RESERVED"; + } + DPRINTK("MTL Transmit FIFO Size : %s\n", str); + + DPRINTK("IEEE 1588 High Word Register Enable : %s\n", + pdata->hw_feat.adv_ts_hi ? "YES" : "NO"); + DPRINTK("Address width : %u\n", + pdata->hw_feat.dma_width); + DPRINTK("DCB Feature Enable : %s\n", + pdata->hw_feat.dcb ? "YES" : "NO"); + DPRINTK("Split Header Feature Enable : %s\n", + pdata->hw_feat.sph ? "YES" : "NO"); + DPRINTK("TCP Segmentation Offload Enable : %s\n", + pdata->hw_feat.tso ? "YES" : "NO"); + DPRINTK("DMA Debug Registers Enabled : %s\n", + pdata->hw_feat.dma_debug ? "YES" : "NO"); + DPRINTK("RSS Feature Enabled : %s\n", + pdata->hw_feat.rss ? "YES" : "NO"); + DPRINTK("*TODO*Number of Traffic classes : %u\n", + (pdata->hw_feat.tc_cnt)); + DPRINTK("AV Feature Enabled : %s\n", + pdata->hw_feat.avsel ? "YES" : "NO"); + DPRINTK("Rx Side Only AV Feature Enabled : %s\n", + (pdata->hw_feat.ravsel ? "YES": "NO")); + DPRINTK("Hash Table Size : %u\n", + pdata->hw_feat.hash_table_size); + DPRINTK("Total number of L3 or L4 Filters : %u\n", + pdata->hw_feat.l3l4_filter_num); + + /* HW Feature Register2 */ + DPRINTK("Number of MTL Receive Queues : %u\n", + pdata->hw_feat.rx_q_cnt); + DPRINTK("Number of MTL Transmit Queues : %u\n", + pdata->hw_feat.tx_q_cnt); + DPRINTK("Number of DMA Receive Channels : %u\n", + pdata->hw_feat.rx_ch_cnt); + DPRINTK("Number of DMA Transmit Channels : %u\n", + pdata->hw_feat.tx_ch_cnt); + + switch (pdata->hw_feat.pps_out_num) { + case 0: + str = "No PPS output"; + break; + case 1: + str = "1 PPS output"; + break; + case 2: + str = "2 PPS output"; + break; + case 3: + str = "3 PPS output"; + break; + case 4: + str = "4 PPS output"; + break; + default: + str = "RESERVED"; + } + DPRINTK("Number of PPS Outputs : %s\n", str); + + switch (pdata->hw_feat.aux_snap_num) { + case 0: + str = "No auxiliary input"; + break; + case 1: + str = "1 auxiliary input"; + break; + case 2: + str = "2 auxiliary input"; + break; + case 3: + str = "3 auxiliary input"; + break; + case 4: + str = "4 auxiliary input"; + break; + default: + str = "RESERVED"; + } + DPRINTK("Number of Auxiliary Snapshot Inputs : %s", str); + + DPRINTK("\n"); + DPRINTK("=====================================================\n"); + DPRINTK("\n"); +} diff --git a/drivers/net/ethernet/motorcomm/fuxi-gmac-debugfs.c b/drivers/net/ethernet/motorcomm/fuxi-gmac-debugfs.c new file mode 100644 index 000000000000..6e3a8684c423 --- /dev/null +++ b/drivers/net/ethernet/motorcomm/fuxi-gmac-debugfs.c @@ -0,0 +1,760 @@ +/*++ + +Copyright (c) 2021 Motor-comm Corporation. +Confidential and Proprietary. All rights reserved. + +This is Motor-comm Corporation NIC driver relevant files. Please don't copy, modify, +distribute without commercial permission. + +--*/ + + + +#include "fuxi-gmac.h" +#include "fuxi-gmac-reg.h" +#ifdef HAVE_FXGMAC_DEBUG_FS +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TEST_MAC_HEAD 14 +#define TEST_TCP_HEAD_LEN_OFFSET 12 +#define TEST_TCP_OFFLOAD_LEN_OFFSET 48 +#define TEST_TCP_FIX_HEAD_LEN 24 +#define TEST_TCP_MSS_OFFSET 56 + +#define DF_MAX_NIC_NUM 16 + +#ifdef HAVE_FXGMAC_DEBUG_FS + +/** + * fxgmac_dbg_netdev_ops_read - read for netdev_ops datum + * @filp: the opened file + * @buffer: where to write the data for the user to read + * @count: the size of the user's buffer + * @ppos: file position offset + **/ +static ssize_t fxgmac_dbg_netdev_ops_read(struct file *filp, + char __user *buffer, + size_t count, loff_t *ppos) +{ + struct fxgmac_pdata *pdata = filp->private_data; + char *buf; + int len; + + /* don't allow partial reads */ + if (*ppos != 0) + return 0; + + buf = kasprintf(GFP_KERNEL, "%s: %s\n", + pdata->netdev->name, + pdata->expansion.fxgmac_dbg_netdev_ops_buf); + if (!buf) + return -ENOMEM; + + if (count < strlen(buf)) { + kfree(buf); + return -ENOSPC; + } + + len = simple_read_from_buffer(buffer, count, ppos, buf, strlen(buf)); + + kfree(buf); + return len; +} + +/** + * fxgmac_dbg_netdev_ops_write - write into netdev_ops datum + * @filp: the opened file + * @buffer: where to find the user's data + * @count: the length of the user's data + * @ppos: file position offset + **/ +static ssize_t fxgmac_dbg_netdev_ops_write(struct file *filp, + const char __user *buffer, + size_t count, loff_t *ppos) +{ + struct fxgmac_pdata *pdata = filp->private_data; + int len; + + /* don't allow partial writes */ + if (*ppos != 0) + return 0; + if (count >= sizeof(pdata->expansion.fxgmac_dbg_netdev_ops_buf)) + return -ENOSPC; + + len = simple_write_to_buffer(pdata->expansion.fxgmac_dbg_netdev_ops_buf, + sizeof(pdata->expansion.fxgmac_dbg_netdev_ops_buf)-1, + ppos, + buffer, + count); + if (len < 0) + return len; + + pdata->expansion.fxgmac_dbg_netdev_ops_buf[len] = '\0'; + + if (strncmp(pdata->expansion.fxgmac_dbg_netdev_ops_buf, "tx_timeout", 10) == 0) { + DPRINTK("tx_timeout called\n"); + } else { + FXGMAC_PR("Unknown command: %s\n", pdata->expansion.fxgmac_dbg_netdev_ops_buf); + FXGMAC_PR("Available commands:\n"); + FXGMAC_PR(" tx_timeout\n"); + } + return count; +} +#endif + +static void fxgmac_dbg_tx_pkt(struct fxgmac_pdata *pdata, u8 *pcmd_data) +{ + unsigned int pktLen = 0; + struct sk_buff *skb; + pfxgmac_test_packet pPkt; + u8 * pTx_data = NULL; + u8 * pSkb_data = NULL; + u32 offload_len = 0; + u8 ipHeadLen, tcpHeadLen, headTotalLen; + static u32 lastGsoSize = 806;//initial default value + //int i = 0; + + /* get fxgmac_test_packet */ + pPkt = (pfxgmac_test_packet)(pcmd_data + sizeof(struct ext_ioctl_data)); + pktLen = pPkt->length; + + /* get pkt data */ + pTx_data = (u8 *)pPkt + sizeof(fxgmac_test_packet); + +#if 0 //for debug + DPRINTK("Send packet len is %d, data:\n", pktLen); +#if 1 + for(i = 0; i < 70 ; i++) + { + DPRINTK("%2x ", pTx_data[i]); + } +#endif +#endif + + /* alloc sk_buff */ + skb = alloc_skb(pktLen, GFP_ATOMIC); + if (!skb){ + DPRINTK("alloc skb fail\n"); + return; + } + + /* copy data to skb */ + pSkb_data = skb_put(skb, pktLen); + memset(pSkb_data, 0, pktLen); + memcpy(pSkb_data, pTx_data, pktLen); + + /* set skb parameters */ + skb->dev = pdata->netdev; + skb->pkt_type = PACKET_OUTGOING; + skb->protocol = ntohs(ETH_P_IP); + skb->no_fcs = 1; + skb->ip_summed = CHECKSUM_PARTIAL; + if(skb->len > 1514){ + /* TSO packet */ + /* set tso test flag */ + pdata->expansion.fxgmac_test_tso_flag = true; + + /* get protocol head length */ + ipHeadLen = (pSkb_data[TEST_MAC_HEAD] & 0xF) * 4; + tcpHeadLen = (pSkb_data[TEST_MAC_HEAD + ipHeadLen + TEST_TCP_HEAD_LEN_OFFSET] >> 4 & 0xF) * 4; + headTotalLen = TEST_MAC_HEAD + ipHeadLen + tcpHeadLen; + offload_len = (pSkb_data[TEST_TCP_OFFLOAD_LEN_OFFSET] << 8 | + pSkb_data[TEST_TCP_OFFLOAD_LEN_OFFSET + 1]) & 0xFFFF; + /* set tso skb parameters */ + //skb->ip_summed = CHECKSUM_PARTIAL; + skb->transport_header = ipHeadLen + TEST_MAC_HEAD; + skb->network_header = TEST_MAC_HEAD; + skb->inner_network_header = TEST_MAC_HEAD; + skb->mac_len = TEST_MAC_HEAD; + + /* set skb_shinfo parameters */ + if(tcpHeadLen > TEST_TCP_FIX_HEAD_LEN){ + skb_shinfo(skb)->gso_size = (pSkb_data[TEST_TCP_MSS_OFFSET] << 8 | + pSkb_data[TEST_TCP_MSS_OFFSET + 1]) & 0xFFFF; + }else{ + skb_shinfo(skb)->gso_size = 0; + } + if(skb_shinfo(skb)->gso_size != 0){ + lastGsoSize = skb_shinfo(skb)->gso_size; + }else{ + skb_shinfo(skb)->gso_size = lastGsoSize; + } + //DPRINTK("offload_len is %d, skb_shinfo(skb)->gso_size is %d", offload_len, skb_shinfo(skb)->gso_size); + /* get segment size */ + if(offload_len % skb_shinfo(skb)->gso_size == 0){ + skb_shinfo(skb)->gso_segs = offload_len / skb_shinfo(skb)->gso_size; + pdata->expansion.fxgmac_test_last_tso_len = skb_shinfo(skb)->gso_size + headTotalLen; + }else{ + skb_shinfo(skb)->gso_segs = offload_len / skb_shinfo(skb)->gso_size + 1; + pdata->expansion.fxgmac_test_last_tso_len = offload_len % skb_shinfo(skb)->gso_size + headTotalLen; + } + pdata->expansion.fxgmac_test_tso_seg_num = skb_shinfo(skb)->gso_segs; + + skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4 ; + skb_shinfo(skb)->frag_list = NULL; + skb->csum_start = skb_headroom(skb) + TEST_MAC_HEAD + ipHeadLen; + skb->csum_offset = skb->len - TEST_MAC_HEAD - ipHeadLen; + + pdata->expansion.fxgmac_test_packet_len = skb_shinfo(skb)->gso_size + headTotalLen; + }else{ + /* set non-TSO packet parameters */ + pdata->expansion.fxgmac_test_packet_len = skb->len; + } + + /* send data */ + if(dev_queue_xmit(skb) != NET_XMIT_SUCCESS){ + DPRINTK("xmit data fail \n"); + } +} + +static void fxgmac_dbg_rx_pkt(struct fxgmac_pdata *pdata, u8 *pcmd_data) +{ + unsigned int totalLen = 0; + struct sk_buff *rx_skb; + struct ext_ioctl_data *pcmd; + fxgmac_test_packet pkt; + void* addr = 0; + u8 *rx_data = (u8*)kzalloc(FXGMAC_MAX_DBG_RX_DATA, GFP_KERNEL); + if (!rx_data) + return; + //int i; + + /* initial dest data region */ + pcmd = (struct ext_ioctl_data *)pcmd_data; + addr = pcmd->cmd_buf.buf; + while(pdata->expansion.fxgmac_test_skb_arr_in_index != pdata->expansion.fxgmac_test_skb_arr_out_index){ + /* get received skb data */ + rx_skb = pdata->expansion.fxgmac_test_skb_array[pdata->expansion.fxgmac_test_skb_arr_out_index]; + + if(rx_skb->len + sizeof(fxgmac_test_packet) + totalLen < 64000){ + pkt.length = rx_skb->len; + pkt.type = 0x80; + pkt.buf[0].offset = totalLen + sizeof(fxgmac_test_packet); + pkt.buf[0].length = rx_skb->len; + + /* get data from skb */ + //DPRINTK("FXG:rx_skb->len=%d", rx_skb->len); + memcpy(rx_data, rx_skb->data, rx_skb->len); + + /* update next pointer */ + if((pdata->expansion.fxgmac_test_skb_arr_out_index + 1) % FXGMAC_MAX_DBG_TEST_PKT == pdata->expansion.fxgmac_test_skb_arr_in_index) + { + pkt.next = NULL; + } + else + { + pkt.next = (pfxgmac_test_packet)(addr + totalLen + sizeof(fxgmac_test_packet) + pkt.length); + } + + /* copy data to user space */ + if(copy_to_user((void *)(addr + totalLen), (void*)(&pkt), sizeof(fxgmac_test_packet))) + { + DPRINTK("cppy pkt data to user fail..."); + } + //FXGMAC_PR("FXG:rx_skb->len=%d", rx_skb->len); + if(copy_to_user((void *)(addr + totalLen + sizeof(fxgmac_test_packet)), (void*)rx_data, rx_skb->len)) + { + DPRINTK("cppy data to user fail..."); + } + + /* update total length */ + totalLen += (sizeof(fxgmac_test_packet) + rx_skb->len); + + /* free skb */ + kfree_skb(rx_skb); + pdata->expansion.fxgmac_test_skb_array[pdata->expansion.fxgmac_test_skb_arr_out_index] = NULL; + + /* update gCurSkbOutIndex */ + pdata->expansion.fxgmac_test_skb_arr_out_index = (pdata->expansion.fxgmac_test_skb_arr_out_index + 1) % FXGMAC_MAX_DBG_TEST_PKT; + }else{ + DPRINTK("receive data more receive buffer... \n"); + break; + } + } + + if (rx_data) + kfree(rx_data); +#if 0 + pPkt = (pfxgmac_test_packet)buf; + DPRINTK("FXG: pPkt->Length is %d", pPkt->length); + DPRINTK("FXG: pPkt->Length is %d", pPkt->length); + DPRINTK("pPkt: %p, buf is %lx",pPkt, pcmd->cmd_buf.buf); + for(i = 0; i < 30; i++){ + DPRINTK("%x",*(((u8*)pPkt + sizeof(fxgmac_test_packet)) + i)); + } +#endif +} + +// Based on the current application scenario,we only use CMD_DATA for data. +// if you use other struct, you should recalculate in_total_size +long fxgmac_dbg_netdev_ops_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + bool ret = true; + int regval = 0; + struct fxgmac_pdata *pdata = file->private_data; + struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops; + FXGMAC_PDATA_OF_PLATFORM *ex = &pdata->expansion; + CMD_DATA ex_data; + struct ext_ioctl_data pcmd; + u8* data = NULL; + u8* buf = NULL; + int in_total_size, in_data_size, out_total_size; + int ioctl_cmd_size = sizeof(struct ext_ioctl_data); + u8 mac[ETH_ALEN] = {0}; + struct sk_buff *tmpskb; + + if (!arg) { + DPRINTK("[%s] command arg is %lx !\n", __func__, arg); + goto err; + } + + /* check device type */ + if (_IOC_TYPE(cmd) != IOC_MAGIC) { + DPRINTK("[%s] command type [%c] error!\n", __func__, _IOC_TYPE(cmd)); + goto err; + } + + /* check command number*/ + if (_IOC_NR(cmd) > IOC_MAXNR) { + DPRINTK("[%s] command numer [%d] exceeded!\n", __func__, _IOC_NR(cmd)); + goto err; + } + + //buf = (u8*)kzalloc(FXGMAC_MAX_DBG_BUF_LEN, GFP_KERNEL); + if(copy_from_user(&pcmd, (void*)arg, ioctl_cmd_size)) { + DPRINTK("copy data from user fail... \n"); + goto err; + } + + in_total_size = pcmd.cmd_buf.size_in; + in_data_size = in_total_size - ioctl_cmd_size; + out_total_size = pcmd.cmd_buf.size_out; + + buf = (u8*)kzalloc(in_total_size, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + if(copy_from_user(buf, (void*)arg, in_total_size)) { + DPRINTK("copy data from user fail... \n"); + goto err; + } + data = buf + ioctl_cmd_size; + + if(arg != 0) { + switch(pcmd.cmd_type) { + /* ioctl diag begin */ + case FUXI_DFS_IOCTL_DIAG_BEGIN: + DPRINTK("Debugfs received diag begin command.\n"); + if (netif_running(pdata->netdev)){ + fxgmac_restart_dev(pdata); + } + + /* release last loopback test abnormal exit buffer */ + while(ex->fxgmac_test_skb_arr_in_index != + ex->fxgmac_test_skb_arr_out_index) + { + tmpskb = ex->fxgmac_test_skb_array[ex->fxgmac_test_skb_arr_out_index]; + if(tmpskb) + { + kfree_skb(tmpskb); + ex->fxgmac_test_skb_array[ex->fxgmac_test_skb_arr_out_index] = NULL; + } + + ex->fxgmac_test_skb_arr_out_index = (ex->fxgmac_test_skb_arr_out_index + 1) % FXGMAC_MAX_DBG_TEST_PKT; + } + + /* init loopback test parameters */ + ex->fxgmac_test_skb_arr_in_index = 0; + ex->fxgmac_test_skb_arr_out_index = 0; + ex->fxgmac_test_tso_flag = false; + ex->fxgmac_test_tso_seg_num = 0; + ex->fxgmac_test_last_tso_len = 0; + ex->fxgmac_test_packet_len = 0; + break; + + /* ioctl diag end */ + case FUXI_DFS_IOCTL_DIAG_END: + DPRINTK("Debugfs received diag end command.\n"); + if (netif_running(pdata->netdev)){ + fxgmac_restart_dev(pdata); + } + break; + + /* ioctl diag tx pkt */ + case FUXI_DFS_IOCTL_DIAG_TX_PKT: + fxgmac_dbg_tx_pkt(pdata, buf); + break; + + /* ioctl diag rx pkt */ + case FUXI_DFS_IOCTL_DIAG_RX_PKT: + fxgmac_dbg_rx_pkt(pdata, buf); + break; + + /* ioctl device reset */ + case FUXI_DFS_IOCTL_DEVICE_RESET: + DPRINTK("Debugfs received device reset command.\n"); + if (netif_running(pdata->netdev)){ + fxgmac_restart_dev(pdata); + } + break; + + case FXGMAC_EFUSE_LED_TEST: + DPRINTK("Debugfs received device led test command.\n"); + memcpy(&pdata->led, data, sizeof(struct led_setting)); + fxgmac_restart_dev(pdata); + break; + + case FXGMAC_EFUSE_UPDATE_LED_CFG: + DPRINTK("Debugfs received device led update command.\n"); + memcpy(&pdata->ledconfig, data, sizeof(struct led_setting)); + ret = hw_ops->write_led_config(pdata); + hw_ops->read_led_config(pdata); + hw_ops->led_under_active(pdata); + break; + + case FXGMAC_EFUSE_WRITE_LED: + memcpy(&ex_data, data, sizeof(CMD_DATA)); + DPRINTK("FXGMAC_EFUSE_WRITE_LED, val = 0x%x\n", ex_data.val0); + ret = hw_ops->write_led(pdata, ex_data.val0); + break; + + case FXGMAC_EFUSE_WRITE_OOB: + DPRINTK("FXGMAC_EFUSE_WRITE_OOB.\n"); + ret = hw_ops->write_oob(pdata); + break; + + case FXGMAC_EFUSE_READ_REGIONABC: + memcpy(&ex_data, data, sizeof(CMD_DATA)); + ret = hw_ops->read_efuse_data(pdata, ex_data.val0, &ex_data.val1); + DPRINTK("FXGMAC_EFUSE_READ_REGIONABC, address = 0x%x, val = 0x%x\n", + ex_data.val0, + ex_data.val1); + if (ret) { + memcpy(data, &ex_data, sizeof(CMD_DATA)); + out_total_size = ioctl_cmd_size + sizeof(CMD_DATA); + if (copy_to_user((void*)arg, (void*)buf, out_total_size)) + goto err; + } + break; + + case FXGMAC_EFUSE_WRITE_PATCH_REG: + memcpy(&ex_data, data, sizeof(CMD_DATA)); + DPRINTK("FXGMAC_EFUSE_WRITE_PATCH_REG, address = 0x%x, val = 0x%x\n", + ex_data.val0, + ex_data.val1); + ret = hw_ops->write_patch_to_efuse(pdata, ex_data.val0, ex_data.val1); + break; + + case FXGMAC_EFUSE_READ_PATCH_REG: + memcpy(&ex_data, data, sizeof(CMD_DATA)); + ret = hw_ops->read_patch_from_efuse(pdata, ex_data.val0, &ex_data.val1); + DPRINTK("FXGMAC_EFUSE_READ_PATCH_REG, address = 0x%x, val = 0x%x\n", + ex_data.val0, ex_data.val1); + if (ret) { + memcpy(data, &ex_data, sizeof(CMD_DATA)); + out_total_size = ioctl_cmd_size + sizeof(CMD_DATA); + if (copy_to_user((void*)arg, (void*)buf, out_total_size)) + goto err; + } + break; + + case FXGMAC_EFUSE_WRITE_PATCH_PER_INDEX: + memcpy(&ex_data, data, sizeof(CMD_DATA)); + ret = hw_ops->write_patch_to_efuse_per_index(pdata, ex_data.val0, + ex_data.val1, + ex_data.val2); + DPRINTK("FXGMAC_EFUSE_WRITE_PATCH_PER_INDEX, index = %d, address = 0x%x, val = 0x%x\n", + ex_data.val0, ex_data.val1, ex_data.val2); + break; + + case FXGMAC_EFUSE_READ_PATCH_PER_INDEX: + memcpy(&ex_data, data, sizeof(CMD_DATA)); + ret = hw_ops->read_patch_from_efuse_per_index(pdata,ex_data.val0, + &ex_data.val1, + &ex_data.val2); + DPRINTK("FXGMAC_EFUSE_READ_PATCH_PER_INDEX, address = 0x%x, val = 0x%x\n", + ex_data.val1, ex_data.val2); + if (ret) { + memcpy(data, &ex_data, sizeof(CMD_DATA)); + out_total_size = ioctl_cmd_size + sizeof(CMD_DATA); + if (copy_to_user((void*)arg, (void*)buf, out_total_size)) + goto err; + } + break; + + case FXGMAC_EFUSE_LOAD: + DPRINTK("FXGMAC_EFUSE_LOAD.\n"); + ret = hw_ops->efuse_load(pdata); + break; + + case FXGMAC_GET_MAC_DATA: + ret = hw_ops->read_mac_subsys_from_efuse(pdata, mac, NULL, NULL); + if (ret) { + memcpy(data, mac, ETH_ALEN); + out_total_size = ioctl_cmd_size + ETH_ALEN; + if (copy_to_user((void*)arg, (void*)buf, out_total_size)) + goto err; + } + break; + + case FXGMAC_SET_MAC_DATA: + if (in_data_size != ETH_ALEN) + goto err; + memcpy(mac, data, ETH_ALEN); + ret = hw_ops->write_mac_subsys_to_efuse(pdata, mac, NULL, NULL); + if (ret) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,17,0)) + eth_hw_addr_set(pdata->netdev, mac); +#else + memcpy(pdata->netdev->dev_addr, mac, ETH_ALEN); +#endif + + memcpy(pdata->mac_addr, mac, ETH_ALEN); + + hw_ops->set_mac_address(pdata, mac); + hw_ops->set_mac_hash(pdata); + } + break; + + case FXGMAC_GET_SUBSYS_ID: + memcpy(&ex_data, data, sizeof(CMD_DATA)); + ret = hw_ops->read_mac_subsys_from_efuse(pdata, + NULL, + &ex_data.val0, + NULL); + if (ret) { + ex_data.val1 = 0xFFFF; // invalid value + memcpy(data, &ex_data, sizeof(CMD_DATA)); + out_total_size = ioctl_cmd_size + sizeof(CMD_DATA); + if (copy_to_user((void*)arg, (void*)buf, out_total_size)) + goto err; + } + break; + + case FXGMAC_SET_SUBSYS_ID: + memcpy(&ex_data, data, sizeof(CMD_DATA)); + ret = hw_ops->write_mac_subsys_to_efuse(pdata, + NULL, + &ex_data.val0, + NULL); + break; + + case FXGMAC_GET_GMAC_REG: + memcpy(&ex_data, data, sizeof(CMD_DATA)); + ex_data.val1 = hw_ops->get_gmac_register(pdata, + (u8*)(pdata->mac_regs + ex_data.val0)); + memcpy(data, &ex_data, sizeof(CMD_DATA)); + out_total_size = ioctl_cmd_size + sizeof(CMD_DATA); + if (copy_to_user((void*)arg, (void*)buf, out_total_size)) + goto err; + break; + + case FXGMAC_SET_GMAC_REG: + memcpy(&ex_data, data, sizeof(CMD_DATA)); + regval = hw_ops->set_gmac_register(pdata, + (u8*)(pdata->mac_regs + ex_data.val0), + ex_data.val1); + ret = (regval == 0 ? true : false); + break; + + case FXGMAC_GET_PHY_REG: + memcpy(&ex_data, data, sizeof(CMD_DATA)); + regval = hw_ops->read_ephy_reg(pdata, ex_data.val0, &ex_data.val1); + if (regval != -1) { + memcpy(data, &ex_data, sizeof(CMD_DATA)); + out_total_size = ioctl_cmd_size + sizeof(CMD_DATA); + if (copy_to_user((void*)arg, (void*)buf, out_total_size)) + goto err; + } + ret = (regval == -1 ? false : true); + break; + + case FXGMAC_SET_PHY_REG: + memcpy(&ex_data, data, sizeof(CMD_DATA)); + regval = hw_ops->write_ephy_reg(pdata, ex_data.val0, ex_data.val1); + ret = (regval == 0 ? true : false); + break; + + case FXGMAC_GET_PCIE_LOCATION: + ex_data.val0 = pdata->pdev->bus->number; + ex_data.val1 = PCI_SLOT(pdata->pdev->devfn); + ex_data.val2 = PCI_FUNC(pdata->pdev->devfn); + memcpy(data, &ex_data, sizeof(CMD_DATA)); + out_total_size = ioctl_cmd_size + sizeof(CMD_DATA); + if (copy_to_user((void*)arg, (void*)buf, out_total_size)) + goto err; + break; + + case FXGMAC_GET_GSO_SIZE: + ex_data.val0 = pdata->netdev->gso_max_size; + memcpy(data, &ex_data, sizeof(CMD_DATA)); + out_total_size = ioctl_cmd_size + sizeof(CMD_DATA); + if (copy_to_user((void*)arg, (void*)buf, out_total_size)) + goto err; + break; + + case FXGMAC_SET_GSO_SIZE: + memcpy(&ex_data, data, sizeof(CMD_DATA)); + pdata->netdev->gso_max_size = ex_data.val0; + break; + + case FXGMAC_SET_RX_MODERATION: + memcpy(&ex_data, data, sizeof(CMD_DATA)); + regval = readreg(pdata->pAdapter, pdata->base_mem + INT_MOD); + regval = FXGMAC_SET_REG_BITS(regval, INT_MOD_RX_POS, INT_MOD_RX_LEN, ex_data.val0); + writereg(pdata->pAdapter, regval, pdata->base_mem + INT_MOD); + break; + + case FXGMAC_SET_TX_MODERATION: + memcpy(&ex_data, data, sizeof(CMD_DATA)); + regval = readreg(pdata->pAdapter, pdata->base_mem + INT_MOD); + regval = FXGMAC_SET_REG_BITS(regval, INT_MOD_TX_POS, INT_MOD_TX_LEN, ex_data.val0); + writereg(pdata->pAdapter, regval, pdata->base_mem + INT_MOD); + break; + + case FXGMAC_GET_TXRX_MODERATION: + regval = readreg(pdata->pAdapter, pdata->base_mem + INT_MOD); + ex_data.val0 = FXGMAC_GET_REG_BITS(regval, INT_MOD_RX_POS, INT_MOD_RX_LEN); + ex_data.val1 = FXGMAC_GET_REG_BITS(regval, INT_MOD_TX_POS, INT_MOD_TX_LEN); + memcpy(data, &ex_data, sizeof(CMD_DATA)); + out_total_size = ioctl_cmd_size + sizeof(CMD_DATA); + if (copy_to_user((void*)arg, (void*)buf, out_total_size)) + goto err; + break; + + default: + DPRINTK("Debugfs received invalid command: %x.\n", pcmd.cmd_type); + ret = false; + break; + } + } + + if (buf) + kfree(buf); + return ret ? FXGMAC_SUCCESS : FXGMAC_FAIL; + +err: + if (buf) + kfree(buf); + return FXGMAC_FAIL; +} + +#ifdef HAVE_FXGMAC_DEBUG_FS + +static struct file_operations fxgmac_dbg_netdev_ops_fops = { + .owner = THIS_MODULE, + .open = simple_open, + .read = fxgmac_dbg_netdev_ops_read, + .write = fxgmac_dbg_netdev_ops_write, + .unlocked_ioctl = fxgmac_dbg_netdev_ops_ioctl, +}; + +/** + * fxgmac_dbg_adapter_init - setup the debugfs directory for the adapter + * @adapter: the adapter that is starting up + **/ +void fxgmac_dbg_adapter_init(struct fxgmac_pdata *pdata) +{ + const char *name = pdata->drv_name; + struct dentry *pfile; + + pdata->expansion.dbg_adapter = debugfs_create_dir(name, pdata->expansion.fxgmac_dbg_root); + if (pdata->expansion.dbg_adapter) { + pfile = debugfs_create_file("netdev_ops", 0600, + pdata->expansion.dbg_adapter, pdata, + &fxgmac_dbg_netdev_ops_fops); + if (!pfile) + DPRINTK("debugfs netdev_ops for %s failed\n", name); + } else { + DPRINTK("debugfs entry for %s failed\n", name); + } +} + +/** + * fxgmac_dbg_adapter_exit - clear out the adapter's debugfs entries + * @adapter: board private structure + **/ +void fxgmac_dbg_adapter_exit(struct fxgmac_pdata *pdata) +{ + if (pdata->expansion.dbg_adapter) + debugfs_remove_recursive(pdata->expansion.dbg_adapter); + pdata->expansion.dbg_adapter = NULL; +} + +/** + * fxgmac_dbg_init - start up debugfs for the driver + **/ +void fxgmac_dbg_init(struct fxgmac_pdata *pdata) +{ + unsigned int i; + char num[3]; + const char debug_path[] = "/sys/kernel/debug/"; + const char file_prefix[] = "fuxi_"; + char file_path[50]; + char file_name[8]; + + /* init file_path */ + memset(file_path, '\0', sizeof(file_path)); + memcpy(file_path, debug_path, sizeof(debug_path)); + + for(i = 0; i < DF_MAX_NIC_NUM; i++) + { + /* init num and filename */ + memset(num, '\0', sizeof(num)); + memset(file_name, '\0', sizeof(file_name)); + + /* int to string */ + sprintf(num, "%d", i); + + /* file name */ + memcpy(file_name, file_prefix, sizeof(file_prefix)); + memcpy(file_name + strlen(file_prefix), num, sizeof(num)); + + /* file path */ + memcpy(file_path + sizeof(debug_path) - 1, file_name, sizeof(file_name)); + //DPRINTK("FXG: file_path is %s", file_path); + + /* whether file exist */ + pdata->expansion.fxgmac_dbg_root = debugfs_lookup(file_name, NULL); + if (!pdata->expansion.fxgmac_dbg_root) + { + /* create file */ + pdata->expansion.fxgmac_dbg_root = debugfs_create_dir(file_name, NULL); + if (IS_ERR(pdata->expansion.fxgmac_dbg_root)) + DPRINTK("fxgmac init of debugfs failed\n"); + + break; + } + } +} + +/** + * fxgmac_dbg_exit - clean out the driver's debugfs entries + **/ +void fxgmac_dbg_exit(struct fxgmac_pdata *pdata) +{ + if (pdata->expansion.fxgmac_dbg_root) + debugfs_remove_recursive(pdata->expansion.fxgmac_dbg_root); +} + +#endif /* HAVE_XLGMAC_DEBUG_FS */ diff --git a/drivers/net/ethernet/motorcomm/fuxi-gmac-desc.c b/drivers/net/ethernet/motorcomm/fuxi-gmac-desc.c new file mode 100644 index 000000000000..d030b6eb9fc3 --- /dev/null +++ b/drivers/net/ethernet/motorcomm/fuxi-gmac-desc.c @@ -0,0 +1,1254 @@ +/*++ + +Copyright (c) 2021 Motorcomm Corporation. +Confidential and Proprietary. All rights reserved. + +This is Motorcomm Corporation NIC driver relevant files. Please don't copy, modify, +distribute without commercial permission. + +--*/ + + +#include "fuxi-gmac.h" +#include "fuxi-gmac-reg.h" + +#if defined(UEFI) +#include "nic_sw.h" +#elif defined(_WIN32) || defined(_WIN64) +#include "fuxi-mp.h" +#endif + +static void fxgmac_unmap_desc_data(struct fxgmac_pdata* pdata, + struct fxgmac_desc_data* desc_data) +{ +#ifndef LINUX + pdata = pdata; + desc_data = desc_data; +#else + if (desc_data->skb_dma) { + if (desc_data->mapped_as_page) { + dma_unmap_page(pdata->dev, desc_data->skb_dma, + desc_data->skb_dma_len, DMA_TO_DEVICE); + } + else { + dma_unmap_single(pdata->dev, desc_data->skb_dma, + desc_data->skb_dma_len, DMA_TO_DEVICE); + } + desc_data->skb_dma = 0; + desc_data->skb_dma_len = 0; + } + + if (desc_data->rx.buf.dma_base) { + dma_unmap_single(pdata->dev, desc_data->rx.buf.dma_base, + pdata->rx_buf_size, DMA_FROM_DEVICE); + desc_data->rx.buf.dma_base = 0; + } + + if (desc_data->skb) { + dev_kfree_skb_any(desc_data->skb); + desc_data->skb = NULL; + } + +#if 0 + if (desc_data->rx.hdr.pa.pages) + put_page(desc_data->rx.hdr.pa.pages); + + if (desc_data->rx.hdr.pa_unmap.pages) { + dma_unmap_page(pdata->dev, desc_data->rx.hdr.pa_unmap.pages_dma, + desc_data->rx.hdr.pa_unmap.pages_len, + DMA_FROM_DEVICE); + put_page(desc_data->rx.hdr.pa_unmap.pages); + } + + if (desc_data->rx.buf.pa.pages) + put_page(desc_data->rx.buf.pa.pages); + + if (desc_data->rx.buf.pa_unmap.pages) { + dma_unmap_page(pdata->dev, desc_data->rx.buf.pa_unmap.pages_dma, + desc_data->rx.buf.pa_unmap.pages_len, + DMA_FROM_DEVICE); + put_page(desc_data->rx.buf.pa_unmap.pages); + } +#endif + memset(&desc_data->tx, 0, sizeof(desc_data->tx)); + memset(&desc_data->rx, 0, sizeof(desc_data->rx)); + + desc_data->mapped_as_page = 0; + + if (desc_data->state_saved) { + desc_data->state_saved = 0; + desc_data->state.skb = NULL; + desc_data->state.len = 0; + desc_data->state.error = 0; + } +#endif +} + +static void fxgmac_free_ring(struct fxgmac_pdata* pdata, + struct fxgmac_ring* ring) +{ +#ifndef LINUX + pdata = pdata; + + if (!ring) + return; +#else + struct fxgmac_desc_data* desc_data; + unsigned int i; + + if (!ring) + return; + + if (ring->desc_data_head) { + for (i = 0; i < ring->dma_desc_count; i++) { + desc_data = FXGMAC_GET_DESC_DATA(ring, i); + fxgmac_unmap_desc_data(pdata, desc_data); + } + + kfree(ring->desc_data_head); + ring->desc_data_head = NULL; + } + +#if 0 + if (ring->rx_hdr_pa.pages) { + dma_unmap_page(pdata->dev, ring->rx_hdr_pa.pages_dma, + ring->rx_hdr_pa.pages_len, DMA_FROM_DEVICE); + put_page(ring->rx_hdr_pa.pages); + + ring->rx_hdr_pa.pages = NULL; + ring->rx_hdr_pa.pages_len = 0; + ring->rx_hdr_pa.pages_offset = 0; + ring->rx_hdr_pa.pages_dma = 0; + } + + if (ring->rx_buf_pa.pages) { + dma_unmap_page(pdata->dev, ring->rx_buf_pa.pages_dma, + ring->rx_buf_pa.pages_len, DMA_FROM_DEVICE); + put_page(ring->rx_buf_pa.pages); + + ring->rx_buf_pa.pages = NULL; + ring->rx_buf_pa.pages_len = 0; + ring->rx_buf_pa.pages_offset = 0; + ring->rx_buf_pa.pages_dma = 0; + } +#endif + + if (ring->dma_desc_head) { + dma_free_coherent(pdata->dev, + (sizeof(struct fxgmac_dma_desc) * + ring->dma_desc_count), + ring->dma_desc_head, + ring->dma_desc_head_addr); + ring->dma_desc_head = NULL; + } +#endif +} + +static int fxgmac_init_ring(struct fxgmac_pdata* pdata, + struct fxgmac_ring* ring, + unsigned int dma_desc_count) +{ + if (!ring) + return 0; + +#ifndef LINUX + pdata = pdata; + dma_desc_count = dma_desc_count; + ring->dma_desc_count = 0; + + return 0; +#else + /* Descriptors */ + ring->dma_desc_count = dma_desc_count; + ring->dma_desc_head = dma_alloc_coherent(pdata->dev, + (sizeof(struct fxgmac_dma_desc) * + dma_desc_count), + &ring->dma_desc_head_addr, + GFP_KERNEL); + if (!ring->dma_desc_head) + return -ENOMEM; + + /* Array of descriptor data */ + ring->desc_data_head = kcalloc(dma_desc_count, + sizeof(struct fxgmac_desc_data), + GFP_KERNEL); + if (!ring->desc_data_head) + return -ENOMEM; + + netif_dbg(pdata, drv, pdata->netdev, + "dma_desc_head=%p, dma_desc_head_addr=%pad, desc_data_head=%p\n", + ring->dma_desc_head, + &ring->dma_desc_head_addr, + ring->desc_data_head); + + return 0; +#endif +} + +static void fxgmac_free_rings(struct fxgmac_pdata* pdata) +{ + struct fxgmac_channel* channel; + unsigned int i; + + if (!pdata->channel_head) + return; + + channel = pdata->channel_head; + for (i = 0; i < pdata->channel_count; i++, channel++) { + fxgmac_free_ring(pdata, channel->tx_ring); + fxgmac_free_ring(pdata, channel->rx_ring); + } +} + +static int fxgmac_alloc_rings(struct fxgmac_pdata* pdata) +{ + struct fxgmac_channel* channel; + unsigned int i; + int ret; + + channel = pdata->channel_head; + for (i = 0; i < pdata->channel_count; i++, channel++) { + netif_dbg(pdata, drv, pdata->netdev, "%s - Tx ring:\n", + channel->name); + + if (i < pdata->tx_ring_count) + { + ret = fxgmac_init_ring(pdata, channel->tx_ring, + pdata->tx_desc_count); + + if (ret) { + netdev_alert(pdata->netdev, "error initializing Tx ring"); + goto err_init_ring; + } + } + + netif_dbg(pdata, drv, pdata->netdev, "%s - Rx ring:\n", channel->name); + + ret = fxgmac_init_ring(pdata, channel->rx_ring, + pdata->rx_desc_count); + if (ret) { + netdev_alert(pdata->netdev, + "error initializing Rx ring\n"); + goto err_init_ring; + } + if(netif_msg_drv(pdata)) DPRINTK("fxgmac_alloc_ring..ch=%u,tx_desc_cnt=%u,rx_desc_cnt=%u\n",i,pdata->tx_desc_count,pdata->rx_desc_count); + } + if(netif_msg_drv(pdata)) DPRINTK("alloc_rings callout ok\n"); + + return 0; + +err_init_ring: + fxgmac_free_rings(pdata); + + DPRINTK("alloc_rings callout err,%d\n",ret); + return ret; +} + +#ifdef LINUX +static void fxgmac_free_channels(struct fxgmac_pdata *pdata) +{ + if (!pdata->channel_head) + return; + if(netif_msg_drv(pdata)) DPRINTK("free_channels,tx_ring=%p\n", pdata->channel_head->tx_ring); + kfree(pdata->channel_head->tx_ring); + pdata->channel_head->tx_ring = NULL; + + if(netif_msg_drv(pdata)) DPRINTK("free_channels,rx_ring=%p\n", pdata->channel_head->rx_ring); + kfree(pdata->channel_head->rx_ring); + pdata->channel_head->rx_ring = NULL; + + if(netif_msg_drv(pdata)) DPRINTK("free_channels,channel=%p\n", pdata->channel_head); + kfree(pdata->channel_head); + + pdata->channel_head = NULL; + //comment out below line for that, channel_count is initialized only once in hw_init() + //pdata->channel_count = 0; +} +#else +static void fxgmac_free_channels(struct fxgmac_pdata* pdata) +{ + if (!pdata->channel_head) + return; + + //kfree(pdata->channel_head->tx_ring); + pdata->channel_head->tx_ring = NULL; + + //kfree(pdata->channel_head->rx_ring); + pdata->channel_head->rx_ring = NULL; + + //kfree(pdata->channel_head); + + pdata->channel_head = NULL; + pdata->channel_count = 0; +} +#endif + +#if defined(UEFI) +static int fxgmac_alloc_channels(struct fxgmac_pdata* pdata) +{ + struct fxgmac_channel* channel_head, * channel; + struct fxgmac_ring* tx_ring, * rx_ring; + int ret = -ENOMEM; + unsigned int i; + EFI_STATUS Status; + UINT64 vir_addr; + UINT64 cache_sz = CACHE_ALIGN_SZ; + PADAPTER adpt = (PADAPTER)pdata->pAdapter; + // + // Allocate memory for transmit and receive resources. + // + DEBUGPRINT(INIT, "[%a,%a,%d]:\n",__FILE__, __func__,__LINE__); + Status = adpt->Io_Function->AllocateBuffer( + adpt->Io_Function, + AllocateAnyPages, + EfiRuntimeServicesData, + UNDI_MEM_PAGES(CHANNEL_MEMORY_NEEDED), + (VOID**)&(adpt->MemoryChannelPtr), + 0 + ); + + if (EFI_ERROR(Status)) { + DEBUGPRINT(INIT, ("Error PCI IO AllocateBuffer returns \n")); + goto err; + } + + DEBUGPRINT(INIT, "[%a,%a,%d]:status=%x,MemoryChannelPtr=%llx\n",__FILE__, __func__,__LINE__,Status,adpt->MemoryChannelPtr); + vir_addr = (adpt->MemoryChannelPtr + cache_sz) & (~(cache_sz - 1)); +#ifdef UEFI_64 + channel_head = (struct fxgmac_channel*)vir_addr; +#else + channel_head = (struct fxgmac_channel*)(UINT32)vir_addr; +#endif + + DEBUGPRINT(INIT, "[%a,%a,%d]:Channel_head=%llx,vir_addr=%llx\n",__FILE__, __func__,__LINE__,channel_head,vir_addr); + netif_dbg(pdata, drv, pdata->netdev, + "channel_head=%p\n", channel_head); + + vir_addr = (vir_addr + 4 * sizeof(struct fxgmac_channel) + cache_sz) & (~(cache_sz - 1)); +#ifdef UEFI_64 + tx_ring = (struct fxgmac_ring*)vir_addr; +#else + tx_ring = (struct fxgmac_ring*)(UINT32)vir_addr; +#endif + + + vir_addr = (vir_addr + 4 * sizeof(struct fxgmac_ring) + cache_sz) & (~(cache_sz - 1)); +#ifdef UEFI_64 + rx_ring = (struct fxgmac_ring*)vir_addr; +#else + rx_ring = (struct fxgmac_ring*)(UINT32)vir_addr; +#endif + + DEBUGPRINT(INIT, "[%a,%a,%d]:Channel_head=%llx,*channel_head=%llx,vir_addr=%llx,tx_ring=%llx,rx_ring=%llx,channelcount=%llx,pdata=%llx\n",__FILE__, __func__,__LINE__,channel_head,*channel_head,vir_addr,tx_ring,rx_ring,pdata->channel_count,&channel_head->pdata); + for (i = 0, channel = channel_head; i < pdata->channel_count; + i++, channel++) { + //snprintf(channel->name, sizeof(channel->name), "channel-%u", i); + //RtlStringCchPrintfA(channel->name, sizeof(channel->name), "channel-%u", i); + //netif_dbg(pdata, drv, pdata->netdev,"channel-%u\n", i); + + DEBUGPRINT(INIT, "[%a,%a,%d]:channel=%llx,&channel->pdata=%llx\n",__FILE__, __func__,__LINE__,channel,&channel->pdata); + channel->pdata = pdata; + DEBUGPRINT(INIT, "[%a,%d]:channel->pdata:%llx,pdata:%llx\n",__func__,__LINE__,channel->pdata,pdata); + channel->queue_index = i; + channel->dma_regs = pdata->mac_regs + DMA_CH_BASE + + (DMA_CH_INC * i); + + if (pdata->per_channel_irq) { + /* Get the per DMA interrupt */ + ret = pdata->channel_irq[i]; + if (ret < 0) { + netdev_err(pdata->netdev, + "get_irq %u failed\n", + i + 1); + goto err; + } + channel->dma_irq = ret; + } + + if (i < pdata->tx_ring_count) + channel->tx_ring = tx_ring++; + + if (i < pdata->rx_ring_count) + channel->rx_ring = rx_ring++; + netif_dbg(pdata, drv, pdata->netdev, + ""STR_FORMAT": dma_regs=%p, tx_ring=%p, rx_ring=%p\n", + channel->name, channel->dma_regs, + channel->tx_ring, channel->rx_ring); + + DEBUGPRINT(INIT, "[%a,%d]:Channel_dma_regs=%llx,channel txring=%llx,channel rx_ring=%llx,i=%llx,channel_count=%llx\n", __func__,__LINE__,channel->dma_regs,channel->tx_ring,channel->rx_ring,i,pdata->channel_count); + } + + pdata->channel_head = channel_head; + + return 0; + + err: + return ret; +} +#elif defined(LINUX) +static int fxgmac_alloc_channels(struct fxgmac_pdata *pdata) +{ + struct fxgmac_channel *channel_head, *channel; + struct fxgmac_ring *tx_ring, *rx_ring; + int ret = -ENOMEM; + unsigned int i; + +#ifdef CONFIG_PCI_MSI + u32 msix = FXGMAC_GET_REG_BITS(pdata->expansion.int_flags, + FXGMAC_FLAG_MSIX_POS, + FXGMAC_FLAG_MSIX_LEN); +#endif + + channel_head = kcalloc(pdata->channel_count, + sizeof(struct fxgmac_channel), GFP_KERNEL); + if(netif_msg_drv(pdata)) DPRINTK("alloc_channels,channel_head=%p,size=%d*%ld\n", channel_head, pdata->channel_count,sizeof(struct fxgmac_channel)); + + if (!channel_head) + return ret; + + netif_dbg(pdata, drv, pdata->netdev, + "channel_head=%p\n", channel_head); + + tx_ring = kcalloc(pdata->tx_ring_count, sizeof(struct fxgmac_ring), + GFP_KERNEL); + if (!tx_ring) + goto err_tx_ring; + + if(netif_msg_drv(pdata)) DPRINTK("alloc_channels,tx_ring=%p,size=%d*%ld\n", tx_ring, pdata->tx_ring_count,sizeof(struct fxgmac_ring)); + rx_ring = kcalloc(pdata->rx_ring_count, sizeof(struct fxgmac_ring), + GFP_KERNEL); + if (!rx_ring) + goto err_rx_ring; + + if(netif_msg_drv(pdata)) DPRINTK("alloc_channels,rx_ring=%p,size=%d*%ld\n", rx_ring, pdata->rx_ring_count,sizeof(struct fxgmac_ring)); + //DPRINTK("fxgmac_alloc_channels ch_num=%d,rxring=%d,txring=%d\n",pdata->channel_count, pdata->rx_ring_count,pdata->tx_ring_count); + + for (i = 0, channel = channel_head; i < pdata->channel_count; + i++, channel++) { + snprintf(channel->name, sizeof(channel->name), "channel-%u", i); + channel->pdata = pdata; + channel->queue_index = i; + channel->dma_regs = pdata->mac_regs + DMA_CH_BASE + + (DMA_CH_INC * i); + + if (pdata->per_channel_irq) { + /* Get the per DMA interrupt */ +#ifdef CONFIG_PCI_MSI + //20210526 for MSIx + if(msix) { + pdata->channel_irq[i] = pdata->expansion.msix_entries[i].vector; + if (FXGMAC_IS_CHANNEL_WITH_TX_IRQ(i)) { + pdata->channel_irq[FXGMAC_MAX_DMA_CHANNELS] = pdata->expansion.msix_entries[FXGMAC_MAX_DMA_CHANNELS].vector; + + if (pdata->channel_irq[FXGMAC_MAX_DMA_CHANNELS] < 0) { + netdev_err(pdata->netdev, + "get_irq %u for tx failed\n", + i + 1); + goto err_irq; + } + + channel->expansion.dma_irq_tx = pdata->channel_irq[FXGMAC_MAX_DMA_CHANNELS]; + DPRINTK("fxgmac_alloc_channels, for MSIx, channel %d dma_irq_tx=%u\n", i, channel->expansion.dma_irq_tx); + } + } +#endif + ret = pdata->channel_irq[i]; + if (ret < 0) { + netdev_err(pdata->netdev, + "get_irq %u failed\n", + i + 1); + goto err_irq; + } + channel->dma_irq = ret; + DPRINTK("fxgmac_alloc_channels, for MSIx, channel %d dma_irq=%u\n", i, channel->dma_irq); + } + + if (i < pdata->tx_ring_count) + channel->tx_ring = tx_ring++; + + if (i < pdata->rx_ring_count) + channel->rx_ring = rx_ring++; + + netif_dbg(pdata, drv, pdata->netdev, + "%s: dma_regs=%p, tx_ring=%p, rx_ring=%p\n", + channel->name, channel->dma_regs, + channel->tx_ring, channel->rx_ring); + } + + pdata->channel_head = channel_head; + + if(netif_msg_drv(pdata)) DPRINTK("alloc_channels callout ok\n"); + return 0; + +err_irq: + kfree(rx_ring); + +err_rx_ring: + kfree(tx_ring); + +err_tx_ring: + kfree(channel_head); + + DPRINTK("fxgmac alloc_channels callout err,%d\n",ret); + return ret; +} +#elif defined(_WIN32) || defined(_WIN64) +static int fxgmac_alloc_channels(struct fxgmac_pdata* pdata) +{ + struct fxgmac_channel* channel_head, * channel; + struct fxgmac_ring* tx_ring, * rx_ring; + PMP_ADAPTER pAdapter = (PMP_ADAPTER)pdata->pAdapter; + int ret = -ENOMEM; + unsigned int i; + + //channel_head = kcalloc(pdata->channel_count, + // sizeof(struct fxgmac_channel), GFP_KERNEL); + //if (!channel_head) + // return ret; + + channel_head = &pAdapter->MpChannelRingResources.fx_channel[0]; + + netif_dbg(pdata, drv, pdata->netdev, + "channel_head=%p\n", channel_head); + + //tx_ring = kcalloc(pdata->tx_ring_count, sizeof(struct fxgmac_ring), + // GFP_KERNEL); + //if (!tx_ring) + // goto err_tx_ring; + tx_ring = &pAdapter->MpChannelRingResources.fx_tx_ring[0]; + + //rx_ring = kcalloc(pdata->rx_ring_count, sizeof(struct fxgmac_ring), + // GFP_KERNEL); + //if (!rx_ring) + // goto err_rx_ring; + rx_ring = &pAdapter->MpChannelRingResources.fx_rx_ring[0]; + + for (i = 0, channel = channel_head; i < pdata->channel_count; + i++, channel++) { + //snprintf(channel->name, sizeof(channel->name), "channel-%u", i); + RtlStringCchPrintfA(channel->name, sizeof(channel->name), "channel-%u", i); + + channel->pdata = pdata; + channel->queue_index = i; + channel->dma_regs = pdata->mac_regs + DMA_CH_BASE + + (DMA_CH_INC * i); + + if (pdata->per_channel_irq) { + /* Get the per DMA interrupt */ + ret = pdata->channel_irq[i]; + if (ret < 0) { + netdev_err(pdata->netdev, + "get_irq %u failed\n", + i + 1); + goto err_irq; + } + channel->dma_irq = ret; + } + + if (i < pdata->tx_ring_count) + channel->tx_ring = tx_ring++; + + if (i < pdata->rx_ring_count) + channel->rx_ring = rx_ring++; + + netif_dbg(pdata, drv, pdata->netdev, + "%s: dma_regs=%p, tx_ring=%p, rx_ring=%p\n", + channel->name, channel->dma_regs, + channel->tx_ring, channel->rx_ring); + } + + pdata->channel_head = channel_head; + + return 0; + +err_irq: + //kfree(rx_ring); + +//err_rx_ring: + //kfree(tx_ring); + +//err_tx_ring: + //kfree(channel_head); + + return ret; + +} +#elif defined(UBOOT) +static int fxgmac_alloc_channels(struct fxgmac_pdata* pdata) +{ + struct fxgmac_channel * channel; + unsigned int i; + + for (i = 0; i < pdata->channel_count; i++) + { + //snprintf(channel->name, sizeof(channel->name), "channel-%u", i); + //RtlStringCchPrintfA(channel->name, sizeof(channel->name), "channel-%u" , i); + //netif_dbg(pdata, drv, pdata->netdev,"channel-%u\n", i); + channel = pdata->channel_head; + + channel->pdata = pdata; + channel->queue_index = i; + channel->dma_regs = pdata->mac_regs + DMA_CH_BASE + + (DMA_CH_INC * i); + + /* set tx/rx channel*/ +#if 1 + pdata->expansion.tx_channel = pdata->channel_head; + + pdata->expansion.rx_channel = pdata->channel_head; +#else + if(i == 0) + pdata->tx_channel = &pdata->channel_head[i]; + else + pdata->rx_channel = &pdata->channel_head[i]; +#endif + } + return 0; +} +#else +static struct fxgmac_channel fx_channel[4]; +static struct fxgmac_ring fx_tx_ring[4]; +static struct fxgmac_ring fx_rx_ring[4]; + +static int fxgmac_alloc_channels(struct fxgmac_pdata* pdata) +{ + struct fxgmac_channel* channel_head, * channel; + struct fxgmac_ring* tx_ring, * rx_ring; + int ret = -ENOMEM; + unsigned int i; + + //channel_head = kcalloc(pdata->channel_count, + // sizeof(struct fxgmac_channel), GFP_KERNEL); + //if (!channel_head) + // return ret; + channel_head = &fx_channel[0]; + + netif_dbg(pdata, drv, pdata->netdev, + "channel_head=%p\n", channel_head); + + //tx_ring = kcalloc(pdata->tx_ring_count, sizeof(struct fxgmac_ring), + // GFP_KERNEL); + //if (!tx_ring) + // goto err_tx_ring; + tx_ring = &fx_tx_ring[0]; + + //rx_ring = kcalloc(pdata->rx_ring_count, sizeof(struct fxgmac_ring), + // GFP_KERNEL); + //if (!rx_ring) + // goto err_rx_ring; + rx_ring = &fx_rx_ring[0]; + + for (i = 0, channel = channel_head; i < pdata->channel_count; + i++, channel++) { + //snprintf(channel->name, sizeof(channel->name), "channel-%u", i); + //RtlStringCchPrintfA(channel->name, sizeof(channel->name), "channel-%u", i); + + channel->pdata = pdata; + channel->queue_index = i; + channel->dma_regs = pdata->mac_regs + DMA_CH_BASE + + (DMA_CH_INC * i); + + if (pdata->per_channel_irq) { + /* Get the per DMA interrupt */ + ret = pdata->channel_irq[i]; + if (ret < 0) { + netdev_err(pdata->netdev, + "get_irq %u failed\n", + i + 1); + goto err_irq; + } + channel->dma_irq = ret; + } + + if (i < pdata->tx_ring_count) + channel->tx_ring = tx_ring++; + + if (i < pdata->rx_ring_count) + channel->rx_ring = rx_ring++; + + netif_dbg(pdata, drv, pdata->netdev, + "%s: dma_regs=%p, tx_ring=%p, rx_ring=%p\n", + channel->name, channel->dma_regs, + channel->tx_ring, channel->rx_ring); + } + + pdata->channel_head = channel_head; + + return 0; + +err_irq: + //kfree(rx_ring); + + //err_rx_ring: + //kfree(tx_ring); + + //err_tx_ring: + //kfree(channel_head); + + return ret; +} +#endif + +static void fxgmac_free_channels_and_rings(struct fxgmac_pdata* pdata) +{ + fxgmac_free_rings(pdata); + + fxgmac_free_channels(pdata); +} + +static int fxgmac_alloc_channels_and_rings(struct fxgmac_pdata* pdata) +{ + int ret; + + ret = fxgmac_alloc_channels(pdata); + if (ret) + goto err_alloc; + + ret = fxgmac_alloc_rings(pdata); + if (ret) + goto err_alloc; + + return 0; + +err_alloc: + fxgmac_free_channels_and_rings(pdata); + + return ret; +} + +#if 0 +static int fxgmac_alloc_pages(struct fxgmac_pdata *pdata, + struct fxgmac_page_alloc *pa, + gfp_t gfp, int order) +{ + struct page *pages = NULL; + dma_addr_t pages_dma; + + /* Try to obtain pages, decreasing order if necessary */ + gfp |= __GFP_COMP | __GFP_NOWARN; + while (order >= 0) { + pages = alloc_pages(gfp, order); + if (pages) + break; + + order--; + } + if (!pages) + return -ENOMEM; + + /* Map the pages */ + pages_dma = dma_map_page(pdata->dev, pages, 0, + PAGE_SIZE << order, DMA_FROM_DEVICE); + if (dma_mapping_error(pdata->dev, pages_dma)) { + put_page(pages); + return -ENOMEM; + } + + pa->pages = pages; + pa->pages_len = PAGE_SIZE << order; + pa->pages_offset = 0; + pa->pages_dma = pages_dma; + + return 0; +} +#endif +#if !(defined(UEFI) || defined(LINUX) || defined(UBOOT)) +static void fxgmac_set_buffer_data(struct fxgmac_buffer_data* bd, + struct fxgmac_page_alloc* pa, + unsigned int len) +{ +#ifndef LINUX + bd = bd; + pa = pa; + len = len; +#else + get_page(pa->pages); + bd->pa = *pa; + + bd->dma_base = pa->pages_dma; + bd->dma_off = pa->pages_offset; + bd->dma_len = len; + + pa->pages_offset += len; + if ((pa->pages_offset + len) > pa->pages_len) { + /* This data descriptor is responsible for unmapping page(s) */ + bd->pa_unmap = *pa; + + /* Get a new allocation next time */ + pa->pages = NULL; + pa->pages_len = 0; + pa->pages_offset = 0; + pa->pages_dma = 0; + } +#endif +} +#endif + +static int fxgmac_map_rx_buffer(struct fxgmac_pdata* pdata, + struct fxgmac_ring* ring, + struct fxgmac_desc_data* desc_data) +{ +#ifndef LINUX + pdata = pdata; + ring = ring; + desc_data = desc_data; +#else +#if 0 + int order, ret; + + if (!ring->rx_hdr_pa.pages) { + ret = fxgmac_alloc_pages(pdata, &ring->rx_hdr_pa, + GFP_ATOMIC, 0); + if (ret) + return ret; + } + + if (!ring->rx_buf_pa.pages) { + order = max_t(int, PAGE_ALLOC_COSTLY_ORDER - 1, 0); + ret = fxgmac_alloc_pages(pdata, &ring->rx_buf_pa, + GFP_ATOMIC, order); + if (ret) + return ret; + } + + /* Set up the header page info */ + fxgmac_set_buffer_data(&desc_data->rx.hdr, &ring->rx_hdr_pa, + FXGMAC_SKB_ALLOC_SIZE); + + /* Set up the buffer page info */ + fxgmac_set_buffer_data(&desc_data->rx.buf, &ring->rx_buf_pa, + pdata->rx_buf_size); +#endif + struct sk_buff *skb; + skb = __netdev_alloc_skb_ip_align(pdata->netdev, pdata->rx_buf_size, GFP_ATOMIC); + if (!skb) { + netdev_err(pdata->netdev, + "%s: Rx init fails; skb is NULL\n", __func__); + return -ENOMEM; + } + + desc_data->skb = skb; + desc_data->rx.buf.dma_base = dma_map_single(pdata->dev, skb->data, pdata->rx_buf_size, DMA_FROM_DEVICE); + if (dma_mapping_error(pdata->dev, desc_data->rx.buf.dma_base)) { + netdev_err(pdata->netdev, "%s: DMA mapping error\n", __func__); + dev_kfree_skb_any(skb); + return -EINVAL; + } + +#endif + return 0; +} + +#ifdef UBOOT +static void yt6801_desc_reset(struct fxgmac_dma_desc *desc_data) +{ + /* 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) + */ + desc_data->desc0 = 0; + desc_data->desc1 = 0; + desc_data->desc2 = 0; + desc_data->desc3 = 0; + + /* Make sure ownership is written to the descriptor */ + //dma_wmb(); +} + +static void fxgmac_hw_tx_desc_init(struct fxgmac_channel *channel) +{ + struct fxgmac_dma_desc *desc_data; + struct fxgmac_pdata * pdata = channel->pdata; + unsigned int i; + + /* Initialize all descriptors */ + for (i = 0; i < NIC_DEF_TBDS; i++) { + desc_data = pdata->expansion.tx_desc_list + i; + + /* Initialize Tx descriptor */ + yt6801_desc_reset(desc_data); + } + + ///* Update the total number of Tx descriptors */ + writereg(pdata->pAdapter, NIC_DEF_TBDS - 1, FXGMAC_DMA_REG(channel, DMA_CH_TDRLR)); + +#if 0 + DbgPrintF(MP_TRACE, "tx_desc_list:%p\n", pdata->tx_desc_list); + DbgPrintF(MP_TRACE, "bus_to_phys:%llx\n", bus_to_phys(pdata->pdev, + (pci_addr_t)(unsigned long)pdata->tx_desc_list));//adpt->TbdPhyAddr + DbgPrintF(MP_TRACE, "lower_32_bits:%x\n", lower_32_bits(bus_to_phys(pdata->pdev, + (pci_addr_t)(unsigned long)pdata->tx_desc_list)));//adpt->TbdPhyAddr + DbgPrintF(MP_TRACE, "dma tdlr lo:%p\n", FXGMAC_DMA_REG(channel, DMA_CH_TDLR_LO)); +#endif + /* Update the starting address of descriptor ring */ + writereg(pdata->pAdapter, upper_32_bits(cpu_to_le64(bus_to_phys(pdata->pdev, + (pci_addr_t)(unsigned long)pdata->expansion.tx_desc_list))),//adpt->TbdPhyAddr + FXGMAC_DMA_REG(channel, DMA_CH_TDLR_HI)); + writereg(pdata->pAdapter, lower_32_bits(cpu_to_le64(bus_to_phys(pdata->pdev, + (pci_addr_t)(unsigned long)pdata->expansion.tx_desc_list))),//adpt->TbdPhyAddr + FXGMAC_DMA_REG(channel, DMA_CH_TDLR_LO)); +#if 0 + DbgPrintF(MP_TRACE, "Read tx starting high address:%x\n", + readreg(pdata->pAdapter, FXGMAC_DMA_REG(channel, DMA_CH_TDLR_HI))); + DbgPrintF(MP_TRACE, "Read tx starting low address:%x\n", + readreg(pdata->pAdapter, FXGMAC_DMA_REG(channel, DMA_CH_TDLR_LO))); +#endif +} + +static void fxgmac_tx_desc_init(struct fxgmac_pdata* pdata) +{ + fxgmac_hw_tx_desc_init(pdata->expansion.tx_channel); +} + +static void fxgmac_hw_rx_desc_init(struct fxgmac_channel *channel) +{ + struct fxgmac_pdata *pdata = channel->pdata; + struct fxgmac_dma_desc *desc_data; + unsigned int i; + uint64_t HwRbdPa; + + /* Initialize all descriptors */ + for (i = 0; i < NIC_DEF_RECV_BUFFERS; i++) { + desc_data = pdata->expansion.rx_desc_list + i; + + /* Initialize Rx descriptor */ + yt6801_desc_reset(desc_data); + desc_data->desc0 = lower_32_bits(bus_to_phys(pdata->pdev, (pci_addr_t)(unsigned long)(pdata->expansion.rx_buffer))); + desc_data->desc1 = upper_32_bits(bus_to_phys(pdata->pdev, (pci_addr_t)(unsigned long)(pdata->expansion.rx_buffer))); + desc_data->desc3 = FXGMAC_SET_REG_BITS_LE( + desc_data->desc3, + RX_NORMAL_DESC3_BUF2V_POS, + RX_NORMAL_DESC3_BUF2V_LEN, + 1); + desc_data->desc3 = FXGMAC_SET_REG_BITS_LE( + desc_data->desc3, + RX_NORMAL_DESC3_BUF1V_POS, + RX_NORMAL_DESC3_BUF1V_LEN, + 1); + desc_data->desc3 = FXGMAC_SET_REG_BITS_LE( + desc_data->desc3, + RX_NORMAL_DESC3_OWN_POS, + RX_NORMAL_DESC3_OWN_LEN, + 1); + } + + /* Update the total number of Rx descriptors */ + writereg(pdata->pAdapter, NIC_DEF_RECV_BUFFERS - 1, FXGMAC_DMA_REG(channel, DMA_CH_RDRLR)); +#if 0 + DbgPrintF(MP_TRACE, "rx_desc_list:%p\n", pdata->rx_desc_list); + DbgPrintF(MP_TRACE, "bus_to_phys:%llx\n", bus_to_phys(pdata->pdev, + (pci_addr_t)(unsigned long)pdata->rx_desc_list));//adpt->TbdPhyAddr + DbgPrintF(MP_TRACE, "lower_32_bits:%x\n", lower_32_bits(bus_to_phys(pdata->pdev, + (pci_addr_t)(unsigned long)pdata->rx_desc_list)));//adpt->TbdPhyAddr + DbgPrintF(MP_TRACE, "dma rdlr lo:%p\n", FXGMAC_DMA_REG(channel, DMA_CH_RDLR_LO)); +#endif + /* Update the starting address of descriptor ring */ + writereg(pdata->pAdapter, upper_32_bits(cpu_to_le64(bus_to_phys(pdata->pdev, + (pci_addr_t)(unsigned long)pdata->expansion.rx_desc_list))), + FXGMAC_DMA_REG(channel, DMA_CH_RDLR_HI)); + writereg(pdata->pAdapter, lower_32_bits(cpu_to_le64(bus_to_phys(pdata->pdev, + (pci_addr_t)(unsigned long)pdata->expansion.rx_desc_list))), + FXGMAC_DMA_REG(channel, DMA_CH_RDLR_LO)); +#if 0 + DbgPrintF(MP_TRACE, "Read rx starting high address:%x\n", + readreg(pdata->pAdapter, FXGMAC_DMA_REG(channel, DMA_CH_RDLR_HI))); + DbgPrintF(MP_TRACE, "Read rx starting low address:%x\n", + readreg(pdata->pAdapter, FXGMAC_DMA_REG(channel, DMA_CH_RDLR_LO))); +#endif + + HwRbdPa = (uint64_t)pdata->expansion.rx_desc_list + (NIC_DEF_RECV_BUFFERS) * sizeof(struct fxgmac_dma_desc); + /* Update the Rx Descriptor Tail Pointer */ + writereg(pdata->pAdapter, lower_32_bits((unsigned long)HwRbdPa), FXGMAC_DMA_REG(channel, DMA_CH_RDTR_LO)); + +} + + +static void fxgmac_rx_desc_init(struct fxgmac_pdata* pdata) +{ + fxgmac_hw_rx_desc_init(pdata->expansion.rx_channel); +} + +#else +static void fxgmac_tx_desc_init(struct fxgmac_pdata* pdata) +{ +#ifndef LINUX + struct fxgmac_hw_ops* hw_ops = &pdata->hw_ops; + struct fxgmac_channel* channel; + channel = pdata->channel_head; + hw_ops->tx_desc_init(channel); +#else + struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops; + struct fxgmac_desc_data *desc_data; + struct fxgmac_dma_desc *dma_desc; + struct fxgmac_channel *channel; + struct fxgmac_ring *ring; + dma_addr_t dma_desc_addr; + unsigned int i, j; + + channel = pdata->channel_head; + for (i = 0; i < pdata->channel_count; i++, channel++) { + ring = channel->tx_ring; + if (!ring) + break; + + /* reset the tx timer status. 20220104 */ + channel->tx_timer_active = 0; + + dma_desc = ring->dma_desc_head; + dma_desc_addr = ring->dma_desc_head_addr; + + for (j = 0; j < ring->dma_desc_count; j++) { + desc_data = FXGMAC_GET_DESC_DATA(ring, j); + + desc_data->dma_desc = dma_desc; + desc_data->dma_desc_addr = dma_desc_addr; + + dma_desc++; + dma_desc_addr += sizeof(struct fxgmac_dma_desc); + } + + ring->cur = 0; + ring->dirty = 0; + memset(&ring->tx, 0, sizeof(ring->tx)); + + hw_ops->tx_desc_init(channel); + } +#endif +} + +static void fxgmac_rx_desc_init(struct fxgmac_pdata* pdata) +{ +#ifndef LINUX + struct fxgmac_hw_ops* hw_ops = &pdata->hw_ops; + struct fxgmac_channel* channel; + int Qid = 0; + + channel = pdata->channel_head; + for (Qid = 0; Qid < RSS_Q_COUNT; Qid++) + { + hw_ops->rx_desc_init(channel + Qid); + } +#else + struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops; + struct fxgmac_desc_data *desc_data; + struct fxgmac_dma_desc *dma_desc; + struct fxgmac_channel *channel; + struct fxgmac_ring *ring; + dma_addr_t dma_desc_addr; + unsigned int i, j; + + channel = pdata->channel_head; + for (i = 0; i < pdata->channel_count; i++, channel++) { + ring = channel->rx_ring; + if (!ring) + break; + + dma_desc = ring->dma_desc_head; + dma_desc_addr = ring->dma_desc_head_addr; + + for (j = 0; j < ring->dma_desc_count; j++) { + desc_data = FXGMAC_GET_DESC_DATA(ring, j); + + desc_data->dma_desc = dma_desc; + desc_data->dma_desc_addr = dma_desc_addr; + + if (fxgmac_map_rx_buffer(pdata, ring, desc_data)) + break; + + dma_desc++; + dma_desc_addr += sizeof(struct fxgmac_dma_desc); + } + + ring->cur = 0; + ring->dirty = 0; + + hw_ops->rx_desc_init(channel); + } +#endif +} +#endif +#ifdef LINUX +static int fxgmac_map_tx_skb(struct fxgmac_channel *channel, + struct sk_buff *skb) +{ + struct fxgmac_pdata *pdata = channel->pdata; + struct fxgmac_ring *ring = channel->tx_ring; + unsigned int start_index, cur_index; + struct fxgmac_desc_data *desc_data; + unsigned int offset, datalen, len; + struct fxgmac_pkt_info *pkt_info; +#if ( LINUX_VERSION_CODE >= KERNEL_VERSION(5,0,0) ) + skb_frag_t *frag; +#else + struct skb_frag_struct *frag; +#endif + unsigned int tso, vlan; + dma_addr_t skb_dma; + unsigned int i; +#if 0 + void* addr; + struct skb_shared_info *info = skb_shinfo(skb); +#endif + + offset = 0; + start_index = ring->cur; + cur_index = ring->cur; + + pkt_info = &ring->pkt_info; + pkt_info->desc_count = 0; + pkt_info->length = 0; + + 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); + + /* Save space for a context descriptor if needed */ + if ((tso && (pkt_info->mss != ring->tx.cur_mss)) || + (vlan && (pkt_info->vlan_ctag != ring->tx.cur_vlan_ctag))) + { + cur_index = FXGMAC_GET_ENTRY(cur_index, ring->dma_desc_count); + } + desc_data = FXGMAC_GET_DESC_DATA(ring, cur_index); + + if (tso) { + /* Map the TSO header */ + skb_dma = dma_map_single(pdata->dev, skb->data, + pkt_info->header_len, DMA_TO_DEVICE); + if (dma_mapping_error(pdata->dev, skb_dma)) { + netdev_alert(pdata->netdev, "dma_map_single failed\n"); + goto err_out; + } + desc_data->skb_dma = skb_dma; + desc_data->skb_dma_len = pkt_info->header_len; + netif_dbg(pdata, tx_queued, pdata->netdev, + "skb header: index=%u, dma=%pad, len=%u\n", + cur_index, &skb_dma, pkt_info->header_len); + + offset = pkt_info->header_len; + + pkt_info->length += pkt_info->header_len; + + cur_index = FXGMAC_GET_ENTRY(cur_index, ring->dma_desc_count); + desc_data = FXGMAC_GET_DESC_DATA(ring, cur_index); + } + + /* Map the (remainder of the) packet */ + for (datalen = skb_headlen(skb) - offset; datalen; ) { + len = min_t(unsigned int, datalen, FXGMAC_TX_MAX_BUF_SIZE); + + skb_dma = dma_map_single(pdata->dev, skb->data + offset, len, + DMA_TO_DEVICE); + if (dma_mapping_error(pdata->dev, skb_dma)) { + netdev_alert(pdata->netdev, "dma_map_single failed\n"); + goto err_out; + } + desc_data->skb_dma = skb_dma; + desc_data->skb_dma_len = len; + netif_dbg(pdata, tx_queued, pdata->netdev, + "skb data: index=%u, dma=%pad, len=%u\n", + cur_index, &skb_dma, len); + + datalen -= len; + offset += len; + + pkt_info->length += len; + + cur_index = FXGMAC_GET_ENTRY(cur_index, ring->dma_desc_count); + desc_data = FXGMAC_GET_DESC_DATA(ring, cur_index); + } + + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + netif_dbg(pdata, tx_queued, pdata->netdev, + "mapping frag %u\n", i); +#if 0 + frag = info->frags + i; + len = skb_frag_size(frag); + addr = skb_frag_address(frag); +#else + frag = &skb_shinfo(skb)->frags[i]; +#endif + offset = 0; + + for (datalen = skb_frag_size(frag); datalen; ) { + len = min_t(unsigned int, datalen, + FXGMAC_TX_MAX_BUF_SIZE); + +#if 1 + skb_dma = skb_frag_dma_map(pdata->dev, frag, offset, + len, DMA_TO_DEVICE); +#else + skb_dma = dma_map_single(pdata->dev, addr + offset, len, DMA_TO_DEVICE); +#endif + if (dma_mapping_error(pdata->dev, skb_dma)) { + netdev_alert(pdata->netdev, + "skb_frag_dma_map failed\n"); + goto err_out; + } + desc_data->skb_dma = skb_dma; + desc_data->skb_dma_len = len; +#if 1 + desc_data->mapped_as_page = 1; +#endif + netif_dbg(pdata, tx_queued, pdata->netdev, + "skb frag: index=%u, dma=%pad, len=%u\n", + cur_index, &skb_dma, len); + + datalen -= len; + offset += len; + + pkt_info->length += len; + + cur_index = FXGMAC_GET_ENTRY(cur_index, ring->dma_desc_count); + desc_data = FXGMAC_GET_DESC_DATA(ring, cur_index); + } + } + + /* Save the skb address in the last entry. We always have some data + * that has been mapped so desc_data is always advanced past the last + * piece of mapped data - use the entry pointed to by cur_index - 1. + */ + desc_data = FXGMAC_GET_DESC_DATA(ring, (cur_index - 1) & (ring->dma_desc_count - 1)); + desc_data->skb = skb; + + /* Save the number of descriptor entries used */ + if (start_index <= cur_index) + pkt_info->desc_count = cur_index - start_index; + else + pkt_info->desc_count = ring->dma_desc_count - start_index + cur_index; + + return pkt_info->desc_count; + +err_out: + while (start_index < cur_index) { + desc_data = FXGMAC_GET_DESC_DATA(ring, start_index); + start_index = FXGMAC_GET_ENTRY(start_index, ring->dma_desc_count); + fxgmac_unmap_desc_data(pdata, desc_data); + } + + return 0; +} +#endif + +void fxgmac_init_desc_ops(struct fxgmac_desc_ops* desc_ops) +{ +#ifdef UBOOT + desc_ops->alloc_channles_and_rings = fxgmac_alloc_channels; +#else + desc_ops->alloc_channles_and_rings = fxgmac_alloc_channels_and_rings; +#endif + desc_ops->free_channels_and_rings = fxgmac_free_channels_and_rings; +#ifndef LINUX + desc_ops->map_tx_skb = NULL; +#else + desc_ops->map_tx_skb = fxgmac_map_tx_skb; +#endif + desc_ops->map_rx_buffer = fxgmac_map_rx_buffer; + desc_ops->unmap_desc_data = fxgmac_unmap_desc_data; + desc_ops->tx_desc_init = fxgmac_tx_desc_init; + desc_ops->rx_desc_init = fxgmac_rx_desc_init; +} diff --git a/drivers/net/ethernet/motorcomm/fuxi-gmac-ethtool.c b/drivers/net/ethernet/motorcomm/fuxi-gmac-ethtool.c new file mode 100644 index 000000000000..bdd1228fc331 --- /dev/null +++ b/drivers/net/ethernet/motorcomm/fuxi-gmac-ethtool.c @@ -0,0 +1,1177 @@ +/*++ + +Copyright (c) 2021 Motor-comm Corporation. +Confidential and Proprietary. All rights reserved. + +This is Motor-comm Corporation NIC driver relevant files. Please don't copy, modify, +distribute without commercial permission. + +--*/ + + +#include +#include +#include + +#include "fuxi-gmac.h" +#include "fuxi-gmac-reg.h" + +struct fxgmac_stats_desc { + char stat_string[ETH_GSTRING_LEN]; + int stat_offset; +}; + +#define FXGMAC_STAT(str, var) \ + { \ + str, \ + offsetof(struct fxgmac_pdata, stats.var), \ + } + +static const struct fxgmac_stats_desc fxgmac_gstring_stats[] = { + /* MMC TX counters */ + FXGMAC_STAT("tx_bytes", txoctetcount_gb), + FXGMAC_STAT("tx_bytes_good", txoctetcount_g), + FXGMAC_STAT("tx_packets", txframecount_gb), + FXGMAC_STAT("tx_packets_good", txframecount_g), + FXGMAC_STAT("tx_unicast_packets", txunicastframes_gb), + FXGMAC_STAT("tx_broadcast_packets", txbroadcastframes_gb), + FXGMAC_STAT("tx_broadcast_packets_good", txbroadcastframes_g), + FXGMAC_STAT("tx_multicast_packets", txmulticastframes_gb), + FXGMAC_STAT("tx_multicast_packets_good", txmulticastframes_g), + FXGMAC_STAT("tx_vlan_packets_good", txvlanframes_g), + FXGMAC_STAT("tx_64_byte_packets", tx64octets_gb), + FXGMAC_STAT("tx_65_to_127_byte_packets", tx65to127octets_gb), + FXGMAC_STAT("tx_128_to_255_byte_packets", tx128to255octets_gb), + FXGMAC_STAT("tx_256_to_511_byte_packets", tx256to511octets_gb), + FXGMAC_STAT("tx_512_to_1023_byte_packets", tx512to1023octets_gb), + FXGMAC_STAT("tx_1024_to_max_byte_packets", tx1024tomaxoctets_gb), + FXGMAC_STAT("tx_underflow_errors", txunderflowerror), + FXGMAC_STAT("tx_pause_frames", txpauseframes), + FXGMAC_STAT("tx_single_collision", txsinglecollision_g), + FXGMAC_STAT("tx_multiple_collision", txmultiplecollision_g), + FXGMAC_STAT("tx_deferred_frames", txdeferredframes), + FXGMAC_STAT("tx_late_collision_frames", txlatecollisionframes), + FXGMAC_STAT("tx_excessive_collision_frames", txexcessivecollisionframes), + FXGMAC_STAT("tx_carrier_error_frames", txcarriererrorframes), + FXGMAC_STAT("tx_excessive_deferral_error", txexcessivedeferralerror), + FXGMAC_STAT("tx_oversize_frames_good", txoversize_g), + + /* MMC RX counters */ + FXGMAC_STAT("rx_bytes", rxoctetcount_gb), + FXGMAC_STAT("rx_bytes_good", rxoctetcount_g), + FXGMAC_STAT("rx_packets", rxframecount_gb), + FXGMAC_STAT("rx_unicast_packets_good", rxunicastframes_g), + FXGMAC_STAT("rx_broadcast_packets_good", rxbroadcastframes_g), + FXGMAC_STAT("rx_multicast_packets_good", rxmulticastframes_g), + FXGMAC_STAT("rx_vlan_packets_mac", rxvlanframes_gb), + FXGMAC_STAT("rx_64_byte_packets", rx64octets_gb), + FXGMAC_STAT("rx_65_to_127_byte_packets", rx65to127octets_gb), + FXGMAC_STAT("rx_128_to_255_byte_packets", rx128to255octets_gb), + FXGMAC_STAT("rx_256_to_511_byte_packets", rx256to511octets_gb), + FXGMAC_STAT("rx_512_to_1023_byte_packets", rx512to1023octets_gb), + FXGMAC_STAT("rx_1024_to_max_byte_packets", rx1024tomaxoctets_gb), + FXGMAC_STAT("rx_undersize_packets_good", rxundersize_g), + FXGMAC_STAT("rx_oversize_packets_good", rxoversize_g), + FXGMAC_STAT("rx_crc_errors", rxcrcerror), + FXGMAC_STAT("rx_align_error", rxalignerror), + FXGMAC_STAT("rx_crc_errors_small_packets", rxrunterror), + FXGMAC_STAT("rx_crc_errors_giant_packets", rxjabbererror), + FXGMAC_STAT("rx_length_errors", rxlengtherror), + FXGMAC_STAT("rx_out_of_range_errors", rxoutofrangetype), + FXGMAC_STAT("rx_fifo_overflow_errors", rxfifooverflow), + FXGMAC_STAT("rx_watchdog_errors", rxwatchdogerror), + FXGMAC_STAT("rx_pause_frames", rxpauseframes), + FXGMAC_STAT("rx_receive_error_frames", rxreceiveerrorframe), + FXGMAC_STAT("rx_control_frames_good", rxcontrolframe_g), + + /* Extra counters */ + FXGMAC_STAT("tx_tso_packets", tx_tso_packets), + FXGMAC_STAT("rx_split_header_packets", rx_split_header_packets), + FXGMAC_STAT("tx_process_stopped", tx_process_stopped), + FXGMAC_STAT("rx_process_stopped", rx_process_stopped), + FXGMAC_STAT("tx_buffer_unavailable", tx_buffer_unavailable), + FXGMAC_STAT("rx_buffer_unavailable", rx_buffer_unavailable), + FXGMAC_STAT("fatal_bus_error", fatal_bus_error), + FXGMAC_STAT("tx_vlan_packets_net", tx_vlan_packets), + FXGMAC_STAT("rx_vlan_packets_net", rx_vlan_packets), + FXGMAC_STAT("napi_poll_isr", napi_poll_isr), + FXGMAC_STAT("napi_poll_txtimer", napi_poll_txtimer), + FXGMAC_STAT("alive_cnt_txtimer", cnt_alive_txtimer), + + FXGMAC_STAT("ephy_poll_timer", ephy_poll_timer_cnt), + FXGMAC_STAT("mgmt_int_isr", mgmt_int_isr), +}; + +#define FXGMAC_STATS_COUNT ARRAY_SIZE(fxgmac_gstring_stats) + +static void fxgmac_ethtool_get_drvinfo(struct net_device *netdev, + struct ethtool_drvinfo *drvinfo) +{ + struct fxgmac_pdata *pdata = netdev_priv(netdev); + u32 ver = pdata->hw_feat.version; + u32 sver, devid, userver; + + strlcpy(drvinfo->driver, pdata->drv_name, sizeof(drvinfo->driver)); + strlcpy(drvinfo->version, pdata->drv_ver, sizeof(drvinfo->version)); + strlcpy(drvinfo->bus_info, dev_name(pdata->dev), + sizeof(drvinfo->bus_info)); + /* + * D|DEVID: Indicates the Device family + * U|USERVER: User-defined Version + */ + sver = FXGMAC_GET_REG_BITS(ver, MAC_VR_SVER_POS, + MAC_VR_SVER_LEN); + devid = FXGMAC_GET_REG_BITS(ver, MAC_VR_DEVID_POS, + MAC_VR_DEVID_LEN); + userver = FXGMAC_GET_REG_BITS(ver, MAC_VR_USERVER_POS, + MAC_VR_USERVER_LEN); + /*DPRINTK("xlgma: No userver (%x) here, sver (%x) should be 0x51\n", userver, sver);*/ + snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version), + "S.D.U: %x.%x.%x", sver, devid, userver); +} + +static u32 fxgmac_ethtool_get_msglevel(struct net_device *netdev) +{ + struct fxgmac_pdata *pdata = netdev_priv(netdev); + + return pdata->msg_enable; +} + +static void fxgmac_ethtool_set_msglevel(struct net_device *netdev, + u32 msglevel) +{ + struct fxgmac_pdata *pdata = netdev_priv(netdev); + + DPRINTK("fxmac, set msglvl from %08x to %08x\n", pdata->msg_enable, msglevel); + pdata->msg_enable = msglevel; +} + +static void fxgmac_ethtool_get_channels(struct net_device *netdev, + struct ethtool_channels *channel) +{ + struct fxgmac_pdata *pdata = netdev_priv(netdev); +#if (FXGMAC_RSS_FEATURE_ENABLED) + /* report maximum channels */ + channel->max_combined = FXGMAC_MAX_DMA_CHANNELS; + channel->max_other = 0; + channel->other_count = 0; + + /* record RSS queues */ + channel->combined_count = FXGMAC_MAX_DMA_CHANNELS; + + /* nothing else to report if RSS is disabled */ + if (channel->combined_count == 1) + return; + DPRINTK("fxmac rss, get channels max=(combined %d,other %d),count(combined %d,other %d)\n", channel->max_combined, channel->max_other, channel->combined_count, channel->other_count); +#endif + + channel->max_rx = FXGMAC_MAX_DMA_CHANNELS; + channel->max_tx = FXGMAC_MAX_DMA_CHANNELS; + channel->rx_count = pdata->rx_q_count; + channel->tx_count = pdata->tx_q_count; + DPRINTK("fxmac, get channels max=(rx %d,tx %d),count(%d,%d)\n", channel->max_rx, channel->max_tx, channel->rx_count, channel->tx_count); +} + +#if ( LINUX_VERSION_CODE >= KERNEL_VERSION(5,15,0) ) +static int fxgmac_ethtool_get_coalesce(struct net_device *netdev, + struct ethtool_coalesce *ec, + struct kernel_ethtool_coalesce *kernel_coal, + struct netlink_ext_ack *extack) +#else +static int fxgmac_ethtool_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *ec) +#endif +{ + struct fxgmac_pdata *pdata = netdev_priv(netdev); + + memset(ec, 0, sizeof(struct ethtool_coalesce)); + ec->rx_coalesce_usecs = pdata->rx_usecs; + ec->tx_coalesce_usecs = pdata->tx_usecs; + /*If we need to assign values to other members, + * we need to modify the supported_coalesce_params of fxgmac_ethtool_ops synchronously + */ + //ec->rx_max_coalesced_frames = pdata->rx_frames; + //ec->tx_max_coalesced_frames = pdata->tx_frames; + + DPRINTK("fxmac, get coalesce\n"); + return 0; +} + +#if ( LINUX_VERSION_CODE >= KERNEL_VERSION(5,15,0) ) +static int fxgmac_ethtool_set_coalesce(struct net_device *netdev, + struct ethtool_coalesce *ec, + struct kernel_ethtool_coalesce *kernel_coal, + struct netlink_ext_ack *extack) +#else +static int fxgmac_ethtool_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *ec) +#endif +{ + struct fxgmac_pdata *pdata = netdev_priv(netdev); + struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops; + unsigned int rx_frames, rx_riwt, rx_usecs; + unsigned int tx_frames; + + /* Check for not supported parameters */ + if ((ec->rx_coalesce_usecs_irq) || (ec->rx_max_coalesced_frames_irq) || + (ec->tx_coalesce_usecs_high) || + (ec->tx_max_coalesced_frames_irq) || (ec->tx_coalesce_usecs_irq) || + (ec->stats_block_coalesce_usecs) || (ec->pkt_rate_low) || + (ec->use_adaptive_rx_coalesce) || (ec->use_adaptive_tx_coalesce) || + (ec->rx_max_coalesced_frames_low) || (ec->rx_coalesce_usecs_low) || + (ec->tx_coalesce_usecs_low) || (ec->tx_max_coalesced_frames_low) || + (ec->pkt_rate_high) || (ec->rx_coalesce_usecs_high) || + (ec->rx_max_coalesced_frames_high) || + (ec->tx_max_coalesced_frames_high) || + (ec->rate_sample_interval)) + return -EOPNOTSUPP; + + rx_usecs = ec->rx_coalesce_usecs; + rx_riwt = hw_ops->usec_to_riwt(pdata, rx_usecs); + rx_frames = ec->rx_max_coalesced_frames; + tx_frames = ec->tx_max_coalesced_frames; + + if ((rx_riwt > FXGMAC_MAX_DMA_RIWT) || + (rx_riwt < FXGMAC_MIN_DMA_RIWT) || + (rx_frames > pdata->rx_desc_count)) + return -EINVAL; + + if (tx_frames > pdata->tx_desc_count) + return -EINVAL; + + pdata->rx_riwt = rx_riwt; + pdata->rx_usecs = rx_usecs; + pdata->rx_frames = rx_frames; + hw_ops->config_rx_coalesce(pdata); + + pdata->tx_frames = tx_frames; + hw_ops->config_tx_coalesce(pdata); + + pdata->tx_usecs = ec->tx_coalesce_usecs; + hw_ops->set_interrupt_moderation(pdata); + + DPRINTK("fxmac, set coalesce\n"); + return 0; +} + +#if (FXGMAC_RSS_FEATURE_ENABLED) +static u32 fxgmac_get_rxfh_key_size(struct net_device *netdev) +{ + return FXGMAC_RSS_HASH_KEY_SIZE; +} + +static u32 fxgmac_rss_indir_size(struct net_device *netdev) +{ + return FXGMAC_RSS_MAX_TABLE_SIZE; +} + +static void fxgmac_get_reta(struct fxgmac_pdata *pdata, u32 *indir) +{ + int i, reta_size = FXGMAC_RSS_MAX_TABLE_SIZE; + u16 rss_m; +#ifdef FXGMAC_ONE_CHANNLE + rss_m = FXGMAC_MAX_DMA_CHANNELS; +#else + rss_m = FXGMAC_MAX_DMA_CHANNELS - 1; //mask for index of channel, 0-3 +#endif + + for (i = 0; i < reta_size; i++) + indir[i] = pdata->rss_table[i] & rss_m; +} + +static int fxgmac_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key, + u8 *hfunc) +{ + struct fxgmac_pdata *pdata = netdev_priv(netdev); + + /* + ETH_RSS_HASH_TOP __ETH_RSS_HASH(TOP) + ETH_RSS_HASH_XOR __ETH_RSS_HASH(XOR) + ETH_RSS_HASH_CRC32 __ETH_RSS_HASH(CRC32) + */ + if (hfunc) + { + //*hfunc = ETH_RSS_HASH_XOR; + *hfunc = ETH_RSS_HASH_TOP; + DPRINTK("fxmac, get_rxfh for hash function\n"); + } + + if (indir) + { + fxgmac_get_reta(pdata, indir); + DPRINTK("fxmac, get_rxfh for indirection tab\n"); + } + + if (key) + { + memcpy(key, pdata->rss_key, fxgmac_get_rxfh_key_size(netdev)); + DPRINTK("fxmac, get_rxfh for hash key\n"); + } + + return 0; +} + +static int fxgmac_set_rxfh(struct net_device *netdev, const u32 *indir, + const u8 *key, const u8 hfunc) +{ + struct fxgmac_pdata *pdata = netdev_priv(netdev); + struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops; + int i; + u32 reta_entries = fxgmac_rss_indir_size(netdev); + int max_queues = FXGMAC_MAX_DMA_CHANNELS; + + DPRINTK("fxmac, set_rxfh callin, indir=%lx, key=%lx, func=%02x\n", (unsigned long)indir, (unsigned long)key, hfunc); + + if (hfunc) + return -EINVAL; + + /* Fill out the redirection table */ + if (indir) { +#if FXGMAC_MSIX_CH0RXDIS_EN + max_queues = max_queues; // kill warning + reta_entries = reta_entries; + i = i; + DPRINTK("fxmac, set_rxfh, change of indirect talbe is not supported.\n"); + return -EINVAL; +#else + /* double check user input. */ + for (i = 0; i < reta_entries; i++) + if (indir[i] >= max_queues) + return -EINVAL; + + for (i = 0; i < reta_entries; i++) + pdata->rss_table[i] = indir[i]; + + hw_ops->write_rss_lookup_table(pdata); +#endif + } + + /* Fill out the rss hash key */ + if (FXGMAC_RSS_HASH_KEY_LINUX && key) { + hw_ops->set_rss_hash_key(pdata, key); + } + + return 0; +} + +static int fxgmac_get_rss_hash_opts(struct fxgmac_pdata *pdata, + struct ethtool_rxnfc *cmd) +{ + u32 reg_opt; + struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops; + cmd->data = 0; + + reg_opt = hw_ops->get_rss_options(pdata); + DPRINTK ("fxgmac_get_rss_hash_opts, hw=%02x, %02x\n", reg_opt, pdata->rss_options); + + if(reg_opt != pdata->rss_options) + { + DPRINTK ("fxgmac_get_rss_hash_opts, warning, options are not consistent\n"); + } + + /* Report default options for RSS */ + switch (cmd->flow_type) { + case TCP_V4_FLOW: + case UDP_V4_FLOW: + if(((TCP_V4_FLOW == (cmd->flow_type)) && (FXGMAC_GET_REG_BITS(pdata->rss_options, MAC_RSSCR_TCP4TE_POS, MAC_RSSCR_TCP4TE_LEN))) || + ((UDP_V4_FLOW == (cmd->flow_type)) && (FXGMAC_GET_REG_BITS(pdata->rss_options, MAC_RSSCR_UDP4TE_POS, MAC_RSSCR_UDP4TE_LEN)))) + { + cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; + } + fallthrough; + case SCTP_V4_FLOW: + case AH_ESP_V4_FLOW: + case AH_V4_FLOW: + case ESP_V4_FLOW: + case IPV4_FLOW: + if(((TCP_V4_FLOW == (cmd->flow_type)) && (FXGMAC_GET_REG_BITS(pdata->rss_options, MAC_RSSCR_TCP4TE_POS, MAC_RSSCR_TCP4TE_LEN))) || + ((UDP_V4_FLOW == (cmd->flow_type)) && (FXGMAC_GET_REG_BITS(pdata->rss_options, MAC_RSSCR_UDP4TE_POS, MAC_RSSCR_UDP4TE_LEN))) || + (FXGMAC_GET_REG_BITS(pdata->rss_options, MAC_RSSCR_IP4TE_POS, MAC_RSSCR_IP4TE_LEN))) + { + cmd->data |= RXH_IP_SRC | RXH_IP_DST; + } + break; + case TCP_V6_FLOW: + case UDP_V6_FLOW: + if(((TCP_V6_FLOW == (cmd->flow_type)) && (FXGMAC_GET_REG_BITS(pdata->rss_options, MAC_RSSCR_TCP6TE_POS, MAC_RSSCR_TCP6TE_LEN))) || + ((UDP_V6_FLOW == (cmd->flow_type)) && (FXGMAC_GET_REG_BITS(pdata->rss_options, MAC_RSSCR_UDP6TE_POS, MAC_RSSCR_UDP6TE_LEN)))) + { + cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; + } + fallthrough; + case SCTP_V6_FLOW: + case AH_ESP_V6_FLOW: + case AH_V6_FLOW: + case ESP_V6_FLOW: + case IPV6_FLOW: + if(((TCP_V6_FLOW == (cmd->flow_type)) && (FXGMAC_GET_REG_BITS(pdata->rss_options, MAC_RSSCR_TCP6TE_POS, MAC_RSSCR_TCP6TE_LEN))) || + ((UDP_V6_FLOW == (cmd->flow_type)) && (FXGMAC_GET_REG_BITS(pdata->rss_options, MAC_RSSCR_UDP6TE_POS, MAC_RSSCR_UDP6TE_LEN))) || + (FXGMAC_GET_REG_BITS(pdata->rss_options, MAC_RSSCR_IP6TE_POS, MAC_RSSCR_IP6TE_LEN))) + { + cmd->data |= RXH_IP_SRC | RXH_IP_DST; + } + break; + default: + return -EINVAL; + } + + return 0; +} + +static int fxgmac_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd, + u32 *rule_locs) +{ + struct fxgmac_pdata *pdata = netdev_priv(dev); + int ret = -EOPNOTSUPP; + + switch (cmd->cmd) { + case ETHTOOL_GRXRINGS: + cmd->data = pdata->rx_q_count; + ret = 0; + DPRINTK("fxmac, get_rxnfc for rx ring cnt\n"); + break; + case ETHTOOL_GRXCLSRLCNT: + cmd->rule_cnt = 0; + ret = 0; + DPRINTK("fxmac, get_rxnfc for classify rule cnt\n"); + break; + case ETHTOOL_GRXCLSRULE: + DPRINTK("fxmac, get_rxnfc for classify rules\n"); + ret = 0;//ixgbe_get_ethtool_fdir_entry(adapter, cmd); + break; + case ETHTOOL_GRXCLSRLALL: + cmd->rule_cnt = 0; + ret = 0; + /*ret = ixgbe_get_ethtool_fdir_all(adapter, cmd, + (u32 *)rule_locs); + */ + DPRINTK("fxmac, get_rxnfc for classify both cnt and rules\n"); + break; + case ETHTOOL_GRXFH: + ret = fxgmac_get_rss_hash_opts(pdata, cmd); + DPRINTK("fxmac, get_rxnfc for hash options\n"); + break; + default: + break; + } + + return ret; +} + +#define UDP_RSS_FLAGS (BIT(MAC_RSSCR_UDP4TE_POS) | \ + BIT(MAC_RSSCR_UDP6TE_POS)) +static int fxgmac_set_rss_hash_opt(struct fxgmac_pdata *pdata, + struct ethtool_rxnfc *nfc) +{ + u32 rssopt = 0; //pdata->rss_options; + struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops; + + DPRINTK("fxgmac_set_rss_hash_opt call in,nfc_data=%llx,cur opt=%x\n", nfc->data, pdata->rss_options); + + /* + * For RSS, it does not support anything other than hashing + * to queues on src,dst IPs and L4 ports + */ + if (nfc->data & ~(RXH_IP_SRC | RXH_IP_DST | + RXH_L4_B_0_1 | RXH_L4_B_2_3)) + return -EINVAL; + + switch (nfc->flow_type) { + case TCP_V4_FLOW: + case TCP_V6_FLOW: + /* default to TCP flow and do nothting */ + if (!(nfc->data & RXH_IP_SRC) || + !(nfc->data & RXH_IP_DST) || + !(nfc->data & RXH_L4_B_0_1) || + !(nfc->data & RXH_L4_B_2_3)) + return -EINVAL; + if(TCP_V4_FLOW == (nfc->flow_type)) + { + rssopt = FXGMAC_SET_REG_BITS( + rssopt, + MAC_RSSCR_IP4TE_POS, + MAC_RSSCR_IP4TE_LEN, 1); + rssopt = FXGMAC_SET_REG_BITS( + rssopt, + MAC_RSSCR_TCP4TE_POS, + MAC_RSSCR_TCP4TE_LEN, 1); + } + + if(TCP_V6_FLOW == (nfc->flow_type)) + { + rssopt = FXGMAC_SET_REG_BITS( + rssopt, + MAC_RSSCR_IP6TE_POS, + MAC_RSSCR_IP6TE_LEN, 1); + rssopt = FXGMAC_SET_REG_BITS( + rssopt, + MAC_RSSCR_TCP6TE_POS, + MAC_RSSCR_TCP6TE_LEN, 1); + } + break; + + case UDP_V4_FLOW: + if (!(nfc->data & RXH_IP_SRC) || + !(nfc->data & RXH_IP_DST)) + return -EINVAL; + rssopt = FXGMAC_SET_REG_BITS( + rssopt, + MAC_RSSCR_IP4TE_POS, + MAC_RSSCR_IP4TE_LEN, 1); + switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) { + case 0: + break; + case (RXH_L4_B_0_1 | RXH_L4_B_2_3): + rssopt = FXGMAC_SET_REG_BITS( + rssopt, + MAC_RSSCR_UDP4TE_POS, + MAC_RSSCR_UDP4TE_LEN, 1); + break; + default: + return -EINVAL; + } + break; + case UDP_V6_FLOW: + if (!(nfc->data & RXH_IP_SRC) || + !(nfc->data & RXH_IP_DST)) + return -EINVAL; + rssopt = FXGMAC_SET_REG_BITS( + rssopt, + MAC_RSSCR_IP6TE_POS, + MAC_RSSCR_IP6TE_LEN, 1); + + switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) { + case 0: + break; + case (RXH_L4_B_0_1 | RXH_L4_B_2_3): + rssopt = FXGMAC_SET_REG_BITS( + rssopt, + MAC_RSSCR_UDP6TE_POS, + MAC_RSSCR_UDP6TE_LEN, 1); + break; + default: + return -EINVAL; + } + break; + case AH_ESP_V4_FLOW: + case AH_V4_FLOW: + case ESP_V4_FLOW: + case SCTP_V4_FLOW: + case AH_ESP_V6_FLOW: + case AH_V6_FLOW: + case ESP_V6_FLOW: + case SCTP_V6_FLOW: + if (!(nfc->data & RXH_IP_SRC) || + !(nfc->data & RXH_IP_DST) || + (nfc->data & RXH_L4_B_0_1) || + (nfc->data & RXH_L4_B_2_3)) + return -EINVAL; + break; + default: + return -EINVAL; + } + + /* if options are changed, then update to hw */ + if (rssopt != pdata->rss_options) { + if ((rssopt & UDP_RSS_FLAGS) && + !(pdata->rss_options & UDP_RSS_FLAGS)) + DPRINTK("enabling UDP RSS: fragmented packets" + " may arrive out of order to the stack above\n"); + + DPRINTK("rss option changed from %x to %x\n", pdata->rss_options, rssopt); + pdata->rss_options = rssopt; +#if 1 + hw_ops->set_rss_options(pdata); +#else + /* Perform hash on these packet types */ + mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4 + | IXGBE_MRQC_RSS_FIELD_IPV4_TCP + | IXGBE_MRQC_RSS_FIELD_IPV6 + | IXGBE_MRQC_RSS_FIELD_IPV6_TCP; + + mrqc &= ~(IXGBE_MRQC_RSS_FIELD_IPV4_UDP | + IXGBE_MRQC_RSS_FIELD_IPV6_UDP); + + if (flags2 & IXGBE_FLAG2_RSS_FIELD_IPV4_UDP) + mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4_UDP; + + if (flags2 & IXGBE_FLAG2_RSS_FIELD_IPV6_UDP) + mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_UDP; + + if ((hw->mac.type >= ixgbe_mac_X550) && + (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED)) + IXGBE_WRITE_REG(hw, IXGBE_PFVFMRQC(pf_pool), mrqc); + else + IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc); +#endif + } + + return 0; +} + +static int fxgmac_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd) +{ + struct fxgmac_pdata *pdata = netdev_priv(dev); + + int ret = -EOPNOTSUPP; + + switch (cmd->cmd) { + case ETHTOOL_SRXCLSRLINS: + //no support. rx classifier rule insert + //ret = ixgbe_add_ethtool_fdir_entry(adapter, cmd); + DPRINTK("set_rxnfc for rx cls rule insert-n\\a\n"); + break; + case ETHTOOL_SRXCLSRLDEL: + //no support. rx classifier rule delete + //ret = ixgbe_del_ethtool_fdir_entry(adapter, cmd); + DPRINTK("set_rxnfc for rx cls rule del-n\\a\n"); + break; + case ETHTOOL_SRXFH: + DPRINTK("set_rxnfc for rx rss option\n"); + ret = fxgmac_set_rss_hash_opt(pdata, cmd); + break; + default: + break; + } + + return ret; +} +#endif //FXGMAC_RSS_FEATURE_ENABLED + +#if ( LINUX_VERSION_CODE >= KERNEL_VERSION(5,17,0) ) +static void fxgmac_get_ringparam(struct net_device *netdev, + struct ethtool_ringparam *ring, + struct kernel_ethtool_ringparam *kernel_ring, + struct netlink_ext_ack *exact) + +#else +static void fxgmac_get_ringparam(struct net_device *netdev, + struct ethtool_ringparam *ring) +#endif +{ + struct fxgmac_pdata *pdata = netdev_priv(netdev); + + DPRINTK("fxmac, get_ringparam callin\n"); + + ring->rx_max_pending = FXGMAC_RX_DESC_CNT; + ring->tx_max_pending = FXGMAC_TX_DESC_CNT; + ring->rx_mini_max_pending = 0; + ring->rx_jumbo_max_pending = 0; + ring->rx_pending = pdata->rx_desc_count; + ring->tx_pending = pdata->tx_desc_count; + ring->rx_mini_pending = 0; + ring->rx_jumbo_pending = 0; +} + +#if ( LINUX_VERSION_CODE >= KERNEL_VERSION(5,17,0) ) +static int fxgmac_set_ringparam(struct net_device *netdev, + struct ethtool_ringparam *ring, + struct kernel_ethtool_ringparam *kernel_ring, + struct netlink_ext_ack *exact) + +#else +static int fxgmac_set_ringparam(struct net_device *netdev, + struct ethtool_ringparam *ring) +#endif +{ + struct fxgmac_pdata *pdata = netdev_priv(netdev); + struct fxgmac_desc_ops *desc_ops = &pdata->desc_ops; + + DPRINTK("fxmac, set_ringparam callin\n"); + + pdata->tx_desc_count = ring->tx_pending; + pdata->rx_desc_count = ring->rx_pending; + + fxgmac_stop(pdata); + fxgmac_free_tx_data(pdata); + fxgmac_free_rx_data(pdata); + desc_ops->alloc_channles_and_rings(pdata); + fxgmac_start(pdata); + + return 0; +} + +#if FXGMAC_WOL_FEATURE_ENABLED +static void fxgmac_get_wol(struct net_device *netdev, + struct ethtool_wolinfo *wol) +{ + struct fxgmac_pdata *pdata = netdev_priv(netdev); + + /* for further feature implementation + wol->supported = WAKE_PHY | WAKE_UCAST | WAKE_MCAST | + WAKE_BCAST | WAKE_MAGIC; + */ + + wol->supported = WAKE_UCAST | WAKE_MCAST | WAKE_BCAST | WAKE_MAGIC | WAKE_ARP; +#if FXGMAC_WOL_UPON_EPHY_LINK + wol->supported |= WAKE_PHY; +#endif + + wol->wolopts = 0; + if (!(pdata->hw_feat.rwk) || !device_can_wakeup(/*pci_dev_to_dev*/(pdata->dev))) { + DPRINTK("fxgmac get_wol, pci does not support wakeup\n"); + return; + } +#if 0 + wol->wolopts |= WAKE_UCAST; + wol->wolopts |= WAKE_MCAST; + wol->wolopts |= WAKE_BCAST; + wol->wolopts |= WAKE_MAGIC; +#else + wol->wolopts = pdata->expansion.wol; +#endif + DPRINTK("fxmac, get_wol, 0x%x, 0x%x\n", wol->wolopts, pdata->expansion.wol); +} + +static int fxgmac_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) +{ + struct fxgmac_pdata *pdata = netdev_priv(netdev); + struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops; + + //currently, we do not support these options +#if FXGMAC_WOL_UPON_EPHY_LINK +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,19,0)) + if (wol->wolopts & (WAKE_MAGICSECURE | WAKE_FILTER)) { +#else + if (wol->wolopts & WAKE_MAGICSECURE) { +#endif +#else +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,19,0)) + if (wol->wolopts & (WAKE_PHY | WAKE_MAGICSECURE | WAKE_FILTER)) { +#else + if (wol->wolopts & (WAKE_PHY | WAKE_MAGICSECURE)) { +#endif +#endif + DPRINTK("fxmac, set_wol, not supported wol options, 0x%x\n", wol->wolopts); + return -EOPNOTSUPP; + } + + if (!(pdata->hw_feat.rwk)) { + DPRINTK("fxmac, set_wol, hw wol feature is n/a\n"); + return (wol->wolopts ? -EOPNOTSUPP : 0); + } + +#if 1 /* normally, pls set this to 1. */ + pdata->expansion.wol = 0; + if (wol->wolopts & WAKE_UCAST) + pdata->expansion.wol |= WAKE_UCAST; + + if (wol->wolopts & WAKE_MCAST) + pdata->expansion.wol |= WAKE_MCAST; + + if (wol->wolopts & WAKE_BCAST) + pdata->expansion.wol |= WAKE_BCAST; + + if (wol->wolopts & WAKE_MAGIC) + pdata->expansion.wol |= WAKE_MAGIC; + + if (wol->wolopts & WAKE_PHY) + pdata->expansion.wol |= WAKE_PHY; + + if (wol->wolopts & WAKE_ARP) + pdata->expansion.wol |= WAKE_ARP; + + hw_ops->set_pattern_data(pdata); + + hw_ops->config_wol(pdata, (!!(pdata->expansion.wol))); +#else + + /* for test only... */ + if (wol->wolopts & WAKE_UCAST) { + DPRINTK("fxmac, set_wol, ucast\n"); + //fxgmac_net_powerdown(pdata, pdata->wol); + //fxgmac_update_aoe_ipv4addr(pdata, (u8 *)NULL); + //fxgmac_get_netdev_ip6addr(pdata, NULL, NULL); + fxgmac_update_ns_offload_ipv6addr(pdata, FXGMAC_NS_IFA_LOCAL_LINK); + } + + if (wol->wolopts & WAKE_MAGIC) { + DPRINTK("fxmac, set_wol, magic\n"); + //fxgmac_net_powerup(pdata); + //fxgmac_update_aoe_ipv4addr(pdata, (u8 *)"192.168.3.33"); + fxgmac_update_ns_offload_ipv6addr(pdata, FXGMAC_NS_IFA_GLOBAL_UNICAST); + } + /* + if (wol->wolopts & WAKE_BCAST) { + extern int fxgmac_disable_pci_msi_config(struct pci_dev *pdev); + DPRINTK("fxmac, set_wol, broadcast\n"); + fxgmac_disable_pci_msi_config(struct pci_dev *pdev); + } + */ +#endif + DPRINTK("fxmac, set_wol, opt=0x%x, 0x%x\n", wol->wolopts, pdata->expansion.wol); + + return 0; +} +#endif /*FXGMAC_WOL_FEATURE_ENABLED*/ + +static int fxgmac_get_regs_len(struct net_device __always_unused *netdev) +{ + return FXGMAC_EPHY_REGS_LEN * sizeof(u32); +} + +static void fxgmac_get_regs(struct net_device *netdev, struct ethtool_regs *regs, + void *p) +{ + struct fxgmac_pdata *pdata = netdev_priv(netdev); + struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops; + + u32 *regs_buff = p; + u8 i; + + memset(p, 0, FXGMAC_EPHY_REGS_LEN * sizeof(u32)); + for (i = REG_MII_BMCR; i < FXGMAC_EPHY_REGS_LEN; i++) { + hw_ops->read_ephy_reg(pdata, i, (unsigned int *)®s_buff[i]); + } + regs->version = regs_buff[REG_MII_PHYSID1] << 16 | regs_buff[REG_MII_PHYSID2]; + + //fxgmac_ephy_soft_reset(pdata); +} + +#if FXGMAC_PAUSE_FEATURE_ENABLED +static int fxgmac_get_link_ksettings(struct net_device *netdev, + struct ethtool_link_ksettings *cmd) +{ + struct fxgmac_pdata *pdata = netdev_priv(netdev); + struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops; + u32 duplex, regval, link_status; + u32 adv = 0xFFFFFFFF; + + regval = fxgmac_ephy_autoneg_ability_get(pdata, &adv); + if (regval) + return -ETIMEDOUT; + + ethtool_link_ksettings_zero_link_mode(cmd, supported); + ethtool_link_ksettings_zero_link_mode(cmd, advertising); + + /* set the supported link speeds */ + ethtool_link_ksettings_add_link_mode(cmd, supported, 1000baseT_Full); + ethtool_link_ksettings_add_link_mode(cmd, supported, 100baseT_Full); + ethtool_link_ksettings_add_link_mode(cmd, supported, 100baseT_Half); + ethtool_link_ksettings_add_link_mode(cmd, supported, 10baseT_Full); + ethtool_link_ksettings_add_link_mode(cmd, supported, 10baseT_Half); + + /* Indicate pause support */ + ethtool_link_ksettings_add_link_mode(cmd, supported, Pause); + ethtool_link_ksettings_add_link_mode(cmd, supported, Asym_Pause); + ethtool_link_ksettings_add_link_mode(cmd, advertising, Pause); + ethtool_link_ksettings_add_link_mode(cmd, advertising, Asym_Pause); + + ethtool_link_ksettings_add_link_mode(cmd, supported, MII); + cmd->base.port = PORT_MII; + + ethtool_link_ksettings_add_link_mode(cmd, supported, Autoneg); + hw_ops->read_ephy_reg(pdata, REG_MII_BMCR, ®val); + regval = FXGMAC_GET_REG_BITS(regval, PHY_CR_AUTOENG_POS, PHY_CR_AUTOENG_LEN); + if (regval) { + if (pdata->phy_autoeng) + ethtool_link_ksettings_add_link_mode(cmd, advertising, Autoneg); + else + clear_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, cmd->link_modes.advertising); + + if (adv & FXGMAC_ADVERTISE_10HALF) + ethtool_link_ksettings_add_link_mode(cmd, advertising, 10baseT_Half); + if (adv & FXGMAC_ADVERTISE_10FULL) + ethtool_link_ksettings_add_link_mode(cmd, advertising, 10baseT_Full); + if (adv & FXGMAC_ADVERTISE_100HALF) + ethtool_link_ksettings_add_link_mode(cmd, advertising, 100baseT_Half); + if (adv & FXGMAC_ADVERTISE_100FULL) + ethtool_link_ksettings_add_link_mode(cmd, advertising, 100baseT_Full); + if (adv & FXGMAC_ADVERTISE_1000FULL) + ethtool_link_ksettings_add_link_mode(cmd, advertising, 1000baseT_Full); + } + else { + clear_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, cmd->link_modes.advertising); + switch (pdata->phy_speed) { + case SPEED_1000M: + if (pdata->phy_duplex) + ethtool_link_ksettings_add_link_mode(cmd, advertising, 1000baseT_Full); + else + ethtool_link_ksettings_add_link_mode(cmd, advertising, 1000baseT_Half); + break; + case SPEED_100M: + if (pdata->phy_duplex) + ethtool_link_ksettings_add_link_mode(cmd, advertising, 100baseT_Full); + else + ethtool_link_ksettings_add_link_mode(cmd, advertising, 100baseT_Half); + break; + case SPEED_10M: + if (pdata->phy_duplex) + ethtool_link_ksettings_add_link_mode(cmd, advertising, 10baseT_Full); + else + ethtool_link_ksettings_add_link_mode(cmd, advertising, 10baseT_Half); + break; + default: + break; + } + } + cmd->base.autoneg = pdata->phy_autoeng ? regval : 0; + + hw_ops->read_ephy_reg(pdata, REG_MII_SPEC_STATUS, ®val); + link_status = regval & (BIT(FUXI_EPHY_LINK_STATUS_BIT)); + if (link_status) { + duplex = FXGMAC_GET_REG_BITS(regval, PHY_MII_SPEC_DUPLEX_POS, PHY_MII_SPEC_DUPLEX_LEN); + cmd->base.duplex = duplex; + cmd->base.speed = pdata->phy_speed; + }else { + cmd->base.duplex = DUPLEX_UNKNOWN; + cmd->base.speed = SPEED_UNKNOWN; + } + + return 0; +} + +static int fxgmac_set_link_ksettings(struct net_device *netdev, + const struct ethtool_link_ksettings *cmd) +{ + u32 advertising, support, adv; + int ret; + struct fxphy_ag_adv; + struct fxgmac_pdata *pdata = netdev_priv(netdev); + struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops; + + if (cmd->base.speed == SPEED_1000 && cmd->base.duplex == DUPLEX_HALF) + return -EINVAL; + + pdata->phy_autoeng = cmd->base.autoneg; + + ethtool_convert_link_mode_to_legacy_u32(&advertising, cmd->link_modes.advertising); + ethtool_convert_link_mode_to_legacy_u32(&support, cmd->link_modes.supported); + advertising &= support; + + if (pdata->phy_autoeng || (!pdata->phy_autoeng && cmd->base.speed == SPEED_1000)){ + ret = hw_ops->read_ephy_reg(pdata, REG_MII_ADVERTISE, &adv); + if (ret < 0) + return -ETIMEDOUT; + adv &= ~REG_BIT_ADVERTISE_100_10_CAP; + adv |= ethtool_adv_to_mii_adv_t(advertising); + ret = hw_ops->write_ephy_reg(pdata, REG_MII_ADVERTISE, adv); + if (ret < 0) + return -ETIMEDOUT; + ret = hw_ops->read_ephy_reg(pdata, REG_MII_CTRL1000, &adv); + if (ret < 0) + return -ETIMEDOUT; + adv &= ~REG_BIT_ADVERTISE_1000_CAP; + adv |= ethtool_adv_to_mii_ctrl1000_t(advertising); + ret = hw_ops->write_ephy_reg(pdata, REG_MII_CTRL1000, adv); + if (ret < 0) + return -ETIMEDOUT; + + ret = hw_ops->read_ephy_reg(pdata, REG_MII_BMCR, &adv); + if (ret < 0) + return -ETIMEDOUT; + adv = FXGMAC_SET_REG_BITS(adv, PHY_CR_AUTOENG_POS, PHY_CR_AUTOENG_LEN, 1); + ret = hw_ops->write_ephy_reg(pdata, REG_MII_BMCR, adv); + if (ret < 0) + return -ETIMEDOUT; + + ret = hw_ops->read_ephy_reg(pdata, REG_MII_BMCR, &adv); + if (ret < 0) + return -ETIMEDOUT; + adv = FXGMAC_SET_REG_BITS(adv, PHY_CR_RE_AUTOENG_POS, PHY_CR_RE_AUTOENG_LEN, 1); + ret = hw_ops->write_ephy_reg(pdata, REG_MII_BMCR, adv); + if (ret < 0) + return -ETIMEDOUT; + } else { + pdata->phy_duplex = cmd->base.duplex; + pdata->phy_speed = cmd->base.speed; + fxgmac_phy_force_speed(pdata, pdata->phy_speed); + fxgmac_phy_force_duplex(pdata, pdata->phy_duplex); + fxgmac_phy_force_autoneg(pdata, pdata->phy_autoeng); + //hw_ops->config_mac_speed(pdata); + } + + ret = fxgmac_ephy_soft_reset(pdata); + if (ret) { + printk("%s: ephy soft reset timeout.\n", __func__); + return -ETIMEDOUT; + } + + return 0; +} + +static void fxgmac_get_pauseparam(struct net_device *netdev, + struct ethtool_pauseparam *pause) +{ + struct fxgmac_pdata *pdata = netdev_priv(netdev); + + pause->autoneg = 1; + pause->rx_pause = pdata->rx_pause; + pause->tx_pause = pdata->tx_pause; + + DPRINTK("fxmac get_pauseparam done, rx=%d, tx=%d\n", pdata->rx_pause, pdata->tx_pause); +} + +static int fxgmac_set_pauseparam(struct net_device *netdev, + struct ethtool_pauseparam *pause) +{ + struct fxgmac_pdata *pdata = netdev_priv(netdev); + struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops; + unsigned int pre_rx_pause = pdata->rx_pause; + unsigned int pre_tx_pause = pdata->tx_pause; + + //if (pause->autoneg == AUTONEG_ENABLE) + //DPRINTK("fxgmac set pause parameter, autoneg=%d\n", pause->autoneg); + + pdata->rx_pause = pause->rx_pause; + pdata->tx_pause = pause->tx_pause; + + if(pre_rx_pause != pdata->rx_pause) { + hw_ops->config_rx_flow_control(pdata); + DPRINTK("fxgmac set pause parameter, rx from %d to %d\n", pre_rx_pause, pdata->rx_pause); + } + if(pre_tx_pause != pdata->tx_pause) { + hw_ops->config_tx_flow_control(pdata); + DPRINTK("fxgmac set pause parameter, tx from %d to %d\n", pre_tx_pause, pdata->tx_pause); + } + + /* + if (netif_running(netdev)) + fxgmac_restart_dev(pdata); + */ + DPRINTK("fxgmac set pause parameter, autoneg=%d, rx=%d, tx=%d\n", pause->autoneg, pause->rx_pause, pause->tx_pause); + + return 0; +} +#endif /*FXGMAC_PAUSE_FEATURE_ENABLED*/ + + +/* yzhang added for debug sake. descriptors status checking + * 2021.03.29 + */ +#define FXGMAC_ETH_GSTRING_LEN 32 + +#if 0 +static char fxgmac_gstrings_test[1024*7][FXGMAC_ETH_GSTRING_LEN]= { +}; + +static char fxgmac_gstrings_header[7][10]= { + "Channel:", "curDesc:", + "baseMem:", "desc0 :", + "desc1 :", "desc2 :", + "desc3 :" +}; +#endif + +#define FXGMAC_TEST_LEN (sizeof(fxgmac_gstrings_test) / FXGMAC_ETH_GSTRING_LEN) +#define DBG_ETHTOOL_CHECK_NUM_OF_DESC 5 +//static u16 fxgmac_ethtool_test_len = DBG_ETHTOOL_CHECK_NUM_OF_DESC; //default value, yzhang + +static void fxgmac_ethtool_get_strings(struct net_device *netdev, + u32 stringset, u8 *data) +{ + int i; + + switch (stringset) { + case ETH_SS_STATS: + for (i = 0; i < FXGMAC_STATS_COUNT; i++) { + memcpy(data, fxgmac_gstring_stats[i].stat_string, + strlen(fxgmac_gstring_stats[i].stat_string)); + data += ETH_GSTRING_LEN; + } + break; + default: + WARN_ON(1); + break; + } +} + +static int fxgmac_ethtool_get_sset_count(struct net_device *netdev, + int stringset) +{ + int ret; + + switch (stringset) { + case ETH_SS_STATS: + ret = FXGMAC_STATS_COUNT; + break; + + default: + ret = -EOPNOTSUPP; + } + + return ret; +} + +static void fxgmac_ethtool_get_ethtool_stats(struct net_device *netdev, + struct ethtool_stats *stats, + u64 *data) +{ + struct fxgmac_pdata *pdata = netdev_priv(netdev); + u8 *stat; + int i; + +#if FXGMAC_PM_FEATURE_ENABLED + /* 20210709 for net power down */ + if(!test_bit(FXGMAC_POWER_STATE_DOWN, &pdata->expansion.powerstate)) +#endif + { + //DPRINTK("fxgmac_ethtool_get_ethtool_stats, here\n"); + pdata->hw_ops.read_mmc_stats(pdata); + } + + for (i = 0; i < FXGMAC_STATS_COUNT; i++) { + stat = (u8 *)pdata + fxgmac_gstring_stats[i].stat_offset; + *data++ = *(u64 *)stat; + } +} + +static inline bool fxgmac_removed(void __iomem *addr) +{ + return unlikely(!addr); +} +#define FXGMAC_REMOVED(a) fxgmac_removed(a) + +static const struct ethtool_ops fxgmac_ethtool_ops = { + .get_drvinfo = fxgmac_ethtool_get_drvinfo, + .get_link = ethtool_op_get_link, + .get_msglevel = fxgmac_ethtool_get_msglevel, + .set_msglevel = fxgmac_ethtool_set_msglevel, + .get_channels = fxgmac_ethtool_get_channels, + .get_coalesce = fxgmac_ethtool_get_coalesce, + .set_coalesce = fxgmac_ethtool_set_coalesce, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0)) + /* + * The process of set is to get first and then set, + * and the result of get is preserved for values that have not been modified. + * + * Therefore, when using, it is necessary to ensure that this macro and the + * assignment operation in the get_coalesce are one-to-one correspondence, + * otherwise the macro and parameters will be verified when set, and the error + * of "Operation not supported " will be reported if the verification fails + */ +#ifdef ETHTOOL_COALESCE_USECS + .supported_coalesce_params = ETHTOOL_COALESCE_USECS, +#endif +#endif + .get_strings = fxgmac_ethtool_get_strings, + .get_sset_count = fxgmac_ethtool_get_sset_count, + .get_ethtool_stats = fxgmac_ethtool_get_ethtool_stats, + .get_regs_len = fxgmac_get_regs_len, + .get_regs = fxgmac_get_regs, + .get_ringparam = fxgmac_get_ringparam, + .set_ringparam = fxgmac_set_ringparam, +#if (FXGMAC_RSS_FEATURE_ENABLED) + .get_rxnfc = fxgmac_get_rxnfc, + .set_rxnfc = fxgmac_set_rxnfc, + .get_rxfh_indir_size = fxgmac_rss_indir_size, + .get_rxfh_key_size = fxgmac_get_rxfh_key_size, + .get_rxfh = fxgmac_get_rxfh, + .set_rxfh = fxgmac_set_rxfh, +#endif +#if (FXGMAC_WOL_FEATURE_ENABLED) + .get_wol = fxgmac_get_wol, + .set_wol = fxgmac_set_wol, +#endif +#if (FXGMAC_PAUSE_FEATURE_ENABLED) +#ifdef ETHTOOL_GLINKSETTINGS + .get_link_ksettings = fxgmac_get_link_ksettings, + .set_link_ksettings = fxgmac_set_link_ksettings, +#endif /* ETHTOOL_GLINKSETTINGS */ + .get_pauseparam = fxgmac_get_pauseparam, + .set_pauseparam = fxgmac_set_pauseparam, +#endif +}; + +const struct ethtool_ops *fxgmac_get_ethtool_ops(void) +{ + return &fxgmac_ethtool_ops; +} diff --git a/drivers/net/ethernet/motorcomm/fuxi-gmac-hw.c b/drivers/net/ethernet/motorcomm/fuxi-gmac-hw.c new file mode 100644 index 000000000000..f63dbb0c9e0b --- /dev/null +++ b/drivers/net/ethernet/motorcomm/fuxi-gmac-hw.c @@ -0,0 +1,6714 @@ +/*++ + +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; +} diff --git a/drivers/net/ethernet/motorcomm/fuxi-gmac-net.c b/drivers/net/ethernet/motorcomm/fuxi-gmac-net.c new file mode 100644 index 000000000000..905bb997a2ab --- /dev/null +++ b/drivers/net/ethernet/motorcomm/fuxi-gmac-net.c @@ -0,0 +1,2366 @@ +/*++ + +Copyright (c) 2021 Motor-comm Corporation. +Confidential and Proprietary. All rights reserved. + +This is Motor-comm Corporation NIC driver relevant files. Please don't copy, modify, +distribute without commercial permission. + +--*/ + + +#include +#include +#include +#include +#include +#include + +#include "fuxi-gmac.h" +#include "fuxi-gmac-reg.h" + + +static int fxgmac_one_poll_rx(struct napi_struct *, int); +static int fxgmac_one_poll_tx(struct napi_struct *, int); +static int fxgmac_all_poll(struct napi_struct *, int); + +unsigned int fxgmac_get_netdev_ip4addr(struct fxgmac_pdata *pdata) +{ + struct net_device *netdev = pdata->netdev; + struct in_ifaddr *ifa; + unsigned int ipval = 0xc0a801ca; //here just hard code to 192.168.1.202 + + rcu_read_lock(); + /* we only get the first IPv4 addr. */ + ifa = rcu_dereference(netdev->ip_ptr->ifa_list); + if(ifa) { + /* binary ipv4 addr with __be */ + ipval = (unsigned int)ifa->ifa_address; + + DPRINTK("%s, netdev %s IPv4 address %pI4, mask: %pI4\n",__FUNCTION__, ifa->ifa_label, &ifa->ifa_address, &ifa->ifa_mask); + } + // ifa = rcu_dereference(ifa->ifa_next); // more ipv4 addr + rcu_read_unlock(); + + return ipval; +} + +unsigned char * fxgmac_get_netdev_ip6addr(struct fxgmac_pdata *pdata, unsigned char *ipval, unsigned char *ip6addr_solicited, unsigned int ifa_flag) +{ + struct net_device *netdev = pdata->netdev; + struct inet6_dev *i6dev; + struct inet6_ifaddr *ifp; + unsigned char local_ipval[16] = {0}; + unsigned char solicited_ipval[16] = {0}; + struct in6_addr *addr_ip6 = (struct in6_addr *)local_ipval; + struct in6_addr *addr_ip6_solicited = (struct in6_addr *)solicited_ipval; + int err = -EADDRNOTAVAIL; + + //in6_pton("fe80::35c6:dd1b:9745:fc9b", -1, (u8*)ipval, -1, NULL); //here just hard code for default + if(ipval) { + addr_ip6 = (struct in6_addr *)ipval; + } + + if(ip6addr_solicited) { + addr_ip6_solicited = (struct in6_addr *)ip6addr_solicited; + } + + in6_pton("fe80::4808:8ffb:d93e:d753", -1, (u8*)addr_ip6, -1, NULL); //here just hard code for default + + if (ifa_flag & FXGMAC_NS_IFA_GLOBAL_UNICAST) + DPRINTK ("%s FXGMAC_NS_IFA_GLOBAL_UNICAST is set, %x\n", __FUNCTION__, ifa_flag); + + if (ifa_flag & FXGMAC_NS_IFA_LOCAL_LINK) + DPRINTK ("%s FXGMAC_NS_IFA_LOCAL_LINK is set, %x\n", __FUNCTION__, ifa_flag); + + rcu_read_lock(); + i6dev = __in6_dev_get(netdev); + if (i6dev != NULL) { + read_lock_bh(&i6dev->lock); + list_for_each_entry(ifp, &i6dev->addr_list, if_list) { + + /* here we need only the ll addr, use scope to filter out it. */ + if (((ifa_flag & FXGMAC_NS_IFA_GLOBAL_UNICAST) && (ifp->scope != IFA_LINK)) || ((ifa_flag & FXGMAC_NS_IFA_LOCAL_LINK) && (ifp->scope == IFA_LINK)/* && + !(ifp->flags & IFA_F_TENTATIVE)*/)) { + + memcpy(addr_ip6, &ifp->addr, 16); + addrconf_addr_solict_mult(addr_ip6, addr_ip6_solicited); + err = 0; + + //DPRINTK("%s, netdev %s IPv6 local-link address %pI6\n",__FUNCTION__, netdev->name, addr_ip6); + //DPRINTK("%s, netdev %s IPv6 solicited-node add %pI6\n",__FUNCTION__, netdev->name, addr_ip6_solicited); + break; + } + } + read_unlock_bh(&i6dev->lock); + } + rcu_read_unlock(); + + if(err) DPRINTK("%s get ipv6 addr failed, use default.\n", __FUNCTION__); + + //DPRINTK("%s, netdev %s IPv6 local-link address %pI6\n",__FUNCTION__, netdev->name, addr_ip6); + //DPRINTK("%s, netdev %s IPv6 solicited-node adr %pI6\n",__FUNCTION__, netdev->name, addr_ip6_solicited); + + return (err ? NULL : ipval); +} + +inline unsigned int fxgmac_tx_avail_desc(struct fxgmac_ring *ring) +{ + //return (ring->dma_desc_count - (ring->cur - ring->dirty)); + unsigned int avail; + + if (ring->dirty > ring->cur) + avail = ring->dirty - ring->cur; + else + avail = ring->dma_desc_count - ring->cur + ring->dirty; + + return avail; +} + +inline unsigned int fxgmac_rx_dirty_desc(struct fxgmac_ring *ring) +{ + //return (ring->cur - ring->dirty); + unsigned int dirty; + + if (ring->dirty <= ring->cur) + dirty = ring->cur - ring->dirty; + else + dirty = ring->dma_desc_count - ring->dirty + ring->cur; + + return dirty; +} + +static int fxgmac_maybe_stop_tx_queue( + struct fxgmac_channel *channel, + struct fxgmac_ring *ring, + unsigned int count) +{ + struct fxgmac_pdata *pdata = channel->pdata; + + if (count > fxgmac_tx_avail_desc(ring)) { + netif_info(pdata, drv, pdata->netdev, + "Tx queue stopped, not enough descriptors available\n"); + netif_stop_subqueue(pdata->netdev, channel->queue_index); + ring->tx.queue_stopped = 1; + + /* If we haven't notified the hardware because of xmit_more + * support, tell it now + */ + if (ring->tx.xmit_more) + pdata->hw_ops.tx_start_xmit(channel, ring); + if(netif_msg_tx_done(pdata)) DPRINTK("about stop tx q, ret BUSY\n"); + + return NETDEV_TX_BUSY; + } + + return 0; +} + +static void fxgmac_prep_vlan(struct sk_buff *skb, + struct fxgmac_pkt_info *pkt_info) +{ + if (skb_vlan_tag_present(skb)) + pkt_info->vlan_ctag = skb_vlan_tag_get(skb); +} + +static int fxgmac_prep_tso(struct fxgmac_pdata *pdata, struct sk_buff *skb, + struct fxgmac_pkt_info *pkt_info) +{ + int ret; + + if (!FXGMAC_GET_REG_BITS(pkt_info->attributes, + TX_PACKET_ATTRIBUTES_TSO_ENABLE_POS, + TX_PACKET_ATTRIBUTES_TSO_ENABLE_LEN)) + return 0; + + ret = skb_cow_head(skb, 0); + if (ret) + return ret; + + pkt_info->header_len = skb_transport_offset(skb) + tcp_hdrlen(skb); + pkt_info->tcp_header_len = tcp_hdrlen(skb); + pkt_info->tcp_payload_len = skb->len - pkt_info->header_len; + pkt_info->mss = skb_shinfo(skb)->gso_size; + + if(netif_msg_tx_done(pdata)){ + DPRINTK("header_len=%u\n", pkt_info->header_len); + DPRINTK("tcp_header_len=%u, tcp_payload_len=%u\n", + pkt_info->tcp_header_len, pkt_info->tcp_payload_len); + DPRINTK("mss=%u\n", pkt_info->mss); + } + /* Update the number of packets that will ultimately be transmitted + * along with the extra bytes for each extra packet + */ + pkt_info->tx_packets = skb_shinfo(skb)->gso_segs; + pkt_info->tx_bytes += (pkt_info->tx_packets - 1) * pkt_info->header_len; + + return 0; +} + +static int fxgmac_is_tso(struct sk_buff *skb) +{ + if (skb->ip_summed != CHECKSUM_PARTIAL) + return 0; + + if (!skb_is_gso(skb)) + return 0; + + return 1; +} + +static void fxgmac_prep_tx_pkt(struct fxgmac_pdata *pdata, + struct fxgmac_ring *ring, + struct sk_buff *skb, + struct fxgmac_pkt_info *pkt_info) +{ +#if ( LINUX_VERSION_CODE >= KERNEL_VERSION(5,0,0) ) + skb_frag_t *frag; +#else + struct skb_frag_struct *frag; +#endif + unsigned int context_desc; + unsigned int len; + unsigned int i; + + pkt_info->skb = skb; + + context_desc = 0; + pkt_info->desc_count = 0; + + pkt_info->tx_packets = 1; + pkt_info->tx_bytes = skb->len; + if(netif_msg_tx_done(pdata)) + DPRINTK ("fxgmac_prep_tx_pkt callin,pkt desc cnt=%d,skb len=%d, skbheadlen=%d\n", pkt_info->desc_count, skb->len, skb_headlen(skb)); + + if (fxgmac_is_tso(skb)) { + /* TSO requires an extra descriptor if mss is different */ + if (skb_shinfo(skb)->gso_size != ring->tx.cur_mss) { + context_desc = 1; + pkt_info->desc_count++; + } + if(netif_msg_tx_done(pdata)) + DPRINTK("fxgmac_is_tso=%d, ip_summed=%d,skb gso=%d\n",((skb->ip_summed == CHECKSUM_PARTIAL) && (skb_is_gso(skb)))?1:0, skb->ip_summed, skb_is_gso(skb)?1:0); + + /* TSO requires an extra descriptor for TSO header */ + pkt_info->desc_count++; + + pkt_info->attributes = FXGMAC_SET_REG_BITS( + pkt_info->attributes, + TX_PACKET_ATTRIBUTES_TSO_ENABLE_POS, + TX_PACKET_ATTRIBUTES_TSO_ENABLE_LEN, + 1); + pkt_info->attributes = FXGMAC_SET_REG_BITS( + pkt_info->attributes, + TX_PACKET_ATTRIBUTES_CSUM_ENABLE_POS, + TX_PACKET_ATTRIBUTES_CSUM_ENABLE_LEN, + 1); + if(netif_msg_tx_done(pdata)) DPRINTK ("fxgmac_prep_tx_pkt,tso, pkt desc cnt=%d\n", pkt_info->desc_count); + } else if (skb->ip_summed == CHECKSUM_PARTIAL) + pkt_info->attributes = FXGMAC_SET_REG_BITS( + pkt_info->attributes, + TX_PACKET_ATTRIBUTES_CSUM_ENABLE_POS, + TX_PACKET_ATTRIBUTES_CSUM_ENABLE_LEN, + 1); + + if (skb_vlan_tag_present(skb)) { + /* VLAN requires an extra descriptor if tag is different */ + if (skb_vlan_tag_get(skb) != ring->tx.cur_vlan_ctag) + /* We can share with the TSO context descriptor */ + if (!context_desc) { + context_desc = 1; + pkt_info->desc_count++; + } + + pkt_info->attributes = FXGMAC_SET_REG_BITS( + pkt_info->attributes, + TX_PACKET_ATTRIBUTES_VLAN_CTAG_POS, + TX_PACKET_ATTRIBUTES_VLAN_CTAG_LEN, + 1); + if(netif_msg_tx_done(pdata)) DPRINTK ("fxgmac_prep_tx_pkt,VLAN, pkt desc cnt=%d,vlan=0x%04x\n", pkt_info->desc_count, skb_vlan_tag_get(skb)); + } + + for (len = skb_headlen(skb); len;) { + pkt_info->desc_count++; + len -= min_t(unsigned int, len, FXGMAC_TX_MAX_BUF_SIZE); + } + + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + frag = &skb_shinfo(skb)->frags[i]; + for (len = skb_frag_size(frag); len; ) { + pkt_info->desc_count++; + len -= min_t(unsigned int, len, FXGMAC_TX_MAX_BUF_SIZE); + } + } + if(netif_msg_tx_done(pdata)) + DPRINTK ("fxgmac_prep_tx_pkt callout,pkt desc cnt=%d,skb len=%d, skbheadlen=%d,frags=%d\n", pkt_info->desc_count, skb->len, skb_headlen(skb), skb_shinfo(skb)->nr_frags); +} + +static int fxgmac_calc_rx_buf_size(struct net_device *netdev, unsigned int mtu) +{ + unsigned int rx_buf_size; + + if (mtu > FXGMAC_JUMBO_PACKET_MTU) { + netdev_alert(netdev, "MTU exceeds maximum supported value\n"); + return -EINVAL; + } + + rx_buf_size = mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN; + rx_buf_size = clamp_val(rx_buf_size, FXGMAC_RX_MIN_BUF_SIZE, PAGE_SIZE * 4 /* follow yonggang's suggestion */); + + rx_buf_size = (rx_buf_size + FXGMAC_RX_BUF_ALIGN - 1) & + ~(FXGMAC_RX_BUF_ALIGN - 1); + + return rx_buf_size; +} + +static void fxgmac_enable_rx_tx_ints(struct fxgmac_pdata *pdata) +{ + struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops; + struct fxgmac_channel *channel; + enum fxgmac_int int_id; + unsigned int i; + + channel = pdata->channel_head; + for (i = 0; i < pdata->channel_count; i++, channel++) { + if (channel->tx_ring && channel->rx_ring) + int_id = FXGMAC_INT_DMA_CH_SR_TI_RI; + else if (channel->tx_ring) + int_id = FXGMAC_INT_DMA_CH_SR_TI; + else if (channel->rx_ring) + int_id = FXGMAC_INT_DMA_CH_SR_RI; + else + continue; + + hw_ops->enable_int(channel, int_id); + } +} + +#if 0 +static void fxgmac_disable_rx_tx_ints(struct fxgmac_pdata *pdata) +{ + struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops; + struct fxgmac_channel *channel; + enum fxgmac_int int_id; + unsigned int i; + + channel = pdata->channel_head; + for (i = 0; i < pdata->channel_count; i++, channel++) { + if (channel->tx_ring && channel->rx_ring) + int_id = FXGMAC_INT_DMA_CH_SR_TI_RI; + else if (channel->tx_ring) + int_id = FXGMAC_INT_DMA_CH_SR_TI; + else if (channel->rx_ring) + int_id = FXGMAC_INT_DMA_CH_SR_RI; + else + continue; + + hw_ops->disable_int(channel, int_id); + } +} +#endif + +static void fxgmac_phy_process(struct fxgmac_pdata *pdata) +{ + int cur_link = 0; + int regval = 0; + int cur_speed = 0; + struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops; + + regval = hw_ops->get_ephy_state(pdata); + + // We should make sure that PHY is done with the reset + if (regval & MGMT_EPHY_CTRL_STA_EPHY_RESET) { + pdata->expansion.phy_link = false; + return; + } + + cur_link = FXGMAC_GET_REG_BITS(regval, + MGMT_EPHY_CTRL_STA_EPHY_LINKUP_POS, + MGMT_EPHY_CTRL_STA_EPHY_LINKUP_LEN); + if (pdata->expansion.phy_link != cur_link) { + pdata->expansion.phy_link = cur_link; + if (pdata->expansion.phy_link) { + cur_speed = FXGMAC_GET_REG_BITS(regval, + MGMT_EPHY_CTRL_STA_SPEED_POS, + MGMT_EPHY_CTRL_STA_SPEED_LEN); + pdata->phy_speed = (cur_speed == 2) ? SPEED_1000 : + (cur_speed == 1) ? SPEED_100 : SPEED_10; + pdata->phy_duplex = FXGMAC_GET_REG_BITS(regval, + MGMT_EPHY_CTRL_STA_EPHY_DUPLEX_POS, + MGMT_EPHY_CTRL_STA_EPHY_DUPLEX_LEN); + hw_ops->config_mac_speed(pdata); + + hw_ops->enable_rx(pdata); + hw_ops->enable_tx(pdata); + netif_carrier_on(pdata->netdev); + if (netif_running(pdata->netdev)) + { + netif_tx_wake_all_queues(pdata->netdev); + DPRINTK("%s now is link up, mac_speed=%d.\n", FXGMAC_DRV_NAME, + pdata->phy_speed); + } + }else { + netif_carrier_off(pdata->netdev); + netif_tx_stop_all_queues(pdata->netdev); + pdata->phy_speed = SPEED_UNKNOWN; + pdata->phy_duplex = DUPLEX_UNKNOWN; + hw_ops->disable_rx(pdata); + hw_ops->disable_tx(pdata); + DPRINTK("%s now is link down\n", FXGMAC_DRV_NAME); + } + } +} + +static int fxgmac_phy_poll(struct napi_struct *napi, int budget) +{ + struct fxgmac_pdata *pdata = container_of(napi, + struct fxgmac_pdata, + expansion.napi_phy); + struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops; + + fxgmac_phy_process(pdata); + if (napi_complete_done(napi, 0)) + hw_ops->enable_msix_one_interrupt(pdata, MSI_ID_PHY_OTHER); + + return 0; +} + +static irqreturn_t fxgmac_phy_isr(int irq, void *data) +{ + struct fxgmac_pdata *pdata = data; + struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops; + u32 regval; + + regval = readreg(pdata->pAdapter, pdata->base_mem + MGMT_INT_CTRL0); + if (!(regval & MGMT_INT_CTRL0_INT_STATUS_PHY)) + return IRQ_HANDLED; + + hw_ops->disable_msix_one_interrupt(pdata, MSI_ID_PHY_OTHER); + hw_ops->read_ephy_reg(pdata, REG_MII_INT_STATUS, NULL); + if (napi_schedule_prep(&pdata->expansion.napi_phy)) { + __napi_schedule_irqoff(&pdata->expansion.napi_phy); + } + + return IRQ_HANDLED; +} + +static irqreturn_t fxgmac_isr(int irq, void *data) +{ + unsigned int dma_isr, dma_ch_isr, mac_isr; + struct fxgmac_pdata *pdata = data; + struct fxgmac_channel *channel; + struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops; + unsigned int i, ti, ri; + u32 val; + + dma_isr = readreg(pdata->pAdapter, pdata->mac_regs + DMA_ISR); + + val = readreg(pdata->pAdapter, pdata->base_mem + MGMT_INT_CTRL0); + if (!(val & MGMT_INT_CTRL0_INT_STATUS_RXTXPHY_MASK)) + return IRQ_HANDLED; + + hw_ops->disable_mgm_interrupt(pdata); + pdata->expansion.mgm_intctrl_val = val; + + pdata->stats.mgmt_int_isr++; + + for (i = 0; i < pdata->channel_count; i++) { + channel = pdata->channel_head + i; + + dma_ch_isr = readl(FXGMAC_DMA_REG(channel, DMA_CH_SR)); + netif_dbg(pdata, intr, pdata->netdev, "DMA_CH%u_ISR=%#010x\n", + i, dma_ch_isr); + + /* The TI or RI interrupt bits may still be set even if using + * per channel DMA interrupts. Check to be sure those are not + * enabled before using the private data napi structure. + */ + ti = FXGMAC_GET_REG_BITS(dma_ch_isr, DMA_CH_SR_TI_POS, + DMA_CH_SR_TI_LEN); + ri = FXGMAC_GET_REG_BITS(dma_ch_isr, DMA_CH_SR_RI_POS, + DMA_CH_SR_RI_LEN); + if (!pdata->per_channel_irq && (ti || ri)) { + if (napi_schedule_prep(&pdata->expansion.napi)) { + pdata->stats.napi_poll_isr++; + /* Turn on polling */ + __napi_schedule_irqoff(&pdata->expansion.napi); + } + } + + if (FXGMAC_GET_REG_BITS(dma_ch_isr, DMA_CH_SR_TPS_POS, + DMA_CH_SR_TPS_LEN)) + pdata->stats.tx_process_stopped++; + + if (FXGMAC_GET_REG_BITS(dma_ch_isr, DMA_CH_SR_RPS_POS, + DMA_CH_SR_RPS_LEN)) + pdata->stats.rx_process_stopped++; + + if (FXGMAC_GET_REG_BITS(dma_ch_isr, DMA_CH_SR_TBU_POS, + DMA_CH_SR_TBU_LEN)) + pdata->stats.tx_buffer_unavailable++; + + if (FXGMAC_GET_REG_BITS(dma_ch_isr, DMA_CH_SR_RBU_POS, + DMA_CH_SR_RBU_LEN)) + pdata->stats.rx_buffer_unavailable++; + + /* Restart the device on a Fatal Bus Error */ + if (FXGMAC_GET_REG_BITS(dma_ch_isr, DMA_CH_SR_FBE_POS, + DMA_CH_SR_FBE_LEN)) { + pdata->stats.fatal_bus_error++; + schedule_work(&pdata->expansion.restart_work); + } + + /* Clear all interrupt signals */ + writel(dma_ch_isr, FXGMAC_DMA_REG(channel, DMA_CH_SR)); + } + + if (FXGMAC_GET_REG_BITS(dma_isr, DMA_ISR_MACIS_POS, + DMA_ISR_MACIS_LEN)) { + mac_isr = readl(pdata->mac_regs + MAC_ISR); + + if (FXGMAC_GET_REG_BITS(mac_isr, MAC_ISR_MMCTXIS_POS, + MAC_ISR_MMCTXIS_LEN)) + hw_ops->tx_mmc_int(pdata); + + if (FXGMAC_GET_REG_BITS(mac_isr, MAC_ISR_MMCRXIS_POS, + MAC_ISR_MMCRXIS_LEN)) + hw_ops->rx_mmc_int(pdata); + + /* Clear all interrupt signals */ + writel(mac_isr, (pdata->mac_regs + MAC_ISR)); + } + + if (pdata->expansion.mgm_intctrl_val & MGMT_INT_CTRL0_INT_STATUS_PHY) { + hw_ops->read_ephy_reg(pdata, REG_MII_INT_STATUS, &val); + if (napi_schedule_prep(&pdata->expansion.napi)) { + pdata->stats.napi_poll_isr++; + /* Turn on polling */ + __napi_schedule_irqoff(&pdata->expansion.napi); + } + } + + return IRQ_HANDLED; + +} + +static irqreturn_t fxgmac_dma_isr(int irq, void *data) +{ + struct fxgmac_channel *channel = data; + struct fxgmac_pdata *pdata = channel->pdata; + struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops; + u32 regval; + int message_id; + + if (irq == channel->expansion.dma_irq_tx) { + message_id = MSI_ID_TXQ0; + hw_ops->disable_msix_one_interrupt(pdata, message_id); + regval = 0; + regval = FXGMAC_SET_REG_BITS(regval, DMA_CH_SR_TI_POS, DMA_CH_SR_TI_LEN, 1); + writereg(pdata->pAdapter, regval, FXGMAC_DMA_REG(channel, DMA_CH_SR)); + if (napi_schedule_prep(&channel->expansion.napi_tx)) { + __napi_schedule_irqoff(&channel->expansion.napi_tx); + } + } else { + message_id = channel->queue_index; + hw_ops->disable_msix_one_interrupt(pdata, message_id); + regval = 0; + regval = readreg(pdata->pAdapter, FXGMAC_DMA_REG(channel, DMA_CH_SR)); + regval = FXGMAC_SET_REG_BITS(regval, DMA_CH_SR_RI_POS, DMA_CH_SR_RI_LEN, 1); + writereg(pdata->pAdapter, regval, FXGMAC_DMA_REG(channel, DMA_CH_SR)); + if (napi_schedule_prep(&channel->expansion.napi_rx)) { + __napi_schedule_irqoff(&channel->expansion.napi_rx); + } + } + + return IRQ_HANDLED; +} + +#if 0 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0)) +static void fxgmac_tx_timer(struct timer_list *t) +#else +static void fxgmac_tx_timer(unsigned long data) +#endif +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0)) + struct fxgmac_channel *channel = from_timer(channel, t, tx_timer); +#else + struct fxgmac_channel *channel = (struct fxgmac_channel *)data; +#endif + + //for msix. since this function is defined for MSIx, it is no need to brace by macro CONFIG_PCI_MSI + struct fxgmac_pdata *pdata = channel->pdata; + struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops; + u32 regval; + + if (pdata->per_channel_irq) { + hw_ops->disable_msix_one_interrupt(pdata, MSI_ID_TXQ0); + regval = 0; + regval = FXGMAC_SET_REG_BITS(regval, DMA_CH_SR_TI_POS, DMA_CH_SR_TI_LEN, 1); + writereg(pdata->pAdapter, regval, FXGMAC_DMA_REG(channel, DMA_CH_SR)); + if (napi_schedule_prep(&channel->expansion.napi_tx)) { + pdata->stats.napi_poll_txtimer++; + __napi_schedule(&channel->expansion.napi_tx); + } + } else { + fxgmac_disable_rx_tx_ints(pdata); + if (napi_schedule_prep(&pdata->expansion.napi)) { + pdata->stats.napi_poll_txtimer++; + __napi_schedule(&pdata->expansion.napi); + } + } + + pdata->stats.cnt_alive_txtimer++; + channel->tx_timer_active = 0; +} +#endif + +#if FXGMAC_TX_HANG_TIMER_EN +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0)) +static void fxgmac_tx_hang_timer_handler(struct timer_list *t) +#else +static void fxgmac_tx_hang_timer_handler(unsigned long data) +#endif +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0)) + struct fxgmac_channel *channel = from_timer(channel, t, expansion.tx_hang_timer); +#else + struct fxgmac_channel *channel = (struct fxgmac_channel *)data; +#endif + +#if FXGMAC_TX_HANG_CHECH_DIRTY + struct fxgmac_ring *ring = channel->tx_ring; +#endif + struct fxgmac_pdata *pdata = channel->pdata; + struct net_device *netdev = pdata->netdev; + unsigned int hw_reg_cur; + unsigned int regval; + +#if FXGMAC_TX_HANG_CHECH_DIRTY + hw_reg_cur = ring->dirty; +#else + hw_reg_cur = readl(FXGMAC_DMA_REG(channel, 0x44/* tx desc curr pointer reg */)); +#endif + if(hw_reg_cur == channel->expansion.tx_hang_hw_cur) { + + /* hw current desc still stucked */ + if(!pdata->tx_hang_restart_queuing) { + pdata->tx_hang_restart_queuing = 1; + DPRINTK("tx_hang_timer_handler: restart scheduled, at desc %u, queuing=%u.\n", channel->expansion.tx_hang_hw_cur, pdata->tx_hang_restart_queuing); + + netif_tx_stop_all_queues(netdev); + + /* Disable MAC Rx */ + regval = readl(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); + writel(regval, pdata->mac_regs + MAC_CR); + + schedule_work(&pdata->expansion.restart_work); + } + } + + channel->expansion.tx_hang_timer_active = 0; +} + +static void fxgmac_tx_hang_timer_start(struct fxgmac_channel *channel) +{ + struct fxgmac_pdata *pdata = channel->pdata; + + /* Start the Tx hang timer */ + if (1 && !channel->expansion.tx_hang_timer_active) { + channel->expansion.tx_hang_timer_active = 1; + + /* FXGMAC_INIT_DMA_TX_USECS is desc3 polling period, we give 2 more checking period */ + mod_timer(&channel->expansion.tx_hang_timer, + jiffies + usecs_to_jiffies(FXGMAC_INIT_DMA_TX_USECS * 10)); + } +} +#endif + +#if 0 +static void fxgmac_init_timers(struct fxgmac_pdata *pdata) +{ + struct fxgmac_channel *channel; + unsigned int i; + + channel = pdata->channel_head; + for (i = 0; i < pdata->channel_count; i++, channel++) { + if (!channel->tx_ring) + break; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0)) + timer_setup(&channel->tx_timer, fxgmac_tx_timer, 0); +#else + setup_timer(&channel->tx_timer, fxgmac_tx_timer, (unsigned long)channel); +#endif +#if FXGMAC_TX_HANG_TIMER_EN + channel->tx_hang_timer_active = 0; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0)) + timer_setup(&channel->tx_hang_timer, fxgmac_tx_hang_timer_handler, 0); +#else + setup_timer(&channel->tx_hang_timer, fxgmac_tx_hang_timer_handler, (unsigned long)channel); +#endif +#endif + } +} + +static void fxgmac_stop_timers(struct fxgmac_pdata *pdata) +{ + struct fxgmac_channel *channel; + unsigned int i; + + channel = pdata->channel_head; + if (channel != NULL) { + for (i = 0; i < pdata->channel_count; i++, channel++) { + if (!channel->tx_ring) + break; + + del_timer_sync(&channel->tx_timer); +#if FXGMAC_TX_HANG_TIMER_EN + del_timer_sync(&channel->tx_hang_timer); + channel->tx_hang_timer_active = 0; +#endif + } + } +} +#endif + +static void fxgmac_napi_enable(struct fxgmac_pdata *pdata, unsigned int add) +{ + struct fxgmac_channel *channel; + unsigned int i; + + if (pdata->per_channel_irq) { + channel = pdata->channel_head; + for (i = 0; i < pdata->channel_count; i++, channel++) { + if (add) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6,1,0)) + netif_napi_add_weight(pdata->netdev, &channel->expansion.napi_rx, + fxgmac_one_poll_rx, NAPI_POLL_WEIGHT); +#else + netif_napi_add(pdata->netdev, &channel->expansion.napi_rx, + fxgmac_one_poll_rx, NAPI_POLL_WEIGHT); +#endif + } + napi_enable(&channel->expansion.napi_rx); + + if (FXGMAC_IS_CHANNEL_WITH_TX_IRQ(i)) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6,1,0)) + netif_napi_add_weight(pdata->netdev, &channel->expansion.napi_tx, + fxgmac_one_poll_tx, NAPI_POLL_WEIGHT); +#else + netif_napi_add(pdata->netdev, &channel->expansion.napi_tx, + fxgmac_one_poll_tx, NAPI_POLL_WEIGHT); +#endif + napi_enable(&channel->expansion.napi_tx); + } + if(netif_msg_drv(pdata)) DPRINTK("napi_enable, msix ch%d napi enabled done,add=%d\n", i, add); + } + + // for phy +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6,1,0)) + netif_napi_add_weight(pdata->netdev, &pdata->expansion.napi_phy, + fxgmac_phy_poll, NAPI_POLL_WEIGHT); +#else + netif_napi_add(pdata->netdev, &pdata->expansion.napi_phy, + fxgmac_phy_poll, NAPI_POLL_WEIGHT); +#endif + napi_enable(&pdata->expansion.napi_phy); + } else { + i = FXGMAC_GET_REG_BITS(pdata->expansion.int_flags, + FXGMAC_FLAG_LEGACY_NAPI_FREE_POS, + FXGMAC_FLAG_LEGACY_NAPI_FREE_LEN); + if (!i) { + if (add) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6,1,0)) + netif_napi_add_weight(pdata->netdev, &pdata->expansion.napi, + fxgmac_all_poll, NAPI_POLL_WEIGHT); +#else + netif_napi_add(pdata->netdev, &pdata->expansion.napi, + fxgmac_all_poll, NAPI_POLL_WEIGHT); +#endif + } + + napi_enable(&pdata->expansion.napi); + pdata->expansion.int_flags = FXGMAC_SET_REG_BITS(pdata->expansion.int_flags, + FXGMAC_FLAG_LEGACY_NAPI_FREE_POS, + FXGMAC_FLAG_LEGACY_NAPI_FREE_LEN, + 1); + } + } +} + +static void fxgmac_napi_disable(struct fxgmac_pdata *pdata, unsigned int del) +{ + struct fxgmac_channel *channel; + unsigned int i; + + if (pdata->per_channel_irq) { + channel = pdata->channel_head; + if (channel != NULL) { + for (i = 0; i < pdata->channel_count; i++, channel++) { + napi_disable(&channel->expansion.napi_rx); + + if (del) { + netif_napi_del(&channel->expansion.napi_rx); + } + + if (FXGMAC_IS_CHANNEL_WITH_TX_IRQ(i)) { + napi_disable(&channel->expansion.napi_tx); + netif_napi_del(&channel->expansion.napi_tx); + } + if(netif_msg_drv(pdata)) DPRINTK("napi_disable, msix ch%d napi disabled done,del=%d\n", i, del); + } + + napi_disable(&pdata->expansion.napi_phy); + netif_napi_del(&pdata->expansion.napi_phy); + } + } else { + i = FXGMAC_GET_REG_BITS(pdata->expansion.int_flags, + FXGMAC_FLAG_LEGACY_NAPI_FREE_POS, + FXGMAC_FLAG_LEGACY_NAPI_FREE_LEN); + if (i) { + napi_disable(&pdata->expansion.napi); + + if (del) + netif_napi_del(&pdata->expansion.napi); + pdata->expansion.int_flags = FXGMAC_SET_REG_BITS(pdata->expansion.int_flags, + FXGMAC_FLAG_LEGACY_NAPI_FREE_POS, + FXGMAC_FLAG_LEGACY_NAPI_FREE_LEN, + 0); + + } + } +} + +static int fxgmac_request_irqs(struct fxgmac_pdata *pdata) +{ + struct net_device *netdev = pdata->netdev; + struct fxgmac_channel *channel; + unsigned int i; + int ret; + u32 msi, msix, need_free; + + msi = FXGMAC_GET_REG_BITS(pdata->expansion.int_flags, + FXGMAC_FLAG_MSI_POS, + FXGMAC_FLAG_MSI_LEN); + + msix = FXGMAC_GET_REG_BITS(pdata->expansion.int_flags, + FXGMAC_FLAG_MSIX_POS, + FXGMAC_FLAG_MSIX_LEN); + + need_free = FXGMAC_GET_REG_BITS(pdata->expansion.int_flags, + FXGMAC_FLAG_LEGACY_IRQ_FREE_POS, + FXGMAC_FLAG_LEGACY_IRQ_FREE_LEN); + + if(!msix) { + if (!need_free) { + ret = devm_request_irq(pdata->dev, pdata->dev_irq, fxgmac_isr, + msi ? 0 : IRQF_SHARED, + netdev->name, pdata); + if (ret) { + netdev_alert(netdev, "error requesting irq %d, ret = %d\n", pdata->dev_irq, ret); + return ret; + } + + pdata->expansion.int_flags = FXGMAC_SET_REG_BITS(pdata->expansion.int_flags, + FXGMAC_FLAG_LEGACY_IRQ_FREE_POS, + FXGMAC_FLAG_LEGACY_IRQ_FREE_LEN, + 1); + } + } + + if (!pdata->per_channel_irq) + return 0; + + ret = devm_request_irq(pdata->dev, pdata->expansion.phy_irq, fxgmac_phy_isr, 0, netdev->name, pdata); + if (ret) { + netdev_alert(netdev, "error requesting phy irq %d, ret = %d\n", pdata->expansion.phy_irq, ret); + return ret; + } + + channel = pdata->channel_head; + for (i = 0; i < pdata->channel_count; i++, channel++) { + snprintf(channel->expansion.dma_irq_name, + sizeof(channel->expansion.dma_irq_name) - 1, + "%s-ch%d-Rx-%u", netdev_name(netdev), i, + channel->queue_index); + if(FXGMAC_IS_CHANNEL_WITH_TX_IRQ(i)) { + snprintf(channel->expansion.dma_irq_name_tx, + sizeof(channel->expansion.dma_irq_name_tx) - 1, + "%s-ch%d-Tx-%u", netdev_name(netdev), i, + channel->queue_index); + + ret = devm_request_irq(pdata->dev, channel->expansion.dma_irq_tx, + fxgmac_dma_isr, 0, + channel->expansion.dma_irq_name_tx, channel); + + if (ret) { + DPRINTK("fxgmac_req_irqs, err with MSIx irq request for ch %d tx, ret=%d\n", i, ret); + /* Using an unsigned int, 'i' will go to UINT_MAX and exit */ + devm_free_irq(pdata->dev, channel->expansion.dma_irq_tx, channel); + //devm_free_irq(pdata->dev, pdata->dev_irq, pdata); + return ret; + } + + if(netif_msg_drv(pdata)) + DPRINTK("fxgmac_req_irqs, MSIx irq_tx request ok, ch=%d, irq=%d,%s\n", + i, channel->expansion.dma_irq_tx, channel->expansion.dma_irq_name_tx); + } + ret = devm_request_irq(pdata->dev, channel->dma_irq, + fxgmac_dma_isr, 0, + channel->expansion.dma_irq_name, channel); + if (ret) { + netdev_alert(netdev, "error requesting irq %d\n", + channel->dma_irq); + goto err_irq; + } + } + + if(netif_msg_drv(pdata)) DPRINTK("fxgmac_req_irqs, MSIx irq request ok, total=%d,%d~%d\n", i, (pdata->channel_head)[0].dma_irq, (pdata->channel_head)[i-1].dma_irq); + return 0; + +err_irq: + DPRINTK("fxgmac_req_irqs, err with MSIx irq request at %d, ret=%d\n", i, ret); + + if (pdata->per_channel_irq) { + for (i--, channel--; i < pdata->channel_count; i--, channel--) { + if(FXGMAC_IS_CHANNEL_WITH_TX_IRQ(i)) { + devm_free_irq(pdata->dev, channel->expansion.dma_irq_tx, channel); + } + devm_free_irq(pdata->dev, channel->dma_irq, channel); + } + + devm_free_irq(pdata->dev, pdata->expansion.phy_irq, pdata); + } + return ret; +} + +static void fxgmac_free_irqs(struct fxgmac_pdata *pdata) +{ + struct fxgmac_channel *channel; + unsigned int i = 0; + u32 need_free, msix; + + msix = FXGMAC_GET_REG_BITS(pdata->expansion.int_flags, + FXGMAC_FLAG_MSIX_POS, + FXGMAC_FLAG_MSIX_LEN); + + need_free = FXGMAC_GET_REG_BITS(pdata->expansion.int_flags, + FXGMAC_FLAG_LEGACY_IRQ_FREE_POS, + FXGMAC_FLAG_LEGACY_IRQ_FREE_LEN); + + if(!msix) { + if (need_free) { + devm_free_irq(pdata->dev, pdata->dev_irq, pdata); + pdata->expansion.int_flags = FXGMAC_SET_REG_BITS(pdata->expansion.int_flags, + FXGMAC_FLAG_LEGACY_IRQ_FREE_POS, + FXGMAC_FLAG_LEGACY_IRQ_FREE_LEN, + 0); + } + } + + if (!pdata->per_channel_irq) + return; + + channel = pdata->channel_head; + if (channel != NULL) { + for (i = 0; i < pdata->channel_count; i++, channel++) { + if(FXGMAC_IS_CHANNEL_WITH_TX_IRQ(i)) { + devm_free_irq(pdata->dev, channel->expansion.dma_irq_tx, channel); + if(netif_msg_drv(pdata)) DPRINTK("fxgmac_free_irqs, MSIx irq_tx clear done, ch=%d\n", i); + } + devm_free_irq(pdata->dev, channel->dma_irq, channel); + } + + devm_free_irq(pdata->dev, pdata->expansion.phy_irq, pdata); + } + if(netif_msg_drv(pdata)) DPRINTK("fxgmac_free_irqs, MSIx rx irq clear done, total=%d\n", i); +} + +void fxgmac_free_tx_data(struct fxgmac_pdata *pdata) +{ + struct fxgmac_desc_ops *desc_ops = &pdata->desc_ops; + struct fxgmac_desc_data *desc_data; + struct fxgmac_channel *channel; + struct fxgmac_ring *ring; + unsigned int i, j; + + channel = pdata->channel_head; + if (channel != NULL) { + for (i = 0; i < pdata->channel_count; i++, channel++) { + ring = channel->tx_ring; + if (!ring) + break; + + for (j = 0; j < ring->dma_desc_count; j++) { + desc_data = FXGMAC_GET_DESC_DATA(ring, j); + desc_ops->unmap_desc_data(pdata, desc_data); + } + } + } +} + +void fxgmac_free_rx_data(struct fxgmac_pdata *pdata) +{ + struct fxgmac_desc_ops *desc_ops = &pdata->desc_ops; + struct fxgmac_desc_data *desc_data; + struct fxgmac_channel *channel; + struct fxgmac_ring *ring; + unsigned int i, j; + + channel = pdata->channel_head; + if (channel != NULL) { + for (i = 0; i < pdata->channel_count; i++, channel++) { + ring = channel->rx_ring; + if (!ring) + break; + + for (j = 0; j < ring->dma_desc_count; j++) { + desc_data = FXGMAC_GET_DESC_DATA(ring, j); + desc_ops->unmap_desc_data(pdata, desc_data); + } + } + } +} + +/* + * since kernel does not clear the MSI mask bits and + * this function clear MSI mask bits when MSI is enabled. + */ +static int fxgmac_disable_pci_msi_config(struct pci_dev *pdev) +{ + u16 pcie_cap_offset; + u32 pcie_msi_mask_bits; + int ret = 0; + + pcie_cap_offset = pci_find_capability(pdev, PCI_CAP_ID_MSI); + if (pcie_cap_offset) { + ret = pci_read_config_dword(pdev, pcie_cap_offset, &pcie_msi_mask_bits); + if (ret) { + printk(KERN_ERR "read pci config space MSI cap. failed, %d\n", ret); + ret = -EFAULT; + } + } + + pcie_msi_mask_bits = FXGMAC_SET_REG_BITS(pcie_msi_mask_bits, + PCI_CAP_ID_MSI_ENABLE_POS, + PCI_CAP_ID_MSI_ENABLE_LEN, + 0); + ret = pci_write_config_dword(pdev, pcie_cap_offset, pcie_msi_mask_bits); + if (ret) { + printk(KERN_ERR "write pci config space MSI mask failed, %d\n", ret); + ret = -EFAULT; + } + + return ret; +} + +static int fxgmac_disable_pci_msix_config(struct pci_dev *pdev) +{ + u16 pcie_cap_offset; + u32 pcie_msi_mask_bits; + int ret = 0; + + pcie_cap_offset = pci_find_capability(pdev, PCI_CAP_ID_MSIX); + if (pcie_cap_offset) { + ret = pci_read_config_dword(pdev, pcie_cap_offset, &pcie_msi_mask_bits); + if (ret) { + printk(KERN_ERR "read pci config space MSIX cap. failed, %d\n", ret); + ret = -EFAULT; + } + } + + pcie_msi_mask_bits = FXGMAC_SET_REG_BITS(pcie_msi_mask_bits, + PCI_CAP_ID_MSIX_ENABLE_POS, + PCI_CAP_ID_MSIX_ENABLE_LEN, + 0); + ret = pci_write_config_dword(pdev, pcie_cap_offset, pcie_msi_mask_bits); + if (ret) { + printk(KERN_ERR "write pci config space MSIX mask failed, %d\n", ret); + ret = -EFAULT; + } + + return ret; +} + +extern int fxgmac_dismiss_all_int(struct fxgmac_pdata *pdata); + +int fxgmac_start(struct fxgmac_pdata *pdata) +{ + struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops; + struct net_device *netdev = pdata->netdev; + int ret; + unsigned int pcie_low_power = 0; + u32 regval; + + if(netif_msg_drv(pdata)) DPRINTK("fxgmac start callin here.\n"); + + /* must reset software again here, to avoid flushing tx queue error caused by the system only run probe + * when installing driver on the arm platform. + */ + hw_ops->exit(pdata); + + if (FXGMAC_GET_REG_BITS(pdata->expansion.int_flags, + FXGMAC_FLAG_LEGACY_POS, + FXGMAC_FLAG_LEGACY_LEN)) { + /* + * we should disable msi and msix here when we use legacy interrupt,for two reasons: + * 1. Exit will restore msi and msix config regisiter, that may enable them. + * 2. When the driver that uses the msix interrupt by default is compiled + * into the OS, uninstall the driver through rmmod, and then install the + * driver that uses the legacy interrupt, at which time the msix enable + * will be turned on again by default after waking up from S4 on some platform. + * such as UOS platform. + */ + ret = fxgmac_disable_pci_msi_config(pdata->pdev); + ret |= fxgmac_disable_pci_msix_config(pdata->pdev); + if (ret) + return ret; + } + + hw_ops->reset_phy(pdata); + hw_ops->release_phy(pdata); + hw_ops->pcie_init(pdata, + pcie_low_power & PCIE_LP_ASPM_LTR, + pcie_low_power & PCIE_LP_ASPM_L1SS, + pcie_low_power & PCIE_LP_ASPM_L1, + pcie_low_power & PCIE_LP_ASPM_L0S); + hw_ops->config_power_up(pdata); + + fxgmac_dismiss_all_int(pdata); + + ret = hw_ops->init(pdata); + if (ret) { + printk("fxgmac hw init error.\n"); + return ret; + } + fxgmac_napi_enable(pdata, 1); + + ret = fxgmac_request_irqs(pdata); + if (ret) + goto err_napi; + + hw_ops->enable_tx(pdata); + hw_ops->enable_rx(pdata); + + //config interrupt to level signal + regval = (u32)readl((const volatile void *)(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); + writel(regval, pdata->mac_regs + DMA_MR); + + writel(0xF0000000, (volatile void *)(netdev->base_addr + MGMT_INT_CTRL0)); + + hw_ops->set_interrupt_moderation(pdata); + + if (pdata->per_channel_irq) + hw_ops->enable_msix_rxtxphyinterrupt(pdata); + + fxgmac_enable_rx_tx_ints(pdata); + +#if 0 + netif_tx_start_all_queues(netdev); +#endif + + hw_ops->led_under_active(pdata); + + return 0; + +err_napi: + fxgmac_napi_disable(pdata, 1); + hw_ops->exit(pdata); + DPRINTK("fxgmac start callout with irq err.\n"); + return ret; +} + +void fxgmac_stop(struct fxgmac_pdata *pdata) +{ + struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops; + struct net_device *netdev = pdata->netdev; + struct fxgmac_channel *channel; + struct netdev_queue *txq; + unsigned int i; + + if (pdata->per_channel_irq) { + hw_ops->disable_msix_interrupt(pdata); + } + else { + hw_ops->disable_mgm_interrupt(pdata); + } + + pdata->expansion.phy_link = false; + + netif_carrier_off(netdev);//yzhang added, 0324 + netif_tx_stop_all_queues(netdev); +#if 0 + fxgmac_stop_timers(pdata); +#endif + hw_ops->disable_tx(pdata); + hw_ops->disable_rx(pdata); + fxgmac_free_irqs(pdata); + fxgmac_napi_disable(pdata, 1); + + channel = pdata->channel_head; + if (channel != NULL) { + for (i = 0; i < pdata->channel_count; i++, channel++) { + if (!channel->tx_ring) + continue; + + txq = netdev_get_tx_queue(netdev, channel->queue_index); + netdev_tx_reset_queue(txq); + } + } + + switch (pdata->expansion.current_state) { + case CURRENT_STATE_SUSPEND: + hw_ops->led_under_sleep(pdata); + break; + case CURRENT_STATE_SHUTDOWN: + case CURRENT_STATE_RESTART: + hw_ops->led_under_shutdown(pdata); + break; + case CURRENT_STATE_CLOSE: + //hw_ops->led_under_disable(pdata); + break; + default: + break; + } +} + +void fxgmac_restart_dev(struct fxgmac_pdata *pdata) +{ + int ret; + + /* If not running, "restart" will happen on open */ + if (!netif_running(pdata->netdev)) + return; + + pdata->expansion.current_state = CURRENT_STATE_RESTART; + fxgmac_stop(pdata); + + fxgmac_free_tx_data(pdata); + fxgmac_free_rx_data(pdata); + + ret = fxgmac_start(pdata); + if (ret) { + printk("fxgmac_restart_dev: fxgmac_start failed.\n"); + } +} + +static void fxgmac_restart(struct work_struct *work) +{ + struct fxgmac_pdata *pdata = container_of(work, + struct fxgmac_pdata, + expansion.restart_work); + + rtnl_lock(); + + fxgmac_restart_dev(pdata); + + rtnl_unlock(); +} + +void fxgmac_net_powerup(struct fxgmac_pdata *pdata) +{ + int ret; + struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops; + + if(netif_msg_drv(pdata)) DPRINTK("fxgmac_net_powerup callin\n"); + + /* signal that we are up now */ + pdata->expansion.powerstate = 0; //clear all bits as normal now + if (__test_and_set_bit(FXGMAC_POWER_STATE_UP, &pdata->expansion.powerstate)) { + return; /* do nothing if already up */ + } + + ret = fxgmac_start(pdata); + if (ret) { + printk("fxgmac_net_powerup: fxgmac_start error\n"); + return; + } + + // must call it after fxgmac_start,because it will be enable in fxgmac_start + hw_ops->disable_arp_offload(pdata); + + if(netif_msg_drv(pdata)) { + DPRINTK("fxgmac_net_powerup callout, powerstate=%ld.\n", pdata->expansion.powerstate); + } +} + +void fxgmac_net_powerdown(struct fxgmac_pdata *pdata, unsigned int wol) +{ + struct net_device *netdev = pdata->netdev; + struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops; + + if(netif_msg_drv(pdata)) DPRINTK("fxgmac_net_powerdown callin here.\n"); + + /* signal that we are down to the interrupt handler */ + if (__test_and_set_bit(FXGMAC_POWER_STATE_DOWN, &pdata->expansion.powerstate)) + return; /* do nothing if already down */ + + if(netif_msg_drv(pdata)) DPRINTK("fxgmac_net_powerdown continue with down process.\n"); + /* phy polling timer should detect the state of fxgmac and stop link status polling accordingly */ + + __clear_bit(FXGMAC_POWER_STATE_UP, &pdata->expansion.powerstate); + +#if 1 + /* Shut off incoming Tx traffic */ + netif_tx_stop_all_queues(netdev); + + /* call carrier off first to avoid false dev_watchdog timeouts */ + netif_carrier_off(netdev); + netif_tx_disable(netdev); + + /* Disable Rx */ + hw_ops->disable_rx(pdata); + + /* synchronize_rcu() needed for pending XDP buffers to drain */ + //if (adapter->xdp_ring[0]) 20210709 + synchronize_rcu(); + + fxgmac_stop(pdata); //some works are redundent in this call +#endif + // must call it after software reset + hw_ops->pre_power_down(pdata, false); + + /* set mac to lowpower mode and enable wol accordingly */ + hw_ops->config_power_down(pdata, wol); + +#if 1 + //handle vfs if it is envolved + + //similar work as in restart() for that, we do need a resume laterly + fxgmac_free_tx_data(pdata); + fxgmac_free_rx_data(pdata); +#endif + if(netif_msg_drv(pdata)) DPRINTK("fxgmac_net_powerdown callout, powerstate=%ld.\n", pdata->expansion.powerstate); +} + +static int fxgmac_open(struct net_device *netdev) +{ + struct fxgmac_pdata *pdata = netdev_priv(netdev); + struct fxgmac_desc_ops *desc_ops; + int ret; + + if(netif_msg_drv(pdata)) DPRINTK("fxgmac_open callin\n"); + + desc_ops = &pdata->desc_ops; + + /* TODO: Initialize the phy */ + + /* Calculate the Rx buffer size before allocating rings */ + //DPRINTK("fxgmac_open, b4 calc rx buf size, mtu,min,max=%d,%d,%d.\n", netdev->mtu, netdev->min_mtu, netdev->max_mtu); + ret = fxgmac_calc_rx_buf_size(netdev, netdev->mtu); + if (ret < 0) + return ret; + pdata->rx_buf_size = ret; + + /* Allocate the channels and rings */ + ret = desc_ops->alloc_channles_and_rings(pdata); + if (ret) + return ret; + + INIT_WORK(&pdata->expansion.restart_work, fxgmac_restart); +#if 0 + fxgmac_init_timers(pdata); +#endif + ret = fxgmac_start(pdata); + if (ret) + goto err_channels_and_rings; + + if(netif_msg_drv(pdata)) DPRINTK("fxgmac_open callout\n"); + + return 0; + +err_channels_and_rings: + desc_ops->free_channels_and_rings(pdata); + DPRINTK("fxgmac_open callout with channel alloc err\n"); + return ret; +} + +static int fxgmac_close(struct net_device *netdev) +{ + struct fxgmac_pdata *pdata = netdev_priv(netdev); + struct fxgmac_desc_ops *desc_ops; + + if(netif_msg_drv(pdata)) DPRINTK("fxgmac_close callin\n"); + + desc_ops = &pdata->desc_ops; + + pdata->expansion.current_state = (pdata->expansion.current_state == CURRENT_STATE_SHUTDOWN) ? + pdata->expansion.current_state : CURRENT_STATE_CLOSE; + + /* Stop the device */ + fxgmac_stop(pdata); + + /* Free the channels and rings */ + desc_ops->free_channels_and_rings(pdata); + + pdata->hw_ops.reset_phy(pdata); + + if(netif_msg_drv(pdata)) DPRINTK("fxgmac_close callout\n"); + + return 0; +} + +#if ((LINUX_VERSION_CODE > KERNEL_VERSION(4,0,0)) && (LINUX_VERSION_CODE < KERNEL_VERSION(5,6,0))) +static void fxgmac_tx_timeout(struct net_device *netdev) +#else +static void fxgmac_tx_timeout(struct net_device *netdev, unsigned int unused) +#endif +{ + struct fxgmac_pdata *pdata = netdev_priv(netdev); + + netdev_warn(netdev, "tx timeout, device restarting\n"); +#if FXGMAC_TX_HANG_TIMER_EN + if(!pdata->tx_hang_restart_queuing) + schedule_work(&pdata->expansion.restart_work); +#else + schedule_work(&pdata->expansion.restart_work); +#endif +} + +static int fxgmac_xmit(struct sk_buff *skb, struct net_device *netdev) +{ + struct fxgmac_pdata *pdata = netdev_priv(netdev); + struct fxgmac_pkt_info *tx_pkt_info; + struct fxgmac_desc_ops *desc_ops; + struct fxgmac_channel *channel; + struct fxgmac_hw_ops *hw_ops; + struct netdev_queue *txq; + struct fxgmac_ring *ring; + int ret; + + desc_ops = &pdata->desc_ops; + hw_ops = &pdata->hw_ops; + + //yzhang disabled + if(netif_msg_tx_done(pdata)) DPRINTK("xmit callin, skb->len=%d,q=%d\n", skb->len, skb->queue_mapping); + + channel = pdata->channel_head + skb->queue_mapping; + txq = netdev_get_tx_queue(netdev, channel->queue_index); + ring = channel->tx_ring; + tx_pkt_info = &ring->pkt_info; +#if 0 + if (1/*yzhang dbg skb->len == 0*/) { + netif_err(pdata, tx_err, netdev, + "empty skb received from stack\n"); + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } +#else + if (skb->len == 0) { + netif_err(pdata, tx_err, netdev, + "empty skb received from stack\n"); + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } +#endif + /* Prepare preliminary packet info for TX */ + memset(tx_pkt_info, 0, sizeof(*tx_pkt_info)); + fxgmac_prep_tx_pkt(pdata, ring, skb, tx_pkt_info); + + /* Check that there are enough descriptors available */ + ret = fxgmac_maybe_stop_tx_queue(channel, ring, + tx_pkt_info->desc_count); + if (ret) + { + return ret; + } + + ret = fxgmac_prep_tso(pdata, skb, tx_pkt_info); + if (ret) { + netif_err(pdata, tx_err, netdev, + "error processing TSO packet\n"); + DPRINTK("dev_xmit,tx err for TSO\n"); + dev_kfree_skb_any(skb); + return ret; + } + fxgmac_prep_vlan(skb, tx_pkt_info); + + if (!desc_ops->map_tx_skb(channel, skb)) { + dev_kfree_skb_any(skb); + DPRINTK("xmit, map tx skb err\n"); + return NETDEV_TX_OK; + } + + /* Report on the actual number of bytes (to be) sent */ + netdev_tx_sent_queue(txq, tx_pkt_info->tx_bytes); + if(netif_msg_tx_done(pdata)) DPRINTK("xmit,before hw_xmit, byte len=%d\n", tx_pkt_info->tx_bytes); + + /* Configure required descriptor fields for transmission */ + hw_ops->dev_xmit(channel); +#if FXGMAC_DUMMY_TX_DEBUG + DPRINTK("tx hw_ops->dev_xmit ok\n"); +#endif + if (netif_msg_pktdata(pdata)) + fxgmac_dbg_pkt(netdev, skb, true); + + /* Stop the queue in advance if there may not be enough descriptors */ + fxgmac_maybe_stop_tx_queue(channel, ring, FXGMAC_TX_MAX_DESC_NR); + + return NETDEV_TX_OK; +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,12,0)) +static void fxgmac_get_stats64(struct net_device *netdev, + struct rtnl_link_stats64 *s) +#else +static struct rtnl_link_stats64 * fxgmac_get_stats64(struct net_device *netdev, + struct rtnl_link_stats64 *s) +#endif +{ + struct fxgmac_pdata *pdata = netdev_priv(netdev); + struct fxgmac_stats *pstats = &pdata->stats; + +#if FXGMAC_PM_FEATURE_ENABLED + /* 20210709 for net power down */ + if(!test_bit(FXGMAC_POWER_STATE_DOWN, &pdata->expansion.powerstate)) +#endif + { + //DPRINTK("get_stats64, ndo op, callin\n"); + pdata->hw_ops.read_mmc_stats(pdata); + } + s->rx_packets = pstats->rxframecount_gb; + s->rx_bytes = pstats->rxoctetcount_gb; + s->rx_errors = pstats->rxframecount_gb - + pstats->rxbroadcastframes_g - + pstats->rxmulticastframes_g - + pstats->rxunicastframes_g; + s->multicast = pstats->rxmulticastframes_g; + s->rx_length_errors = pstats->rxlengtherror; + s->rx_crc_errors = pstats->rxcrcerror; + s->rx_fifo_errors = pstats->rxfifooverflow; + + s->tx_packets = pstats->txframecount_gb; + s->tx_bytes = pstats->txoctetcount_gb; + s->tx_errors = pstats->txframecount_gb - pstats->txframecount_g; + s->tx_dropped = netdev->stats.tx_dropped; + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,12,0)) + return s; +#endif +} + +static int fxgmac_set_mac_address(struct net_device *netdev, void *addr) +{ + struct fxgmac_pdata *pdata = netdev_priv(netdev); + struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops; + struct sockaddr *saddr = addr; + + if (!is_valid_ether_addr(saddr->sa_data)) + return -EADDRNOTAVAIL; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,17,0)) + eth_hw_addr_set(netdev, saddr->sa_data); +#else + memcpy(netdev->dev_addr, saddr->sa_data, netdev->addr_len); +#endif + memcpy(pdata->mac_addr, saddr->sa_data, netdev->addr_len); + + hw_ops->set_mac_address(pdata, saddr->sa_data); + hw_ops->set_mac_hash(pdata); + + DPRINTK("fxgmac,set mac addr to %02x:%02x:%02x:%02x:%02x:%02x\n",netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2], + netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5]); + return 0; +} + +// cmd = [0x89F0, 0x89FF] +static int fxgmac_ioctl(struct net_device *netdev, + struct ifreq *ifr, int cmd) +{ + struct file f; + int ret = FXGMAC_SUCCESS; + struct fxgmac_pdata *pdata = netdev_priv(netdev); + + if (!netif_running(netdev)) + return -ENODEV; + + f.private_data = pdata; + + switch (cmd) { + case FXGMAC_DEV_CMD: + ret = fxgmac_dbg_netdev_ops_ioctl(&f, FXGMAC_IOCTL_DFS_COMMAND, (unsigned long)(ifr->ifr_data)); + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +#if ( LINUX_VERSION_CODE >= KERNEL_VERSION(5,15,0) ) +static int fxgmac_siocdevprivate(struct net_device *dev, + struct ifreq *ifr, + void __user *data, + int cmd) +{ + return fxgmac_ioctl(dev, ifr, cmd); +} +#endif + +static int fxgmac_change_mtu(struct net_device *netdev, int mtu) +{ + struct fxgmac_pdata *pdata = netdev_priv(netdev); + int ret; +#ifdef FXGMAC_DEBUG + int old_mtu = netdev->mtu; +#endif + + fxgmac_stop(pdata); + fxgmac_free_tx_data(pdata); + + // We must unmap rx desc's dma before we change rx_buf_size. + // Becaues the size of the unmapped DMA is set according to rx_buf_size + fxgmac_free_rx_data(pdata); + + pdata->jumbo = mtu > ETH_DATA_LEN ? 1 : 0; + + ret = fxgmac_calc_rx_buf_size(netdev, mtu); + if (ret < 0) + return ret; + + pdata->rx_buf_size = ret; + netdev->mtu = mtu; + + if (netif_running(netdev)) + fxgmac_start(pdata); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0)) + DPRINTK("fxgmac,set MTU from %d to %d. min, max=(%d,%d)\n",old_mtu, netdev->mtu, netdev->min_mtu, netdev->max_mtu); +#else + DPRINTK("fxgmac,set MTU from %d to %d.\n",old_mtu, netdev->mtu); +#endif + + return 0; +} + +static int fxgmac_vlan_rx_add_vid(struct net_device *netdev, + __be16 proto, + u16 vid) +{ + struct fxgmac_pdata *pdata = netdev_priv(netdev); + struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops; + + set_bit(vid, pdata->active_vlans); +#if FXGMAC_FILTER_SINGLE_VLAN_ENABLED + pdata->vlan = vid; + hw_ops->enable_rx_vlan_filtering(pdata); +#else + hw_ops->update_vlan_hash_table(pdata); +#endif + DPRINTK("fxgmac,add rx vlan %d\n", vid); + return 0; +} + +static int fxgmac_vlan_rx_kill_vid(struct net_device *netdev, + __be16 proto, + u16 vid) +{ + struct fxgmac_pdata *pdata = netdev_priv(netdev); + struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops; + + clear_bit(vid, pdata->active_vlans); +#if FXGMAC_FILTER_SINGLE_VLAN_ENABLED + pdata->vlan = 0; + hw_ops->disable_rx_vlan_filtering(pdata); +#else + hw_ops->update_vlan_hash_table(pdata); +#endif + + DPRINTK("fxgmac,del rx vlan %d\n", vid); + return 0; +} + +#ifdef CONFIG_NET_POLL_CONTROLLER +static void fxgmac_poll_controller(struct net_device *netdev) +{ + struct fxgmac_pdata *pdata = netdev_priv(netdev); + struct fxgmac_channel *channel; + unsigned int i; + + if (pdata->per_channel_irq) { + channel = pdata->channel_head; + for (i = 0; i < pdata->channel_count; i++, channel++) + fxgmac_dma_isr(channel->dma_irq, channel); + } else { + disable_irq(pdata->dev_irq); + fxgmac_isr(pdata->dev_irq, pdata); + enable_irq(pdata->dev_irq); + } +} +#endif /* CONFIG_NET_POLL_CONTROLLER */ + +static int fxgmac_set_features(struct net_device *netdev, + netdev_features_t features) +{ + netdev_features_t rxhash, rxcsum, rxvlan, rxvlan_filter, tso; + struct fxgmac_pdata *pdata = netdev_priv(netdev); + struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops; + int ret = 0; + + rxhash = pdata->expansion.netdev_features & NETIF_F_RXHASH; + rxcsum = pdata->expansion.netdev_features & NETIF_F_RXCSUM; + rxvlan = pdata->expansion.netdev_features & NETIF_F_HW_VLAN_CTAG_RX; + rxvlan_filter = pdata->expansion.netdev_features & NETIF_F_HW_VLAN_CTAG_FILTER; + tso = pdata->expansion.netdev_features & (NETIF_F_TSO | NETIF_F_TSO6); + + if ((features & (NETIF_F_TSO | NETIF_F_TSO6)) && !tso) { + printk("enable tso.\n"); + pdata->hw_feat.tso = 1; + hw_ops->config_tso(pdata); + } else if (!(features & (NETIF_F_TSO | NETIF_F_TSO6)) && tso) { + printk("disable tso.\n"); + pdata->hw_feat.tso = 0; + hw_ops->config_tso(pdata); + } + + if ((features & NETIF_F_RXHASH) && !rxhash) + ret = hw_ops->enable_rss(pdata); + else if (!(features & NETIF_F_RXHASH) && rxhash) + ret = hw_ops->disable_rss(pdata); + if (ret) + return ret; + + if ((features & NETIF_F_RXCSUM) && !rxcsum) + hw_ops->enable_rx_csum(pdata); + else if (!(features & NETIF_F_RXCSUM) && rxcsum) + hw_ops->disable_rx_csum(pdata); + + if ((features & NETIF_F_HW_VLAN_CTAG_RX) && !rxvlan) + hw_ops->enable_rx_vlan_stripping(pdata); + else if (!(features & NETIF_F_HW_VLAN_CTAG_RX) && rxvlan) + hw_ops->disable_rx_vlan_stripping(pdata); + + if ((features & NETIF_F_HW_VLAN_CTAG_FILTER) && !rxvlan_filter) + hw_ops->enable_rx_vlan_filtering(pdata); + else if (!(features & NETIF_F_HW_VLAN_CTAG_FILTER) && rxvlan_filter) + hw_ops->disable_rx_vlan_filtering(pdata); + + pdata->expansion.netdev_features = features; + + DPRINTK("fxgmac,set features done,%llx\n", (u64)features); + return 0; +} + +static void fxgmac_set_rx_mode(struct net_device *netdev) +{ + struct fxgmac_pdata *pdata = netdev_priv(netdev); + struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops; + + hw_ops->config_rx_mode(pdata); +} + +static const struct net_device_ops fxgmac_netdev_ops = { + .ndo_open = fxgmac_open, + .ndo_stop = fxgmac_close, + .ndo_start_xmit = fxgmac_xmit, + .ndo_tx_timeout = fxgmac_tx_timeout, + .ndo_get_stats64 = fxgmac_get_stats64, + .ndo_change_mtu = fxgmac_change_mtu, + .ndo_set_mac_address = fxgmac_set_mac_address, + .ndo_validate_addr = eth_validate_addr, + .ndo_do_ioctl = fxgmac_ioctl, +#if ( LINUX_VERSION_CODE >= KERNEL_VERSION(5,15,0) ) + .ndo_siocdevprivate = fxgmac_siocdevprivate, +#endif + .ndo_vlan_rx_add_vid = fxgmac_vlan_rx_add_vid, + .ndo_vlan_rx_kill_vid = fxgmac_vlan_rx_kill_vid, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = fxgmac_poll_controller, +#endif + .ndo_set_features = fxgmac_set_features, + .ndo_set_rx_mode = fxgmac_set_rx_mode, +}; + +const struct net_device_ops *fxgmac_get_netdev_ops(void) +{ + return &fxgmac_netdev_ops; +} + +static void fxgmac_rx_refresh(struct fxgmac_channel *channel) +{ + struct fxgmac_pdata *pdata = channel->pdata; + struct fxgmac_ring *ring = channel->rx_ring; + struct fxgmac_desc_data *desc_data; +#if 0 + struct fxgmac_desc_ops *desc_ops = &pdata->desc_ops; +#endif + struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops; + + while (ring->dirty != ring->cur) { + desc_data = FXGMAC_GET_DESC_DATA(ring, ring->dirty); +#if 0 + /* Reset desc_data values */ + desc_ops->unmap_desc_data(pdata, desc_data); + + if (desc_ops->map_rx_buffer(pdata, ring, desc_data)) + break; +#endif + hw_ops->rx_desc_reset(pdata, desc_data, ring->dirty); + ring->dirty = FXGMAC_GET_ENTRY(ring->dirty, ring->dma_desc_count); + } + + /* Make sure everything is written before the register write */ + wmb(); + + /* Update the Rx Tail Pointer Register with address of + * the last cleaned entry + */ + desc_data = FXGMAC_GET_DESC_DATA(ring, (ring->dirty - 1) & (ring->dma_desc_count - 1)); + writel(lower_32_bits(desc_data->dma_desc_addr), FXGMAC_DMA_REG(channel, DMA_CH_RDTR_LO)); +} + +static struct sk_buff *fxgmac_create_skb(struct fxgmac_pdata *pdata, + struct napi_struct *napi, + struct fxgmac_desc_data *desc_data, + unsigned int len) +{ +#if 0 + unsigned int copy_len; + struct sk_buff *skb; + u8 *packet; + + skb = napi_alloc_skb(napi, desc_data->rx.hdr.dma_len); + if (!skb) + return NULL; + + /* Start with the header buffer which may contain just the header + * or the header plus data + */ + dma_sync_single_range_for_cpu(pdata->dev, desc_data->rx.hdr.dma_base, + desc_data->rx.hdr.dma_off, + desc_data->rx.hdr.dma_len, + DMA_FROM_DEVICE); + + packet = page_address(desc_data->rx.hdr.pa.pages) + + desc_data->rx.hdr.pa.pages_offset; + copy_len = (desc_data->rx.hdr_len) ? desc_data->rx.hdr_len : len; + copy_len = min(desc_data->rx.hdr.dma_len, copy_len); + skb_copy_to_linear_data(skb, packet, copy_len); + skb_put(skb, copy_len); + + len -= copy_len; + if (len) { + /* Add the remaining data as a frag */ + dma_sync_single_range_for_cpu(pdata->dev, + desc_data->rx.buf.dma_base, + desc_data->rx.buf.dma_off, + desc_data->rx.buf.dma_len, + DMA_FROM_DEVICE); + + skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, + desc_data->rx.buf.pa.pages, + desc_data->rx.buf.pa.pages_offset, + len, desc_data->rx.buf.dma_len); + desc_data->rx.buf.pa.pages = NULL; + } + + return skb; +#endif + struct sk_buff *skb; + skb = __netdev_alloc_skb_ip_align(pdata->netdev, len, GFP_ATOMIC); + if (!skb) { + netdev_err(pdata->netdev, "%s: Rx init fails; skb is NULL\n", __func__); + return NULL; + } + + dma_sync_single_for_cpu(pdata->dev, desc_data->rx.buf.dma_base, len, DMA_FROM_DEVICE); + skb_copy_to_linear_data(skb, desc_data->skb->data, len); + skb_put(skb, len); + dma_sync_single_for_device(pdata->dev, desc_data->rx.buf.dma_base, len, DMA_FROM_DEVICE); + + return skb; +} + +static int fxgmac_tx_poll(struct fxgmac_channel *channel) +{ + struct fxgmac_pdata *pdata = channel->pdata; + struct fxgmac_ring *ring = channel->tx_ring; + struct net_device *netdev = pdata->netdev; + unsigned int tx_packets = 0, tx_bytes = 0; + struct fxgmac_desc_data *desc_data; + struct fxgmac_dma_desc *dma_desc; + struct fxgmac_desc_ops *desc_ops; + struct fxgmac_hw_ops *hw_ops; + struct netdev_queue *txq; + int processed = 0; + unsigned int cur; + + static int fxgmac_restart_need = 0; + static u32 change_cnt = 0; + static u32 reg_cur_pre = 0xffffffff; + +#if FXGMAC_TX_HANG_TIMER_EN + static u32 reg_cur = 0; +#endif + + desc_ops = &pdata->desc_ops; + hw_ops = &pdata->hw_ops; + + /* Nothing to do if there isn't a Tx ring for this channel */ + if (!ring){ + if(netif_msg_tx_done(pdata) && (channel->queue_index < pdata->tx_q_count)) DPRINTK("tx_poll, null point to ring %d\n", channel->queue_index); + return 0; + } + if((ring->cur != ring->dirty) && (netif_msg_tx_done(pdata))) + DPRINTK("tx_poll callin, ring_cur=%d,ring_dirty=%d,qIdx=%d\n", ring->cur, ring->dirty, channel->queue_index); + + cur = ring->cur; + + /* Be sure we get ring->cur before accessing descriptor data */ + smp_rmb(); + + txq = netdev_get_tx_queue(netdev, channel->queue_index); + + while (ring->dirty != cur) { + desc_data = FXGMAC_GET_DESC_DATA(ring, ring->dirty); + dma_desc = desc_data->dma_desc; + + if (!hw_ops->tx_complete(dma_desc)) { +#if FXGMAC_TRIGGER_TX_HANG + struct net_device *netdev = pdata->netdev; + #define FXGMAC_HANG_THRESHOLD 1 + //static u32 reg_tail = 0, reg_tail_pre = 0xffffffff; + + reg_cur = readl(FXGMAC_DMA_REG(channel, 0x44/* tx desc curr pointer reg */)); + + if(reg_cur != reg_cur_pre){ + reg_cur_pre = reg_cur; + change_cnt = 0; + } else { + change_cnt++; + } + + if (change_cnt > 2) + { + //change_cnt = 0; + + DPRINTK("after complete check, cur=%d, dirty=%d,qIdx=%d, hw desc cur=%#x, pre=%#x\n", ring->cur, ring->dirty, channel->queue_index, + reg_cur, reg_cur_pre); + + if((ring->cur > ring->dirty) && ((ring->cur - ring->dirty) > FXGMAC_HANG_THRESHOLD) ) { + DPRINTK("after complete check warning..., too many TBD occupied by HW, 0xdbbb, %d.\n", (ring->cur - ring->dirty)); + (* ((u32 *)(netdev->base_addr + 0x1000))) = 0xdbbb; + + if(!fxgmac_restart_need ) { + schedule_work(&pdata->expansion.restart_work); + fxgmac_restart_need = 1; + change_cnt = 0; + } + }else if((ring->cur < ring->dirty) && ((ring->cur + (ring->dma_desc_count - ring->dirty)) > FXGMAC_HANG_THRESHOLD) ) { + DPRINTK("after complete check warning..., too many TBD occupied by HW, 0xdb00, %d.\n", (ring->cur + (ring->dma_desc_count - ring->dirty))); + (* ((u32 *)(netdev->base_addr + 0x1000))) = 0xdb00; + + if(!fxgmac_restart_need ) { + schedule_work(&pdata->expansion.restart_work); + fxgmac_restart_need = 1; + change_cnt = 0; + } + } + } +#endif +#if FXGMAC_TX_HANG_TIMER_EN + if((!pdata->tx_hang_restart_queuing) && (!channel->expansion.tx_hang_timer_active)) { + reg_cur = ring->dirty; + if(reg_cur_pre != reg_cur) { + reg_cur_pre = reg_cur; + change_cnt = 0; + }else { + change_cnt++; + } + + if (change_cnt > 4) + { +#if FXGMAC_TX_HANG_CHECH_DIRTY + channel->expansion.tx_hang_hw_cur = ring->dirty; +#else + channel->expansion.tx_hang_hw_cur = readl(FXGMAC_DMA_REG(channel, 0x44/* tx desc curr pointer reg */)); +#endif + /* double check for race conditione */ + if ((!pdata->tx_hang_restart_queuing) && (!channel->expansion.tx_hang_timer_active)) { + DPRINTK("tx_hang polling: start timer at desc %u, timer act=%u, queuing=%u, qidx=%u.\n", reg_cur, channel->expansion.tx_hang_timer_active, pdata->tx_hang_restart_queuing, channel->queue_index); + fxgmac_tx_hang_timer_start(channel); + } + } + }else if (pdata->tx_hang_restart_queuing) { + //if(netif_msg_drv(pdata)) DPRINTK("tx_hang_timer_handler: restart scheduled.\n"); + } +#endif + + break; + } + + reg_cur_pre = 0xffffffff; + fxgmac_restart_need = 0; + change_cnt = 0; + + /* Make sure descriptor fields are read after reading + * the OWN bit + */ + dma_rmb(); + + if (netif_msg_tx_done(pdata)) + fxgmac_dump_tx_desc(pdata, ring, ring->dirty, 1, 0); + + if (hw_ops->is_last_desc(dma_desc)) { + tx_packets += desc_data->tx.packets; + tx_bytes += desc_data->tx.bytes; + } + + /* Free the SKB and reset the descriptor for re-use */ + desc_ops->unmap_desc_data(pdata, desc_data); + hw_ops->tx_desc_reset(desc_data); + + processed++; + //ring->dirty++; + ring->dirty = FXGMAC_GET_ENTRY(ring->dirty, ring->dma_desc_count); + } + + if (!processed) + return 0; + + netdev_tx_completed_queue(txq, tx_packets, tx_bytes); + + if ((ring->tx.queue_stopped == 1) && + (fxgmac_tx_avail_desc(ring) > FXGMAC_TX_DESC_MIN_FREE)) { + ring->tx.queue_stopped = 0; + netif_tx_wake_queue(txq); + } + + //yzhang comment out to reduce print + if(netif_msg_tx_done(pdata)){ + DPRINTK("tx_poll callout, processed=%d\n", processed); + } + + return processed; +} +extern void fxgmac_print_pkt(struct net_device *netdev, + struct sk_buff *skb, bool tx_rx); + +static int fxgmac_rx_poll(struct fxgmac_channel *channel, int budget) +{ + struct fxgmac_pdata *pdata = channel->pdata; + struct fxgmac_ring *ring = channel->rx_ring; + struct net_device *netdev = pdata->netdev; + unsigned int len; + unsigned int context_next, context; + struct fxgmac_desc_data *desc_data; + struct fxgmac_pkt_info *pkt_info; + unsigned int incomplete; + struct fxgmac_hw_ops *hw_ops; + struct napi_struct *napi; + struct sk_buff *skb; + int packet_count = 0; + u32 ipce,iphe; + + hw_ops = &pdata->hw_ops; + + /* Nothing to do if there isn't a Rx ring for this channel */ + if (!ring) + return 0; + + incomplete = 0; + context_next = 0; + + napi = (pdata->per_channel_irq) ? &channel->expansion.napi_rx : &pdata->expansion.napi; + + desc_data = FXGMAC_GET_DESC_DATA(ring, ring->cur); + pkt_info = &ring->pkt_info; + + while (packet_count < budget) { + memset(pkt_info, 0, sizeof(*pkt_info)); + skb = NULL; + len = 0; + + read_again: + desc_data = FXGMAC_GET_DESC_DATA(ring, ring->cur); + + if (fxgmac_rx_dirty_desc(ring) > FXGMAC_RX_DESC_MAX_DIRTY) + fxgmac_rx_refresh(channel); + + if (hw_ops->dev_read(channel)) + break; + + ring->cur = FXGMAC_GET_ENTRY(ring->cur, ring->dma_desc_count); + + incomplete = FXGMAC_GET_REG_BITS( + pkt_info->attributes, + RX_PACKET_ATTRIBUTES_INCOMPLETE_POS, + RX_PACKET_ATTRIBUTES_INCOMPLETE_LEN); + context_next = FXGMAC_GET_REG_BITS( + pkt_info->attributes, + RX_PACKET_ATTRIBUTES_CONTEXT_NEXT_POS, + RX_PACKET_ATTRIBUTES_CONTEXT_NEXT_LEN); + context = FXGMAC_GET_REG_BITS( + pkt_info->attributes, + RX_PACKET_ATTRIBUTES_CONTEXT_POS, + RX_PACKET_ATTRIBUTES_CONTEXT_LEN); + + if (incomplete || context_next) + goto read_again; + + if (pkt_info->errors) { + netif_err(pdata, rx_err, netdev, "error in received packet\n"); + dev_kfree_skb(skb); + goto next_packet; + } + + if (!context) { + len = desc_data->rx.len; + if (len > pdata->rx_buf_size) { + if (net_ratelimit()) + netdev_err(pdata->netdev,"len %d larger than size (%d)\n", len, pdata->rx_buf_size); + pdata->netdev->stats.rx_dropped++; + goto next_packet; + } + + if (len == 0) { + if (net_ratelimit()) + netdev_err(pdata->netdev,"A packet of length 0 was received\n"); + pdata->netdev->stats.rx_length_errors++; + goto next_packet; + } + + if (len && !skb) { + skb = fxgmac_create_skb(pdata, napi, desc_data, len); + if (unlikely(!skb)) { + if (net_ratelimit()) + netdev_warn(pdata->netdev, "create skb failed\n"); + goto next_packet; + } + } + } + + if (!skb) + goto next_packet; + + if(netif_msg_pktdata(pdata)) + fxgmac_print_pkt(netdev, skb, false); + + skb_checksum_none_assert(skb); + if (netdev->features & NETIF_F_RXCSUM) + { + ipce = FXGMAC_GET_REG_BITS_LE(desc_data->dma_desc->desc1, + RX_NORMAL_DESC1_WB_IPCE_POS, + RX_NORMAL_DESC1_WB_IPCE_LEN); + iphe = FXGMAC_GET_REG_BITS_LE(desc_data->dma_desc->desc1, + RX_NORMAL_DESC1_WB_IPHE_POS, + RX_NORMAL_DESC1_WB_IPHE_LEN); + /* if csum error,let the stack verify checksum errors.otherwise don't verify */ + if (!ipce && !iphe && FXGMAC_GET_REG_BITS(pkt_info->attributes, + RX_PACKET_ATTRIBUTES_CSUM_DONE_POS, + RX_PACKET_ATTRIBUTES_CSUM_DONE_LEN)) + skb->ip_summed = CHECKSUM_UNNECESSARY; + } + + if (FXGMAC_GET_REG_BITS(pkt_info->attributes, + RX_PACKET_ATTRIBUTES_VLAN_CTAG_POS, + RX_PACKET_ATTRIBUTES_VLAN_CTAG_LEN)) { + __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), + pkt_info->vlan_ctag); + pdata->stats.rx_vlan_packets++; + } + + if (FXGMAC_GET_REG_BITS(pkt_info->attributes, + RX_PACKET_ATTRIBUTES_RSS_HASH_POS, + RX_PACKET_ATTRIBUTES_RSS_HASH_LEN)) + skb_set_hash(skb, pkt_info->rss_hash, + pkt_info->rss_hash_type); + + skb->dev = netdev; + skb->protocol = eth_type_trans(skb, netdev); + skb_record_rx_queue(skb, channel->queue_index); + + if(pdata->expansion.fxgmac_test_tso_flag) + { + /* tso test */ + if(pdata->expansion.fxgmac_test_tso_seg_num == 1) + { + /* last segment */ + if(pdata->expansion.fxgmac_test_last_tso_len == skb->len + FXGMAC_TEST_MAC_HEAD_LEN) + { + /* receive last segment, reset flag */ + pdata->expansion.fxgmac_test_tso_flag = false; + pdata->expansion.fxgmac_test_tso_seg_num = 0; + pdata->expansion.fxgmac_test_packet_len = 0; + pdata->expansion.fxgmac_test_last_tso_len = 0; + + /* process packet */ + if((pdata->expansion.fxgmac_test_skb_arr_in_index + 1) % FXGMAC_MAX_DBG_TEST_PKT != pdata->expansion.fxgmac_test_skb_arr_out_index){ + struct sk_buff *tmpskb = skb_copy(skb, GFP_ATOMIC); + skb_push(tmpskb, FXGMAC_TEST_MAC_HEAD_LEN); + + pdata->expansion.fxgmac_test_skb_array[pdata->expansion.fxgmac_test_skb_arr_in_index] = tmpskb; + pdata->expansion.fxgmac_test_skb_arr_in_index = (pdata->expansion.fxgmac_test_skb_arr_in_index + 1) % FXGMAC_MAX_DBG_TEST_PKT; + } + else{ + DPRINTK("loopback test buffer is full."); + } + } + } + else /* non last segment */ + { + if(pdata->expansion.fxgmac_test_packet_len == skb->len + FXGMAC_TEST_MAC_HEAD_LEN){ + /* receive a segment */ + pdata->expansion.fxgmac_test_tso_seg_num--; + + /* process packet */ + if((pdata->expansion.fxgmac_test_skb_arr_in_index + 1) % FXGMAC_MAX_DBG_TEST_PKT != pdata->expansion.fxgmac_test_skb_arr_out_index){ + struct sk_buff *tmpskb = skb_copy(skb, GFP_ATOMIC); + skb_push(tmpskb, FXGMAC_TEST_MAC_HEAD_LEN); + + pdata->expansion.fxgmac_test_skb_array[pdata->expansion.fxgmac_test_skb_arr_in_index] = tmpskb; + pdata->expansion.fxgmac_test_skb_arr_in_index = (pdata->expansion.fxgmac_test_skb_arr_in_index + 1) % FXGMAC_MAX_DBG_TEST_PKT; + } + else{ + DPRINTK("loopback test buffer is full."); + } + } + } + } + else if(pdata->expansion.fxgmac_test_packet_len != 0) + { + /* xsum and phy loopback test */ + if(pdata->expansion.fxgmac_test_packet_len == skb->len + FXGMAC_TEST_MAC_HEAD_LEN) + { + /* reset fxg_packet_len */ + pdata->expansion.fxgmac_test_packet_len = 0; + + if((pdata->expansion.fxgmac_test_skb_arr_in_index + 1) % FXGMAC_MAX_DBG_TEST_PKT != pdata->expansion.fxgmac_test_skb_arr_out_index){ + struct sk_buff *tmpskb = skb_copy(skb, GFP_ATOMIC); + skb_push(tmpskb, FXGMAC_TEST_MAC_HEAD_LEN); + + pdata->expansion.fxgmac_test_skb_array[pdata->expansion.fxgmac_test_skb_arr_in_index] = tmpskb; + pdata->expansion.fxgmac_test_skb_arr_in_index = (pdata->expansion.fxgmac_test_skb_arr_in_index + 1) % FXGMAC_MAX_DBG_TEST_PKT; + } + else{ + DPRINTK("loopback test buffer is full."); + } + } + } +#if 1 + napi_gro_receive(napi, skb); +#else + netif_receive_skb(skb); +#endif + +next_packet: + packet_count++; + + pdata->netdev->stats.rx_packets++; + pdata->netdev->stats.rx_bytes += len; + } + + fxgmac_rx_refresh(channel); + + return packet_count; +} + +static int fxgmac_one_poll_tx(struct napi_struct *napi, int budget) +{ + struct fxgmac_channel *channel = container_of(napi, + struct fxgmac_channel, + expansion.napi_tx); + int ret = 0; + struct fxgmac_pdata *pdata = channel->pdata; + struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops; + + ret = fxgmac_tx_poll(channel); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0)) + if (napi_complete_done(napi, 0)) { + hw_ops->enable_msix_one_interrupt(pdata, MSI_ID_TXQ0); + } +#else + napi_complete(napi); + hw_ops->enable_msix_one_interrupt(pdata, MSI_ID_TXQ0); +#endif + return 0; + +} + +static int fxgmac_one_poll_rx(struct napi_struct *napi, int budget) +{ + struct fxgmac_channel *channel = container_of(napi, + struct fxgmac_channel, + expansion.napi_rx); + int processed = 0; + struct fxgmac_pdata *pdata = channel->pdata; + struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops; + + processed = fxgmac_rx_poll(channel, budget); + if (processed < budget) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0)) + /* if there no interrupt occured when this interrupt running,struct napi's state is NAPIF_STATE_SCHED, + * napi_complete_done return true and we can enable irq,it will not cause unbalanced iqr issure. + * if there more interrupt occured when this interrupt running,struct napi's state is NAPIF_STATE_SCHED | NAPIF_STATE_MISSED + * because napi_schedule_prep will make it. At this time napi_complete_done will return false and + * schedule poll again because of NAPIF_STATE_MISSED,it will cause unbalanced irq issure. + */ + if (napi_complete_done(napi, processed)) { + hw_ops->enable_msix_one_interrupt(pdata, channel->queue_index); + } +#else + napi_complete(napi); + hw_ops->enable_msix_one_interrupt(pdata, channel->queue_index); +#endif + } + + return processed; +} + +static int fxgmac_all_poll(struct napi_struct *napi, int budget) +{ + struct fxgmac_pdata *pdata = container_of(napi, + struct fxgmac_pdata, + expansion.napi); + struct fxgmac_channel *channel; + struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops; + int processed; + unsigned int i; + + //yzhang comment out + if(netif_msg_rx_status(pdata)){ + DPRINTK("rx all_poll callin budget=%d\n", budget); + } + + processed = 0; + do { + channel = pdata->channel_head; + /* Cleanup Tx ring first */ + /*since only 1 tx channel supported in this version, poll ch 0 always. */ + fxgmac_tx_poll(pdata->channel_head + 0); + for (i = 0; i < pdata->channel_count; i++, channel++) { + processed += fxgmac_rx_poll(channel, budget); + } + } while (false); + + // for phy, we needn't to process any packet,so processed will be 0 + if (pdata->expansion.mgm_intctrl_val & MGMT_INT_CTRL0_INT_STATUS_PHY) { + fxgmac_phy_process(pdata); + pdata->expansion.mgm_intctrl_val &= ~MGMT_INT_CTRL0_INT_STATUS_PHY; + } + + /* If we processed everything, we are done */ + if (processed < budget) { + /* Turn off polling */ + if (napi_complete_done(napi, processed)) + hw_ops->enable_mgm_interrupt(pdata); + } + + if((processed) && (netif_msg_rx_status(pdata))) { //yzhang for debug + DPRINTK("rx all_poll callout received = %d\n", processed); + } + + return processed; +} diff --git a/drivers/net/ethernet/motorcomm/fuxi-gmac-pci.c b/drivers/net/ethernet/motorcomm/fuxi-gmac-pci.c new file mode 100644 index 000000000000..7233de3438d7 --- /dev/null +++ b/drivers/net/ethernet/motorcomm/fuxi-gmac-pci.c @@ -0,0 +1,365 @@ +/*++ + +Copyright (c) 2021 Motor-comm Corporation. +Confidential and Proprietary. All rights reserved. + +This is Motor-comm Corporation NIC driver relevant files. Please don't copy, modify, +distribute without commercial permission. + +--*/ + + +#include +#include +#include + +/* for file operation */ +#include + +#include "fuxi-gmac.h" +#include "fuxi-gmac-reg.h" + +#define FXGMAC_DBG 0 +/* for power state debug using, 20210629. */ +#if FXGMAC_DBG +static struct file *dbg_file = NULL; +#define FXGMAC_DBG_BUF_SIZE 128 +static char log_buf[FXGMAC_DBG_BUF_SIZE + 2]; +#endif + +#if FXGMAC_DBG +static char * file_name = "/home/fxgmac/fxgmac_dbg.log"; +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5,13,0)) +#if FXGMAC_DBG +#define fxgmac_dbg_log(logstr, arg...) \ + do { \ + static struct kstat dbg_stat; \ + static loff_t pos = 0; \ + if (!(IS_ERR(dbg_file))) { \ + mm_segment_t previous_fs; /*for address-space switch */ \ + sprintf (&log_buf[0], (logstr), ##arg); \ + previous_fs = get_fs(); \ + set_fs(KERNEL_DS); \ + vfs_stat(file_name, &dbg_stat); \ + pos = (loff_t)dbg_stat.size; \ + kernel_write(dbg_file, (const char*)log_buf, strlen(log_buf) > FXGMAC_DBG_BUF_SIZE ? FXGMAC_DBG_BUF_SIZE : strlen(log_buf), /*&dbg_file->f_pos*/&pos)/**/; \ + /*DPRINTK("kernel write done, file size=%d, s=%s", (int)dbg_stat.size, log_buf)*/; \ + set_fs(previous_fs); \ + /*dbg_file->f_op->flush(dbg_file)*/; \ + } \ + }while(0) +#else +#define fxgmac_dbg_log(logstr, arg...) \ + do { \ + /*nothing*/; \ + }while(0) +#endif + +#else +#if FXGMAC_DBG +/* in kernel 5.14, get_fs/set_fs are removed. */ +#define fxgmac_dbg_log(logstr, arg...) \ + do { \ + static struct kstat dbg_stat; \ + static loff_t pos = 0; \ + fxgmac_dbg_log_init(); \ + if (!(IS_ERR(dbg_file))) { \ + sprintf (&log_buf[0], (logstr), ##arg); \ + vfs_getattr(&(dbg_file->f_path), &dbg_stat, 0, 0); \ + pos = (loff_t)dbg_stat.size; \ + kernel_write(dbg_file, (const char*)log_buf, strlen(log_buf) > FXGMAC_DBG_BUF_SIZE ? FXGMAC_DBG_BUF_SIZE : strlen(log_buf), /*&dbg_file->f_pos*/&pos)/**/; \ + /*DPRINTK("kernel write done, file size=%d, s=%s", (int)dbg_stat.size, log_buf)*/; \ + /*dbg_file->f_op->flush(dbg_file)*/; \ + } \ + fxgmac_dbg_log_uninit();\ + }while(0) + +#else +#define fxgmac_dbg_log(logstr, arg...) \ + do { \ + /*nothing*/; \ + }while(0) +#endif +#endif + +/* declarations */ +static void fxgmac_shutdown(struct pci_dev *pdev); + +/* + * functions definitions + */ +int fxgmac_dbg_log_init( void ) +{ +#if FXGMAC_DBG + dbg_file = filp_open(file_name, O_RDWR | O_CREAT, 0644); + if (IS_ERR(dbg_file)) + { + DPRINTK("File fxgmac_dbg.log open or created failed.\n"); + return PTR_ERR(dbg_file); + } +#endif + + return 0; +} + +int fxgmac_dbg_log_uninit( void ) +{ +#if FXGMAC_DBG + if(IS_ERR(dbg_file)) + { + DPRINTK("Invalid fd for file fxgmac_dbg.log, %p.\n", dbg_file); + dbg_file= NULL; + return PTR_ERR(dbg_file); + } + + filp_close(dbg_file, NULL); + dbg_file= NULL; +#endif + + return 0; +} + +static int fxgmac_probe(struct pci_dev *pcidev, const struct pci_device_id *id) +{ + struct device *dev = &pcidev->dev; + struct fxgmac_resources res; + int i, ret; + + ret = pcim_enable_device(pcidev); + if (ret) { + dev_err(dev, "ERROR: fxgmac_probe failed to enable device\n"); + return ret; + } + + for (i = 0; i <= PCI_STD_RESOURCE_END; i++) { + if (pci_resource_len(pcidev, i) == 0) + continue; + + ret = pcim_iomap_regions(pcidev, BIT(i), FXGMAC_DRV_NAME); + if (ret) + { + DPRINTK(KERN_INFO "fxgmac_probe pcim_iomap_regions failed\n"); + return ret; + } + DPRINTK(KERN_INFO "fxgmac_probe iomap_region i=%#x,ret=%#x\n",(int)i,(int)ret); + break; + } + + pci_set_master(pcidev); + + memset(&res, 0, sizeof(res)); + res.irq = pcidev->irq; + res.addr = pcim_iomap_table(pcidev)[i]; + + //fxgmac_dbg_log_init(); + fxgmac_dbg_log("fxpm,_fxgmac_probe\n"); + + return fxgmac_drv_probe(&pcidev->dev, &res); +} + +static void fxgmac_remove(struct pci_dev *pcidev) +{ + struct net_device *netdev = dev_get_drvdata(&pcidev->dev); + struct fxgmac_pdata * pdata = netdev_priv(netdev); + +#ifdef CONFIG_PCI_MSI + u32 msix = FXGMAC_GET_REG_BITS(pdata->expansion.int_flags, + FXGMAC_FLAG_MSIX_POS, + FXGMAC_FLAG_MSIX_LEN); +#endif + + fxgmac_drv_remove(&pcidev->dev); +#ifdef CONFIG_PCI_MSI + if(msix){ + pci_disable_msix(pcidev); + kfree(pdata->expansion.msix_entries); + pdata->expansion.msix_entries = NULL; + } +#endif + + fxgmac_dbg_log("fxpm,_fxgmac_remove\n"); + +#ifdef HAVE_FXGMAC_DEBUG_FS + fxgmac_dbg_exit(pdata); +#endif /* HAVE_FXGMAC_DEBUG_FS */ + + //fxgmac_dbg_log_uninit(); +} + +/* for Power management, 20210628 */ +static int __fxgmac_shutdown(struct pci_dev *pdev, bool *enable_wake) +{ + struct net_device *netdev = dev_get_drvdata(&pdev->dev); + struct fxgmac_pdata *pdata = netdev_priv(netdev); + u32 wufc = pdata->expansion.wol; +#ifdef CONFIG_PM + int retval = 0; +#endif + + DPRINTK("fxpm,_fxgmac_shutdown, callin\n"); + fxgmac_dbg_log("fxpm,_fxgmac_shutdown, callin.\n"); + + rtnl_lock(); + + /* for linux shutdown, we just treat it as power off wol can be ignored + * for suspend, we do need recovery by wol + */ + fxgmac_net_powerdown(pdata, (unsigned int)!!wufc); + netif_device_detach(netdev); + rtnl_unlock(); + +#ifdef CONFIG_PM + retval = pci_save_state(pdev); + if (retval) { + DPRINTK("fxpm,_fxgmac_shutdown, save pci state failed.\n"); + return retval; + } +#endif + + DPRINTK("fxpm,_fxgmac_shutdown, save pci state done.\n"); + fxgmac_dbg_log("fxpm,_fxgmac_shutdown, save pci state done.\n"); + + pci_wake_from_d3(pdev, !!wufc); + *enable_wake = !!wufc; + + pci_disable_device(pdev); + + DPRINTK("fxpm,_fxgmac_shutdown callout, enable wake=%d.\n", *enable_wake); + fxgmac_dbg_log("fxpm,_fxgmac_shutdown callout, enable wake=%d.\n", *enable_wake); + + return 0; +} + +static void fxgmac_shutdown(struct pci_dev *pdev) +{ + bool wake; + struct net_device *netdev = dev_get_drvdata(&pdev->dev); + struct fxgmac_pdata *pdata = netdev_priv(netdev); + + DPRINTK("fxpm, fxgmac_shutdown callin\n"); + fxgmac_dbg_log("fxpm, fxgmac_shutdown callin\n"); + + pdata->expansion.current_state = CURRENT_STATE_SHUTDOWN; + __fxgmac_shutdown(pdev, &wake); + + if (system_state == SYSTEM_POWER_OFF) { + pci_wake_from_d3(pdev, wake); + pci_set_power_state(pdev, PCI_D3hot); + } + DPRINTK("fxpm, fxgmac_shutdown callout, system power off=%d\n", (system_state == SYSTEM_POWER_OFF)? 1 : 0); + fxgmac_dbg_log("fxpm, fxgmac_shutdown callout, system power off=%d\n", (system_state == SYSTEM_POWER_OFF)? 1 : 0); +} + +#ifdef CONFIG_PM +/* yzhang, 20210628 for PM */ +static int fxgmac_suspend(struct pci_dev *pdev, + pm_message_t __always_unused state) +{ + int retval; + bool wake; + struct net_device *netdev = dev_get_drvdata(&pdev->dev); + struct fxgmac_pdata *pdata = netdev_priv(netdev); + + DPRINTK("fxpm, fxgmac_suspend callin\n"); + fxgmac_dbg_log("fxpm, fxgmac_suspend callin\n"); + + pdata->expansion.current_state = CURRENT_STATE_SUSPEND; + + if (netif_running(netdev)) { + retval = __fxgmac_shutdown(pdev, &wake); + if (retval) + return retval; + } else { + wake = !!(pdata->expansion.wol); + } + + if (wake) { + pci_prepare_to_sleep(pdev); + } else { + pci_wake_from_d3(pdev, false); + pci_set_power_state(pdev, PCI_D3hot); + } + + DPRINTK("fxpm, fxgmac_suspend callout to %s\n", wake ? "sleep" : "D3hot"); + fxgmac_dbg_log("fxpm, fxgmac_suspend callout to %s\n", wake ? "sleep" : "D3hot"); + + return 0; +} + +static int fxgmac_resume(struct pci_dev *pdev) +{ + struct fxgmac_pdata *pdata; + struct net_device *netdev; + u32 err; + + DPRINTK("fxpm, fxgmac_resume callin\n"); + fxgmac_dbg_log("fxpm, fxgmac_resume callin\n"); + + netdev = dev_get_drvdata(&pdev->dev); + pdata = netdev_priv(netdev); + + pdata->expansion.current_state = CURRENT_STATE_RESUME; + + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); + /* + * pci_restore_state clears dev->state_saved so call + * pci_save_state to restore it. + */ + pci_save_state(pdev); + + err = pci_enable_device_mem(pdev); + if (err) { + dev_err(pdata->dev, "fxgmac_resume, failed to enable PCI device from suspend\n"); + return err; + } + smp_mb__before_atomic(); + __clear_bit(FXGMAC_POWER_STATE_DOWN, &pdata->expansion.powerstate); + pci_set_master(pdev); + + pci_wake_from_d3(pdev, false); + + rtnl_lock(); + err = 0;//ixgbe_init_interrupt_scheme(adapter); + if (!err && netif_running(netdev)) + fxgmac_net_powerup(pdata); + + if (!err) + netif_device_attach(netdev); + + rtnl_unlock(); + + DPRINTK("fxpm, fxgmac_resume callout\n"); + fxgmac_dbg_log("fxpm, fxgmac_resume callout\n"); + + return err; +} +#endif + +static const struct pci_device_id fxgmac_pci_tbl[] = { + { PCI_DEVICE(0x1f0a, 0x6801) }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, fxgmac_pci_tbl); + +static struct pci_driver fxgmac_pci_driver = { + .name = FXGMAC_DRV_NAME, + .id_table = fxgmac_pci_tbl, + .probe = fxgmac_probe, + .remove = fxgmac_remove, +#ifdef CONFIG_PM + /* currently, we only use USE_LEGACY_PM_SUPPORT */ + .suspend = fxgmac_suspend, + .resume = fxgmac_resume, +#endif + .shutdown = fxgmac_shutdown, +}; + +module_pci_driver(fxgmac_pci_driver); + +MODULE_DESCRIPTION(FXGMAC_DRV_DESC); +MODULE_VERSION(FXGMAC_DRV_VERSION); +MODULE_AUTHOR("Frank "); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/ethernet/motorcomm/fuxi-gmac-phy.c b/drivers/net/ethernet/motorcomm/fuxi-gmac-phy.c new file mode 100644 index 000000000000..59b017a37f41 --- /dev/null +++ b/drivers/net/ethernet/motorcomm/fuxi-gmac-phy.c @@ -0,0 +1,422 @@ +/*++ + +Copyright (c) 2021 Motor-comm Corporation. +Confidential and Proprietary. All rights reserved. + +This is Motor-comm Corporation NIC driver relevant files. Please don't copy, modify, +distribute without commercial permission. + +--*/ + + +#include +#include + +#include "fuxi-gmac.h" +#include "fuxi-gmac-reg.h" + +void fxgmac_phy_force_speed(struct fxgmac_pdata *pdata, int speed) +{ + struct fxgmac_hw_ops* hw_ops = &pdata->hw_ops; + u32 regval = 0; + unsigned int high_bit = 0, low_bit = 0; + + switch (speed) + { + case SPEED_1000: + high_bit = 1, low_bit = 0; + break; + case SPEED_100: + high_bit = 0, low_bit = 1; + break; + case SPEED_10: + high_bit = 0, low_bit = 0; + break; + default: + break; + } + + /* disable autoneg */ + hw_ops->read_ephy_reg(pdata, REG_MII_BMCR, ®val); + regval = FXGMAC_SET_REG_BITS(regval, PHY_CR_AUTOENG_POS, PHY_CR_AUTOENG_LEN, 0); + regval = FXGMAC_SET_REG_BITS(regval, PHY_CR_SPEED_SEL_H_POS, PHY_CR_SPEED_SEL_H_LEN, high_bit); + regval = FXGMAC_SET_REG_BITS(regval, PHY_CR_SPEED_SEL_L_POS, PHY_CR_SPEED_SEL_L_LEN, low_bit); + hw_ops->write_ephy_reg(pdata, REG_MII_BMCR, regval); + +} + +void fxgmac_phy_force_duplex(struct fxgmac_pdata *pdata, int duplex) +{ + struct fxgmac_hw_ops* hw_ops = &pdata->hw_ops; + u32 regval = 0; + hw_ops->read_ephy_reg(pdata, REG_MII_BMCR, ®val); + regval = FXGMAC_SET_REG_BITS(regval, PHY_CR_DUPLEX_POS, PHY_CR_DUPLEX_LEN, (duplex ? 1 : 0)); + hw_ops->write_ephy_reg(pdata, REG_MII_BMCR, regval); + +} + +void fxgmac_phy_force_autoneg(struct fxgmac_pdata *pdata, int autoneg) +{ + struct fxgmac_hw_ops* hw_ops = &pdata->hw_ops; + u32 regval = 0; + hw_ops->read_ephy_reg(pdata, REG_MII_BMCR, ®val); + regval = FXGMAC_SET_REG_BITS(regval, PHY_CR_AUTOENG_POS, PHY_CR_AUTOENG_LEN, (autoneg? 1 : 0)); + hw_ops->write_ephy_reg(pdata, REG_MII_BMCR, regval); +} + + +/* + * input: lport + * output: + * cap_mask, bit definitions: + * pause capbility and 100/10 capbilitys follow the definition of mii reg4. + * for 1000M capability, bit0=1000M half; bit1=1000M full, refer to mii reg9.[9:8]. + */ +int fxgmac_ephy_autoneg_ability_get(struct fxgmac_pdata *pdata, unsigned int *cap_mask) +{ + struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops; + unsigned int val; + unsigned int reg; + + if((!hw_ops->read_ephy_reg) || (!hw_ops->write_ephy_reg)) + return -1; + + reg = REG_MII_ADVERTISE; + if(hw_ops->read_ephy_reg(pdata, reg, &val) < 0) + goto busy_exit; + + //DPRINTK("fxgmac_ephy_autoneg_ability_get, reg %d=0x%04x\n", reg, val); + + if(FXGMAC_ADVERTISE_10HALF & val) + { + *cap_mask |= FXGMAC_ADVERTISE_10HALF; + } + else + { + *cap_mask &= ~FXGMAC_ADVERTISE_10HALF; + } + + if(FXGMAC_ADVERTISE_10FULL & val) + { + *cap_mask |= FXGMAC_ADVERTISE_10FULL; + } + else + { + *cap_mask &= ~FXGMAC_ADVERTISE_10FULL; + } + + if(FXGMAC_ADVERTISE_100HALF & val) + { + *cap_mask |= FXGMAC_ADVERTISE_100HALF; + } + else + { + *cap_mask &= ~FXGMAC_ADVERTISE_100HALF; + } + + if(FXGMAC_ADVERTISE_100FULL & val) + { + *cap_mask |= FXGMAC_ADVERTISE_100FULL; + } + else + { + *cap_mask &= ~FXGMAC_ADVERTISE_100FULL; + } + + if(FXGMAC_ADVERTISE_PAUSE_CAP & val) + { + *cap_mask |= FXGMAC_ADVERTISE_PAUSE_CAP; + } + else + { + *cap_mask &= ~FXGMAC_ADVERTISE_PAUSE_CAP; + } + + if(FXGMAC_ADVERTISE_PAUSE_ASYM & val) + { + *cap_mask |= FXGMAC_ADVERTISE_PAUSE_ASYM; + } + else + { + *cap_mask &= ~FXGMAC_ADVERTISE_PAUSE_ASYM; + } + + reg = REG_MII_CTRL1000; + if(hw_ops->read_ephy_reg(pdata, reg, &val) < 0) + goto busy_exit; + + //DPRINTK("fxgmac_ephy_autoneg_ability_get, reg %d=0x%04x\n", reg, val); + if(REG_BIT_ADVERTISE_1000HALF & val ) + { + *cap_mask |= FXGMAC_ADVERTISE_1000HALF; + } + else + { + *cap_mask &= ~FXGMAC_ADVERTISE_1000HALF; + } + + if(REG_BIT_ADVERTISE_1000FULL & val ) + { + *cap_mask |= FXGMAC_ADVERTISE_1000FULL; + } + else + { + *cap_mask &= ~FXGMAC_ADVERTISE_1000FULL; + } + + //DPRINTK("fxgmac_ephy_autoneg_ability_get done, 0x%08x.\n", *cap_mask); + + return 0; + +busy_exit: + DPRINTK("fxgmac_ephy_autoneg_ability_get exit due to ephy reg access fail.\n"); + + return -1; +} + +int fxgmac_ephy_soft_reset(struct fxgmac_pdata *pdata) +{ + struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops; + int ret; + volatile unsigned int val; + int busy = 15; + + ret = hw_ops->read_ephy_reg(pdata, REG_MII_BMCR, (unsigned int *)&val); + if (0 > ret) + goto busy_exit; + + ret = hw_ops->write_ephy_reg(pdata, REG_MII_BMCR, (val | 0x8000)); + if (0 > ret) + goto busy_exit; + + do { + ret = hw_ops->read_ephy_reg(pdata, REG_MII_BMCR, (unsigned int *)&val); + busy--; + //DPRINTK("fxgmac_ephy_soft_reset, check busy=%d.\n", busy); + }while((ret >= 0) && (0 != (val & 0x8000)) && (busy)); + + if(0 == (val & 0x8000)) return 0; + + DPRINTK("fxgmac_ephy_soft_reset, timeout, busy=%d.\n", busy); + return -EBUSY; + +busy_exit: + DPRINTK("fxgmac_ephy_soft_reset exit due to ephy reg access fail.\n"); + + return ret; +} + +/* this function used to double check the speed. for fiber, to correct there is no 10M */ +static int fxgmac_ephy_adjust_status(u32 lport, int val, int is_utp, int* speed, int* duplex) +{ + int speed_mode; + + *speed = -1; + *duplex = (val & BIT(FUXI_EPHY_DUPLEX_BIT)) >> FUXI_EPHY_DUPLEX_BIT; + speed_mode = (val & FUXI_EPHY_SPEED_MODE) >> FUXI_EPHY_SPEED_MODE_BIT; + switch (speed_mode) { + case 0: + if (is_utp) + *speed = SPEED_10M; + break; + case 1: + *speed = SPEED_100M; + break; + case 2: + *speed = SPEED_1000M; + break; + case 3: + break; + default: + break; + } + + return 0; +} + +/* + * this function for polling to get status of ephy link. + * output: + * speed: SPEED_10M, SPEED_100M, SPEED_1000M or -1; + * duplex: 0 or 1, see reg 0x11, bit YT8614_DUPLEX_BIT. + * ret_link: 0 or 1, link down or up. + * media: only valid when ret_link=1, (YT8614_SMI_SEL_SDS_SGMII + 1) for fiber; (YT8614_SMI_SEL_PHY + 1) for utp. -1 for link down. + */ +int fxgmac_ephy_status_get(struct fxgmac_pdata *pdata, int* speed, int* duplex, int* ret_link, int *media) +{ + struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops; + int ret; + u16 reg; + volatile unsigned int val; + volatile int link; + int link_utp = 0, link_fiber = 0; + + reg = REG_MII_SPEC_STATUS; + ret = hw_ops->read_ephy_reg(pdata, reg, (unsigned int *)&val); + if (0 > ret) + goto busy_exit; + + link = val & (BIT(FUXI_EPHY_LINK_STATUS_BIT)); + if (link) { + link_utp = 1; + fxgmac_ephy_adjust_status(0, val, 1, speed, duplex); + } else { + link_utp = 0; + } + + if (link_utp || link_fiber) { + /* case of fiber of priority */ + if(link_utp) *media = (FUXI_EPHY_SMI_SEL_PHY + 1); + if(link_fiber) *media = (FUXI_EPHY_SMI_SEL_SDS_SGMII + 1); + + *ret_link = 1; + } else + { + *ret_link = 0; + *media = -1; + *speed= -1; + *duplex = -1; + } + + return 0; + +busy_exit: + DPRINTK("fxgmac_ephy_status_get exit due to ephy reg access fail.\n"); + + return ret; +} + +#if 0 +/** + * fxgmac_phy_update_link - update the phy link status + * @adapter: pointer to the device adapter structure + **/ +static void fxgmac_phy_update_link(struct net_device *netdev) +{ + struct fxgmac_pdata *pdata = netdev_priv(netdev); + struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops; + bool b_linkup = false; + u32 phy_speed = 0, ephy_val1, ephy_val2; + u32 pre_phy_speed = 0xff; + + if (hw_ops->get_xlgmii_phy_status) { + hw_ops->get_xlgmii_phy_status(pdata, (u32*)&phy_speed, (bool *)&b_linkup, 0); + } else { + /* always assume link is down, if no check link function */ + } + + pre_phy_speed = ((SPEED_1000 == pdata->phy_speed) ? 2 : ((SPEED_100 == pdata->phy_speed) ? 1 : 0) ); + + if(pre_phy_speed != phy_speed) + { + DPRINTK("fuxi_phy link phy speed changed,%d->%d\n", pre_phy_speed, phy_speed); + switch(phy_speed){ + case 2: + pdata->phy_speed = SPEED_1000; + break; + case 1: + pdata->phy_speed = SPEED_100; + break; + case 0: + pdata->phy_speed = SPEED_10; + break; + default: + pdata->phy_speed = SPEED_1000; + break; + } + fxgmac_config_mac_speed(pdata); + pre_phy_speed = phy_speed; + } + + if(pdata->phy_link != b_linkup) + { + pdata->phy_link = b_linkup; + fxgmac_act_phy_link(pdata); + + if(b_linkup && (hw_ops->read_ephy_reg)) + { + hw_ops->read_ephy_reg(pdata, 0x1/* ephy latched status */, (unsigned int *)&ephy_val1); + hw_ops->read_ephy_reg(pdata, 0x1/* ephy latched status */, (unsigned int *)&ephy_val2); + DPRINTK("%s phy reg1=0x%04x, 0x%04x\n", __FUNCTION__, ephy_val1 & 0xffff, ephy_val2 & 0xffff); + } + } +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,15,0)) +static void fxgmac_phy_link_poll(struct timer_list *t) +#else +static void fxgmac_phy_link_poll(unsigned long data) +#endif +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,15,0)) + struct fxgmac_pdata *pdata = from_timer(pdata, t, expansion.phy_poll_tm); +#else + struct fxgmac_pdata *pdata = (struct fxgmac_pdata*)data; +#endif + + if(NULL == pdata->netdev) + { + DPRINTK("fuxi_phy_timer polling with NULL netdev %lx\n",(unsigned long)(pdata->netdev)); + return; + } + + pdata->stats.ephy_poll_timer_cnt++; + +#if FXGMAC_PM_FEATURE_ENABLED + /* 20210709 for net power down */ + if(!test_bit(FXGMAC_POWER_STATE_DOWN, &pdata->expansion.powerstate)) +#endif + { + //yzhang if(2 > pdata->stats.ephy_poll_timer_cnt) + { + mod_timer(&pdata->phy_poll_tm,jiffies + HZ / 2); + } + fxgmac_phy_update_link(pdata->netdev); + }else { + DPRINTK("fuxi_phy_timer polling, powerstate changed, %ld, netdev=%lx, tm=%lx\n", pdata->expansion.powerstate, (unsigned long)(pdata->netdev), (unsigned long)&pdata->phy_poll_tm); + } + + //DPRINTK("fuxi_phy_timer polled,%d\n",cnt_polling); +} + +/* + * used when fxgmac is powerdown and resume + * 20210709 for net power down + */ +void fxgmac_phy_timer_resume(struct fxgmac_pdata *pdata) +{ + if(NULL == pdata->netdev) + { + DPRINTK("fxgmac_phy_timer_resume, failed due to NULL netdev %lx\n",(unsigned long)(pdata->netdev)); + return; + } + + mod_timer(&pdata->phy_poll_tm,jiffies + HZ / 2); + + DPRINTK("fxgmac_phy_timer_resume ok, fxgmac powerstate=%ld, netdev=%lx, tm=%lx\n", pdata->expansion.powerstate, (unsigned long)(pdata->netdev), (unsigned long)&pdata->phy_poll_tm); +} + +int fxgmac_phy_timer_init(struct fxgmac_pdata *pdata) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,15,0)) + init_timer_key(&pdata->phy_poll_tm,NULL/*function*/,0/*flags*/,"fuxi_phy_link_update_timer"/*name*/,NULL/*class lock key*/); +#else + init_timer_key(&pdata->phy_poll_tm,0/*flags*/,"fuxi_phy_link_update_timer"/*name*/,NULL/*class lock key*/); +#endif + pdata->phy_poll_tm.expires = jiffies + HZ / 2; + pdata->phy_poll_tm.function = (void *)(fxgmac_phy_link_poll); +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,15,0)) + pdata->phy_poll_tm.data = (unsigned long)pdata; +#endif + add_timer(&pdata->phy_poll_tm); + + DPRINTK("fuxi_phy_timer started, %lx\n", jiffies); + return 0; +} + +void fxgmac_phy_timer_destroy(struct fxgmac_pdata *pdata) +{ + del_timer_sync(&pdata->phy_poll_tm); + DPRINTK("fuxi_phy_timer removed\n"); +} +#endif diff --git a/drivers/net/ethernet/motorcomm/fuxi-gmac-reg.h b/drivers/net/ethernet/motorcomm/fuxi-gmac-reg.h new file mode 100644 index 000000000000..5977de44f7b9 --- /dev/null +++ b/drivers/net/ethernet/motorcomm/fuxi-gmac-reg.h @@ -0,0 +1,1876 @@ +/*++ + +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. + +--*/ + +#ifndef __FUXI_GMAC_REG_H__ +#define __FUXI_GMAC_REG_H__ + +#define AISC_MODE + +#define FUXI_REV_01 0x01 // The first NTO version. +#define FUXI_REV_03 0x03 // ECO back on 07/2023. + +/* MAC register offsets */ +#define MAC_OFFSET 0x2000 +#define MAC_CR 0x0000 //The MAC Configuration Register +#define MAC_ECR 0x0004 +#define MAC_PFR 0x0008 +#define MAC_HTR0 0x0010 +#define MAC_VLANTR 0x0050 +#define MAC_VLANHTR 0x0058 +#define MAC_VLANIR 0x0060 +#define MAC_Q0TFCR 0x0070 +#define MAC_RFCR 0x0090 +#define MAC_RQC0R 0x00a0 +#define MAC_RQC1R 0x00a4 +#define MAC_RQC2R 0x00a8 +#define MAC_RQC3R 0x00ac +#define MAC_ISR 0x00b0 +#define MAC_IER 0x00b4 +#define MAC_TX_RX_STA 0x00b8 +#define MAC_PMT_STA 0x00c0 +#define MAC_RWK_PAC 0x00c4 // This is the FIFO address, the pointer will be increased automatically after writting. +#define MAC_LPI_STA 0x00d0 +#define MAC_LPI_CONTROL 0x00d4 +#define MAC_LPI_TIMER 0x00d8 +#define MAC_MS_TIC_COUNTER 0x00dc +#define MAC_AN_SR 0x00E4 +#define MAC_PHYIF_STA 0x00F8 +#define MAC_VR 0x0110 +#define MAC_DBG_STA 0x0114 +#define MAC_HWF0R 0x011c +#define MAC_HWF1R 0x0120 +#define MAC_HWF2R 0x0124 +#define MAC_HWF3R 0x0128 +#define MAC_MDIO_ADDRESS 0x0200 +#define MAC_MDIO_DATA 0x0204 +#define MAC_GPIO_SR 0x020c +#define MAC_ARP_PROTO_ADDR 0x0210 +#define MAC_CSR_SW_CTRL 0x0230 + +#define MAC_MACA0HR 0x0300 // mac[5]->bit15:8, mac[4]->bit7:0 +#define MAC_MACA0LR 0x0304 // mac[0]->bit7:0, mac[1]->bit15:8, mac[2]->bit23:16, mac[3]->bit31:24 + +#define MAC_MACA1HR 0x0308 +#define MAC_MACA1HR_AE_POS 31 +#define MAC_MACA1HR_AE_LEN 1 + +#define MAC_MACA1LR 0x030c + + +#define MAC_RSSCR 0x3c80//TODO +#define MAC_RSSAR 0x3c88//TODO +#define MAC_RSSDR 0x3c8c//TODO + + + +#define MAC_QTFCR_INC 4 +#define MAC_MACA_INC 4 +#define MAC_HTR_INC 4 +#define MAC_RQC2_INC 4 +#define MAC_RQC2_Q_PER_REG 4 + +/* MAC register entry bit positions and sizes */ +#define MAC_HWF0R_ADDMACADRSEL_POS 18 +#define MAC_HWF0R_ADDMACADRSEL_LEN 5 +#define MAC_HWF0R_ARPOFFSEL_POS 9 +#define MAC_HWF0R_ARPOFFSEL_LEN 1 +#define MAC_HWF0R_EEESEL_POS 13 +#define MAC_HWF0R_EEESEL_LEN 1 +#define MAC_HWF0R_ACTPHYIFSEL_POS 28 +#define MAC_HWF0R_ACTPHYIFSEL_LEN 3 +#define MAC_HWF0R_MGKSEL_POS 7 +#define MAC_HWF0R_MGKSEL_LEN 1 +#define MAC_HWF0R_MMCSEL_POS 8 +#define MAC_HWF0R_MMCSEL_LEN 1 +#define MAC_HWF0R_RWKSEL_POS 6 +#define MAC_HWF0R_RWKSEL_LEN 1 +#define MAC_HWF0R_RXCOESEL_POS 16 +#define MAC_HWF0R_RXCOESEL_LEN 1 +#define MAC_HWF0R_SAVLANINS_POS 27 +#define MAC_HWF0R_SAVLANINS_LEN 1 +#define MAC_HWF0R_SMASEL_POS 5 +#define MAC_HWF0R_SMASEL_LEN 1 +#define MAC_HWF0R_TSSEL_POS 12 +#define MAC_HWF0R_TSSEL_LEN 1 +#define MAC_HWF0R_TSSTSSEL_POS 25 +#define MAC_HWF0R_TSSTSSEL_LEN 2 +#define MAC_HWF0R_TXCOESEL_POS 14 +#define MAC_HWF0R_TXCOESEL_LEN 1 +#define MAC_HWF0R_VLHASH_POS 4 +#define MAC_HWF0R_VLHASH_LEN 1 +#define MAC_HWF1R_ADDR64_POS 14 +#define MAC_HWF1R_ADDR64_LEN 2 +#define MAC_HWF1R_ADVTHWORD_POS 13 +#define MAC_HWF1R_ADVTHWORD_LEN 1 +#define MAC_HWF1R_DBGMEMA_POS 19 +#define MAC_HWF1R_DBGMEMA_LEN 1 +#define MAC_HWF1R_DCBEN_POS 16 +#define MAC_HWF1R_DCBEN_LEN 1 +#define MAC_HWF1R_HASHTBLSZ_POS 24 +#define MAC_HWF1R_HASHTBLSZ_LEN 2 +#define MAC_HWF1R_L3L4FNUM_POS 27 +#define MAC_HWF1R_L3L4FNUM_LEN 4 +//#define MAC_HWF1R_NUMTC_POS 21 +//#define MAC_HWF1R_NUMTC_LEN 3 +//#define MAC_HWF1R_RSSEN_POS 20 +//#define MAC_HWF1R_RSSEN_LEN 1 +#define MAC_HWF1R_RAVSEL_POS 21 +#define MAC_HWF1R_RAVSEL_LEN 1 +#define MAC_HWF1R_AVSEL_POS 20 +#define MAC_HWF1R_AVSEL_LEN 1 +#define MAC_HWF1R_RXFIFOSIZE_POS 0 +#define MAC_HWF1R_RXFIFOSIZE_LEN 5 +#define MAC_HWF1R_SPHEN_POS 17 +#define MAC_HWF1R_SPHEN_LEN 1 +#define MAC_HWF1R_TSOEN_POS 18 +#define MAC_HWF1R_TSOEN_LEN 1 +#define MAC_HWF1R_TXFIFOSIZE_POS 6 +#define MAC_HWF1R_TXFIFOSIZE_LEN 5 +#define MAC_HWF2R_AUXSNAPNUM_POS 28 +#define MAC_HWF2R_AUXSNAPNUM_LEN 3 +#define MAC_HWF2R_PPSOUTNUM_POS 24 +#define MAC_HWF2R_PPSOUTNUM_LEN 3 +#define MAC_HWF2R_RXCHCNT_POS 12 +#define MAC_HWF2R_RXCHCNT_LEN 4 +#define MAC_HWF2R_RXQCNT_POS 0 +#define MAC_HWF2R_RXQCNT_LEN 4 +#define MAC_HWF2R_TXCHCNT_POS 18 +#define MAC_HWF2R_TXCHCNT_LEN 4 +#define MAC_HWF2R_TXQCNT_POS 6 +#define MAC_HWF2R_TXQCNT_LEN 4 +#define MAC_IER_TSIE_POS 12 +#define MAC_IER_TSIE_LEN 1 +#define MAC_ISR_MMCRXIS_POS 9 +#define MAC_ISR_MMCRXIS_LEN 1 +#define MAC_ISR_MMCTXIS_POS 10 +#define MAC_ISR_MMCTXIS_LEN 1 +#define MAC_ISR_PMTIS_POS 4 +#define MAC_ISR_PMTIS_LEN 1 +#define MAC_ISR_TSIS_POS 12 +#define MAC_ISR_TSIS_LEN 1 +#define MAC_MACA1HR_AE_POS 31 +#define MAC_MACA1HR_AE_LEN 1 +#define MAC_PFR_HMC_POS 2 +#define MAC_PFR_HMC_LEN 1 +#define MAC_PFR_HPF_POS 10 +#define MAC_PFR_HPF_LEN 1 +#define MAC_PFR_PM_POS 4 // Pass all Multicast. +#define MAC_PFR_PM_LEN 1 +#define MAC_PFR_DBF_POS 5 // Disable Broadcast Packets. +#define MAC_PFR_DBF_LEN 1 +#define MAC_PFR_HUC_POS 1 // Hash Unicast. 0x0 (DISABLE). compares the DA field with the values programmed in DA registers. +#define MAC_PFR_HUC_LEN 1 +#define MAC_PFR_PR_POS 0 // Enable Promiscuous Mode. +#define MAC_PFR_PR_LEN 1 +#define MAC_PFR_VTFE_POS 16 +#define MAC_PFR_VTFE_LEN 1 +#define MAC_Q0TFCR_PT_POS 16 +#define MAC_Q0TFCR_PT_LEN 16 +#define MAC_Q0TFCR_TFE_POS 1 +#define MAC_Q0TFCR_TFE_LEN 1 +#define MAC_CR_ARPEN_POS 31 +#define MAC_CR_ARPEN_LEN 1 +#define MAC_CR_ACS_POS 20 +#define MAC_CR_ACS_LEN 1 +#define MAC_CR_CST_POS 21 +#define MAC_CR_CST_LEN 1 +#define MAC_CR_IPC_POS 27 +#define MAC_CR_IPC_LEN 1 +#define MAC_CR_JE_POS 16 +#define MAC_CR_JE_LEN 1 +#define MAC_CR_LM_POS 12 +#define MAC_CR_LM_LEN 1 +#define MAC_CR_RE_POS 0 +#define MAC_CR_RE_LEN 1 +#define MAC_CR_PS_POS 15 +#define MAC_CR_PS_LEN 1 +#define MAC_CR_FES_POS 14 +#define MAC_CR_FES_LEN 1 +#define MAC_CR_DM_POS 13 +#define MAC_CR_DM_LEN 1 +#define MAC_CR_TE_POS 1 +#define MAC_CR_TE_LEN 1 +#define MAC_ECR_DCRCC_POS 16 +#define MAC_ECR_DCRCC_LEN 1 +#define MAC_ECR_HDSMS_POS 20 +#define MAC_ECR_HDSMS_LEN 3 +#define MAC_RFCR_PFCE_POS 8 +#define MAC_RFCR_PFCE_LEN 1 +#define MAC_RFCR_RFE_POS 0 +#define MAC_RFCR_RFE_LEN 1 +#define MAC_RFCR_UP_POS 1 +#define MAC_RFCR_UP_LEN 1 +#define MAC_RQC0R_RXQ0EN_POS 0 +#define MAC_RQC0R_RXQ0EN_LEN 2 +#define MAC_LPIIE_POS 5 +#define MAC_LPIIE_LEN 1 +#define MAC_LPIATE_POS 20 +#define MAC_LPIATE_LEN 1 +#define MAC_LPITXA_POS 19 +#define MAC_LPITXA_LEN 1 +#define MAC_PLS_POS 17 +#define MAC_PLS_LEN 1 +#define MAC_LPIEN_POS 16 +#define MAC_LPIEN_LEN 1 +#define MAC_LPI_ENTRY_TIMER 8 +#define MAC_LPIET_POS 3 +#define MAC_LPIET_LEN 17 +#define MAC_TWT_TIMER 0x10 +#define MAC_TWT_POS 0 +#define MAC_TWT_LEN 16 +#define MAC_LST_TIMER 2 +#define MAC_LST_POS 16 +#define MAC_LST_LEN 10 +#define MAC_MS_TIC 24 +#define MAC_MS_TIC_POS 0 +#define MAC_MS_TIC_LEN 12 + +/* RSS table */ +#define MAC_RSSAR_ADDRT_POS 2 +#define MAC_RSSAR_ADDRT_LEN 1 +#define MAC_RSSAR_CT_POS 1 +#define MAC_RSSAR_CT_LEN 1 +#define MAC_RSSAR_OB_POS 0 +#define MAC_RSSAR_OB_LEN 1 +#define MAC_RSSAR_RSSIA_POS 8 +#define MAC_RSSAR_RSSIA_LEN 8 +/* RSS control and options */ +/* note, below options definitions are used only for pdata->options, + * not for register, so the position is not consistent with register. + * [0] ipv4 + * [1] tcpv4 + * [2] udpv4 + * [3] ipv6 + * [4] tcpv6 + * [5] udpv6 + */ +#define MAC_RSSCR_IP4TE_POS 0 +#define MAC_RSSCR_IP4TE_LEN 1 +#define MAC_RSSCR_IP6TE_POS 3 +#define MAC_RSSCR_IP6TE_LEN 1 +#define MAC_RSSCR_TCP4TE_POS 1 +#define MAC_RSSCR_TCP4TE_LEN 1 +#define MAC_RSSCR_UDP4TE_POS 2 +#define MAC_RSSCR_UDP4TE_LEN 1 +#define MAC_RSSCR_TCP6TE_POS 4 +#define MAC_RSSCR_TCP6TE_LEN 1 +#define MAC_RSSCR_UDP6TE_POS 5 +#define MAC_RSSCR_UDP6TE_LEN 1 + +/* RSS indirection table */ +#define MAC_RSSDR_DMCH_POS 0 +#define MAC_RSSDR_DMCH_LEN 2 + +#define MAC_VLANHTR_VLHT_POS 0 +#define MAC_VLANHTR_VLHT_LEN 16 +#define MAC_VLANIR_VLTI_POS 20 +#define MAC_VLANIR_VLTI_LEN 1 +#define MAC_VLANIR_CSVL_POS 19 +#define MAC_VLANIR_CSVL_LEN 1 +#define MAC_VLANIR_VLP_POS 18 +#define MAC_VLANIR_VLP_LEN 1 +#define MAC_VLANIR_VLC_POS 16 +#define MAC_VLANIR_VLC_LEN 2 +#define MAC_VLANIR_VLT_POS 0 +#define MAC_VLANIR_VLT_LEN 16 +#define MAC_VLANTR_DOVLTC_POS 20 +#define MAC_VLANTR_DOVLTC_LEN 1 +#define MAC_VLANTR_ERSVLM_POS 19 +#define MAC_VLANTR_ERSVLM_LEN 1 +#define MAC_VLANTR_ESVL_POS 18 +#define MAC_VLANTR_ESVL_LEN 1 +#define MAC_VLANTR_ETV_POS 16 +#define MAC_VLANTR_ETV_LEN 1 +#define MAC_VLANTR_EVLS_POS 21 +#define MAC_VLANTR_EVLS_LEN 2 +#define MAC_VLANTR_EVLRXS_POS 24 +#define MAC_VLANTR_EVLRXS_LEN 1 +#define MAC_VLANTR_VL_POS 0 +#define MAC_VLANTR_VL_LEN 16 +#define MAC_VLANTR_VTHM_POS 25 +#define MAC_VLANTR_VTHM_LEN 1 +#define MAC_VLANTR_VTIM_POS 17 +#define MAC_VLANTR_VTIM_LEN 1 +#define MAC_VR_DEVID_POS 16 +#define MAC_VR_DEVID_LEN 16 +#define MAC_VR_SVER_POS 0 +#define MAC_VR_SVER_LEN 8 +#define MAC_VR_USERVER_POS 8 +#define MAC_VR_USERVER_LEN 8 + +#define MAC_DBG_STA_TX_BUSY 0x70000 +#define MTL_TXQ_DEG_TX_BUSY 0x10 + +#define MAC_MDIO_ADDRESS_BUSY 1 //bit 0 + +#define MAC_MDIO_ADDR_GOC_POS 2 +#define MAC_MDIO_ADDR_GOC_LEN 2 +#define MAC_MDIO_ADDR_GB_POS 0 +#define MAC_MDIO_ADDR_GB_LEN 1 + +#define MAC_MDIO_DATA_RA_POS 16 +#define MAC_MDIO_DATA_RA_LEN 16 +#define MAC_MDIO_DATA_GD_POS 0 +#define MAC_MDIO_DATA_GD_LEN 16 + +/* bit definitions for PMT and WOL, 20210622 */ +#define MAC_PMT_STA_PWRDWN_POS 0 +#define MAC_PMT_STA_PWRDWN_LEN 1 +#define MAC_PMT_STA_MGKPKTEN_POS 1 +#define MAC_PMT_STA_MGKPKTEN_LEN 1 +#define MAC_PMT_STA_RWKPKTEN_POS 2 +#define MAC_PMT_STA_RWKPKTEN_LEN 1 +#define MAC_PMT_STA_MGKPRCVD_POS 5 +#define MAC_PMT_STA_MGKPRCVD_LEN 1 +#define MAC_PMT_STA_RWKPRCVD_POS 6 +#define MAC_PMT_STA_RWKPRCVD_LEN 1 +#define MAC_PMT_STA_GLBLUCAST_POS 9 +#define MAC_PMT_STA_GLBLUCAST_LEN 1 +#define MAC_PMT_STA_RWKPTR_POS 24 +#define MAC_PMT_STA_RWKPTR_LEN 4 +#define MAC_PMT_STA_RWKFILTERST_POS 31 +#define MAC_PMT_STA_RWKFILTERST_LEN 1 +/* MMC register offsets */ +#define MMC_CR 0x0700 +#define MMC_RISR 0x0704 +#define MMC_TISR 0x0708 +#define MMC_RIER 0x070c +#define MMC_TIER 0x0710 +#define MMC_TXOCTETCOUNT_GB_LO 0x0714 +#define MMC_TXFRAMECOUNT_GB_LO 0x0718 +#define MMC_TXBROADCASTFRAMES_G_LO 0x071c +#define MMC_TXMULTICASTFRAMES_G_LO 0x0720 +#define MMC_TX64OCTETS_GB_LO 0x0724 +#define MMC_TX65TO127OCTETS_GB_LO 0x0728 +#define MMC_TX128TO255OCTETS_GB_LO 0x072c +#define MMC_TX256TO511OCTETS_GB_LO 0x0730 +#define MMC_TX512TO1023OCTETS_GB_LO 0x0734 +#define MMC_TX1024TOMAXOCTETS_GB_LO 0x0738 +#define MMC_TXUNICASTFRAMES_GB_LO 0x073c +#define MMC_TXMULTICASTFRAMES_GB_LO 0x0740 +#define MMC_TXBROADCASTFRAMES_GB_LO 0x0744 +#define MMC_TXUNDERFLOWERROR_LO 0x0748 +#define MMC_TXSINGLECOLLISION_G 0x074c +#define MMC_TXMULTIPLECOLLISION_G 0x0750 +#define MMC_TXDEFERREDFRAMES 0x0754 +#define MMC_TXLATECOLLISIONFRAMES 0x0758 +#define MMC_TXEXCESSIVECOLLSIONFRAMES 0x075c +#define MMC_TXCARRIERERRORFRAMES 0x0760 +#define MMC_TXOCTETCOUNT_G_LO 0x0764 +#define MMC_TXFRAMECOUNT_G_LO 0x0768 +#define MMC_TXEXCESSIVEDEFERRALERROR 0x076c +#define MMC_TXPAUSEFRAMES_LO 0x0770 +#define MMC_TXVLANFRAMES_G_LO 0x0774 +#define MMC_TXOVERSIZEFRAMES 0x0778 +#define MMC_RXFRAMECOUNT_GB_LO 0x0780 +#define MMC_RXOCTETCOUNT_GB_LO 0x0784 +#define MMC_RXOCTETCOUNT_G_LO 0x0788 +#define MMC_RXBROADCASTFRAMES_G_LO 0x078c +#define MMC_RXMULTICASTFRAMES_G_LO 0x0790 +#define MMC_RXCRCERROR_LO 0x0794 +#define MMC_RXALIGNERROR 0x0798 +#define MMC_RXRUNTERROR 0x079c +#define MMC_RXJABBERERROR 0x07a0 +#define MMC_RXUNDERSIZE_G 0x07a4 +#define MMC_RXOVERSIZE_G 0x07a8 +#define MMC_RX64OCTETS_GB_LO 0x07ac +#define MMC_RX65TO127OCTETS_GB_LO 0x07b0 +#define MMC_RX128TO255OCTETS_GB_LO 0x07b4 +#define MMC_RX256TO511OCTETS_GB_LO 0x07b8 +#define MMC_RX512TO1023OCTETS_GB_LO 0x07bc +#define MMC_RX1024TOMAXOCTETS_GB_LO 0x07c0 +#define MMC_RXUNICASTFRAMES_G_LO 0x07c4 +#define MMC_RXLENGTHERROR_LO 0x07c8 +#define MMC_RXOUTOFRANGETYPE_LO 0x07cc +#define MMC_RXPAUSEFRAMES_LO 0x07d0 +#define MMC_RXFIFOOVERFLOW_LO 0x07d4 +#define MMC_RXVLANFRAMES_GB_LO 0x07d8 +#define MMC_RXWATCHDOGERROR 0x07dc +#define MMC_RXRECEIVEERRORFRAME 0x07e0 +#define MMC_RXCONTROLFRAME_G 0x07e4 + +#define MMC_IPCRXINTMASK 0x800 +#define MMC_IPCRXINT 0x808 + +/* MMC register entry bit positions and sizes */ +#define MMC_CR_CR_POS 0 +#define MMC_CR_CR_LEN 1 +#define MMC_CR_CSR_POS 1 +#define MMC_CR_CSR_LEN 1 +#define MMC_CR_ROR_POS 2 +#define MMC_CR_ROR_LEN 1 +#define MMC_CR_MCF_POS 3 +#define MMC_CR_MCF_LEN 1 +//#define MMC_CR_MCT_POS 4 +//#define MMC_CR_MCT_LEN 2 +#define MMC_RIER_ALL_INTERRUPTS_POS 0 +#define MMC_RIER_ALL_INTERRUPTS_LEN 26 +#define MMC_RISR_RXFRAMECOUNT_GB_POS 0 +#define MMC_RISR_RXFRAMECOUNT_GB_LEN 1 +#define MMC_RISR_RXOCTETCOUNT_GB_POS 1 +#define MMC_RISR_RXOCTETCOUNT_GB_LEN 1 +#define MMC_RISR_RXOCTETCOUNT_G_POS 2 +#define MMC_RISR_RXOCTETCOUNT_G_LEN 1 +#define MMC_RISR_RXBROADCASTFRAMES_G_POS 3 +#define MMC_RISR_RXBROADCASTFRAMES_G_LEN 1 +#define MMC_RISR_RXMULTICASTFRAMES_G_POS 4 +#define MMC_RISR_RXMULTICASTFRAMES_G_LEN 1 +#define MMC_RISR_RXCRCERROR_POS 5 +#define MMC_RISR_RXCRCERROR_LEN 1 +#define MMC_RISR_RXALIGNERROR_POS 6 +#define MMC_RISR_RXALIGNERROR_LEN 1 +#define MMC_RISR_RXRUNTERROR_POS 7 +#define MMC_RISR_RXRUNTERROR_LEN 1 +#define MMC_RISR_RXJABBERERROR_POS 8 +#define MMC_RISR_RXJABBERERROR_LEN 1 +#define MMC_RISR_RXUNDERSIZE_G_POS 9 +#define MMC_RISR_RXUNDERSIZE_G_LEN 1 +#define MMC_RISR_RXOVERSIZE_G_POS 10 +#define MMC_RISR_RXOVERSIZE_G_LEN 1 +#define MMC_RISR_RX64OCTETS_GB_POS 11 +#define MMC_RISR_RX64OCTETS_GB_LEN 1 +#define MMC_RISR_RX65TO127OCTETS_GB_POS 12 +#define MMC_RISR_RX65TO127OCTETS_GB_LEN 1 +#define MMC_RISR_RX128TO255OCTETS_GB_POS 13 +#define MMC_RISR_RX128TO255OCTETS_GB_LEN 1 +#define MMC_RISR_RX256TO511OCTETS_GB_POS 14 +#define MMC_RISR_RX256TO511OCTETS_GB_LEN 1 +#define MMC_RISR_RX512TO1023OCTETS_GB_POS 15 +#define MMC_RISR_RX512TO1023OCTETS_GB_LEN 1 +#define MMC_RISR_RX1024TOMAXOCTETS_GB_POS 16 +#define MMC_RISR_RX1024TOMAXOCTETS_GB_LEN 1 +#define MMC_RISR_RXUNICASTFRAMES_G_POS 17 +#define MMC_RISR_RXUNICASTFRAMES_G_LEN 1 +#define MMC_RISR_RXLENGTHERROR_POS 18 +#define MMC_RISR_RXLENGTHERROR_LEN 1 +#define MMC_RISR_RXOUTOFRANGETYPE_POS 19 +#define MMC_RISR_RXOUTOFRANGETYPE_LEN 1 +#define MMC_RISR_RXPAUSEFRAMES_POS 20 +#define MMC_RISR_RXPAUSEFRAMES_LEN 1 +#define MMC_RISR_RXFIFOOVERFLOW_POS 21 +#define MMC_RISR_RXFIFOOVERFLOW_LEN 1 +#define MMC_RISR_RXVLANFRAMES_GB_POS 22 +#define MMC_RISR_RXVLANFRAMES_GB_LEN 1 +#define MMC_RISR_RXWATCHDOGERROR_POS 23 +#define MMC_RISR_RXWATCHDOGERROR_LEN 1 +#define MMC_RISR_RXERRORFRAMES_POS 24 +#define MMC_RISR_RXERRORFRAMES_LEN 1 +#define MMC_RISR_RXERRORCONTROLFRAMES_POS 25 +#define MMC_RISR_RXERRORCONTROLFRAMES_LEN 1 +#define MMC_RISR_RXLPIMICROSECOND_POS 26 //no counter register +#define MMC_RISR_RXLPIMICROSECOND_LEN 1 +#define MMC_RISR_RXLPITRANSITION_POS 27 //no counter register +#define MMC_RISR_RXLPITRANSITION_LEN 1 + +#define MMC_TIER_ALL_INTERRUPTS_POS 0 +#define MMC_TIER_ALL_INTERRUPTS_LEN 26 +#define MMC_TISR_TXOCTETCOUNT_GB_POS 0 +#define MMC_TISR_TXOCTETCOUNT_GB_LEN 1 +#define MMC_TISR_TXFRAMECOUNT_GB_POS 1 +#define MMC_TISR_TXFRAMECOUNT_GB_LEN 1 +#define MMC_TISR_TXBROADCASTFRAMES_G_POS 2 +#define MMC_TISR_TXBROADCASTFRAMES_G_LEN 1 +#define MMC_TISR_TXMULTICASTFRAMES_G_POS 3 +#define MMC_TISR_TXMULTICASTFRAMES_G_LEN 1 +#define MMC_TISR_TX64OCTETS_GB_POS 4 +#define MMC_TISR_TX64OCTETS_GB_LEN 1 +#define MMC_TISR_TX65TO127OCTETS_GB_POS 5 +#define MMC_TISR_TX65TO127OCTETS_GB_LEN 1 +#define MMC_TISR_TX128TO255OCTETS_GB_POS 6 +#define MMC_TISR_TX128TO255OCTETS_GB_LEN 1 +#define MMC_TISR_TX256TO511OCTETS_GB_POS 7 +#define MMC_TISR_TX256TO511OCTETS_GB_LEN 1 +#define MMC_TISR_TX512TO1023OCTETS_GB_POS 8 +#define MMC_TISR_TX512TO1023OCTETS_GB_LEN 1 +#define MMC_TISR_TX1024TOMAXOCTETS_GB_POS 9 +#define MMC_TISR_TX1024TOMAXOCTETS_GB_LEN 1 +#define MMC_TISR_TXUNICASTFRAMES_GB_POS 10 +#define MMC_TISR_TXUNICASTFRAMES_GB_LEN 1 +#define MMC_TISR_TXMULTICASTFRAMES_GB_POS 11 +#define MMC_TISR_TXMULTICASTFRAMES_GB_LEN 1 +#define MMC_TISR_TXBROADCASTFRAMES_GB_POS 12 +#define MMC_TISR_TXBROADCASTFRAMES_GB_LEN 1 +#define MMC_TISR_TXUNDERFLOWERROR_POS 13 +#define MMC_TISR_TXUNDERFLOWERROR_LEN 1 +#define MMC_TISR_TXSINGLECOLLISION_G_POS 14 +#define MMC_TISR_TXSINGLECOLLISION_G_LEN 1 +#define MMC_TISR_TXMULTIPLECOLLISION_G_POS 15 +#define MMC_TISR_TXMULTIPLECOLLISION_G_LEN 1 +#define MMC_TISR_TXDEFERREDFRAMES_POS 16 +#define MMC_TISR_TXDEFERREDFRAMES_LEN 1 +#define MMC_TISR_TXLATECOLLISIONFRAMES_POS 17 +#define MMC_TISR_TXLATECOLLISIONFRAMES_LEN 1 +#define MMC_TISR_TXEXCESSIVECOLLISIONFRAMES_POS 18 +#define MMC_TISR_TXEXCESSIVECOLLISIONFRAMES_LEN 1 +#define MMC_TISR_TXCARRIERERRORFRAMES_POS 19 +#define MMC_TISR_TXCARRIERERRORFRAMES_LEN 1 +#define MMC_TISR_TXOCTETCOUNT_G_POS 20 +#define MMC_TISR_TXOCTETCOUNT_G_LEN 1 +#define MMC_TISR_TXFRAMECOUNT_G_POS 21 +#define MMC_TISR_TXFRAMECOUNT_G_LEN 1 +#define MMC_TISR_TXEXCESSIVEDEFERRALFRAMES_POS 22 +#define MMC_TISR_TXEXCESSIVEDEFERRALFRAMES_LEN 1 +#define MMC_TISR_TXPAUSEFRAMES_POS 23 +#define MMC_TISR_TXPAUSEFRAMES_LEN 1 +#define MMC_TISR_TXVLANFRAMES_G_POS 24 +#define MMC_TISR_TXVLANFRAMES_G_LEN 1 +#define MMC_TISR_TXOVERSIZE_G_POS 25 +#define MMC_TISR_TXOVERSIZE_G_LEN 1 +#define MMC_TISR_TXLPIMICROSECOND_POS 26 //no counter register +#define MMC_TISR_TXLPIMICROSECOND_LEN 1 +#define MMC_TISR_TXLPITRANSITION_POS 27 //no counter register +#define MMC_TISR_TXLPITRANSITION_LEN 1 + +/* MTL register offsets */ +#define MTL_OMR 0x0c00 +#define MTL_FDDR 0x0c10 +#define MTL_INT_SR 0x0c20 +#define MTL_RQDCM0R 0x0c30 +#define MTL_ECC_INT_SR 0x0ccc + +#define MTL_RQDCM_INC 4 +#define MTL_RQDCM_Q_PER_REG 4 + +/* MTL register entry bit positions and sizes */ +#define MTL_OMR_ETSALG_POS 5 +#define MTL_OMR_ETSALG_LEN 2 +#define MTL_OMR_RAA_POS 2 +#define MTL_OMR_RAA_LEN 1 + +/* MTL queue register offsets + * Multiple queues can be active. The first queue has registers + * that begin at 0x0d00. Each subsequent queue has registers that + * are accessed using an offset of 0x40 from the previous queue. + */ +#define MTL_Q_BASE 0x0d00 +#define MTL_Q_INC 0x40 +#define MTL_Q_INT_CTL_SR 0x0d2c + +#define MTL_Q_TQOMR 0x00 +#define MTL_Q_RQOMR 0x30 +#define MTL_Q_RQDR 0x38 +#define MTL_Q_IER 0x2c +#define MTL_Q_ISR 0x2c //no isr register +#define MTL_TXQ_DEG 0x08 //transmit debug + +/* MTL queue register entry bit positions and sizes */ +#define MTL_Q_RQDR_PRXQ_POS 16 +#define MTL_Q_RQDR_PRXQ_LEN 14 +#define MTL_Q_RQDR_RXQSTS_POS 4 +#define MTL_Q_RQDR_RXQSTS_LEN 2 +#define MTL_Q_RQOMR_RFA_POS 8 +#define MTL_Q_RQOMR_RFA_LEN 6 +#define MTL_Q_RQOMR_RFD_POS 14 +#define MTL_Q_RQOMR_RFD_LEN 6 +#define MTL_Q_RQOMR_EHFC_POS 7 +#define MTL_Q_RQOMR_EHFC_LEN 1 +#define MTL_Q_RQOMR_RQS_POS 20 +#define MTL_Q_RQOMR_RQS_LEN 9 +#define MTL_Q_RQOMR_RSF_POS 5 +#define MTL_Q_RQOMR_RSF_LEN 1 +#define MTL_Q_RQOMR_FEP_POS 4 +#define MTL_Q_RQOMR_FEP_LEN 1 +#define MTL_Q_RQOMR_FUP_POS 3 +#define MTL_Q_RQOMR_FUP_LEN 1 +#define MTL_Q_RQOMR_RTC_POS 0 +#define MTL_Q_RQOMR_RTC_LEN 2 +#define MTL_Q_TQOMR_FTQ_POS 0 +#define MTL_Q_TQOMR_FTQ_LEN 1 +//#define MTL_Q_TQOMR_Q2TCMAP_POS 8 // no register +//#define MTL_Q_TQOMR_Q2TCMAP_LEN 3 // no register +#define MTL_Q_TQOMR_TQS_POS 16 +#define MTL_Q_TQOMR_TQS_LEN 7 +#define MTL_Q_TQOMR_TSF_POS 1 +#define MTL_Q_TQOMR_TSF_LEN 1 +#define MTL_Q_TQOMR_TTC_POS 4 +#define MTL_Q_TQOMR_TTC_LEN 3 +#define MTL_Q_TQOMR_TXQEN_POS 2 +#define MTL_Q_TQOMR_TXQEN_LEN 2 + +/* MTL queue register value */ +#define MTL_RSF_DISABLE 0x00 +#define MTL_RSF_ENABLE 0x01 +#define MTL_TSF_DISABLE 0x00 +#define MTL_TSF_ENABLE 0x01 +#define MTL_FEP_DISABLE 0x00 +#define MTL_FEP_ENABLE 0x01 + +#define MTL_RX_THRESHOLD_64 0x00 +#define MTL_RX_THRESHOLD_32 0x01 +#define MTL_RX_THRESHOLD_96 0x02 +#define MTL_RX_THRESHOLD_128 0x03 +#define MTL_TX_THRESHOLD_32 0x00 +#define MTL_TX_THRESHOLD_64 0x01 +#define MTL_TX_THRESHOLD_96 0x02 +#define MTL_TX_THRESHOLD_128 0x03 +#define MTL_TX_THRESHOLD_192 0x04 +#define MTL_TX_THRESHOLD_256 0x05 +#define MTL_TX_THRESHOLD_384 0x06 +#define MTL_TX_THRESHOLD_512 0x07 + +#define MTL_ETSALG_WRR 0x00 +#define MTL_ETSALG_WFQ 0x01 +#define MTL_ETSALG_DWRR 0x02 +#define MTL_ETSALG_SP 0x03 + +#define MTL_RAA_SP 0x00 +#define MTL_RAA_WSP 0x01 + +#define MTL_Q_DISABLED 0x00 +#define MTL_Q_EN_IF_AV 0x01 +#define MTL_Q_ENABLED 0x02 + +#define MTL_RQDCM0R_Q0MDMACH 0x0 +#define MTL_RQDCM0R_Q1MDMACH 0x00000100 +#define MTL_RQDCM0R_Q2MDMACH 0x00020000 +#define MTL_RQDCM0R_Q3MDMACH 0x03000000 +#define MTL_RQDCM1R_Q4MDMACH 0x00000004 +#define MTL_RQDCM1R_Q5MDMACH 0x00000500 +#define MTL_RQDCM1R_Q6MDMACH 0x00060000 +#define MTL_RQDCM1R_Q7MDMACH 0x07000000 +#define MTL_RQDCM2R_Q8MDMACH 0x00000008 +#define MTL_RQDCM2R_Q9MDMACH 0x00000900 +#define MTL_RQDCM2R_Q10MDMACH 0x000A0000 +#define MTL_RQDCM2R_Q11MDMACH 0x0B000000 + +#define MTL_RQDCM0R_Q0DDMACH 0x10 +#define MTL_RQDCM0R_Q1DDMACH 0x00001000 +#define MTL_RQDCM0R_Q2DDMACH 0x00100000 +#define MTL_RQDCM0R_Q3DDMACH 0x10000000 +#define MTL_RQDCM1R_Q4DDMACH 0x00000010 +#define MTL_RQDCM1R_Q5DDMACH 0x00001000 +#define MTL_RQDCM1R_Q6DDMACH 0x00100000 +#define MTL_RQDCM1R_Q7DDMACH 0x10000000 + + +/* MTL traffic class register offsets + * Multiple traffic classes can be active. The first class has registers + * that begin at 0x1100. Each subsequent queue has registers that + * are accessed using an offset of 0x80 from the previous queue. + */ +/* NO TRAFFIC CLASS REGISTER DESCRIPTION */ +#if 1 +#define MTL_TC_BASE MTL_Q_BASE +#define MTL_TC_INC MTL_Q_INC + +#define MTL_TC_ETSCR 0x10 +#define MTL_TC_ETSSR 0x14 +#define MTL_TC_QWR 0x18 + +/* MTL traffic class register entry bit positions and sizes */ +#define MTL_TC_ETSCR_TSA_POS 0 +#define MTL_TC_ETSCR_TSA_LEN 2 +#define MTL_TC_QWR_QW_POS 0 +#define MTL_TC_QWR_QW_LEN 21 + +/* MTL traffic class register value */ +#define MTL_TSA_SP 0x00 +#define MTL_TSA_ETS 0x02 +#endif + +/* DMA register offsets */ +#define DMA_MR 0x1000 +#define DMA_SBMR 0x1004 +#define DMA_ISR 0x1008 +#define DMA_DSR0 0x100c +#define DMA_DSR1 0x1010 +#define DMA_DSR2 0x1014 +#define DMA_ECC_INT_SR 0x1088 + +/* DMA register entry bit positions and sizes */ +#define DMA_ISR_MACIS_POS 17 +#define DMA_ISR_MACIS_LEN 1 +#define DMA_ISR_MTLIS_POS 16 +#define DMA_ISR_MTLIS_LEN 1 +#define DMA_MR_SWR_POS 0 +#define DMA_MR_SWR_LEN 1 +#define DMA_MR_INTM_POS 16 +#define DMA_MR_INTM_LEN 2 +#define DMA_MR_QUREAD_POS 19 +#define DMA_MR_QUREAD_LEN 1 + +#define DMA_SBMR_EN_LPI_POS 31 +#define DMA_SBMR_EN_LPI_LEN 1 +#define DMA_SBMR_LPI_XIT_PKT_POS 30 +#define DMA_SBMR_LPI_XIT_PKT_LEN 1 +#define DMA_SBMR_WR_OSR_LMT_POS 24 +#define DMA_SBMR_WR_OSR_LMT_LEN 6 +#define DMA_SBMR_RD_OSR_LMT_POS 16 +#define DMA_SBMR_RD_OSR_LMT_LEN 8 +#define DMA_SBMR_EAME_POS 11 +#define DMA_SBMR_EAME_LEN 1 +#define DMA_SBMR_AALE_POS 10 +#define DMA_SBMR_AALE_LEN 1 +#define DMA_SBMR_BLEN_4_POS 1 +#define DMA_SBMR_BLEN_4_LEN 1 +#define DMA_SBMR_BLEN_8_POS 2 +#define DMA_SBMR_BLEN_8_LEN 1 +#define DMA_SBMR_BLEN_16_POS 3 +#define DMA_SBMR_BLEN_16_LEN 1 +#define DMA_SBMR_BLEN_32_POS 4 +#define DMA_SBMR_BLEN_32_LEN 1 +#define DMA_SBMR_BLEN_64_POS 5 +#define DMA_SBMR_BLEN_64_LEN 1 +#define DMA_SBMR_BLEN_128_POS 6 +#define DMA_SBMR_BLEN_128_LEN 1 +#define DMA_SBMR_BLEN_256_POS 7 +#define DMA_SBMR_BLEN_256_LEN 1 +#define DMA_SBMR_FB_POS 0 +#define DMA_SBMR_FB_LEN 1 + +/* DMA register values */ +#define DMA_DSR_RPS_LEN 4 +#define DMA_DSR_TPS_LEN 4 +#define DMA_DSR_Q_LEN (DMA_DSR_RPS_LEN + DMA_DSR_TPS_LEN) +#define DMA_DSR0_TPS_START 12 +#define DMA_DSRX_FIRST_QUEUE 3 +#define DMA_DSRX_INC 4 +#define DMA_DSRX_QPR 4 // no definition +#define DMA_DSRX_TPS_START 4 +#define DMA_TPS_STOPPED 0x00 +#define DMA_TPS_SUSPENDED 0x06 + +/* DMA channel register offsets + * Multiple channels can be active. The first channel has registers + * that begin at 0x1100. Each subsequent channel has registers that + * are accessed using an offset of 0x80 from the previous channel. + */ +#define DMA_CH_BASE 0x1100 +#define DMA_CH_INC 0x80 + +#define DMA_CH_CR 0x00 +#define DMA_CH_TCR 0x04 +#define DMA_CH_RCR 0x08 +#define DMA_CH_TDLR_HI 0x10 +#define DMA_CH_TDLR_LO 0x14 +#define DMA_CH_RDLR_HI 0x18 +#define DMA_CH_RDLR_LO 0x1c +#define DMA_CH_TDTR_LO 0x20 +#define DMA_CH_RDTR_LO 0x28 +#define DMA_CH_TDRLR 0x2c +#define DMA_CH_RDRLR 0x30 +#define DMA_CH_IER 0x34 +#define DMA_CH_RIWT 0x38 +#define DMA_CH_SR 0x60 + +/* DMA channel register entry bit positions and sizes */ +#define DMA_CH_CR_PBLX8_POS 16 +#define DMA_CH_CR_PBLX8_LEN 1 +#define DMA_CH_CR_SPH_POS 24 +#define DMA_CH_CR_SPH_LEN 1 +#define DMA_CH_IER_AIE_POS 14 +#define DMA_CH_IER_AIE_LEN 1 +#define DMA_CH_IER_FBEE_POS 12 +#define DMA_CH_IER_FBEE_LEN 1 +#define DMA_CH_IER_NIE_POS 15 +#define DMA_CH_IER_NIE_LEN 1 +#define DMA_CH_IER_RBUE_POS 7 +#define DMA_CH_IER_RBUE_LEN 1 +#define DMA_CH_IER_RIE_POS 6 +#define DMA_CH_IER_RIE_LEN 1 +#define DMA_CH_IER_RSE_POS 8 +#define DMA_CH_IER_RSE_LEN 1 +#define DMA_CH_IER_TBUE_POS 2 +#define DMA_CH_IER_TBUE_LEN 1 +#define DMA_CH_IER_TIE_POS 0 +#define DMA_CH_IER_TIE_LEN 1 +#define DMA_CH_IER_TXSE_POS 1 +#define DMA_CH_IER_TXSE_LEN 1 +#define DMA_CH_RCR_PBL_POS 16 +#define DMA_CH_RCR_PBL_LEN 6 +#define DMA_CH_RCR_RBSZ_POS 1 +#define DMA_CH_RCR_RBSZ_LEN 14 +#define DMA_CH_RCR_SR_POS 0 +#define DMA_CH_RCR_SR_LEN 1 +#define DMA_CH_RIWT_RWT_POS 0 +#define DMA_CH_RIWT_RWT_LEN 8 +#define DMA_CH_SR_FBE_POS 12 +#define DMA_CH_SR_FBE_LEN 1 +#define DMA_CH_SR_RBU_POS 7 +#define DMA_CH_SR_RBU_LEN 1 +#define DMA_CH_SR_RI_POS 6 +#define DMA_CH_SR_RI_LEN 1 +#define DMA_CH_SR_RPS_POS 8 +#define DMA_CH_SR_RPS_LEN 1 +#define DMA_CH_SR_TBU_POS 2 +#define DMA_CH_SR_TBU_LEN 1 +#define DMA_CH_SR_TI_POS 0 +#define DMA_CH_SR_TI_LEN 1 +#define DMA_CH_SR_TPS_POS 1 +#define DMA_CH_SR_TPS_LEN 1 +#define DMA_CH_TCR_OSP_POS 4 +#define DMA_CH_TCR_OSP_LEN 1 +#define DMA_CH_TCR_PBL_POS 16 +#define DMA_CH_TCR_PBL_LEN 6 +#define DMA_CH_TCR_ST_POS 0 +#define DMA_CH_TCR_ST_LEN 1 +#define DMA_CH_TCR_TSE_POS 12 +#define DMA_CH_TCR_TSE_LEN 1 + +/* DMA channel register values */ +#define DMA_OSP_DISABLE 0x00 +#define DMA_OSP_ENABLE 0x01 +#define DMA_PBL_1 1 +#define DMA_PBL_2 2 +#define DMA_PBL_4 4 +#define DMA_PBL_8 8 +#define DMA_PBL_16 16 +#define DMA_PBL_32 32 +#define DMA_PBL_64 64 +#define DMA_PBL_128 128 +#define DMA_PBL_256 256 +#define DMA_PBL_X8_DISABLE 0x00 +#define DMA_PBL_X8_ENABLE 0x01 + +/* Descriptor/Packet entry bit positions and sizes */ +#define RX_PACKET_ERRORS_CRC_POS 2 +#define RX_PACKET_ERRORS_CRC_LEN 1 +#define RX_PACKET_ERRORS_FRAME_POS 3 +#define RX_PACKET_ERRORS_FRAME_LEN 1 +#define RX_PACKET_ERRORS_LENGTH_POS 0 +#define RX_PACKET_ERRORS_LENGTH_LEN 1 +#define RX_PACKET_ERRORS_OVERRUN_POS 1 +#define RX_PACKET_ERRORS_OVERRUN_LEN 1 + +#define RX_PACKET_ATTRIBUTES_CSUM_DONE_POS 0 +#define RX_PACKET_ATTRIBUTES_CSUM_DONE_LEN 1 +#define RX_PACKET_ATTRIBUTES_VLAN_CTAG_POS 1 +#define RX_PACKET_ATTRIBUTES_VLAN_CTAG_LEN 1 +#define RX_PACKET_ATTRIBUTES_INCOMPLETE_POS 2 +#define RX_PACKET_ATTRIBUTES_INCOMPLETE_LEN 1 +#define RX_PACKET_ATTRIBUTES_CONTEXT_NEXT_POS 3 +#define RX_PACKET_ATTRIBUTES_CONTEXT_NEXT_LEN 1 +#define RX_PACKET_ATTRIBUTES_CONTEXT_POS 4 +#define RX_PACKET_ATTRIBUTES_CONTEXT_LEN 1 +#define RX_PACKET_ATTRIBUTES_RX_TSTAMP_POS 5 +#define RX_PACKET_ATTRIBUTES_RX_TSTAMP_LEN 1 +#define RX_PACKET_ATTRIBUTES_RSS_HASH_POS 6 +#define RX_PACKET_ATTRIBUTES_RSS_HASH_LEN 1 + +#define RX_NORMAL_DESC0_OVT_POS 0 +#define RX_NORMAL_DESC0_OVT_LEN 16 +#define RX_NORMAL_DESC2_HL_POS 0 +#define RX_NORMAL_DESC2_HL_LEN 10 +//#define RX_NORMAL_DESC3_CDA_POS 27// +#define RX_NORMAL_DESC3_CDA_LEN 1 +#define RX_NORMAL_DESC3_CTXT_POS 30 +#define RX_NORMAL_DESC3_CTXT_LEN 1 +#define RX_NORMAL_DESC3_ES_POS 15 +#define RX_NORMAL_DESC3_ES_LEN 1 +#define RX_NORMAL_DESC3_ETLT_POS 16 +#define RX_NORMAL_DESC3_ETLT_LEN 3 +#define RX_NORMAL_DESC3_FD_POS 29 +#define RX_NORMAL_DESC3_FD_LEN 1 +#define RX_NORMAL_DESC3_INTE_POS 30 +#define RX_NORMAL_DESC3_INTE_LEN 1 +//#define RX_NORMAL_DESC3_L34T_POS 20// +#define RX_NORMAL_DESC3_L34T_LEN 4 +#define RX_NORMAL_DESC3_LD_POS 28 +#define RX_NORMAL_DESC3_LD_LEN 1 +#define RX_NORMAL_DESC3_OWN_POS 31 +#define RX_NORMAL_DESC3_OWN_LEN 1 +#define RX_NORMAL_DESC3_BUF2V_POS 25 +#define RX_NORMAL_DESC3_BUF2V_LEN 1 +#define RX_NORMAL_DESC3_BUF1V_POS 24 +#define RX_NORMAL_DESC3_BUF1V_LEN 1 +#define RX_NORMAL_DESC3_PL_POS 0 +#define RX_NORMAL_DESC3_PL_LEN 15 +//#define RX_NORMAL_DESC3_RSV_POS 26 // +#define RX_NORMAL_DESC3_RSV_LEN 1 + +#define RX_NORMAL_DESC0_WB_IVT_POS 16 // Inner VLAN Tag. Valid only when Double VLAN tag processing and VLAN tag stripping are enabled. +#define RX_NORMAL_DESC0_WB_IVT_LEN 16 +#define RX_NORMAL_DESC0_WB_OVT_POS 0 // Outer VLAN Tag. +#define RX_NORMAL_DESC0_WB_OVT_LEN 16 +#define RX_NORMAL_DESC0_WB_OVT_VLANID_POS 0 // Outer VLAN ID. +#define RX_NORMAL_DESC0_WB_OVT_VLANID_LEN 12 +#define RX_NORMAL_DESC0_WB_OVT_CFI_POS 12 // Outer VLAN CFI. +#define RX_NORMAL_DESC0_WB_OVT_CFI_LEN 1 +#define RX_NORMAL_DESC0_WB_OVT_PRIO_POS 13 // Outer VLAN Priority. +#define RX_NORMAL_DESC0_WB_OVT_PRIO_LEN 3 + +#define RX_NORMAL_DESC1_WB_IPCE_POS 7 // IP Payload Error. +#define RX_NORMAL_DESC1_WB_IPCE_LEN 1 +#define RX_NORMAL_DESC1_WB_IPV6_POS 5 // IPV6 Header Present. +#define RX_NORMAL_DESC1_WB_IPV6_LEN 1 +#define RX_NORMAL_DESC1_WB_IPV4_POS 4 // IPV4 Header Present. +#define RX_NORMAL_DESC1_WB_IPV4_LEN 1 +#define RX_NORMAL_DESC1_WB_IPHE_POS 3 // IP Header Error. +#define RX_NORMAL_DESC1_WB_IPHE_LEN 1 +#define RX_NORMAL_DESC1_WB_PT_POS 0 // +#define RX_NORMAL_DESC1_WB_PT_LEN 3 + +#define RX_NORMAL_DESC2_WB_HF_POS 18 // Hash Filter Status. When this bit is set, it indicates that the packet passed the MAC address hash filter +#define RX_NORMAL_DESC2_WB_HF_LEN 1 +#define RX_NORMAL_DESC2_WB_DAF_POS 17 /* Destination Address Filter Fail. When Flexible RX Parser is disabled, and this bit is set, it indicates that the packet failed + the DA Filter in the MAC.*/ +#define RX_NORMAL_DESC2_WB_DAF_LEN 1 + +#define RX_NORMAL_DESC3_WB_LD_POS 28 +#define RX_NORMAL_DESC3_WB_LD_LEN 1 +#define RX_NORMAL_DESC3_WB_RS0V_POS 25 // When this bit is set, it indicates that the status in RDES0 is valid and it is written by the DMA. +#define RX_NORMAL_DESC3_WB_RS0V_LEN 1 +#define RX_NORMAL_DESC3_WB_CE_POS 24 // When this bit is set, it indicates that a Cyclic Redundancy Check (CRC) Error occurred on the +//received packet.This field is valid only when the LD bit of RDES3 is set. +#define RX_NORMAL_DESC3_WB_CE_LEN 1 + +#define RX_DESC3_L34T_IPV4_TCP 1 +#define RX_DESC3_L34T_IPV4_UDP 2 +#define RX_DESC3_L34T_IPV4_ICMP 3 +#define RX_DESC3_L34T_IPV6_TCP 9 +#define RX_DESC3_L34T_IPV6_UDP 10 +#define RX_DESC3_L34T_IPV6_ICMP 11 + +#define RX_DESC1_PT_UDP 1 +#define RX_DESC1_PT_TCP 2 +#define RX_DESC1_PT_ICMP 3 +#define RX_DESC1_PT_AV_TAG_DATA 6 +#define RX_DESC1_PT_AV_TAG_CTRL 7 +#define RX_DESC1_PT_AV_NOTAG_CTRL 5 + + + + +//#define RX_CONTEXT_DESC3_TSA_POS 4// +#define RX_CONTEXT_DESC3_TSA_LEN 1 +//#define RX_CONTEXT_DESC3_TSD_POS 6// +#define RX_CONTEXT_DESC3_TSD_LEN 1 + +#define TX_PACKET_ATTRIBUTES_CSUM_ENABLE_POS 0 +#define TX_PACKET_ATTRIBUTES_CSUM_ENABLE_LEN 1 +#define TX_PACKET_ATTRIBUTES_TSO_ENABLE_POS 1 +#define TX_PACKET_ATTRIBUTES_TSO_ENABLE_LEN 1 +#define TX_PACKET_ATTRIBUTES_VLAN_CTAG_POS 2 +#define TX_PACKET_ATTRIBUTES_VLAN_CTAG_LEN 1 +#define TX_PACKET_ATTRIBUTES_PTP_POS 3 +#define TX_PACKET_ATTRIBUTES_PTP_LEN 1 + +#define TX_CONTEXT_DESC2_MSS_POS 0 +#define TX_CONTEXT_DESC2_MSS_LEN 14 +#define TX_CONTEXT_DESC2_IVLTV_POS 16 // Inner VLAN Tag. +#define TX_CONTEXT_DESC2_IVLTV_LEN 16 + +#define TX_CONTEXT_DESC3_CTXT_POS 30 +#define TX_CONTEXT_DESC3_CTXT_LEN 1 +#define TX_CONTEXT_DESC3_TCMSSV_POS 26 +#define TX_CONTEXT_DESC3_TCMSSV_LEN 1 +#define TX_CONTEXT_DESC3_IVTIR_POS 18 +#define TX_CONTEXT_DESC3_IVTIR_LEN 2 +#define TX_CONTEXT_DESC3_IVTIR_INSERT 2 // Insert an inner VLAN tag with the tag value programmed in the MAC_Inner_VLAN_Incl register or context descriptor. +#define TX_CONTEXT_DESC3_IVLTV_POS 17 // Indicates that the Inner VLAN TAG, IVLTV field of context TDES2 is valid. +#define TX_CONTEXT_DESC3_IVLTV_LEN 1 +#define TX_CONTEXT_DESC3_VLTV_POS 16 // Indicates that the VT field of context TDES3 is valid. +#define TX_CONTEXT_DESC3_VLTV_LEN 1 +#define TX_CONTEXT_DESC3_VT_POS 0 +#define TX_CONTEXT_DESC3_VT_LEN 16 + +#define TX_NORMAL_DESC2_HL_B1L_POS 0 // Header Length or Buffer 1 Length. +#define TX_NORMAL_DESC2_HL_B1L_LEN 14 +#define TX_NORMAL_DESC2_IC_POS 31 // Interrupt on Completion. +#define TX_NORMAL_DESC2_IC_LEN 1 +#define TX_NORMAL_DESC2_TTSE_POS 30 // Transmit Timestamp Enable or External TSO Memory Write Enable. +#define TX_NORMAL_DESC2_TTSE_LEN 1 +#define TX_NORMAL_DESC2_VTIR_POS 14 //LAN Tag Insertion or Replacement. +#define TX_NORMAL_DESC2_VTIR_LEN 2 +#define TX_NORMAL_DESC2_VLAN_INSERT 0x2 + +#define TX_NORMAL_DESC3_TCPPL_POS 0 +#define TX_NORMAL_DESC3_TCPPL_LEN 18 +#define TX_NORMAL_DESC3_FL_POS 0 // Frame Length or TCP Payload Length. +#define TX_NORMAL_DESC3_FL_LEN 15 +#define TX_NORMAL_DESC3_CIC_POS 16 /* Checksum Insertion Control or TCP Payload Length. + 2'b00: Checksum Insertion Disabled. + 2'b01: Only IP header checksum calculation and insertion are enabled. + 2'b10: IP header checksum and payload checksum calculation and insertion are + enabled, but pseudo-header checksum is not calculated in hardware. + 2'b11: IP Header checksum and payload checksum calculation and insertion are + enabled, and pseudo - header checksum is calculated in hardware. */ +#define TX_NORMAL_DESC3_CIC_LEN 2 +#define TX_NORMAL_DESC3_TSE_POS 18 // TCP Segmentation Enable. +#define TX_NORMAL_DESC3_TSE_LEN 1 +#define TX_NORMAL_DESC3_TCPHDRLEN_POS 19 /* THL: TCP/UDP Header Length.If the TSE bit is set, this field contains + the length of the TCP / UDP header.The minimum value of this field must + be 5 for TCP header.The value must be equal to 2 for UDP header. This + field is valid only for the first descriptor.*/ +#define TX_NORMAL_DESC3_TCPHDRLEN_LEN 4 +#define TX_NORMAL_DESC3_CPC_POS 26 // CRC Pad Control. +#define TX_NORMAL_DESC3_CPC_LEN 2 +#define TX_NORMAL_DESC3_LD_POS 28 // Last Descriptor. +#define TX_NORMAL_DESC3_LD_LEN 1 +#define TX_NORMAL_DESC3_FD_POS 29 // First Descriptor. +#define TX_NORMAL_DESC3_FD_LEN 1 +#define TX_NORMAL_DESC3_CTXT_POS 30 // Context Type.This bit should be set to 1'b0 for normal descriptor. +#define TX_NORMAL_DESC3_CTXT_LEN 1 +#define TX_NORMAL_DESC3_OWN_POS 31 // Own Bit. +#define TX_NORMAL_DESC3_OWN_LEN 1 + +/* for ephy generic register definitions */ +#define FXGMAC_EPHY_REGS_LEN 32 //32 ethernet phy registers under spec + +#define REG_MII_BMCR 0x00 /* Basic mode control register */ +#define PHY_CR_RESET_POS 15 +#define PHY_CR_RESET_LEN 1 +#define PHY_CR_SPEED_SEL_H_POS 6 +#define PHY_CR_SPEED_SEL_H_LEN 1 +#define PHY_CR_SPEED_SEL_L_POS 13 +#define PHY_CR_SPEED_SEL_L_LEN 1 +#define PHY_CR_AUTOENG_POS 12 +#define PHY_CR_AUTOENG_LEN 1 +#define PHY_CR_RE_AUTOENG_POS 9 +#define PHY_CR_RE_AUTOENG_LEN 1 +#define PHY_CR_DUPLEX_POS 8 +#define PHY_CR_DUPLEX_LEN 1 +#define REG_MII_BMCR_ENABLE_LOOPBACK 0x8140 +#define REG_MII_BMCR_DISABLE_LOOPBACK 0x9140 +#define REG_MII_BMSR 0x01 /* Basic mode status register */ +#define REG_MII_PHYSID1 0x02 /* PHYS ID 1 */ +#define REG_MII_PHYSID2 0x03 /* PHYS ID 2 */ +#define REG_MII_ADVERTISE 0x04 /* Advertisement control reg */ +#define PHY_MII_ADVERTISE_ASYPAUSE_POS 11 +#define PHY_MII_ADVERTISE_ASYPAUSE_LEN 1 +#define PHY_MII_ADVERTISE_PAUSE_POS 10 +#define PHY_MII_ADVERTISE_PAUSE_LEN 1 +#define PHY_MII_ADVERTISE_100FULL_POS 8 +#define PHY_MII_ADVERTISE_100FULL_LEN 1 +#define PHY_MII_ADVERTISE_100HALF_POS 7 +#define PHY_MII_ADVERTISE_100HALF_LEN 1 +#define PHY_MII_ADVERTISE_10FULL_POS 6 +#define PHY_MII_ADVERTISE_10FULL_LEN 1 +#define PHY_MII_ADVERTISE_10HALF_POS 5 +#define PHY_MII_ADVERTISE_10HALF_LEN 1 +#define REG_MII_LPA 0x05 /* Link partner ability reg */ +#define REG_MII_EXPANSION 0x06 /* Expansion register */ +#define REG_MII_NEXT_PAGE 0x07 /* Next page register */ +#define REG_MII_LPR_NEXT_PAGE 0x08 /* LPR next page register */ +#define REG_MII_CTRL1000 0x09 /* 1000BASE-T control */ +#define PHY_MII_CTRL1000_1000FULL_POS 9 +#define PHY_MII_CTRL1000_1000FULL_LEN 1 +#define PHY_MII_CTRL1000_1000HALF_POS 8 +#define PHY_MII_CTRL1000_1000HALF_LEN 1 +#define REG_MII_STAT1000 0x0A /* 1000BASE-T status */ +#define PHY_MII_STAT1000_CFG_ERROR_POS 15 +#define PHY_MII_STAT1000_CFG_ERROR_LEN 1 + +#define REG_MII_MMD_CTRL 0x0D /* MMD access control register */ +#define REG_MII_MMD_DATA 0x0E /* MMD access data register */ + +#define REG_MII_ESTATUS 0x0F /* Extended Status */ + +#define REG_MII_SPEC_CTRL 0x10 /* PHY specific func control */ +#define PHY_MII_SPEC_CTRL_CRS_ON_POS 3 +#define PHY_MII_SPEC_CTRL_CRS_ON_LEN 1 +#define REG_MII_SPEC_STATUS 0x11 /* PHY specific status */ +#define PHY_MII_SPEC_DUPLEX_POS 13 +#define PHY_MII_SPEC_DUPLEX_LEN 1 +#define REG_MII_INT_MASK 0x12 /* Interrupt mask register */ + +#ifdef AISC_MODE +#define PHY_INT_MASK_LINK_UP_POS 10 +#define PHY_INT_MASK_LINK_UP_LEN 1 +#define PHY_INT_MASK_LINK_DOWN_POS 11 +#define PHY_INT_MASK_LINK_DOWN_LEN 1 +#else //FPGA_MODE +#define PHY_INT_MASK_LINK_UP_POS 1 +#define PHY_INT_MASK_LINK_UP_LEN 1 +#define PHY_INT_MASK_LINK_DOWN_POS 0 +#define PHY_INT_MASK_LINK_DOWN_LEN 1 +#endif +#define REG_MII_INT_STATUS 0x13 /* Interrupt status register */ +#define PHY_INT_STAT_LINK_UP_POS 1 +#define PHY_INT_STAT_LINK_UP_LEN 1 +#define PHY_INT_STAT_LINK_DOWN_POS 0 +#define PHY_INT_STAT_LINK_DOWN_LEN 1 +#define REG_MII_DOWNG_CTRL 0x14 /* Speed auto downgrade control*/ +#define REG_MII_RERRCOUNTER 0x15 /* Receive error counter */ + +#define REG_MII_EXT_ADDR 0x1E /* Extended reg's address */ +#define REG_MII_EXT_DATA 0x1F /* Extended reg's date */ + +#define FXGMAC_EPHY_ID_MASK 0x0000ffff + +/* for ephy link capability + * Advertisement control register(0x04) + */ + /* Advertisement control register(0x04) */ +#define FXGMAC_ADVERTISE_SLCT 0x001f /* Selector bits */ +#define FXGMAC_ADVERTISE_CSMA 0x0001 /* Only selector supported */ +#define FXGMAC_ADVERTISE_1000FULL 0x0004 /* trt fir 1000BASE-T full duplex */ +#define FXGMAC_ADVERTISE_1000HALF 0x0008 /* try for 1000BASE-T half duplex */ +#define FXGMAC_ADVERTISE_10HALF 0x0020 /* Try for 10mbps half-duplex */ +#define FXGMAC_ADVERTISE_10FULL 0x0040 /* Try for 10mbps full-duplex */ +#define FXGMAC_ADVERTISE_100HALF 0x0080 /* Try for 100mbps half-duplex */ +#define FXGMAC_ADVERTISE_100FULL 0x0100 /* Try for 100mbps full-duplex */ +#define FXGMAC_ADVERTISE_100BASE4 0x0200 /* Try for 100mbps 4k packets */ +#define FXGMAC_ADVERTISE_PAUSE_CAP 0x0400 /* Try for pause */ +#define FXGMAC_ADVERTISE_PAUSE_ASYM 0x0800 /* Try for asymetric pause */ +#define FXGMAC_ADVERTISE_RESV 0x1000 /* Unused... */ +#define FXGMAC_ADVERTISE_RFAULT 0x2000 /* Say we can detect faults */ +#define FXGMAC_ADVERTISE_LPACK 0x4000 /* Ack link partners response */ +#define FXGMAC_ADVERTISE_NPAGE 0x8000 /* Next page bit */ + +/* 1000BASE-T Control register(0x09) */ +#define REG_BIT_ADVERTISE_1000FULL 0x0200 /* Advertise 1000BASE-T full duplex */ +#define REG_BIT_ADVERTISE_1000HALF 0x0100 /* Advertise 1000BASE-T half duplex */ + +#define REG_BIT_ADVERTISE_1000_CAP (REG_BIT_ADVERTISE_1000FULL | REG_BIT_ADVERTISE_1000HALF) +#define REG_BIT_ADVERTISE_100_10_CAP (FXGMAC_ADVERTISE_100FULL | FXGMAC_ADVERTISE_100HALF | FXGMAC_ADVERTISE_10FULL | FXGMAC_ADVERTISE_10HALF ) + +#ifndef SPEED_1000M +#define SPEED_1000M 1000 +#endif +#ifndef SPEED_100M +#define SPEED_100M 100 +#endif +#ifndef SPEED_10M +#define SPEED_10M 10 +#endif + +#ifndef SPEED_UNKNOWN +#define SPEED_UNKNOWN 0xffff +#endif + +#ifndef DUPLEX_FULL +#define DUPLEX_FULL 1 +#endif +#ifndef DUPLEX_HALF +#define DUPLEX_HALF 0 +#endif + +#ifndef BIT +#define BIT(n) (0x1<<(n)) +#endif + +#ifndef FUXI_EPHY_SPEED_MODE_BIT +#define FUXI_EPHY_SPEED_MODE 0xc000 +#define FUXI_EPHY_DUPLEX 0x2000 +#define FUXI_EPHY_SPEED_MODE_BIT 14 +#define FUXI_EPHY_DUPLEX_BIT 13 +#define FUXI_EPHY_LINK_STATUS_BIT 10 + +#endif + +#define FUXI_EPHY_SMI_SEL_PHY 0x0 +#define FUXI_EPHY_SMI_SEL_SDS_QSGMII 0x02 +#define FUXI_EPHY_SMI_SEL_SDS_SGMII 0x03 + +#define REG_MII_EXT_ANALOG_CFG3 0x52 +#define MII_EXT_ANALOG_CFG3_ADC_START_CFG_POS 14 +#define MII_EXT_ANALOG_CFG3_ADC_START_CFG_LEN 2 +// VGA bandwidth, default is 2 after reset. Set to 0 to mitigate unstable issue in 130m. +#define MII_EXT_ANALOG_CFG3_ADC_START_CFG_DEFAULT 0x0 +#define MII_EXT_ANALOG_CFG3_ON_TIME_CFG_POS 12 +#define MII_EXT_ANALOG_CFG3_ON_TIME_CFG_LEN 2 +#define MII_EXT_ANALOG_CFG3_VGA_AMP_GAIN_CFG_POS 8 +#define MII_EXT_ANALOG_CFG3_VGA_AMP_GAIN_CFG_LEN 4 +#define MII_EXT_ANALOG_CFG3_VGA_IBIAS_CFG_POS 4 +#define MII_EXT_ANALOG_CFG3_VGA_IBIAS_CFG_LEN 3 +#define MII_EXT_ANALOG_CFG3_OCP_CFG_POS 2 +#define MII_EXT_ANALOG_CFG3_OCP_CFG_LEN 2 +#define MII_EXT_ANALOG_CFG3_VGA_LPF_CFG_POS 0 +#define MII_EXT_ANALOG_CFG3_VGA_LPF_CFG_LEN 2 + +#define REG_MII_EXT_PMA_DEBUG_KCOEF 0x78 +#define MII_EXT_PMA_DEBUG_KCOEF_IPR_KCOEF_GE_LNG_POS 8 +#define MII_EXT_PMA_DEBUG_KCOEF_IPR_KCOEF_GE_LNG_LEN 6 +// After reset, it's 0x10. We need change it to 0x20 to make it easier to linkup in gigabit mode with long cable. +#define MII_EXT_PMA_DEBUG_KCOEF_IPR_KCOEF_GE_LNG_DEFAULT 0x20 +#define MII_EXT_PMA_DEBUG_KCOEF_IPR_KCOEF_DEFAULT_POS 0 +#define MII_EXT_PMA_DEBUG_KCOEF_IPR_KCOEF_DEFAULT_LEN 6 + +#define REG_MII_EXT_LPBK_REG 0x0a +#define REG_MII_EXT_LPBK_REG_ENABLE_LOOPBACK 0x3a18 +#define REG_MII_EXT_LPBK_REG_CLEAN_LOOPBACK 0x3a08 +#define REG_MII_EXT_SLEEP_CONTROL_REG 0x27 +#define REG_MII_EXT_SLEEP_REG_ENABLE_LOOPBACK 0x6812 +#define REG_MII_EXT_SLEEP_REG_CLEAN_LOOPBACK 0xe812 + +#define REG_MII_EXT_ANALOG_CFG2 0x51 +#define REG_MII_EXT_ANALOG_CFG2_LED_VALUE 0x4a9 +#define REG_MII_EXT_ANALOG_CFG8 0x57 +#define REG_MII_EXT_ANALOG_CFG8_LED_VALUE 0x274c + +#define REG_MII_EXT_COMMON_LED_CFG 0xA00B +#define REG_MII_EXT_COMMON_LED0_CFG 0xA00C +#define REG_MII_EXT_COMMON_LED0_CFG_VALUE_SOLUTION0 0x2600 +#define REG_MII_EXT_COMMON_LED0_CFG_VALUE_SOLUTION1 0x00 +#define REG_MII_EXT_COMMON_LED0_CFG_VALUE_SOLUTION2 0x20 +#define REG_MII_EXT_COMMON_LED0_CFG_VALUE_SOLUTION3 0x2600 +#define REG_MII_EXT_COMMON_LED1_CFG 0xA00D +#define REG_MII_EXT_COMMON_LED1_CFG_VALUE_SOLUTION0 0x1800 +#define REG_MII_EXT_COMMON_LED1_CFG_VALUE_SOLUTION1 0x00 +#define REG_MII_EXT_COMMON_LED1_CFG_VALUE_SOLUTION2 0x40 +#define REG_MII_EXT_COMMON_LED2_CFG 0xA00E +#define REG_MII_EXT_COMMON_LED2_CFG_VALUE_SOLUTION0 0x00 +#define REG_MII_EXT_COMMON_LED2_CFG_VALUE_SOLUTION2 0x07 +#define REG_MII_EXT_COMMON_LED2_CFG_VALUE_SOLUTION3 0x20 +#define REG_MII_EXT_COMMON_LED2_CFG_VALUE_SOLUTION4 0x1800 +#define REG_MII_EXT_COMMON_LED_BLINK_CFG 0xA00F +#define REG_MII_EXT_COMMON_LED_BLINK_CFG_SOLUTION2 0x0F + +#define REG_MII_EXT_COMMON_LED0_CFG_VALUE_SLEEP_SOLUTION3 0x2600 + +#define REG_MII_EXT_PKG_CFG0 0xA0 +#define REG_MII_EXT_PKG_CHECK_POS 14 +#define REG_MII_EXT_PKG_CHECK_LEN 2 +#define REG_MII_EXT_PKG_ENABLE_CHECK 0x2 +#define REG_MII_EXT_PKG_DISABLE_CHECK 0x1 +#define REG_MII_EXT_SLEEP_CONTROL1 0x27 +#define MII_EXT_SLEEP_CONTROL1_EN_POS 15 +#define MII_EXT_SLEEP_CONTROL1_EN_LEN 1 +#define MII_EXT_SLEEP_CONTROL1_PLLON_IN_SLP_POS 14 +#define MII_EXT_SLEEP_CONTROL1_PLLON_IN_SLP_LEN 1 +#define REG_MII_EXT_PKG_RX_VALID0 0xA3 +#define REG_MII_EXT_REG_RX_VALID1 0xA4 +#define REG_MII_EXT_REG_RX_OS0 0xA5 +#define REG_MII_EXT_REG_RX_OS1 0xA6 +#define REG_MII_EXT_REG_RX_US0 0xA7 +#define REG_MII_EXT_REG_RX_US1 0xA8 +#define REG_MII_EXT_REG_RX_ERR 0xA9 +#define REG_MII_EXT_REG_RX_0S_BAD 0xAA +#define REG_MII_EXT_REG_RX_FRAGMENT 0xAB +#define REG_MII_EXT_REG_RX_NOSFD 0xAC +#define REG_MII_EXT_REG_TX_VALID0 0xAD +#define REG_MII_EXT_REG_TX_VALID1 0xAE +#define REG_MII_EXT_REG_TX_OS0 0xAF +#define REG_MII_EXT_REG_TX_OS1 0xB0 +#define REG_MII_EXT_REG_TX_US0 0xB1 +#define REG_MII_EXT_REG_TX_US1 0xB2 +#define REG_MII_EXT_REG_TX_ERR 0xB3 +#define REG_MII_EXT_REG_TX_OS_BAD 0xB4 +#define REG_MII_EXT_REG_TX_FRAGMENT 0xB5 +#define REG_MII_EXT_REG_TX_NOSFD 0xB6 +#define REG_MII_EXT_REG_PMA_DBG0_ADC 0x13 +#define REG_MII_EXT_ENABLE_GIGA_POWER_SAVING_FOR_SHORT_CABLE 0x3538 +#define REG_MII_EXT_REG_CLD_REG0 0x3A0 +#define REG_MII_EXT_ENABLE_CLD_NP_WP 0xEB24 +#define REG_MII_EXT_REG_CLD_REG1 0x3CC +#define REG_MII_EXT_ENABLE_CLD_GT_HT_BT 0x7001 +#define REG_MMD_EEE_ABILITY_REG 0x3C +#define REG_MMD_EEE_ABILITY_VALUE 0x06 + +/* Below registers don't belong to GMAC, it has zero offset, not 0x2000 offset. mem_base + REG_XXX. */ +/***When issue happens, driver write this register to trigger pcie sniffer. ***/ +#define REG_PCIE_TRIGGER 0x1000 +#define PCIE_TRIGGER_CODE_TX_HANG 0x00000002 +#define PCIE_TRIGGER_CODE_LINKDOWN 0x00000003 + + +#define MGMT_EPHY_CTRL 0x1004 +/* 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.0-reset, 1-unreset. Should be set to 1 before use phy. +*/ +#define MGMT_EPHY_CTRL_RESET_POS 0 +#define MGMT_EPHY_CTRL_RESET_LEN 1 +#define MGMT_EPHY_CTRL_STA_EPHY_RESET 0 // 0: reset state. +#define MGMT_EPHY_CTRL_STA_EPHY_RELEASE 1 // 1: release state. +#define MGMT_EPHY_CTRL_STA_EPHY_LINKUP 2 // 1: link up; 0: link down. +#define MGMT_EPHY_CTRL_STA_EPHY_LINKUP_POS 1 +#define MGMT_EPHY_CTRL_STA_EPHY_LINKUP_LEN 1 +#define MGMT_EPHY_CTRL_STA_EPHY_DUPLEX_POS 2 // ephy duplex +#define MGMT_EPHY_CTRL_STA_EPHY_DUPLEX_LEN 1 // + +#define MGMT_EPHY_CTRL_STA_SPEED_POS 3 +#define MGMT_EPHY_CTRL_STA_SPEED_LEN 2 +#define MGMT_EPHY_CTRL_STA_SPEED_MASK 0x18 + +#define MGMT_EPHY_CTRL_ERROR_VAULE 0xFFFFFFFF + +#define MGMT_PCIE_EP_CTRL 0x1008 + +#define MGMT_PCIE_EP_CTRL_DBI_CS_EN_POS 0 +#define MGMT_PCIE_EP_CTRL_DBI_CS_EN_LEN 1 + +#define MGMT_PCIE_CFG_CTRL 0x8BC +#define PCIE_CFG_CTRL_DEFAULT_VAL 0x7ff40 + +#define MGMT_PCIE_CFG_CTRL_CS_EN_POS 0 +#define MGMT_PCIE_CFG_CTRL_CS_EN_LEN 1 + +/***power management ***/ +#define WOL_CTL 0x100C +#define WOL_PKT_EN_POS 1 //set means magic and remote packet wakeup enable +#define WOL_PKT_EN_LEN 1 +#define WOL_LINKCHG_EN_POS 0 //set means link change wakeup enable +#define WOL_LINKCHG_EN_LEN 1 + +#define OOB_WOL_CTRL 0x1010 +#define OOB_WOL_CTRL_DIS_POS 0 +#define OOB_WOL_CTRL_DIS_LEN 1 + +#define MGMT_INT_CTRL0 0x1100 +/* b3:0 per rx ch interrupt + * b7:4 per tx ch interrupt + * b8 Safety interrupt signal for un-correctable error + * b9 Safety interrupt signal for correctable error + * b10 Interrupt signal to host system + * b11 Magic Packet Received or Remote Wake-up Packet Received + * b12 ethernet phy interrupt + */ + +/* MAC management registers bit positions and sizes */ +#define MGMT_INT_CTRL0_INT_MASK_POS 16 +#define MGMT_INT_CTRL0_INT_MASK_LEN 16 +#define MGMT_INT_CTRL0_INT_MASK_MASK 0xFFFF +#define MGMT_INT_CTRL0_INT_MASK_RXCH 0xF +#define MGMT_INT_CTRL0_INT_MASK_TXCH 0x10 +#define MGMT_INT_CTRL0_INT_MASK_EX_PMT 0xF7FF +#define MGMT_INT_CTRL0_INT_MASK_DISABLE 0xF000 + +#define MGMT_INT_CTRL0_INT_STATUS_POS 0 +#define MGMT_INT_CTRL0_INT_STATUS_LEN 16 +#define MGMT_INT_CTRL0_INT_STATUS_MASK 0xFFFF +#define MGMT_INT_CTRL0_INT_STATUS_RX 0x0001 +#define MGMT_INT_CTRL0_INT_STATUS_TX 0x0010 +#define MGMT_INI_CTRL0_INT_STATUS_TX_INVERSE 0xFFEF +#define MGMG_INT_CTRL0_INT_STATUS_PHY_INVERSE 0xFFDF +#define MGMT_INT_CTRL0_INT_STATUS_PHY 0x0020 + +#define MGMT_INT_CTRL0_INT_MASK_RXCH_POS 16 +#define MGMT_INT_CTRL0_INT_STATUS_RXCH_POS 0 +#define MGMT_INT_CTRL0_INT_STATUS_RXCH_LEN 4 +#define MGMT_INT_CTRL0_INT_STATUS_RXCH_MASK 0xF +#define MGMT_INT_CTRL0_INT_STATUS_RXTX_LEN 5 +#define MGMT_INT_CTRL0_INT_STATUS_RXTX_MASK 0x1F +#define MGMT_INT_CTRL0_INT_STATUS_RXTXPHY_MASK 0x3F + +#define MGMT_INT_CTRL0_INT_MASK_TXCH_POS 20 +#define MGMT_INT_CTRL0_INT_STATUS_TXCH_POS 4 +#define MGMT_INT_CTRL0_INT_STATUS_TXCH_LEN 1 +#define MGMT_INT_CTRL0_INT_STATUS_TXCH_MASK 0x1 + + +/* Interrupt Ctrl1 */ +#define INT_CTRL1 0x1104 +#define INT_CTRL1_TMR_CNT_CFG_MAX_POS 0 /* Timer counter cfg max. Default 0x19, 1us. */ +#define INT_CTRL1_TMR_CNT_CFG_MAX_LEN 10 +#define INT_CTRL1_TMR_CNT_CFG_DEF_VAL 0x19 +#define INT_CTRL1_MSI_AIO_EN_POS 16 +#define INT_CTRL1_MSI_AIO_EN_LEN 1 + +/* Interrupt Moderation */ +#define INT_MOD 0x1108 +#define INT_MOD_TX_POS 16 +#define INT_MOD_TX_LEN 12 +#define INT_MOD_RX_POS 0 +#define INT_MOD_RX_LEN 12 +#define INT_MOD_IN_US 200 /*in us*/ + +/* PCIE LTR 2 working modes: +Two working mode: +1. SW trigger +LTR idle threshold timer set as 0, enable LTR enable will trigger one LTR message +Note: PCIe cfg enable should set in initilization before enable LTR. +2. HW auto trigger +LTR idle threshold timer set as one non-zero value, HW monitor system status, +when system idle timer over threshold, HW send out LTR message +system exit idle state, send out one LTR exit message. +*/ +#define LTR_CTRL 0x1130 +#define LTR_CTRL_IDLE_THRE_TIMER_POS 16 +#define LTR_CTRL_IDLE_THRE_TIMER_LEN 14 /* in 8ns units*/ +#define LTR_CTRL_IDLE_THRE_TIMER_VAL 0x3FFF +#define LTR_CTRL_EN_POS 0 +#define LTR_CTRL_EN_LEN 1 + +#define LTR_CTRL1 0x1134 /* LTR latency message, only for SW enable. */ +#define LTR_CTRL1_LTR_MSG_POS 0 +#define LTR_CTRL1_LTR_MSG_LEN 32 + +#define LTR_CTRL2 0x1138 +#define LTR_CTRL2_DBG_DATA_POS 0 +#define LTR_CTRL2_DBG_DATA_LEN 32 + +#define LTR_IDLE_ENTER 0x113C /* LTR_CTRL3, LTR latency message, only for System IDLE Start. */ +#define LTR_IDLE_ENTER_POS 0 +#define LTR_IDLE_ENTER_LEN 10 +#define LTR_IDLE_ENTER_USVAL 900 +#define LTR_IDLE_ENTER_SCALE_POS 10 +#define LTR_IDLE_ENTER_SCALE_LEN 5 +#define LTR_IDLE_ENTER_SCALE 2 /* 0-1ns, 1-32ns, 2-1024ns, 3-32,768ns, 4-1,048,576ns, 5-33,554,432ns, 110-111-Not Permitted.*/ +#define LTR_IDLE_ENTER_REQUIRE_POS 15 +#define LTR_IDLE_ENTER_REQUIRE_LEN 1 +#define LTR_IDLE_ENTER_REQUIRE 1 + +#define LTR_IDLE_EXIT 0x1140 /* LTR_CTRL4, LTR latency message, only for System IDLE End. */ +#define LTR_IDLE_EXIT_POS 0 +#define LTR_IDLE_EXIT_LEN 10 +#define LTR_IDLE_EXIT_USVAL 2 +#define LTR_IDLE_EXIT_SCALE_POS 10 +#define LTR_IDLE_EXIT_SCALE_LEN 5 +#define LTR_IDLE_EXIT_SCALE 2 +#define LTR_IDLE_EXIT_REQUIRE_POS 15 +#define LTR_IDLE_EXIT_REQUIRE_LEN 1 +#define LTR_IDLE_EXIT_REQUIRE 1 + +#define LPW_CTRL 0x1188 +#define LPW_CTRL_L1SS_EN_POS 22 +#define LPW_CTRL_L1SS_EN_LEN 1 +#define LPW_CTRL_L1SS_SEL_POS 21 /* 0 - up to both CFG0x158 and reg1188 L1ss setting. 1 - up to CFG0x158 L1ss setting. */ +#define LPW_CTRL_L1SS_SEL_LEN 1 +#define LPW_CTRL_L1SS_SEL_CFG 1 /* */ +#define LPW_CTRL_ASPM_L1_CPM_POS 19 /*L1.CPM mode enable bit. Default 0,set as 1 enable this mode. clkreq pin need to connect RC*/ +#define LPW_CTRL_ASPM_L1_CPM_LEN 1 +#define LPW_CTRL_ASPM_L0S_EN_POS 17 +#define LPW_CTRL_ASPM_L0S_EN_LEN 1 +#define LPW_CTRL_ASPM_L1_EN_POS 16 +#define LPW_CTRL_ASPM_L1_EN_LEN 1 +#define LPW_CTRL_ASPM_LPW_EN_POS 9 /* application ready to enter L23. */ +#define LPW_CTRL_ASPM_LPW_EN_LEN 1 +#define LPW_CTRL_SYS_CLK_125_SEL_POS 8 /* system 125M select: 125M or 62.5MHz. Default: 125MHz.*/ +#define LPW_CTRL_SYS_CLK_125_SEL_LEN 1 +#define LPW_CTRL_PCIE_RADM_CG_EN_POS 5 /* clock gating enable bit of PCIe Radm clock. Default 1; set as 1, enable gating.*/ +#define LPW_CTRL_PCIE_RADM_CG_EN_LEN 1 +#define LPW_CTRL_PCIE_CORE_CG_EN_POS 4 /* clock gating enable bit of PCIe Core clock. Default 1; set as 1, enable gating.*/ +#define LPW_CTRL_PCIE_CORE_CG_EN_LEN 1 +#define LPW_CTRL_PCIE_AXI_CG_EN_POS 3 /* clock gating enable bit of PCIe AXI clock.Default 1; set as 1, enable gating.*/ +#define LPW_CTRL_PCIE_AXI_CG_EN_LEN 1 +#define LPW_CTRL_GMAC_AXI_CG_EN_POS 2 /* clock gating enable bit of GMAC AXI clock. Default 1; set as 1, enable gating.*/ +#define LPW_CTRL_GMAC_AXI_CG_EN_LEN 1 +#define LPW_CTRL_MDIO2APB_CG_EN_POS 1 /* clock gating enable bit of MDIO2APB, default 1. Set as 1, enable clock gating feature. */ +#define LPW_CTRL_MDIO2APB_CG_EN_LEN 1 +#define LPW_CTRL_OTP_CLK_ON_POS 0 /* Turn on before SW OTP operation, default 1. */ +#define LPW_CTRL_OTP_CLK_ON_LEN 1 + +#define MSI_PBA_REG 0x1300 +#define SYS_RESET_REG 0x152C +#define SYS_RESET_POS 31 +#define SYS_RESET_LEN 1 + +#define REG_PCIE_PSM_STATE 0x1994 /* PCIe PHY power state. */ +#define PCIE_PSM_STATE_POS 0 +#define PCIE_PSM_STATE_LEN 4 +#define PCIE_PSM_STATE_P0 2 +#define PCIE_PSM_STATE_P0s 3 +#define PCIE_PSM_STATE_P1 4 +#define PCIE_PSM_STATE_P1_CPM 5 +#define PCIE_PSM_STATE_P1_1 6 +#define PCIE_PSM_STATE_P1_2 7 +#define PCIE_PSM_STATE_P2 8 + +#define REG_PCIE_SERDES_STATUS 0x1998 +#define PCIE_SERDES_STATUS_DRV_ON_POS 11 +#define PCIE_SERDES_STATUS_DRV_ON_LEN 1 +#define PCIE_SERDES_STATUS_RX_PD_POS 10 +#define PCIE_SERDES_STATUS_RX_PD_LEN 1 +#define PCIE_SERDES_STATUS_PI_PD_POS 9 +#define PCIE_SERDES_STATUS_PI_PD_LEN 1 +#define PCIE_SERDES_STATUS_SIGDET_ON_POS 8 +#define PCIE_SERDES_STATUS_SIGDET_ON_LEN 1 +#define PCIE_SERDES_STATUS_TX_VCM_POS 7 +#define PCIE_SERDES_STATUS_TX_VCM_LEN 1 +#define PCIE_SERDES_STATUS_RX_RT50_POS 6 +#define PCIE_SERDES_STATUS_RX_RT50_LEN 1 +#define PCIE_SERDES_STATUS_BEACON_ON_POS 5 +#define PCIE_SERDES_STATUS_BEACON_ON_LEN 1 +#define PCIE_SERDES_STATUS_PLL_ON_POS 4 +#define PCIE_SERDES_STATUS_PLL_ON_LEN 1 +#define PCIE_SERDES_STATUS_REFCLK_ON_POS 3 +#define PCIE_SERDES_STATUS_REFCLK_ON_LEN 1 +#define PCIE_SERDES_STATUS_LDO_ON_POS 2 +#define PCIE_SERDES_STATUS_LDO_ON_LEN 1 +#define PCIE_SERDES_STATUS_HW_EN_SDS_BIAS_POS 1 +#define PCIE_SERDES_STATUS_HW_EN_SDS_BIAS_LEN 1 +#define PCIE_SERDES_STATUS_HW_BIAS_ON_POS 0 +#define PCIE_SERDES_STATUS_HW_BIAS_ON_LEN 1 + +#define REG_PCIE_SERDES_PLL 0x199C +#define PCIE_SERDES_PLL_AUTOOFF_POS 0 +#define PCIE_SERDES_PLL_AUTOOFF_LEN 1 + +#define NS_OF_GLB_CTL 0x1B00 +#define NS_TPID_PRO 0x1B04 +#define NS_LUT_ROMOTE0 0x1B08 +#define NS_LUT_ROMOTE1 0X1B0C +#define NS_LUT_ROMOTE2 0X1B10 +#define NS_LUT_ROMOTE3 0X1B14 +#define NS_LUT_TARGET0 0X1B18 +#define NS_LUT_TARGET1 0X1B1C +#define NS_LUT_TARGET2 0X1B20 +#define NS_LUT_TARGET3 0X1B24 +#define NS_LUT_SOLICITED0 0X1B28 +#define NS_LUT_SOLICITED1 0X1B2C +#define NS_LUT_SOLICITED2 0X1B30 +#define NS_LUT_SOLICITED3 0X1B34 +#define NS_LUT_MAC_ADDR 0X1B38 +#define NS_LUT_MAC_ADDR_CTL 0X1B3C +#define NS_LUT_TARGET4 0X1B78 +#define NS_LUT_TARGET5 0X1B7c +#define NS_LUT_TARGET6 0X1B80 +#define NS_LUT_TARGET7 0X1B84 + +#define NS_OF_GLB_CTL_TX_CLK_EN_POS 2 +#define NS_OF_GLB_CTL_TX_CLK_EN_LEN 1 +#define NS_OF_GLB_CTL_RX_CLK_EN_POS 1 +#define NS_OF_GLB_CTL_RX_CLK_EN_LEN 1 +#define NS_OF_GLB_CTL_EN_POS 0 +#define NS_OF_GLB_CTL_EN_ELN 1 +#define NS_TPID_PRO_STPID_POS 16 +#define NS_TPID_PRO_STPID_LEN 16 +#define NS_TPID_PRO_CTPID_POS 0 +#define NS_TPID_PRO_CTPID_LEN 16 +#define NS_LUT_DST_CMP_TYPE_POS 19 +#define NS_LUT_DST_CMP_TYPE_LEN 1 +#define NS_LUT_DST_IGNORED_POS 18 +#define NS_LUT_DST_IGNORED_LEN 1 +#define NS_LUT_REMOTE_AWARED_POS 17 +#define NS_LUT_REMOTE_AWARED_LEN 1 +#define NS_LUT_TARGET_ISANY_POS 16 +#define NS_LUT_TARGET_ISANY_LEN 1 +#define NS_LUT_MAC_ADDR_LOW_POS 0 +#define NS_LUT_MAC_ADDR_LOW_LEN 16 + +/* RSS implementation registers, 20210817 */ + +/* 10 RSS key registers */ +#define MGMT_RSS_KEY0 0x1020 +#define MGMT_RSS_KEY9 0x1044 +#define MGMT_RSS_KEY_REG_INC 0x4 + +/* RSS control register */ +#define MGMT_RSS_CTRL 0x1048 +/* b31 enable + * b12:10 indirection table size. 2^(val+1) + * b9:8 default Queue NO. + * b7:0 hash type or options + */ + +/* RSS ctrl register bit definitions. + * [0] ipv4 + * [1] tcpv4 + * [2] udpv4 + * [3] ipv6 + * [4] tcpv6 + * [5] udpv6 +* [6] only ipv4 udp check IP hash +* [7] only ipv6 udp check IP hash + */ +#define MGMT_RSS_CTRL_OPT_POS 0 +#define MGMT_RSS_CTRL_OPT_LEN 8 +#define MGMT_RSS_CTRL_OPT_MASK 0xFF +#define MGMT_RSS_CTRL_IPV4_EN 0x01 +#define MGMT_RSS_CTRL_TCPV4_EN 0x02 +#define MGMT_RSS_CTRL_UDPV4_EN 0x04 +#define MGMT_RSS_CTRL_IPV6_EN 0x08 +#define MGMT_RSS_CTRL_TCPV6_EN 0x10 +#define MGMT_RSS_CTRL_UDPV6_EN 0x20 +#define MGMT_RSS_CTRL_IPV4 0x0 +#define MGMT_RSS_CTRL_IPV4 0x0 + +#define MGMT_RSS_CTRL_DEFAULT_Q_POS 8 +#define MGMT_RSS_CTRL_DEFAULT_Q_LEN 2 +#define MGMT_RSS_CTRL_DEFAULT_Q_MASK 0x3 + +#define MGMT_RSS_CTRL_TBL_SIZE_POS 10 +#define MGMT_RSS_CTRL_TBL_SIZE_LEN 3 +#define MGMT_RSS_CTRL_TBL_SIZE_MASK 0x7 + +#define MAC_RSSCR_RSSE_POS 31 +#define MAC_RSSCR_RSSE_LEN 1 + +/* rss indirection table (IDT) */ +#define MGMT_RSS_IDT 0x1050 +/* b0:1 entry0 + * b2:3 entry1 + * ... + */ +#define MGMT_RSS_IDT_REG_INC 4 +#define MGMT_RSS_IDT_ENTRY_PER_REG 16 +#define MGMT_RSS_IDT_ENTRY_MASK 0x3 +#define MAC_CRC_LENGTH 4 + + /* osc_ctrl */ +#define MGMT_XST_OSC_CTRL 0x1158 +#define MGMT_XST_OSC_CTRL_XST_OSC_SEL_POS 2 +#define MGMT_XST_OSC_CTRL_XST_OSC_SEL_LEN 1 +#define MGMT_XST_OSC_CTRL_EN_OSC_POS 1 +#define MGMT_XST_OSC_CTRL_EN_OSC_LEN 1 +#define MGMT_XST_OSC_CTRL_EN_XST_POS 0 +#define MGMT_XST_OSC_CTRL_EN_XST_LEN 1 + +/* for WPI, yzhang, 20210826 */ +#define MGMT_WPI_CTRL0 0x1160 + /* b1:0 wpi_mode "2b00: normal working mode; 2b01: WPI write mode, work in sleep mode; 2b10: WPI read mode, work after sleep before normal working mode;" + * b2 ram_op_done Each row ram read done, SW can start read after done; + * b3 wpi_op_done WPI read done for the total packet; + * b17:4 wpi_pkt_len WOL packet length, unit byte; + * b31 wpi_fail Error status in Sleep mode; + */ +#define MGMT_WPI_CTRL0_WPI_MODE_POS 0 +#define MGMT_WPI_CTRL0_WPI_MODE_LEN 2 +#define MGMT_WPI_CTRL0_WPI_MODE_NORMAL 0x00 // normal working mode. +#define MGMT_WPI_CTRL0_WPI_MODE_WR 0x01 // WPI write mode, work in sleep mode. +#define MGMT_WPI_CTRL0_WPI_MODE_RD 0x02 // WPI read mode, work after sleep before normal working mode. +#define MGMT_WPI_CTRL0_RAM_OP_DONE 0x4 +#define MGMT_WPI_CTRL0_WPI_OP_DONE 0x8 +#define MGMT_WPI_CTRL0_WPI_PKT_LEN_POS 4 +#define MGMT_WPI_CTRL0_WPI_PKT_LEN_LEN 14 +#define MGMT_WPI_CTRL0_WPI_FAIL 0x80000000 + +#define MGMT_WPI_CTRL1_DATA 0x1164 + +#define MGMT_WOL_CTRL 0x1530 + /* b0 link_chg_status 1: waken by link-change + * b1 mgk_pkt_status 1: waken by magic-packet + * b2 rwk_pkt_status 1: waken by remote patten packet + */ +#define MGMT_WOL_CTRL_WPI_LINK_CHG 1 +#define MGMT_WOL_CTRL_WPI_MGC_PKT 2 +#define MGMT_WOL_CTRL_WPI_RWK_PKT 4 +#define MGMT_WOL_CTRL_WPI_RWK_PKT_NUMBER 0x010000 + +#define MGMT_RMK_CTRL 0x1400 + +#define MGMT_SIGDET 0x17F8 +#define MGMT_SIGDET_POS 13 +#define MGMT_SIGDET_LEN 3 +#define MGMT_SIGDET_55MV 7 +#define MGMT_SIGDET_50MV 6 +#define MGMT_SIGDET_45MV 5 //default value +#define MGMT_SIGDET_40MV 4 +#define MGMT_SIGDET_35MV 3 +#define MGMT_SIGDET_30MV 2 +#define MGMT_SIGDET_25MV 1 +#define MGMT_SIGDET_20MV 0 + +#define FXGMAC_MTL_REG(pdata, n, reg) \ + ((pdata)->mac_regs + MTL_Q_BASE + ((n) * MTL_Q_INC) + (reg)) + +#define FXGMAC_DMA_REG(channel, reg) ((channel)->dma_regs + (reg)) + +//#define RSS_Q_COUNT 4 +#define MSI_ID_RXQ0 0 +#define MSI_ID_RXQ1 1 +#define MSI_ID_RXQ2 2 +#define MSI_ID_RXQ3 3 +#define MSI_ID_TXQ0 4 + +#if 1//msi table modify to 6 0~3 rx 4 tx 5 phy/other +#define MSI_ID_PHY_OTHER 5 +//#define MSI_ID_TXQ2 6 +//#define MSI_ID_TXQ3 7 +//#define MSI_ID_SFTUE 8 +//#define MSI_ID_SFTCE 9 +//#define MSI_ID_SBD 10 +//#define MSI_ID_PMT 11 +//#define MSI_ID_PHY 12 + +#define MSIX_TBL_MAX_NUM 6 +#define MSIX_TBL_RXTX_NUM 5 + +#else +#define MSI_ID_TXQ1 5 +#define MSI_ID_TXQ2 6 +#define MSI_ID_TXQ3 7 +#define MSI_ID_SFTUE 8 +#define MSI_ID_SFTCE 9 +#define MSI_ID_SBD 10 +#define MSI_ID_PMT 11 +#define MSI_ID_PHY 12 + +#define MSIX_TBL_MAX_NUM 16 +#define MSIX_TBL_RXTX_NUM 8 +#endif +#define MSIX_TBL_BASE_ADDR 0x1200 +#define MSIX_TBL_MASK_OFFSET 0xC +#define MSIX_TBL_DATA_OFFSET 0x8 +#define MSIX_TBL_ADDR_OFFSET 0x0 + +/******************************************************************* + efuse entry. val31:0 -> offset15:0 + offset7:0 + offset15:8 + val7:0 + val15:8 + val23:16 + val31:24 +*******************************************************************/ +#define EFUSE_OP_CTRL_0 0x1500 +#define EFUSE_OP_WR_DATA_POS 16 +#define EFUSE_OP_WR_DATA_LEN 8 +#define EFUSE_OP_ADDR_POS 8 +#define EFUSE_OP_ADDR_LEN 8 +#define EFUSE_OP_START_POS 2 +#define EFUSE_OP_START_LEN 1 +#define EFUSE_OP_MODE_POS 0 +#define EFUSE_OP_MODE_LEN 2 +#define EFUSE_OP_MODE_ROW_WRITE 0x0 +#define EFUSE_OP_MODE_ROW_READ 0x1 +#define EFUSE_OP_MODE_AUTO_LOAD 0x2 +#define EFUSE_OP_MODE_READ_BLANK 0x3 + +#define EFUSE_OP_CTRL_1 0x1504 +#define EFUSE_OP_RD_DATA_POS 24 +#define EFUSE_OP_RD_DATA_LEN 8 +#define EFUSE_OP_BIST_ERR_ADDR_POS 16 +#define EFUSE_OP_BIST_ERR_ADDR_LEN 8 +#define EFUSE_OP_BIST_ERR_CNT_POS 8 +#define EFUSE_OP_BIST_ERR_CNT_LEN 8 +#define EFUSE_OP_PGM_PASS_POS 2 +#define EFUSE_OP_PGM_PASS_LEN 1 +#define EFUSE_OP_DONE_POS 1 +#define EFUSE_OP_DONE_LEN 1 + +//efuse layout refer to http://redmine.motor-comm.com/issues/3856 +#define EFUSE_FISRT_UPDATE_ADDR 255 +#define EFUSE_SECOND_UPDATE_ADDR 209 +#define FUXI_EFUSE_MAX_ENTRY 39 +#define FUXI_EFUSE_MAX_ENTRY_UNDER_LED_COMMON 24 +#define EFUSE_PATCH_ADDR_START_BYTE 0 +#define EFUSE_PATCH_DATA_START_BYTE 2 +#define EFUSE_REGION_A_B_LENGTH 18 +#define EFUSE_EACH_PATH_SIZE 6 + +#define EFUSE_REVID_REGISTER 0x0008 +#define EFUSE_SUBSYS_REGISTER 0x002C +#define MACA0LR_FROM_EFUSE 0x1520 //mac[5]->bit7:0, mac[4]->bit15:8, mac[3]->bit23:16, mac[2]->bit31:24. +#define MACA0HR_FROM_EFUSE 0x1524 //mac[1]->bit7:0, mac[0]->bit15:8. mac[6] = {00, 01, 02, 03, 04, 05} 00-01-02-03-04-05. + +#define EFUSE_LED_ADDR 0x00 +#define EFUSE_LED_POS 0 +#define EFUSE_LED_LEN 5 +#define EFUSE_OOB_ADDR 0x07 +#define EFUSE_OOB_POS 2 +#define EFUSE_OOB_LEN 1 +#define EFUSE_LED_SOLUTION0 0 +#define EFUSE_LED_SOLUTION1 1 +#define EFUSE_LED_SOLUTION2 2 +#define EFUSE_LED_SOLUTION3 3 +#define EFUSE_LED_SOLUTION4 4 +#define EFUSE_LED_COMMON_SOLUTION 0x1F + +/******************** Below for pcie configuration register. *********************/ +#define REG_PCI_VENDOR_ID 0x0 /* WORD reg */ +#define REG_PCI_DEVICE_ID 0x2 /* WORD reg */ +#define PCI_DEVICE_ID_FUXI 0x6801 + +#define REG_PCI_COMMAND 0x4 +#define PCI_COMMAND_IO_SPACE_POS 0 +#define PCI_COMMAND_IO_SPACE_LEN 1 +#define PCI_COMAMND_MEM_SPACE_POS 1 +#define PCI_COMAMND_MEM_SPACE_LEN 1 +#define PCI_COMMAND_MASTER_POS 2 +#define PCI_COMMAND_MASTER_LEN 1 +#define PCI_COMMAND_DIS_INT_POS 10 +#define PCI_COMMAND_DIS_INT_LEN 1 +#define PCI_COMMAND_INTX_STATUS_POS 19 +#define PCI_COMMAND_INTX_STATUS_LEN 1 + +#define REG_PCI_REVID 0x8 /* BYTE reg */ +#define REG_PCI_PROGRAM_INTF 0x9 /* BYTE reg */ /* PCI Class Program Interface */ +#define REG_PCI_SUB_CLASS 0xA /* BYTE reg */ +#define REG_PCI_BASE_CLASS 0xB /* BYTE reg */ +#define REG_CACHE_LINE_SIZE 0xC + + +#define REG_MEM_BASE 0x10 /* DWORD or QWORD reg */ +#define REG_MEM_BASE_HI 0x14 /* DWORD or QWORD reg */ + +#define REG_IO_BASE 0x20 /* DWORD reg */ + +#define REG_PCI_SUB_VENDOR_ID 0x2C /* WORD reg */ +#define REG_PCI_SUB_DEVICE_ID 0x2E /* WORD reg */ + +#define REG_INT_LINE 0x3C /* BYTE reg */ + +#define REG_PM_STATCTRL 0x44 /* WORD reg */ +#define PM_STATCTRL_PWR_STAT_POS 0 +#define PM_STATCTRL_PWR_STAT_LEN 2 +#define PM_STATCTRL_PWR_STAT_D3 3 +#define PM_STATCTRL_PWR_STAT_D0 0 +#define PM_CTRLSTAT_PME_EN_POS 8 +#define PM_CTRLSTAT_PME_EN_LEN 1 +#define PM_CTRLSTAT_DATA_SEL_POS 9 +#define PM_CTRLSTAT_DATA_SEL_LEN 4 +#define PM_CTRLSTAT_DATA_SCAL_POS 13 +#define PM_CTRLSTAT_DATA_SCAL_LEN 2 +#define PM_CTRLSTAT_PME_STAT_POS 15 +#define PM_CTRLSTAT_PME_STAT_LEN 1 + +#define REG_DEVICE_CTRL1 0x78 +#define DEVICE_CTRL1_CONTROL_POS 0 +#define DEVICE_CTRL1_CONTROL_LEN 16 +#define DEVICE_CTRL1_STATUS_POS 16 +#define DEVICE_CTRL1_STATUS_LEN 16 + +#define REG_PCI_LINK_CTRL 0x80 +#define PCI_LINK_CTRL_CONTROL_POS 0 +#define PCI_LINK_CTRL_CONTROL_LEN 16 +#define PCI_LINK_CTRL_ASPM_CONTROL_POS 0 +#define PCI_LINK_CTRL_ASPM_CONTROL_LEN 2 +#define PCI_LINK_CTRL_L1_STATUS 2 +#define PCI_LINK_CTRL_CONTROL_CPM_POS 8 /*L1.CPM mode enable bit. Default 0,set as 1 enable this mode. clkreq pin need to connect RC*/ +#define PCI_LINK_CTRL_CONTROL_CPM_LEN 1 +#define PCI_LINK_CTRL_STATUS_POS 16 +#define PCI_LINK_CTRL_STATUS_LEN 16 + +#define REG_DEVICE_CTRL2 0x98 /* WORD reg */ +#define DEVICE_CTRL2_LTR_EN_POS 10 /* Enable from BIOS side. */ +#define DEVICE_CTRL2_LTR_EN_LEN 1 + +#define REG_MSIX_CAPABILITY 0xB0 + +/* ASPM L1ss PM Substates */ +#define REG_ASPM_L1SS_CAP 0x154 /* Capabilities Register */ +#define ASPM_L1SS_CAP_PCIPM_L1_2_POS 0 /* PCI-PM L1.2 Supported */ +#define ASPM_L1SS_CAP_PCIPM_L1_2_LEN 1 +#define ASPM_L1SS_CAP_PCIPM_L1_1_POS 1 /* PCI-PM L1.1 Supported */ +#define ASPM_L1SS_CAP_PCIPM_L1_1_LEN 1 +#define ASPM_L1SS_CAP_ASPM_L1_2_POS 2 /* ASPM L1.2 Supported */ +#define ASPM_L1SS_CAP_ASPM_L1_2_LEN 1 +#define ASPM_L1SS_CAP_ASPM_L1_1_POS 3 /* ASPM L1.1 Supported */ +#define ASPM_L1SS_CAP_ASPM_L1_1_LEN 1 +#define ASPM_L1SS_CAP_L1_PM_SS_POS 4 /* L1 PM Substates Supported */ +#define ASPM_L1SS_CAP_L1_PM_SS_LEN 1 +#define ASPM_L1SS_CAP_CM_RESTORE_TIME_POS 8 /* Port Common_Mode_Restore_Time */ +#define ASPM_L1SS_CAP_CM_RESTORE_TIME_LEN 8 +#define ASPM_L1SS_CAP_P_PWR_ON_SCALE_POS 16 /* Port T_POWER_ON scale */ +#define ASPM_L1SS_CAP_P_PWR_ON_SCALE_LEN 2 +#define ASPM_L1SS_CAP_P_PWR_ON_VALUE_POS 19 /* Port T_POWER_ON value */ +#define ASPM_L1SS_CAP_P_PWR_ON_VALUE_LEN 5 + +#define REG_ASPM_L1SS_CTRL1 0x158 +#define REG_ASPM_L1SS_CTRL1_VALUE 0x405e000f +#define ASPM_L1SS_CTRL1_L12_PCIPM_EN_POS 0 /* L1.2 in D3 state. */ +#define ASPM_L1SS_CTRL1_L12_PCIPM_EN_LEN 1 +#define ASPM_L1SS_CTRL1_L11_PCIPM_EN_POS 1 /* L1.1 in D3 state. */ +#define ASPM_L1SS_CTRL1_L11_PCIPM_EN_LEN 1 +#define ASPM_L1SS_CTRL1_L12_EN_POS 2 +#define ASPM_L1SS_CTRL1_L12_EN_LEN 1 +#define ASPM_L1SS_CTRL1_L11_EN_POS 3 +#define ASPM_L1SS_CTRL1_L11_EN_LEN 1 +#define ASPM_L1SS_CTRL1_CM_RESTORE_TIME_POS 8 /* Common_Mode_Restore_Time */ +#define ASPM_L1SS_CTRL1_CM_RESTORE_TIME_LEN 8 +#define ASPM_L1SS_CTRL1_LTR_L12_TH_VALUE_POS 16 /* LTR_L1.2_THRESHOLD_Value */ +#define ASPM_L1SS_CTRL1_LTR_L12_TH_VALUE_LEN 10 +#define ASPM_L1SS_CTRL1_L12_TH_SCALE_POS 29 /* LTR_L1.2_THRESHOLD_Scale */ +#define ASPM_L1SS_CTRL1_L12_TH_SCALE_LEN 3 + +#define REG_ASPM_L1SS_CTL2 0x15c /* Control 2 Register */ + +#define REG_ASPM_CONTROL 0x70C +#define ASPM_L1_IDLE_THRESHOLD_POS 27 +#define ASPM_L1_IDLE_THRESHOLD_LEN 3 +#define ASPM_L1_IDLE_THRESHOLD_1US 0 +#define ASPM_L1_IDLE_THRESHOLD_2US 1 +#define ASPM_L1_IDLE_THRESHOLD_4US 2 +#define ASPM_L1_IDLE_THRESHOLD_8US 3 /* default value after reset. */ +#define ASPM_L1_IDLE_THRESHOLD_16US 4 +#define ASPM_L1_IDLE_THRESHOLD_32US 5 +#define ASPM_L1_IDLE_THRESHOLD_64US 6 + +#define REG_POWER_EIOS 0x710 +#define POWER_EIOS_POS 7 +#define POWER_EIOS_LEN 1 + +#endif /* __FUXI_GMAC_REG_H__ */ diff --git a/drivers/net/ethernet/motorcomm/fuxi-gmac.h b/drivers/net/ethernet/motorcomm/fuxi-gmac.h new file mode 100644 index 000000000000..855a82bd11be --- /dev/null +++ b/drivers/net/ethernet/motorcomm/fuxi-gmac.h @@ -0,0 +1,924 @@ +/*++ + +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. + +--*/ + +#ifndef __FUXI_GMAC_H__ +#define __FUXI_GMAC_H__ + +#include "fuxi-os.h" + +// For fpga before 20210507 +#define FXGMAC_FPGA_VER_B4_0507 0 +#define FXGMAC_FPGA_VER_20210507 1 + +#define FXGMAC_DRV_NAME "yt6801" + +#define FXGMAC_DRV_DESC "Motorcomm FUXI GMAC Driver" + +#define FUXI_MAC_REGS_OFFSET 0x2000 + +#define FUXI_EPHY_INTERRUPT_D0_OFF 0 //1: in normal D0 state, turn off ephy link change interrupt. +#define FUXI_ALLOC_NEW_RECBUFFER 0 //1:when rec buffer is not enough,to create rbd and rec buffer ,but the rdb need to be continus with the intialized rdb,so close the feature + +#define RESUME_MAX_TIME 3000000 +#define PHY_LINK_TIMEOUT 3000 +#define ESD_RESET_MAXIMUM 0 + +#define REGWR_RETRY_MAXIMUM 2600 +#define PCIE_LINKDOWN_VALUE 0xFFFFFFFF + +#define FXGMAC_MSIX_Q_VECTORS 4 + +#define FXGMAC_IS_CHANNEL_WITH_TX_IRQ(chId) (0 == (chId) ? 1 : 0) + +/* flags for ipv6 NS offload address, local link or Global unicast */ +#define FXGMAC_NS_IFA_LOCAL_LINK 1 +#define FXGMAC_NS_IFA_GLOBAL_UNICAST 2 + +#define FXGMAX_ASPM_WAR_EN +/* Descriptor related parameters */ +#if FXGMAC_TX_HANG_TIMER_EN +#define FXGMAC_TX_DESC_CNT 1024 +#else +#define FXGMAC_TX_DESC_CNT 256 //256 to make sure the tx ring is in the 4k range when FXGMAC_TX_HANG_TIMER_EN is 0 +#endif +#define FXGMAC_TX_DESC_MIN_FREE (FXGMAC_TX_DESC_CNT >> 3) +#define FXGMAC_TX_DESC_MAX_PROC (FXGMAC_TX_DESC_CNT >> 1) +#define FXGMAC_RX_DESC_CNT 1024 +#define FXGMAC_RX_DESC_MAX_DIRTY (FXGMAC_RX_DESC_CNT >> 3) + +/* Descriptors required for maximum contiguous TSO/GSO packet */ +#define FXGMAC_TX_MAX_SPLIT ((GSO_MAX_SIZE / FXGMAC_TX_MAX_BUF_SIZE) + 1) + +/* Maximum possible descriptors needed for a SKB */ +#define FXGMAC_TX_MAX_DESC_NR (MAX_SKB_FRAGS + FXGMAC_TX_MAX_SPLIT + 2) + +#define FXGMAC_TX_MAX_BUF_SIZE (0x3fff & ~(64 - 1)) +#define FXGMAC_RX_MIN_BUF_SIZE (ETH_FRAME_LEN + ETH_FCS_LEN + VLAN_HLEN) +#define FXGMAC_RX_BUF_ALIGN 64 + +/* Maximum Size for Splitting the Header Data + * Keep in sync with SKB_ALLOC_SIZE + * 3'b000: 64 bytes, 3'b001: 128 bytes + * 3'b010: 256 bytes, 3'b011: 512 bytes + * 3'b100: 1023 bytes , 3'b101'3'b111: Reserved + */ +#define FXGMAC_SPH_HDSMS_SIZE 3 +#define FXGMAC_SKB_ALLOC_SIZE 512 + +//2022-04-22 xiaojiang comment +//In Linux Driver, it set MAX_FIFO size 131072, here it uses the same value as windows driver +#define FXGMAC_MAX_FIFO 81920 + +#define FXGMAC_MAX_DMA_CHANNELS FXGMAC_MSIX_Q_VECTORS +#define FXGMAC_DMA_STOP_TIMEOUT 5 +#define FXGMAC_DMA_INTERRUPT_MASK 0x31c7 +#define FXGMAC_MAX_DMA_CHANNELS_PLUS_1TX (FXGMAC_MAX_DMA_CHANNELS + 1) + +/* Default coalescing parameters */ +//2022-04-22 xiaojiang comment +//In Windows Driver, the DMA_TX_USECS is not used, here it uses the linux driver value +#define FXGMAC_INIT_DMA_TX_USECS INT_MOD_IN_US +#define FXGMAC_INIT_DMA_TX_FRAMES 25 +#define FXGMAC_INIT_DMA_RX_USECS INT_MOD_IN_US +#define FXGMAC_INIT_DMA_RX_FRAMES 25 +#define FXGMAC_MAX_DMA_RIWT 0xff +#define FXGMAC_MIN_DMA_RIWT 0x01 + +/* Flow control queue count */ +#define FXGMAC_MAX_FLOW_CONTROL_QUEUES 8 + +/* System clock is 125 MHz */ +#define FXGMAC_SYSCLOCK 125000000 + +/* Maximum MAC address hash table size (256 bits = 8 bytes) */ +#define FXGMAC_MAC_HASH_TABLE_SIZE 8 + +/* wol pattern settings */ +#define MAX_PATTERN_SIZE 128 // PATTERN length +#define MAX_PATTERN_COUNT 16 // pattern count +#define MAX_LPP_ARP_OFFLOAD_COUNT 1 +#define MAX_LPP_NS_OFFLOAD_COUNT 2 + +#define MAX_WPI_LENGTH_SIZE 1536 // WPI packet. +#define PM_WAKE_PKT_ALIGN 8 // try use 64 bit boundary... + +/* Receive Side Scaling */ +#define FXGMAC_RSS_HASH_KEY_SIZE 40 +#define FXGMAC_RSS_MAX_TABLE_SIZE 128 +#define FXGMAC_RSS_LOOKUP_TABLE_TYPE 0 +#define FXGMAC_RSS_HASH_KEY_TYPE 1 +#define MAX_MSI_COUNT 16 // Max Msi/Msix supported. + +#define FXGMAC_STD_PACKET_MTU 1500 +#define FXGMAC_JUMBO_PACKET_MTU 9014 + +#define NIC_MAX_TCP_OFFLOAD_SIZE 7300 +#define NIC_MIN_LSO_SEGMENT_COUNT 2 + +/* power management */ +#define FXGMAC_POWER_STATE_DOWN 0 +#define FXGMAC_POWER_STATE_UP 1 + +// Don't change the member variables or types, this inherits from Windows OS. +struct wol_bitmap_pattern +{ + u32 flags; + u32 pattern_size; + u32 mask_size; + u8 mask_info[MAX_PATTERN_SIZE / 8]; + u8 pattern_info[MAX_PATTERN_SIZE]; + u8 pattern_offset; + u16 pattern_crc; +}; + +struct led_setting +{ + u32 s0_led_setting[5]; + u32 s3_led_setting[5]; + u32 s5_led_setting[5]; + u32 disable_led_setting[5]; +}; + +typedef struct led_setting LED_SETTING; +typedef struct wol_bitmap_pattern WOL_BITMAP_PATTERN; + +typedef enum +{ + WAKE_REASON_NONE = 0, + WAKE_REASON_MAGIC, + WAKE_REASON_PATTERNMATCH, + WAKE_REASON_LINK, + WAKE_REASON_TCPSYNV4, + WAKE_REASON_TCPSYNV6, + WAKE_REASON_TBD, //for wake up method like Link-change, for that, GMAC cannot identify and need more checking. + WAKE_REASON_HW_ERR, +} WAKE_REASON; //note, maybe we should refer to NDIS_PM_WAKE_REASON_TYPE to avoid duplication definition.... + +/* Helper macro for descriptor handling + * Always use FXGMAC_GET_DESC_DATA to access the descriptor data + */ +#if 0 //No need to round +#define FXGMAC_GET_DESC_DATA(ring, idx) ({ \ + typeof(ring) _ring = (ring); \ + ((_ring)->desc_data_head + \ + ((idx) & ((_ring)->dma_desc_count - 1))); \ +}) +#endif + +#define FXGMAC_GET_DESC_DATA(ring, idx) ((ring)->desc_data_head + (idx)) +#define FXGMAC_GET_ENTRY(x, size) ((x + 1) & (size - 1)) + +struct fxgmac_pdata; + +enum fxgmac_int { + FXGMAC_INT_DMA_CH_SR_TI, + FXGMAC_INT_DMA_CH_SR_TPS, + FXGMAC_INT_DMA_CH_SR_TBU, + FXGMAC_INT_DMA_CH_SR_RI, + FXGMAC_INT_DMA_CH_SR_RBU, + FXGMAC_INT_DMA_CH_SR_RPS, + FXGMAC_INT_DMA_CH_SR_TI_RI, + FXGMAC_INT_DMA_CH_SR_FBE, + FXGMAC_INT_DMA_ALL, +}; + +struct fxgmac_stats { + /* MMC TX counters */ + u64 txoctetcount_gb; + u64 txframecount_gb; + u64 txbroadcastframes_g; + u64 txmulticastframes_g; + u64 tx64octets_gb; + u64 tx65to127octets_gb; + u64 tx128to255octets_gb; + u64 tx256to511octets_gb; + u64 tx512to1023octets_gb; + u64 tx1024tomaxoctets_gb; + u64 txunicastframes_gb; + u64 txmulticastframes_gb; + u64 txbroadcastframes_gb; + u64 txunderflowerror; + u64 txsinglecollision_g; + u64 txmultiplecollision_g; + u64 txdeferredframes; + u64 txlatecollisionframes; + u64 txexcessivecollisionframes; + u64 txcarriererrorframes; + u64 txoctetcount_g; + u64 txframecount_g; + u64 txexcessivedeferralerror; + u64 txpauseframes; + u64 txvlanframes_g; + u64 txoversize_g; + + /* MMC RX counters */ + u64 rxframecount_gb; + u64 rxoctetcount_gb; + u64 rxoctetcount_g; + u64 rxbroadcastframes_g; + u64 rxmulticastframes_g; + u64 rxcrcerror; + u64 rxalignerror; + u64 rxrunterror; + u64 rxjabbererror; + u64 rxundersize_g; + u64 rxoversize_g; + u64 rx64octets_gb; + u64 rx65to127octets_gb; + u64 rx128to255octets_gb; + u64 rx256to511octets_gb; + u64 rx512to1023octets_gb; + u64 rx1024tomaxoctets_gb; + u64 rxunicastframes_g; + u64 rxlengtherror; + u64 rxoutofrangetype; + u64 rxpauseframes; + u64 rxfifooverflow; + u64 rxvlanframes_gb; + u64 rxwatchdogerror; + u64 rxreceiveerrorframe; + u64 rxcontrolframe_g; + + /* Extra counters */ + u64 tx_tso_packets; + u64 rx_split_header_packets; + u64 tx_process_stopped; + u64 rx_process_stopped; + u64 tx_buffer_unavailable; + u64 rx_buffer_unavailable; + u64 fatal_bus_error; + u64 tx_vlan_packets; + u64 rx_vlan_packets; + u64 napi_poll_isr; + u64 napi_poll_txtimer; + u64 cnt_alive_txtimer; + + u64 ephy_poll_timer_cnt; + u64 mgmt_int_isr; +}; + +struct fxgmac_ring_buf { + struct sk_buff* skb; + DMA_ADDR_T skb_dma; + unsigned int skb_len; +}; + +/* Common Tx and Rx DMA hardware descriptor */ +struct fxgmac_dma_desc { + __le32 desc0; + __le32 desc1; + __le32 desc2; + __le32 desc3; +}; + +/* Page allocation related values */ +struct fxgmac_page_alloc { + struct page* pages; + unsigned int pages_len; + unsigned int pages_offset; + DMA_ADDR_T pages_dma; +}; + +/* Ring entry buffer data */ +struct fxgmac_buffer_data { + struct fxgmac_page_alloc pa; + struct fxgmac_page_alloc pa_unmap; + + DMA_ADDR_T dma_base; + unsigned long dma_off; + unsigned int dma_len; +}; + +/* Tx-related desc data */ +struct fxgmac_tx_desc_data { + unsigned int packets; /* BQL packet count */ + unsigned int bytes; /* BQL byte count */ +}; + +/* Rx-related desc data */ +struct fxgmac_rx_desc_data { + struct fxgmac_buffer_data hdr; /* Header locations */ + struct fxgmac_buffer_data buf; /* Payload locations */ + + unsigned short hdr_len; /* Length of received header */ + unsigned short len; /* Length of received packet */ +}; + +struct fxgmac_pkt_info { + struct sk_buff* skb; + + unsigned int attributes; + + unsigned int errors; + + /* descriptors needed for this packet */ + unsigned int desc_count; + unsigned int length; + + unsigned int tx_packets; + unsigned int tx_bytes; + + unsigned int header_len; + unsigned int tcp_header_len; + unsigned int tcp_payload_len; + unsigned short mss; + + unsigned short vlan_ctag; + + u64 rx_tstamp; + + u32 rss_hash; + RSS_HASH_TYPE rss_hash_type; +}; + +struct fxgmac_desc_data { + /* dma_desc: Virtual address of descriptor + * dma_desc_addr: DMA address of descriptor + */ + struct fxgmac_dma_desc* dma_desc; + DMA_ADDR_T dma_desc_addr; + + /* skb: Virtual address of SKB + * skb_dma: DMA address of SKB data + * skb_dma_len: Length of SKB DMA area + */ + struct sk_buff* skb; + DMA_ADDR_T skb_dma; + unsigned int skb_dma_len; + + /* Tx/Rx -related data */ + struct fxgmac_tx_desc_data tx; + struct fxgmac_rx_desc_data rx; + + unsigned int mapped_as_page; + + /* Incomplete receive save location. If the budget is exhausted + * or the last descriptor (last normal descriptor or a following + * context descriptor) has not been DMA'd yet the current state + * of the receive processing needs to be saved. + */ + unsigned int state_saved; + struct { + struct sk_buff* skb; + unsigned int len; + unsigned int error; + } state; +}; + +struct fxgmac_ring { + /* Per packet related information */ + struct fxgmac_pkt_info pkt_info; + + /* Virtual/DMA addresses of DMA descriptor list and the total count */ + struct fxgmac_dma_desc *dma_desc_head; + DMA_ADDR_T dma_desc_head_addr; + unsigned int dma_desc_count; + + /* Array of descriptor data corresponding the DMA descriptor + * (always use the FXGMAC_GET_DESC_DATA macro to access this data) + */ + struct fxgmac_desc_data *desc_data_head; + + /* Page allocation for RX buffers */ + struct fxgmac_page_alloc rx_hdr_pa; + struct fxgmac_page_alloc rx_buf_pa; + + /* Ring index values + * cur - Tx: index of descriptor to be used for current transfer + * Rx: index of descriptor to check for packet availability + * dirty - Tx: index of descriptor to check for transfer complete + * Rx: index of descriptor to check for buffer reallocation + */ + unsigned int cur; + unsigned int dirty; + + /* Coalesce frame count used for interrupt bit setting */ + unsigned int coalesce_count; + + struct { + unsigned int xmit_more; + unsigned int queue_stopped; + unsigned short cur_mss; + unsigned short cur_vlan_ctag; + } tx; +} ____cacheline_aligned; + +struct fxgmac_channel { + char name[16]; + + /* Address of private data area for device */ + struct fxgmac_pdata* pdata; + + /* Queue index and base address of queue's DMA registers */ + unsigned int queue_index; + + IOMEM dma_regs; + + /* Per channel interrupt irq number */ + u32 dma_irq; + FXGMAC_CHANNEL_OF_PLATFORM expansion; + + unsigned int saved_ier; + + unsigned int tx_timer_active; + + struct fxgmac_ring *tx_ring; + struct fxgmac_ring *rx_ring; +} ____cacheline_aligned; + +struct fxphy_ag_adv { + u8 auto_neg_en : 1; + u8 full_1000m : 1; + u8 half_1000m : 1; + u8 full_100m : 1; + u8 half_100m : 1; + u8 full_10m : 1; + u8 half_10m : 1; +}; + +struct fxgmac_desc_ops { + int (*alloc_channles_and_rings)(struct fxgmac_pdata* pdata); + void (*free_channels_and_rings)(struct fxgmac_pdata* pdata); + int (*map_tx_skb)(struct fxgmac_channel* channel, + struct sk_buff* skb); + int (*map_rx_buffer)(struct fxgmac_pdata* pdata, + struct fxgmac_ring* ring, + struct fxgmac_desc_data* desc_data); + void (*unmap_desc_data)(struct fxgmac_pdata* pdata, + struct fxgmac_desc_data* desc_data); + void (*tx_desc_init)(struct fxgmac_pdata* pdata); + void (*rx_desc_init)(struct fxgmac_pdata* pdata); +}; + +struct fxgmac_hw_ops { + int (*init)(struct fxgmac_pdata* pdata); + int (*exit)(struct fxgmac_pdata* pdata); + void (*save_nonstick_reg)(struct fxgmac_pdata* pdata); + void (*restore_nonstick_reg)(struct fxgmac_pdata* pdata); +#if defined(UEFI) || defined(PXE) + int (*set_gmac_register)(struct fxgmac_pdata* pdata, u32 address, unsigned int data); + u32 (*get_gmac_register)(struct fxgmac_pdata* pdata, u32 address); +#else + int (*set_gmac_register)(struct fxgmac_pdata* pdata, u8* address, unsigned int data); + u32 (*get_gmac_register)(struct fxgmac_pdata* pdata, u8* address); + void (*esd_restore_pcie_cfg)(struct fxgmac_pdata* pdata); +#endif + + int (*tx_complete)(struct fxgmac_dma_desc* dma_desc); + + void (*enable_tx)(struct fxgmac_pdata* pdata); + void (*disable_tx)(struct fxgmac_pdata* pdata); + void (*enable_rx)(struct fxgmac_pdata* pdata); + void (*disable_rx)(struct fxgmac_pdata* pdata); + void (*enable_channel_rx)(struct fxgmac_pdata* pdata, unsigned int queue); + + int (*enable_int)(struct fxgmac_channel* channel, + enum fxgmac_int int_id); + int (*disable_int)(struct fxgmac_channel* channel, + enum fxgmac_int int_id); + void (*set_interrupt_moderation)(struct fxgmac_pdata* pdata); + void (*enable_msix_rxtxinterrupt)(struct fxgmac_pdata* pdata); + void (*disable_msix_interrupt)(struct fxgmac_pdata* pdata); + void (*enable_msix_rxtxphyinterrupt)(struct fxgmac_pdata* pdata); + void (*enable_msix_one_interrupt)(struct fxgmac_pdata* pdata, u32 intid); + void (*disable_msix_one_interrupt)(struct fxgmac_pdata* pdata, u32 intid); + bool (*enable_mgm_interrupt)(struct fxgmac_pdata* pdata); + bool (*disable_mgm_interrupt)(struct fxgmac_pdata* pdata); + + void (*dev_xmit)(struct fxgmac_channel* channel); + int (*dev_read)(struct fxgmac_channel* channel); + + int (*set_mac_address)(struct fxgmac_pdata* pdata, u8* addr); + int (*set_mac_hash)(struct fxgmac_pdata* pdata); + int (*config_rx_mode)(struct fxgmac_pdata* pdata); + int (*enable_rx_csum)(struct fxgmac_pdata* pdata); + int (*disable_rx_csum)(struct fxgmac_pdata* pdata); + void (*config_tso)(struct fxgmac_pdata *pdata); + + /* For MII speed configuration */ + int (*config_mac_speed)(struct fxgmac_pdata* pdata); + int (*set_xlgmii_2500_speed)(struct fxgmac_pdata *pdata); + int (*set_xlgmii_1000_speed)(struct fxgmac_pdata *pdata); + int (*set_xlgmii_100_speed)(struct fxgmac_pdata *pdata); + int (*get_xlgmii_phy_status)(struct fxgmac_pdata *pdata, u32 *speed, bool *link_up, bool link_up_wait_to_complete); + + /* For descriptor related operation */ + void (*tx_desc_init)(struct fxgmac_channel* channel); + void (*rx_desc_init)(struct fxgmac_channel* channel); + void (*tx_desc_reset)(struct fxgmac_desc_data* desc_data); + void (*rx_desc_reset)(struct fxgmac_pdata* pdata, + struct fxgmac_desc_data* desc_data, + unsigned int index); + int (*is_last_desc)(struct fxgmac_dma_desc* dma_desc); + int (*is_context_desc)(struct fxgmac_dma_desc* dma_desc); + void (*tx_start_xmit)(struct fxgmac_channel* channel, + struct fxgmac_ring* ring); + void (*set_pattern_data)(struct fxgmac_pdata* pdata); + void (*config_wol)(struct fxgmac_pdata *pdata, int en); + + /* For Flow Control */ + int (*config_tx_flow_control)(struct fxgmac_pdata* pdata); + int (*config_rx_flow_control)(struct fxgmac_pdata* pdata); + + /* For Jumbo Frames */ + int (*config_mtu)(struct fxgmac_pdata* pdata); + int (*enable_jumbo)(struct fxgmac_pdata* pdata); + + /* For Vlan related config */ + int (*enable_tx_vlan)(struct fxgmac_pdata* pdata); + int (*disable_tx_vlan)(struct fxgmac_pdata* pdata); + int (*enable_rx_vlan_stripping)(struct fxgmac_pdata* pdata); + int (*disable_rx_vlan_stripping)(struct fxgmac_pdata* pdata); + int (*enable_rx_vlan_filtering)(struct fxgmac_pdata* pdata); + int (*disable_rx_vlan_filtering)(struct fxgmac_pdata* pdata); + int (*update_vlan_hash_table)(struct fxgmac_pdata* pdata); + + /* For RX coalescing */ + int (*config_rx_coalesce)(struct fxgmac_pdata* pdata); + int (*config_tx_coalesce)(struct fxgmac_pdata* pdata); + unsigned int (*usec_to_riwt)(struct fxgmac_pdata* pdata, + unsigned int usec); + unsigned int (*riwt_to_usec)(struct fxgmac_pdata* pdata, + unsigned int riwt); + + /* For RX and TX threshold config */ + int (*config_rx_threshold)(struct fxgmac_pdata* pdata, + unsigned int val); + int (*config_tx_threshold)(struct fxgmac_pdata* pdata, + unsigned int val); + + /* For RX and TX Store and Forward Mode config */ + int (*config_rsf_mode)(struct fxgmac_pdata* pdata, + unsigned int val); + int (*config_tsf_mode)(struct fxgmac_pdata* pdata, + unsigned int val); + + /* For TX DMA Operate on Second Frame config */ + int (*config_osp_mode)(struct fxgmac_pdata* pdata); + + /* For RX and TX PBL config */ + int (*config_rx_pbl_val)(struct fxgmac_pdata* pdata); + int (*get_rx_pbl_val)(struct fxgmac_pdata* pdata); + int (*config_tx_pbl_val)(struct fxgmac_pdata* pdata); + int (*get_tx_pbl_val)(struct fxgmac_pdata* pdata); + int (*config_pblx8)(struct fxgmac_pdata* pdata); + + /* For MMC statistics */ + void (*rx_mmc_int)(struct fxgmac_pdata* pdata); + void (*tx_mmc_int)(struct fxgmac_pdata* pdata); + void (*read_mmc_stats)(struct fxgmac_pdata* pdata); + bool (*update_stats_counters)(struct fxgmac_pdata* pdata, bool ephy_check_en); + + /* For Receive Side Scaling */ + int (*enable_rss)(struct fxgmac_pdata* pdata); + int (*disable_rss)(struct fxgmac_pdata* pdata); + u32(*get_rss_options)(struct fxgmac_pdata* pdata); + int (*set_rss_options)(struct fxgmac_pdata* pdata); + int (*set_rss_hash_key)(struct fxgmac_pdata* pdata, const u8* key); + int (*set_rss_lookup_table)(struct fxgmac_pdata* pdata, const u32* table); + + /*For Offload*/ +#if defined(LINUX) || defined(_WIN64) || defined(_WIN32) + void (*set_arp_offload)(struct fxgmac_pdata* pdata, unsigned char* ip_addr); + int (*enable_arp_offload)(struct fxgmac_pdata* pdata); + int (*disable_arp_offload)(struct fxgmac_pdata* pdata); + + /*NS offload*/ + int (*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); + int (*enable_ns_offload)(struct fxgmac_pdata* pdata); + int (*disable_ns_offload)(struct fxgmac_pdata* pdata); + + int (*enable_wake_magic_pattern)(struct fxgmac_pdata* pdata); + int (*disable_wake_magic_pattern)(struct fxgmac_pdata* pdata); + + int (*enable_wake_link_change)(struct fxgmac_pdata* pdata); + int (*disable_wake_link_change)(struct fxgmac_pdata* pdata); + + int (*check_wake_pattern_fifo_pointer)(struct fxgmac_pdata* pdata); + int (*set_wake_pattern)(struct fxgmac_pdata* pdata, struct wol_bitmap_pattern* wol_pattern, u32 pattern_cnt); + int (*enable_wake_pattern)(struct fxgmac_pdata* pdata);//int XlgmacEnableArpload(struct fxgmac_pdata* pdata,unsigned char *ip_addr) + int (*disable_wake_pattern)(struct fxgmac_pdata* pdata); + int (*set_wake_pattern_mask)(struct fxgmac_pdata* pdata, u32 filter_index, u8 register_index, u32 Data); +#if defined(FUXI_PM_WPI_READ_FEATURE_EN) && FUXI_PM_WPI_READ_FEATURE_EN + void (*get_wake_packet_indication)(struct fxgmac_pdata* pdata, int* wake_reason, u32* wake_pattern_number, u8* wpi_buf, u32 buf_size, u32* packet_size); + void (*enable_wake_packet_indication)(struct fxgmac_pdata* pdata, int en); +#endif +#endif + + void (*reset_phy)(struct fxgmac_pdata* pdata); + /*for release phy,phy write and read, and provide clock to GMAC. */ + void (*release_phy)(struct fxgmac_pdata* pdata); +#if !defined(UEFI) + void (*enable_phy_check)(struct fxgmac_pdata* pdata); + void (*disable_phy_check)(struct fxgmac_pdata* pdata); + void (*setup_cable_loopback)(struct fxgmac_pdata* pdata); + void (*clean_cable_loopback)(struct fxgmac_pdata* pdata); + void (*disable_phy_sleep)(struct fxgmac_pdata* pdata); + void (*enable_phy_sleep)(struct fxgmac_pdata* pdata); + void (*phy_green_ethernet)(struct fxgmac_pdata* pdata); + void (*phy_eee_feature)(struct fxgmac_pdata* pdata); +#endif + int (*get_ephy_state)(struct fxgmac_pdata* pdata); + int (*write_ephy_reg)(struct fxgmac_pdata* pdata, u32 val, u32 data); + int (*read_ephy_reg)(struct fxgmac_pdata* pdata, u32 val, u32 *data); + int (*set_ephy_autoneg_advertise)(struct fxgmac_pdata* pdata, struct fxphy_ag_adv phy_ag_adv); + int (*phy_config)(struct fxgmac_pdata* pdata); + void (*close_phy_led)(struct fxgmac_pdata* pdata); + void (*led_under_active)(struct fxgmac_pdata* pdata); + void (*led_under_sleep)(struct fxgmac_pdata* pdata); + void (*led_under_shutdown)(struct fxgmac_pdata* pdata); + void (*led_under_disable)(struct fxgmac_pdata* pdata); + + /* For power management */ + void (*pre_power_down)(struct fxgmac_pdata* pdata, bool phyloopback); +#if defined(LINUX) + int (*diag_sanity_check)(struct fxgmac_pdata *pdata); + int (*write_rss_lookup_table)(struct fxgmac_pdata *pdata); + int (*get_rss_hash_key)(struct fxgmac_pdata *pdata, u8 *key_buf); + void (*config_power_down)(struct fxgmac_pdata *pdata, unsigned int wol); +#else + void (*config_power_down)(struct fxgmac_pdata* pdata, unsigned int offloadcount, bool magic_en, bool remote_pattern_en); +#endif + void (*config_power_up)(struct fxgmac_pdata* pdata); + unsigned char (*set_suspend_int)(void* pdata); + void(*set_resume_int)(struct fxgmac_pdata* pdata); + int (*set_suspend_txrx)(struct fxgmac_pdata* pdata); + void (*set_pwr_clock_gate)(struct fxgmac_pdata* pdata); + void (*set_pwr_clock_ungate)(struct fxgmac_pdata* pdata); + + /* for multicast address list */ + int (*set_all_multicast_mode)(struct fxgmac_pdata* pdata, unsigned int enable); + void (*config_multicast_mac_hash_table)(struct fxgmac_pdata* pdata, unsigned char* pmc_mac, int b_add); + + /* for packet filter-promiscuous and broadcast */ + int (*set_promiscuous_mode)(struct fxgmac_pdata* pdata, unsigned int enable); + int (*enable_rx_broadcast)(struct fxgmac_pdata* pdata, unsigned int enable); + + /* efuse relevant operation. */ + bool (*read_patch_from_efuse)(struct fxgmac_pdata* pdata, u32 offset, u32* value); /* read patch per index. */ + bool (*read_patch_from_efuse_per_index)(struct fxgmac_pdata* pdata, u8 index, u32* offset, u32* value); /* read patch per index. */ + bool (*write_patch_to_efuse)(struct fxgmac_pdata* pdata, u32 offset, u32 value); + bool (*write_patch_to_efuse_per_index)(struct fxgmac_pdata* pdata, u8 index, u32 offset, u32 value); + bool (*read_mac_subsys_from_efuse)(struct fxgmac_pdata* pdata, u8* mac_addr, u32* subsys, u32* revid); + bool (*write_mac_subsys_to_efuse)(struct fxgmac_pdata* pdata, u8* mac_addr, u32* subsys, u32* revid); + bool (*read_mac_addr_from_efuse)(struct fxgmac_pdata* pdata, u8* mac_addr); + bool (*write_mac_addr_to_efuse)(struct fxgmac_pdata* pdata, u8* mac_addr); + bool (*efuse_load)(struct fxgmac_pdata* pdata); + bool (*read_efuse_data)(struct fxgmac_pdata* pdata, u32 offset, u32* value); + bool (*write_oob)(struct fxgmac_pdata* pdata); + bool (*write_led)(struct fxgmac_pdata* pdata, u32 value); + bool (*read_led_config)(struct fxgmac_pdata* pdata); + bool (*write_led_config)(struct fxgmac_pdata* pdata); + + int (*pcie_init)(struct fxgmac_pdata* pdata, bool ltr_en, bool aspm_l1ss_en, bool aspm_l1_en, bool aspm_l0s_en); + void (*trigger_pcie)(struct fxgmac_pdata* pdata, u32 code); // To trigger pcie sniffer for analysis. +#ifdef DPDK + int (*phy_init)(struct fxgmac_pdata *); + int (*phy_start)(struct fxgmac_pdata *); + void (*phy_stop)(struct fxgmac_pdata *); + void (*phy_status)(struct fxgmac_pdata *); + void (*an_isr)(struct fxgmac_pdata *); /* phy_if->an_isr For single interrupt support */ +#endif +}; + +/* This structure contains flags that indicate what hardware features + * or configurations are present in the device. + */ +struct fxgmac_hw_features { + /* HW Version */ + unsigned int version; + + /* HW Feature Register0 */ + unsigned int phyifsel; /* PHY interface support */ + unsigned int vlhash; /* VLAN Hash Filter */ + unsigned int sma; /* SMA(MDIO) Interface */ + unsigned int rwk; /* PMT remote wake-up packet */ + unsigned int mgk; /* PMT magic packet */ + unsigned int mmc; /* RMON module */ + unsigned int aoe; /* ARP Offload */ + unsigned int ts; /* IEEE 1588-2008 Advanced Timestamp */ + unsigned int eee; /* Energy Efficient Ethernet */ + unsigned int tx_coe; /* Tx Checksum Offload */ + unsigned int rx_coe; /* Rx Checksum Offload */ + unsigned int addn_mac; /* Additional MAC Addresses */ + unsigned int ts_src; /* Timestamp Source */ + unsigned int sa_vlan_ins; /* Source Address or VLAN Insertion */ + + /* HW Feature Register1 */ + unsigned int rx_fifo_size; /* MTL Receive FIFO Size */ + unsigned int tx_fifo_size; /* MTL Transmit FIFO Size */ + unsigned int adv_ts_hi; /* Advance Timestamping High Word */ + unsigned int dma_width; /* DMA width */ + unsigned int dcb; /* DCB Feature */ + unsigned int sph; /* Split Header Feature */ + unsigned int tso; /* TCP Segmentation Offload */ + unsigned int dma_debug; /* DMA Debug Registers */ + unsigned int rss; /* Receive Side Scaling */ + unsigned int tc_cnt; /* Number of Traffic Classes */ + unsigned int avsel; /* AV Feature Enable */ + unsigned int ravsel; /* Rx Side Only AV Feature Enable */ + unsigned int hash_table_size; /* Hash Table Size */ + unsigned int l3l4_filter_num; /* Number of L3-L4 Filters */ + + /* HW Feature Register2 */ + unsigned int rx_q_cnt; /* Number of MTL Receive Queues */ + unsigned int tx_q_cnt; /* Number of MTL Transmit Queues */ + unsigned int rx_ch_cnt; /* Number of DMA Receive Channels */ + unsigned int tx_ch_cnt; /* Number of DMA Transmit Channels */ + unsigned int pps_out_num; /* Number of PPS outputs */ + unsigned int aux_snap_num; /* Number of Aux snapshot inputs */ + + /* HW Feature Register3 */ + u32 hwfr3; +}; + +struct fxgmac_resources { + IOMEM addr; + int irq; +}; + +struct fxgmac_pdata { + struct net_device *netdev; + struct device *dev; + PCI_DEV *pdev; + void *pAdapter; + + struct fxgmac_hw_ops hw_ops; + struct fxgmac_desc_ops desc_ops; + + /* Device statistics */ + struct fxgmac_stats stats; + + u32 msg_enable; + u32 reg_nonstick[0x300 >> 2]; + + /* MAC registers base */ + IOMEM mac_regs; + IOMEM base_mem; + + /* Hardware features of the device */ + struct fxgmac_hw_features hw_feat; + + /* Rings for Tx/Rx on a DMA channel */ + struct fxgmac_channel *channel_head; + unsigned int channel_count; + unsigned int tx_ring_count; + unsigned int rx_ring_count; + unsigned int tx_desc_count; + unsigned int rx_desc_count; + unsigned int tx_q_count; + unsigned int rx_q_count; + + /* Tx/Rx common settings */ + unsigned int pblx8; + + /* Tx settings */ + unsigned int tx_sf_mode; + unsigned int tx_threshold; + unsigned int tx_pbl; + unsigned int tx_osp_mode; +#if FXGMAC_TX_HANG_TIMER_EN + /* for tx hang checking. 20211227 */ + unsigned int tx_hang_restart_queuing; +#endif + + /* Rx settings */ + unsigned int rx_sf_mode; + unsigned int rx_threshold; + unsigned int rx_pbl; + + /* Tx coalescing settings */ + unsigned int tx_usecs; + unsigned int tx_frames; + + /* Rx coalescing settings */ + unsigned int rx_riwt; + unsigned int rx_usecs; + unsigned int rx_frames; + + /* Current Rx buffer size */ + unsigned int rx_buf_size; + + /* Flow control settings */ + unsigned int tx_pause; + unsigned int rx_pause; + + /* Jumbo frames */ + unsigned int mtu; + unsigned int jumbo; + + /* CRC checking */ + unsigned int crc_check; + + /* MSIX */ + unsigned int msix; + + /* RSS */ + unsigned int rss; + + /* VlanID */ + unsigned int vlan; + unsigned int vlan_exist; + unsigned int vlan_filter; + unsigned int vlan_strip; + + /* Interrupt Moderation */ + unsigned int intr_mod; + unsigned int intr_mod_timer; + + /* Device interrupt number */ + int dev_irq; + unsigned int per_channel_irq; + u32 channel_irq[FXGMAC_MAX_DMA_CHANNELS_PLUS_1TX]; // change type from int to u32 to match MSIx, p_msix_entry.vector; + + /* Netdev related settings */ + unsigned char mac_addr[ETH_ALEN]; + + /* Filtering support */ +#if FXGMAC_FILTER_MULTIPLE_VLAN_ENABLED + unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)]; +#endif + + /* Device clocks */ + unsigned long sysclk_rate; + + /* Receive Side Scaling settings */ + u8 rss_key[FXGMAC_RSS_HASH_KEY_SIZE]; + u32 rss_table[FXGMAC_RSS_MAX_TABLE_SIZE]; + u32 rss_options; + + int phy_speed; + int phy_duplex; + int phy_autoeng; + + char drv_name[32]; + char drv_ver[32]; + + struct wol_bitmap_pattern pattern[MAX_PATTERN_COUNT]; + + struct led_setting led; + struct led_setting ledconfig; + + FXGMAC_PDATA_OF_PLATFORM expansion; + + u32 pcie_link_status; +}; + +//#ifdef CONFIG_PCI_MSI +#if 1 +#define FXGMAC_FLAG_MSI_CAPABLE (u32)(1 << 0) // bit0 +#define FXGMAC_FLAG_MSI_ENABLED (u32)(1 << 1) // bit1 +#define FXGMAC_FLAG_MSIX_CAPABLE (u32)(1 << 2) // bit2 +#define FXGMAC_FLAG_MSIX_ENABLED (u32)(1 << 3) // bit3 +#define FXGMAC_FLAG_LEGACY_ENABLED (u32)(1 << 4) // bit4 + +#define FXGMAC_FLAG_INTERRUPT_POS 0 +#define FXGMAC_FLAG_INTERRUPT_LEN 5 + +#define FXGMAC_FLAG_MSI_POS 1 +#define FXGMAC_FLAG_MSI_LEN 1 +#define FXGMAC_FLAG_MSIX_POS 3 +#define FXGMAC_FLAG_MSIX_LEN 1 +#define FXGMAC_FLAG_LEGACY_POS 4 +#define FXGMAC_FLAG_LEGACY_LEN 1 +#define FXGMAC_FLAG_LEGACY_IRQ_FREE_POS 31 //bit31 +#define FXGMAC_FLAG_LEGACY_IRQ_FREE_LEN 1 +#define FXGMAC_FLAG_LEGACY_NAPI_FREE_POS 30 //bit30 +#define FXGMAC_FLAG_LEGACY_NAPI_FREE_LEN 1 +#endif + +void fxgmac_init_desc_ops(struct fxgmac_desc_ops *desc_ops); +void fxgmac_init_hw_ops(struct fxgmac_hw_ops *hw_ops); +const struct net_device_ops *fxgmac_get_netdev_ops(void); +const struct ethtool_ops *fxgmac_get_ethtool_ops(void); +void fxgmac_dump_tx_desc(struct fxgmac_pdata *pdata, + struct fxgmac_ring *ring, + unsigned int idx, + unsigned int count, + unsigned int flag); +void fxgmac_dump_rx_desc(struct fxgmac_pdata *pdata, + struct fxgmac_ring *ring, + unsigned int idx); +void fxgmac_dbg_pkt(struct net_device *netdev, + struct sk_buff *skb, bool tx_rx); +void fxgmac_get_all_hw_features(struct fxgmac_pdata *pdata); +void fxgmac_print_all_hw_features(struct fxgmac_pdata *pdata); +int fxgmac_drv_probe(struct device *dev, + struct fxgmac_resources *res); +int fxgmac_drv_remove(struct device *dev); + +#endif /* __FUXI_GMAC_H__ */ diff --git a/drivers/net/ethernet/motorcomm/fuxi-os.h b/drivers/net/ethernet/motorcomm/fuxi-os.h new file mode 100644 index 000000000000..26518fae6ae6 --- /dev/null +++ b/drivers/net/ethernet/motorcomm/fuxi-os.h @@ -0,0 +1,560 @@ +/*++ + +Copyright (c) 2021 Motor-comm Corporation. +Confidential and Proprietary. All rights reserved. + +This is Motor-comm Corporation NIC driver relevant files. +Please don't copy, modify,distribute without commercial permission. + +--*/ + + +#ifndef __FUXI_OS_H__ +#define __FUXI_OS_H__ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_PCI_MSI +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#define LINUX + +#ifndef LINUX_VERSION_CODE +#include +#else +#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,19,0)) +#include +#endif + +#include "fuxi-dbg.h" + +struct fxgmac_ring; +struct fxgmac_pdata; + +#define FXGMAC_DRV_VERSION "1.0.27" + +#ifdef CONFIG_PCI_MSI +//#undef CONFIG_PCI_MSI //undefined for legacy interupt mode +#endif + +#define PCIE_LP_ASPM_L0S 1 +#define PCIE_LP_ASPM_L1 2 +#define PCIE_LP_ASPM_L1SS 4 +#define PCIE_LP_ASPM_LTR 8 + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,19,0)) +/* + * There are multiple 16-bit CRC polynomials in common use, but this is + * *the* standard CRC-32 polynomial, first popularized by Ethernet. + * x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x^1+x^0 + */ +#define CRC32_POLY_LE 0xedb88320 +#define CRC32_POLY_BE 0x04c11db7 + +/* + * This is the CRC32c polynomial, as outlined by Castagnoli. + * x^32+x^28+x^27+x^26+x^25+x^23+x^22+x^20+x^19+x^18+x^14+x^13+x^11+x^10+x^9+ + * x^8+x^6+x^0 + */ +#define CRC32C_POLY_LE 0x82F63B78 +#endif + +#define FXGMAC_FAIL -1 +#define FXGMAC_SUCCESS 0 +#define FXGMAC_DEV_CMD (SIOCDEVPRIVATE + 1) +#define FXGMAC_IOCTL_DFS_COMMAND _IOWR('M', 0x80, struct ext_ioctl_data) + +#define FXGMAC_MAX_DBG_TEST_PKT 150 +#define FXGMAC_MAX_DBG_BUF_LEN 64000 +#define FXGMAC_MAX_DBG_RX_DATA 1600 +#define FXGMAC_NETDEV_OPS_BUF_LEN 256 + +#define FXGMAC_TEST_MAC_HEAD_LEN 14 + +#define FUXI_PM_WPI_READ_FEATURE_EN 1 + +#define RSS_Q_COUNT 4 + +//#define FXGMAC_TX_INTERRUPT_EN 1 +#define FXGMAC_TX_HANG_TIMER_EN 0 +/* only for debug. for normal run, pls keep them both 0 */ +//0: use default tx q; other: specify txq-1: 1 txq; +#define FXGMAC_NUM_OF_TX_Q_USED 0 +//1 to enable a dummy tx,ie, no tail for gmac; +#define FXGMAC_DUMMY_TX_DEBUG 0 +//1 to trigger(write reg 0x1000) for sniffer stop +#define FXGMAC_TRIGGER_TX_HANG 0 + +/* driver feature configuration */ +#if FXGMAC_TX_HANG_TIMER_EN +//0: check hw current desc; 1: check software dirty +#define FXGMAC_TX_HANG_CHECH_DIRTY 0 +#endif + +// 1:poll tx of 4 channels; 0: since only 1 tx channel supported in this +// version, poll ch 0 always. +#define FXGMAC_FULL_TX_CHANNEL 0 + +#ifdef CONFIG_ARM64 +// when you want to run this driver on 64bit arm,you should open this,otherwise +// dma's mask cannot be set successfully. +#define FUXI_DMA_BIT_MASK 64 +#endif + +#ifdef CONFIG_PCI_MSI +//should be same as FXGMAC_MAX_DMA_CHANNELS + 1 tx_irq +#define FXGMAC_MAX_MSIX_Q_VECTORS (FXGMAC_MSIX_Q_VECTORS + 1) +#define FXGMAC_MSIX_CH0RXDIS_EN 0 //set to 1 for ch0 unbalance fix; +#define FXGMAC_MSIX_INTCTRL_EN 1 + +#define FXGMAC_PHY_INT_NUM 1 +#define FXGMAC_MSIX_INT_NUMS (FXGMAC_MAX_MSIX_Q_VECTORS + FXGMAC_PHY_INT_NUM) +#else //for case of no CONFIG_PCI_MSI +#define FXGMAC_MSIX_CH0RXDIS_EN 0 //NO modification needed! for non-MSI, set to 0 always +#define FXGMAC_MSIX_INTCTRL_EN 0 +#endif + +/*RSS features*/ +#ifdef FXGMAC_ONE_CHANNEL +#define FXGMAC_RSS_FEATURE_ENABLED 0 // 1:enable rss ; 0: rss not included. +#else +#define FXGMAC_RSS_FEATURE_ENABLED 1 // 1:enable rss ; 0: rss not included. +#endif +#define FXGMAC_RSS_HASH_KEY_LINUX 1 // 0:hard to default rss key ;1: normal hash key process from Linux. + +/*WOL features*/ +#define FXGMAC_WOL_FEATURE_ENABLED 1 // 1:enable wol ; 0: wol not included. +/*since wol upon link will cause issue, disabled it always. */ +#define FXGMAC_WOL_UPON_EPHY_LINK 1 // 1:enable ephy link change wol ; 0: ephy link change wol is not supported. + +/*Pause features*/ +#define FXGMAC_PAUSE_FEATURE_ENABLED 1 // 1:enable flow control/pause framce ; 0: flow control/pause frame not included. + +/*ARP offload engine (AOE)*/ +#define FXGMAC_AOE_FEATURE_ENABLED 1 // 1:enable arp offload engine ; 0: aoe is not included. + +/*NS offload engine*/ +#define FXGMAC_NS_OFFLOAD_ENABLED 1 // 1:enable NS offload for IPv6 ; 0: NS is not included. + +/*for fpga ver after, which needs release phy before set of MAC tx/rx */ +#define FXGMAC_TXRX_EN_AFTER_PHY_RELEASE 1 // 1:release ephy before mac tx/rx bits are set. + +/*power management features*/ +#define FXGMAC_PM_FEATURE_ENABLED 1 // 1:enable PM ; 0: PM not included. + +/*sanity check*/ +#define FXGMAC_SANITY_CHECK_ENABLED 0 // 1:enable health checking ; + +/*vlan id filter*/ +#define FXGMAC_FILTER_SINGLE_VLAN_ENABLED 1 // 1:enable health checking ; + +//Linux driver implement VLAN HASH Table feature to support mutliple VLAN feautre +#define FXGMAC_FILTER_MULTIPLE_VLAN_ENABLED 1 + +//Linux driver implement MAC HASH Table feature +#define FUXI_MAC_HASH_TABLE 1 + +//Linux driver implement write multiple mac addr +#define FXGMAC_FILTER_MULTIPLE_MAC_ADDR_ENABLED 1 + +//Linux driver disable MISC Interrupt +#define FUXI_MISC_INT_HANDLE_FEATURE_EN 1 + +#define HAVE_FXGMAC_DEBUG_FS + +#ifndef offsetof +#define offsetof(TYPE, MEMBER) ((size_t) &(((TYPE*)0)->MEMBER)) +#endif + +#define ETH_IS_ZEROADDRESS(Address) \ + ((((u8*)(Address))[0] == ((u8)0x00)) \ + && (((u8*)(Address))[1] == ((u8)0x00)) \ + && (((u8*)(Address))[2] == ((u8)0x00)) \ + && (((u8*)(Address))[3] == ((u8)0x00)) \ + && (((u8*)(Address))[4] == ((u8)0x00)) \ + && (((u8*)(Address))[5] == ((u8)0x00))) + + /* read from 8bit register via pci config space */ +#define cfg_r8(_pdata, reg, pdat) pci_read_config_byte((_pdata)->pdev, (reg), (u8 *)(pdat)) + + /* read from 16bit register via pci config space */ +#define cfg_r16(_pdata, reg, pdat) pci_read_config_word((_pdata)->pdev, (reg), (u16 *)(pdat)) + + /* read from 32bit register via pci config space */ +#define cfg_r32(_pdata, reg, pdat) pci_read_config_dword((_pdata)->pdev, (reg), (u32 *)(pdat)) + +/* write to 8bit register via pci config space */ +#define cfg_w8(_pdata, reg, val) pci_write_config_byte((_pdata)->pdev, (reg), (u8)(val)) + +/* write to 16bit register via pci config space */ +#define cfg_w16(_pdata, reg, val) pci_write_config_word((_pdata)->pdev, (reg), (u16)(val)) + +/* write to 32bit register via pci config space */ +#define cfg_w32(_pdata, reg, val) pci_write_config_dword((_pdata)->pdev, (reg), (u32)(val)) + +#define readreg(pAdapter, addr) (readl(addr)) +#define writereg(pAdapter, val, addr) (writel(val, addr)) +#define usleep_range_ex(pAdapter, a, b) (usleep_range(a, b)) +#define _CR(Record, TYPE, Field) ((TYPE *) ((char *) (Record) - (char *) &(((TYPE *) 0)->Field))) + +#define FXGMAC_GET_REG_BITS(var, pos, len) ({ \ + typeof(pos) _pos = (pos); \ + typeof(len) _len = (len); \ + ((var) & GENMASK(_pos + _len - 1, _pos)) >> (_pos); \ +}) + +#define FXGMAC_GET_REG_BITS_LE(var, pos, len) ({ \ + typeof(pos) _pos = (pos); \ + typeof(len) _len = (len); \ + typeof(var) _var = le32_to_cpu((var)); \ + ((_var) & GENMASK(_pos + _len - 1, _pos)) >> (_pos); \ +}) + +#define FXGMAC_SET_REG_BITS(var, pos, len, val) ({ \ + typeof(var) _var = (var); \ + typeof(pos) _pos = (pos); \ + typeof(len) _len = (len); \ + typeof(val) _val = (val); \ + _val = (_val << _pos) & GENMASK(_pos + _len - 1, _pos); \ + _var = (_var & ~GENMASK(_pos + _len - 1, _pos)) | _val; \ +}) + +#define FXGMAC_SET_REG_BITS_LE(var, pos, len, val) ({ \ + typeof(var) _var = (var); \ + typeof(pos) _pos = (pos); \ + typeof(len) _len = (len); \ + typeof(val) _val = (val); \ + _val = (_val << _pos) & GENMASK(_pos + _len - 1, _pos); \ + _var = (_var & ~GENMASK(_pos + _len - 1, _pos)) | _val; \ + cpu_to_le32(_var); \ +}) + +#define STR_FORMAT "%s" + +#define DbgPrintF(level, fmt, ...) +#define DBGPRINT(Level, Fmt) +#define DBGPRINT_RAW(Level, Fmt) +#define DBGPRINT_S(Status, Fmt) +#define DBGPRINT_UNICODE(Level, UString) +#define Dump(p,cb,fAddress,ulGroup) + +#undef ASSERT +#define ASSERT(x) + +#define DbgPrintOidName(_Oid) +#define DbgPrintAddress(_pAddress) + +#define fxgmac_dump_buffer(_skb, _len, _tx_rx) +#define DumpLine(_p, _cbLine, _fAddress, _ulGroup ) + +#ifndef FXGMAC_DEBUG +#define FXGMAC_DEBUG +#endif + +/* For debug prints */ +#ifdef FXGMAC_DEBUG +#define FXGMAC_PR(fmt, args...) \ + pr_alert("[%s,%d]:" fmt, __func__, __LINE__, ## args) + +#define DPRINTK printk +#else +#define FXGMAC_PR(x...) do { } while (0) +#define DPRINTK(x...) +#endif + +#define IOC_MAGIC 'M' +#define IOC_MAXNR (0x80 + 5) + +#define FUXI_DFS_IOCTL_DEVICE_INACTIVE 0x10001 +#define FUXI_DFS_IOCTL_DEVICE_RESET 0x10002 +#define FUXI_DFS_IOCTL_DIAG_BEGIN 0x10003 +#define FUXI_DFS_IOCTL_DIAG_END 0x10004 +#define FUXI_DFS_IOCTL_DIAG_TX_PKT 0x10005 +#define FUXI_DFS_IOCTL_DIAG_RX_PKT 0x10006 + +#define FXGMAC_EFUSE_UPDATE_LED_CFG 0x10007 +#define FXGMAC_EFUSE_WRITE_LED 0x10008 +#define FXGMAC_EFUSE_WRITE_PATCH_REG 0x10009 +#define FXGMAC_EFUSE_WRITE_PATCH_PER_INDEX 0x1000A +#define FXGMAC_EFUSE_WRITE_OOB 0x1000B +#define FXGMAC_EFUSE_LOAD 0x1000C +#define FXGMAC_EFUSE_READ_REGIONABC 0x1000D +#define FXGMAC_EFUSE_READ_PATCH_REG 0x1000E +#define FXGMAC_EFUSE_READ_PATCH_PER_INDEX 0x1000F +#define FXGMAC_EFUSE_LED_TEST 0x10010 + +#define FXGMAC_GET_MAC_DATA 0x10011 +#define FXGMAC_SET_MAC_DATA 0x10012 +#define FXGMAC_GET_SUBSYS_ID 0x10013 +#define FXGMAC_SET_SUBSYS_ID 0x10014 +#define FXGMAC_GET_GMAC_REG 0x10015 +#define FXGMAC_SET_GMAC_REG 0x10016 +#define FXGMAC_GET_PHY_REG 0x10017 +#define FXGMAC_SET_PHY_REG 0x10018 +#define FXGMAC_EPHYSTATISTICS 0x10019 +#define FXGMAC_GET_STATISTICS 0x1001A +#define FXGMAC_GET_PCIE_LOCATION 0x1001B + +#define FXGMAC_GET_GSO_SIZE 0x1001C +#define FXGMAC_SET_GSO_SIZE 0x1001D +#define FXGMAC_SET_RX_MODERATION 0x1001E +#define FXGMAC_SET_TX_MODERATION 0x1001F +#define FXGMAC_GET_TXRX_MODERATION 0x10020 + +#define MAX_PKT_BUF 1 +#define FXGAMC_MAX_DATA_SIZE (1024 * 4 + 16) + +#ifndef PCI_CAP_ID_MSI +#define PCI_CAP_ID_MSI 0x05 /* Message Signalled Interrupts */ +#endif + +#ifndef PCI_CAP_ID_MSIX +#define PCI_CAP_ID_MSIX 0x11 /* MSI-X */ +#endif + +#define PCI_CAP_ID_MSI_ENABLE_POS 0x10 +#define PCI_CAP_ID_MSI_ENABLE_LEN 0x1 +#define PCI_CAP_ID_MSIX_ENABLE_POS 0x1F +#define PCI_CAP_ID_MSIX_ENABLE_LEN 0x1 + +#ifndef fallthrough +#if __has_attribute(__fallthrough__) +# define fallthrough __attribute__((__fallthrough__)) +#else +# define fallthrough do {} while (0) /* fallthrough */ +#endif +#endif + + +#pragma pack(1) +// it's better to make this struct's size to 128byte. +struct pattern_packet{ + u8 ether_daddr[ETH_ALEN]; + u8 ether_saddr[ETH_ALEN]; + u16 ether_type; + + __be16 ar_hrd; /* format of hardware address */ + __be16 ar_pro; /* format of protocol */ + unsigned char ar_hln; /* length of hardware address */ + unsigned char ar_pln; /* length of protocol address */ + __be16 ar_op; /* ARP opcode (command) */ + unsigned char ar_sha[ETH_ALEN]; /* sender hardware address */ + unsigned char ar_sip[4]; /* sender IP address */ + unsigned char ar_tha[ETH_ALEN]; /* target hardware address */ + unsigned char ar_tip[4]; /* target IP address */ + + u8 reverse[86]; +}; +#pragma pack() + +typedef enum +{ + CURRENT_STATE_SHUTDOWN = 0, + CURRENT_STATE_RESUME = 1, + CURRENT_STATE_INIT = 2, + CURRENT_STATE_SUSPEND = 3, + CURRENT_STATE_CLOSE = 4, + CURRENT_STATE_OPEN = 5, + CURRENT_STATE_RESTART = 6, + CURRENT_STATE_REMOVE = 7, +}CURRENT_STATE; + +typedef dma_addr_t DMA_ADDR_T; +typedef enum pkt_hash_types RSS_HASH_TYPE; +typedef void __iomem* IOMEM; +typedef struct pci_dev PCI_DEV; + +struct ext_command_buf { + void* buf; + u32 size_in; + u32 size_out; +}; + +struct ext_command_mac { + u32 num; + union { + u32 val32; + u16 val16; + u8 val8; + }; +}; + +struct ext_command_mii { + u16 dev; + u16 num; + u16 val; +}; + +struct ext_ioctl_data { + u32 cmd_type; + struct ext_command_buf cmd_buf; +}; + +typedef struct _fxgmac_test_buf { + u8* addr; + u32 offset; + u32 length; +} fxgmac_test_buf, *pfxgmac_test_buf; + +typedef struct _fxgmac_test_packet { + struct _fxgmac_test_packet * next; + u32 length; /* total length of the packet(buffers) */ + u32 type; /* packet type, vlan, ip checksum, TSO, etc. */ + + fxgmac_test_buf buf[MAX_PKT_BUF]; + fxgmac_test_buf sGList[MAX_PKT_BUF]; + u16 vlanID; + u16 mss; + u32 hash; + u16 cpuNum; + u16 xsum; /* rx, ip-payload checksum */ + u16 csumStart; /* custom checksum offset to the mac-header */ + u16 csumPos; /* custom checksom position (to the mac_header) */ + void* upLevelReserved[4]; + void* lowLevelReserved[4]; +} fxgmac_test_packet, *pfxgmac_test_packet; + +typedef struct fxgmac_channel_of_platform +{ + char dma_irq_name[IFNAMSIZ + 32]; + + u32 dma_irq_tx; //for MSIx to match the type of struct msix_entry.vector + char dma_irq_name_tx[IFNAMSIZ + 32]; + + /* Netdev related settings */ + struct napi_struct napi_tx; + + /* Netdev related settings */ + struct napi_struct napi_rx; + struct timer_list tx_timer; + +#if FXGMAC_TX_HANG_TIMER_EN + unsigned int tx_hang_timer_active; + struct timer_list tx_hang_timer; + unsigned int tx_hang_hw_cur; +#endif +}FXGMAC_CHANNEL_OF_PLATFORM; + +typedef struct per_regisiter_info +{ + unsigned int size; + unsigned int address; + unsigned int value; + unsigned char data[FXGAMC_MAX_DATA_SIZE]; +}PER_REG_INFO; + +// for FXGMAC_EFUSE_WRITE_PATCH_PER_INDEX,val0 is index, val1 is offset, +// val2 is value +typedef struct ext_command_data { + u32 val0; + u32 val1; + u32 val2; +}CMD_DATA; + +typedef struct fxgmac_pdata_of_platform +{ + u32 cfg_pci_cmd; + u32 cfg_cache_line_size; + u32 cfg_mem_base; + u32 cfg_mem_base_hi; + u32 cfg_io_base; + u32 cfg_int_line; + u32 cfg_device_ctrl1; + u32 cfg_pci_link_ctrl; + u32 cfg_device_ctrl2; + u32 cfg_msix_capability; + + struct work_struct restart_work; + u32 int_flags; //legacy, msi or msix + int phy_irq; +#ifdef CONFIG_PCI_MSI + struct msix_entry *msix_entries; +#endif + + /* power management and wol*/ + u32 wol; //wol options + unsigned long powerstate; //power state + unsigned int ns_offload_tab_idx; //for ns-offload table. 2 entries supported. + CURRENT_STATE current_state; + netdev_features_t netdev_features; + struct napi_struct napi; + struct napi_struct napi_phy; + u32 mgm_intctrl_val; + bool phy_link; + bool fxgmac_test_tso_flag; + u32 fxgmac_test_tso_seg_num; + u32 fxgmac_test_last_tso_len; + u32 fxgmac_test_packet_len; + volatile u32 fxgmac_test_skb_arr_in_index; + volatile u32 fxgmac_test_skb_arr_out_index; + //CMD_DATA ex_cmd_data; + //PER_REG_INFO per_reg_data; + struct sk_buff *fxgmac_test_skb_array[FXGMAC_MAX_DBG_TEST_PKT]; +#ifdef HAVE_FXGMAC_DEBUG_FS + struct dentry *dbg_adapter; + struct dentry *fxgmac_dbg_root; + char fxgmac_dbg_netdev_ops_buf[FXGMAC_NETDEV_OPS_BUF_LEN]; +#endif +}FXGMAC_PDATA_OF_PLATFORM; + + +#ifdef HAVE_FXGMAC_DEBUG_FS +void fxgmac_dbg_adapter_init(struct fxgmac_pdata *pdata); +void fxgmac_dbg_adapter_exit(struct fxgmac_pdata *pdata); +void fxgmac_dbg_init(struct fxgmac_pdata *pdata); +void fxgmac_dbg_exit(struct fxgmac_pdata *pdata); +#endif /* HAVE_FXGMAC_DEBUG_FS */ + +void fxgmac_restart_dev(struct fxgmac_pdata *pdata); +long fxgmac_dbg_netdev_ops_ioctl(struct file *file, unsigned int cmd, + unsigned long arg); + +int fxgmac_init(struct fxgmac_pdata *pdata, bool save_private_reg); +/* for phy interface */ +int fxgmac_ephy_autoneg_ability_get(struct fxgmac_pdata *pdata, + unsigned int *cap_mask); +int fxgmac_ephy_status_get(struct fxgmac_pdata *pdata, int* speed, + int* duplex, int* ret_link, int *media); +int fxgmac_ephy_soft_reset(struct fxgmac_pdata *pdata); +void fxgmac_phy_force_speed(struct fxgmac_pdata *pdata, int speed); +void fxgmac_phy_force_duplex(struct fxgmac_pdata *pdata, int duplex); +void fxgmac_phy_force_autoneg(struct fxgmac_pdata *pdata, int autoneg); + +unsigned int fxgmac_get_netdev_ip4addr(struct fxgmac_pdata *pdata); +unsigned char * fxgmac_get_netdev_ip6addr(struct fxgmac_pdata *pdata, + unsigned char *ipval, + unsigned char *ip6addr_solicited, + unsigned int ifa_flag); + +#if FXGMAC_PM_FEATURE_ENABLED +void fxgmac_net_powerdown(struct fxgmac_pdata *pdata, unsigned int wol); +void fxgmac_net_powerup(struct fxgmac_pdata *pdata); +#endif + +inline unsigned int fxgmac_tx_avail_desc(struct fxgmac_ring *ring); +inline unsigned int fxgmac_rx_dirty_desc(struct fxgmac_ring *ring); +int fxgmac_start(struct fxgmac_pdata *pdata); +void fxgmac_stop(struct fxgmac_pdata *pdata); +void fxgmac_free_rx_data(struct fxgmac_pdata *pdata); +void fxgmac_free_tx_data(struct fxgmac_pdata *pdata); + +#endif //__FUXI_OS_H__ + -- 2.34.3