pax_global_header 0000666 0000000 0000000 00000000064 15126421535 0014516 g ustar 00root root 0000000 0000000 52 comment=96cca17e199dbfbd4df48db08936171117239cd8
yt6801-dkms-1.0.31/ 0000775 0000000 0000000 00000000000 15126421535 0013507 5 ustar 00root root 0000000 0000000 yt6801-dkms-1.0.31/src/ 0000775 0000000 0000000 00000000000 15126421535 0014276 5 ustar 00root root 0000000 0000000 yt6801-dkms-1.0.31/src/Makefile 0000664 0000000 0000000 00000007173 15126421535 0015746 0 ustar 00root root 0000000 0000000 # SPDX-License-Identifier: GPL-2.0
# Copyright (c) 2021 Motor-comm Corporation.
#
# Makefile for the Motorcomm(R) 6801 PCI-Express ethernet driver
#
moderation_en?=1
moderation_param?=200
FXGMAC_SMART_SPEED_DISABLE = OFF
FXGMAC_PHY_SLEEP_ENABLE = OFF
FXGMAC_ASPM_ENABLED = OFF
FXGMAC_NOT_USE_PAGE_MAPPING = OFF
FXGMAC_ZERO_COPY = OFF
FXGMAC_DEBUG = ON
FXGMAC_TX_DMA_MAP_SINGLE = OFF
FXGMAC_EPHY_LOOPBACK_DETECT_ENABLED = OFF
FXGMAC_USE_STATIC_ALLOC = ON
obj-m += yt6801.o
EXTRA_CFLAGS += -I$(PWD)
EXTRA_CFLAGS += -Wall -g -fstack-protector-all -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now -Wl,--disable-new-dtags,--rpath
EXTRA_CFLAGS += -DFXGMAC_INT_MODERATION_ENABLED=$(moderation_en)
EXTRA_CFLAGS += -DINT_MOD_IN_US=$(moderation_param)
ifeq (,$(filter OFF off, $(FXGMAC_SMART_SPEED_DISABLE)))
EXTRA_CFLAGS += -DFXGMAC_SMART_SPEED_DISABLE
endif
ifeq (,$(filter OFF off, $(FXGMAC_PHY_SLEEP_ENABLE)))
EXTRA_CFLAGS += -DFXGMAC_PHY_SLEEP_ENABLE
endif
ifeq (,$(filter OFF off, $(FXGMAC_NOT_USE_PAGE_MAPPING)))
EXTRA_CFLAGS += -DFXGMAC_NOT_USE_PAGE_MAPPING
ifeq (,$(filter OFF off, $(FXGMAC_ZERO_COPY)))
EXTRA_CFLAGS += -DFXGMAC_ZERO_COPY
endif
endif
ifeq (,$(filter OFF off, $(FXGMAC_DEBUG)))
EXTRA_CFLAGS += -DFXGMAC_DEBUG
endif
ifeq (,$(filter OFF off, $(FXGMAC_TX_DMA_MAP_SINGLE)))
EXTRA_CFLAGS += -DFXGMAC_TX_DMA_MAP_SINGLE
endif
ifeq (,$(filter OFF off, $(FXGMAC_EPHY_LOOPBACK_DETECT_ENABLED)))
EXTRA_CFLAGS += -DFXGMAC_EPHY_LOOPBACK_DETECT_ENABLED
endif
ifeq (,$(filter OFF off, $(FXGMAC_ASPM_ENABLED)))
EXTRA_CFLAGS += -DFXGMAC_ASPM_ENABLED
endif
ifeq (,$(filter OFF off, $(FXGMAC_USE_STATIC_ALLOC)))
EXTRA_CFLAGS += -DFXGMAC_USE_STATIC_ALLOC
endif
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-gmac-ioctl.o
BASEDIR := /lib/modules/$(shell uname -r)
KERNELDIR ?= $(BASEDIR)/build
PWD :=$(shell pwd)
DRIVERDIR := $(BASEDIR)/kernel/drivers/net/ethernet/motorcomm/yt6801
YTDIR := $(subst $(BASEDIR)/,,$(DRIVERDIR))
KERNEL_GCC_VERSION := $(shell cat /proc/version | sed -n 's/.*gcc version \([[:digit:]]\.[[:digit:]]\.[[:digit:]]\).*/\1/p')
CCVERSION = $(shell $(CC) -dumpversion)
KVER = $(shell uname -r)
KMAJ = $(shell echo $(KVER) | \
sed -e 's/^\([0-9][0-9]*\)\.[0-9][0-9]*\.[0-9][0-9]*.*/\1/')
KMIN = $(shell echo $(KVER) | \
sed -e 's/^[0-9][0-9]*\.\([0-9][0-9]*\)\.[0-9][0-9]*.*/\1/')
KREV = $(shell echo $(KVER) | \
sed -e 's/^[0-9][0-9]*\.[0-9][0-9]*\.\([0-9][0-9]*\).*/\1/')
kver_ge = $(shell \
echo test | awk '{if($(KMAJ) < $(1)) {print 0} else { \
if($(KMAJ) > $(1)) {print 1} else { \
if($(KMIN) < $(2)) {print 0} else { \
if($(KMIN) > $(2)) {print 1} else { \
if($(KREV) < $(3)) {print 0} else { print 1 } \
}}}}}' \
)
OS_NAME := $(shell grep '^NAME=' /etc/os-release | cut -d= -f2 | tr -d '"')
ifneq (, $(findstring Kylin, $(OS_NAME)))
SYS_TYPE := kylin
endif
.PHONY: all
all: print_vars clean modules
print_vars:
@echo
@echo "CC: " $(CC)
@echo "CCVERSION: " $(CCVERSION)
@echo "KERNEL_GCC_VERSION: " $(KERNEL_GCC_VERSION)
@echo "KVER: " $(KVER)
@echo "KMAJ: " $(KMAJ)
@echo "KMIN: " $(KMIN)
@echo "KREV: " $(KREV)
@echo "BASEDIR: " $(BASEDIR)
@echo "DRIVERDIR: " $(DRIVERDIR)
@echo "PWD: " $(PWD)
@echo "YTDIR: " $(YTDIR)
@echo
.PHONY:modules
modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
ifeq ($(SYS_TYPE),kylin)
install -D ./motorcomm /usr/share/initramfs-tools/hooks/motorcomm
endif
.PHONY:clean
clean:
$(MAKE) -C $(KERNELDIR) M=$(PWD) clean
@rm -f *.o
.PHONY:install
install:
$(MAKE) -C $(KERNELDIR) M=$(PWD) INSTALL_MOD_DIR=$(YTDIR) modules_install
depmod -a
.PHONY:uninstall
uninstall:
@rm -rf $(DRIVERDIR)
depmod -a
yt6801-dkms-1.0.31/src/Notice.txt 0000664 0000000 0000000 00000003017 15126421535 0016261 0 ustar 00root root 0000000 0000000 =============================================================================
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.
=============================================================================
yt6801-dkms-1.0.31/src/dkms.conf 0000664 0000000 0000000 00000000326 15126421535 0016104 0 ustar 00root root 0000000 0000000 PACKAGE_NAME="yt6801"
PACKAGE_VERSION="1.0.31"
CLEAN="make clean"
MAKE[0]="make"
BUILT_MODULE_NAME[0]="yt6801"
DEST_MODULE_LOCATION[0]="/kernel/drivers/net/ethernet/motorcomm"
AUTOINSTALL="yes"
REMAKE_INITRD="yes"
yt6801-dkms-1.0.31/src/fuxi-dbg.h 0000664 0000000 0000000 00000002025 15126421535 0016153 0 ustar 00root root 0000000 0000000 /* SPDX-License-Identifier: GPL-2.0+ */
/* Copyright (c) 2021 Motor-comm Corporation. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#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
yt6801-dkms-1.0.31/src/fuxi-efuse.c 0000664 0000000 0000000 00000136577 15126421535 0016545 0 ustar 00root root 0000000 0000000 // SPDX-License-Identifier: GPL-2.0+
/* Copyright (c) 2021 Motor-comm Corporation. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "fuxi-gmac.h"
#include "fuxi-gmac-reg.h"
#include "fuxi-efuse.h"
#ifdef FXGMAC_USE_ADAPTER_HANDLE
#include "fuxi-mp.h"
#endif
bool fxgmac_read_patch_from_efuse_per_index(struct fxgmac_pdata* pdata, u8 index, u32 __far* offset, u32 __far* value) /* read patch per index. */
{
unsigned int wait, i;
u32 regval = 0;
bool succeed = false;
if (index >= FXGMAC_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_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 < FXGMAC_EFUSE_MAX_ENTRY; 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_efuse_read_data(struct fxgmac_pdata* pdata, u32 offset, u32 __far* 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;
}
#ifndef COMMENT_UNUSED_CODE_TO_REDUCE_SIZE
bool fxgmac_read_patch_from_efuse(struct fxgmac_pdata* pdata, u32 offset, u32* value)
{
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 < FXGMAC_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 = FXGMAC_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 = FXGMAC_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 < FXGMAC_EFUSE_MAX_ENTRY; 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_write_mac_subsys_to_efuse(struct fxgmac_pdata* pdata, u8* mac_addr, u32* subsys, u32* revid)
{
#ifdef DBG
u32 machr = 0, maclr = 0;
#endif
u32 cur_subsysid = 0;
u32 pcie_cfg_ctrl= PCIE_CFG_CTRL_DEFAULT_VAL;
if (mac_addr) {
#ifdef DBG
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);
#endif
if(!fxgmac_write_patch_to_efuse(pdata, MACA0HR_FROM_EFUSE, (((u32)mac_addr[0]) << 8) | mac_addr[1])){
return 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])){
return false;
}
}
if (revid) {
if(!fxgmac_write_patch_to_efuse(pdata, EFUSE_REVID_REGISTER, *revid)){
return false;
}
}
if (subsys) {
if (!fxgmac_read_mac_subsys_from_efuse(pdata, NULL, &cur_subsysid, NULL))
return false;
if (cur_subsysid != *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)) {
return false;
}
if (!fxgmac_write_patch_to_efuse(pdata, EFUSE_SUBSYS_REGISTER, *subsys)) {
return 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)) {
return false;
}
}
}
return true;
}
bool fxgmac_write_mac_addr_to_efuse(struct fxgmac_pdata* pdata, u8* mac_addr)
{
#ifdef DBG
u32 machr = 0, maclr = 0;
#endif
if (mac_addr) {
#ifdef DBG
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);
#endif
if(!fxgmac_write_patch_to_efuse(pdata, MACA0HR_FROM_EFUSE, (((u32)mac_addr[0]) << 8) | mac_addr[1])){
return 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])){
return false;
}
}
return true;
}
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 < FXGMAC_EFUSE_MAX_ENTRY; 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)
{
/* write subsys info */
if (revid) {
if(!fxgmac_write_patch_to_efuse(pdata, EFUSE_REVID_REGISTER, *revid)){
return false;
}
}
if (subsys) {
if(!fxgmac_write_patch_to_efuse(pdata, EFUSE_SUBSYS_REGISTER, *subsys)){
return false;
}
}
return true;
}
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_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;
}
#endif
yt6801-dkms-1.0.31/src/fuxi-efuse.h 0000664 0000000 0000000 00000004423 15126421535 0016532 0 ustar 00root root 0000000 0000000 /* SPDX-License-Identifier: GPL-2.0+ */
/* Copyright (c) 2021 Motor-comm Corporation. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifndef __FXGMAC_EFUSE_H__
#define __FXGMAC_EFUSE_H__
bool fxgmac_read_patch_from_efuse_per_index(struct fxgmac_pdata* pdata, u8 index, u32 __far* offset, u32 __far* value); /* read patch per 0-based index. */
bool fxgmac_read_mac_subsys_from_efuse(struct fxgmac_pdata* pdata, u8* mac_addr, u32* subsys, u32* revid);
bool fxgmac_efuse_read_data(struct fxgmac_pdata* pdata, u32 offset, u32 __far* value);
#ifndef COMMENT_UNUSED_CODE_TO_REDUCE_SIZE
bool fxgmac_read_patch_from_efuse(struct fxgmac_pdata* pdata, u32 offset, u32* value); /* read patch per register offset. */
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_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_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
#endif // __FXGMAC_EFUSE_H__
yt6801-dkms-1.0.31/src/fuxi-errno.h 0000664 0000000 0000000 00000022402 15126421535 0016545 0 ustar 00root root 0000000 0000000 /* SPDX-License-Identifier: GPL-2.0+ */
/* Copyright (c) 2021 Motor-comm Corporation. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifndef __FXGMAC_ERROR_H__
#define __FXGMAC_ERROR_H__
#define EOK 0
/* ref linux https://elixir.bootlin.com/linux/v5.18-rc7/source/include/uapi/asm-generic/errno.h#L93 */
#define EPERM 1 /* Operation not permitted */
#define ENOENT 2 /* No such file or directory */
#define ESRCH 3 /* No such process */
#define EINTR 4 /* Interrupted system call */
#define EIO 5 /* I/O error */
#define ENXIO 6 /* No such device or address */
#define E2BIG 7 /* Argument list too long */
#define ENOEXEC 8 /* Exec format error */
#define EBADF 9 /* Bad file number */
#define ECHILD 10 /* No child processes */
#define EAGAIN 11 /* Try again */
#define ENOMEM 12 /* Out of memory */
#define EACCES 13 /* Permission denied */
#define EFAULT 14 /* Bad address */
#define ENOTBLK 15 /* Block device required */
#define EBUSY 16 /* Device or resource busy */
#define EEXIST 17 /* File exists */
#define EXDEV 18 /* Cross-device link */
#define ENODEV 19 /* No such device */
#define ENOTDIR 20 /* Not a directory */
#define EISDIR 21 /* Is a directory */
#define EINVAL 22 /* Invalid argument */
#define ENFILE 23 /* File table overflow */
#define EMFILE 24 /* Too many open files */
#define ENOTTY 25 /* Not a typewriter */
#define ETXTBSY 26 /* Text file busy */
#define EFBIG 27 /* File too large */
#define ENOSPC 28 /* No space left on device */
#define ESPIPE 29 /* Illegal seek */
#define EROFS 30 /* Read-only file system */
#define EMLINK 31 /* Too many links */
#define EPIPE 32 /* Broken pipe */
#define EDOM 33 /* Math argument out of domain of func */
#define ERANGE 34 /* Math result not representable */
#define EDEADLK 35 /* Resource deadlock would occur */
#define ENAMETOOLONG 36 /* File name too long */
#define ENOLCK 37 /* No record locks available */
/*
* This error code is special: arch syscall entry code will return
* -ENOSYS if users try to call a syscall that doesn't exist. To keep
* failures of syscalls that really do exist distinguishable from
* failures due to attempts to use a nonexistent syscall, syscall
* implementations should refrain from returning -ENOSYS.
*/
#define ENOSYS 38 /* Invalid system call number */
#define ENOTEMPTY 39 /* Directory not empty */
#define ELOOP 40 /* Too many symbolic links encountered */
#define EWOULDBLOCK EAGAIN /* Operation would block */
#define ENOMSG 42 /* No message of desired type */
#define EIDRM 43 /* Identifier removed */
#define ECHRNG 44 /* Channel number out of range */
#define EL2NSYNC 45 /* Level 2 not synchronized */
#define EL3HLT 46 /* Level 3 halted */
#define EL3RST 47 /* Level 3 reset */
#define ELNRNG 48 /* Link number out of range */
#define EUNATCH 49 /* Protocol driver not attached */
#define ENOCSI 50 /* No CSI structure available */
#define EL2HLT 51 /* Level 2 halted */
#define EBADE 52 /* Invalid exchange */
#define EBADR 53 /* Invalid request descriptor */
#define EXFULL 54 /* Exchange full */
#define ENOANO 55 /* No anode */
#define EBADRQC 56 /* Invalid request code */
#define EBADSLT 57 /* Invalid slot */
#define EDEADLOCK EDEADLK
#define EBFONT 59 /* Bad font file format */
#define ENOSTR 60 /* Device not a stream */
#define ENODATA 61 /* No data available */
#define ETIME 62 /* Timer expired */
#define ENOSR 63 /* Out of streams resources */
#define ENONET 64 /* Machine is not on the network */
#define ENOPKG 65 /* Package not installed */
#define EREMOTE 66 /* Object is remote */
#define ENOLINK 67 /* Link has been severed */
#define EADV 68 /* Advertise error */
#define ESRMNT 69 /* Srmount error */
#define ECOMM 70 /* Communication error on send */
#define EPROTO 71 /* Protocol error */
#define EMULTIHOP 72 /* Multihop attempted */
#define EDOTDOT 73 /* RFS specific error */
#define EBADMSG 74 /* Not a data message */
#define EOVERFLOW 75 /* Value too large for defined data type */
#define ENOTUNIQ 76 /* Name not unique on network */
#define EBADFD 77 /* File descriptor in bad state */
#define EREMCHG 78 /* Remote address changed */
#define ELIBACC 79 /* Can not access a needed shared library */
#define ELIBBAD 80 /* Accessing a corrupted shared library */
#define ELIBSCN 81 /* .lib section in a.out corrupted */
#define ELIBMAX 82 /* Attempting to link in too many shared libraries */
#define ELIBEXEC 83 /* Cannot exec a shared library directly */
#define EILSEQ 84 /* Illegal byte sequence */
#define ERESTART 85 /* Interrupted system call should be restarted */
#define ESTRPIPE 86 /* Streams pipe error */
#define EUSERS 87 /* Too many users */
#define ENOTSOCK 88 /* Socket operation on non-socket */
#define EDESTADDRREQ 89 /* Destination address required */
#define EMSGSIZE 90 /* Message too long */
#define EPROTOTYPE 91 /* Protocol wrong type for socket */
#define ENOPROTOOPT 92 /* Protocol not available */
#define EPROTONOSUPPORT 93 /* Protocol not supported */
#define ESOCKTNOSUPPORT 94 /* Socket type not supported */
#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */
#define EPFNOSUPPORT 96 /* Protocol family not supported */
#define EAFNOSUPPORT 97 /* Address family not supported by protocol */
#define EADDRINUSE 98 /* Address already in use */
#define EADDRNOTAVAIL 99 /* Cannot assign requested address */
#define ENETDOWN 100 /* Network is down */
#define ENETUNREACH 101 /* Network is unreachable */
#define ENETRESET 102 /* Network dropped connection because of reset */
#define ECONNABORTED 103 /* Software caused connection abort */
#define ECONNRESET 104 /* Connection reset by peer */
#define ENOBUFS 105 /* No buffer space available */
#define EISCONN 106 /* Transport endpoint is already connected */
#define ENOTCONN 107 /* Transport endpoint is not connected */
#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */
#define ETOOMANYREFS 109 /* Too many references: cannot splice */
#define ETIMEDOUT 110 /* Connection timed out */
#define ECONNREFUSED 111 /* Connection refused */
#define EHOSTDOWN 112 /* Host is down */
#define EHOSTUNREACH 113 /* No route to host */
#define EALREADY 114 /* Operation already in progress */
#define EINPROGRESS 115 /* Operation now in progress */
#define ESTALE 116 /* Stale file handle */
#define EUCLEAN 117 /* Structure needs cleaning */
#define ENOTNAM 118 /* Not a XENIX named type file */
#define ENAVAIL 119 /* No XENIX semaphores available */
#define EISNAM 120 /* Is a named type file */
#define EREMOTEIO 121 /* Remote I/O error */
#define EDQUOT 122 /* Quota exceeded */
#define ENOMEDIUM 123 /* No medium found */
#define EMEDIUMTYPE 124 /* Wrong medium type */
#define ECANCELED 125 /* Operation Canceled */
#define ENOKEY 126 /* Required key not available */
#define EKEYEXPIRED 127 /* Key has expired */
#define EKEYREVOKED 128 /* Key has been revoked */
#define EKEYREJECTED 129 /* Key was rejected by service */
/* for robust mutexes */
#define EOWNERDEAD 130 /* Owner died */
#define ENOTRECOVERABLE 131 /* State not recoverable */
#define ERFKILL 132 /* Operation not possible due to RF-kill */
#define EHWPOISON 133 /* Memory page has hardware error */
#endif // __FXGMAC_ERROR_H__
yt6801-dkms-1.0.31/src/fuxi-gmac-common.c 0000664 0000000 0000000 00000105677 15126421535 0017630 0 ustar 00root root 0000000 0000000 // SPDX-License-Identifier: GPL-2.0+
/* Copyright (c) 2021 Motor-comm Corporation. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "fuxi-gmac.h"
#include "fuxi-gmac-reg.h"
MODULE_LICENSE("GPL");
static int debug = 16;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "FUXI ethernet debug level (0=none,...,16=all)");
static int fxgmac_read_mac_addr(struct fxgmac_pdata *pdata)
{
struct net_device *netdev = pdata->netdev;
struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops;
unsigned char dev_addr[6] = {0, 0x55, 0x7b, 0xb5, 0x7d, 0xf7};
int ret;
/* DPRINTK("read mac from eFuse\n"); */
/* if efuse have mac addr,use it.if not,use static mac address. */
ret = hw_ops->read_mac_subsys_from_efuse(pdata, pdata->mac_addr, NULL, NULL);
if (!ret )
{
DPRINTK("eFuse mac addr err\n");
return -1;
}
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);
}
return 0;
}
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_ENABLE;//MTL_RSF_DISABLE 20210514
pdata->pblx8 = DMA_PBL_X8_ENABLE;//DMA_PBL_X8_ENABLE 20210514
pdata->tx_pbl = DMA_PBL_16;
pdata->rx_pbl = DMA_PBL_4;//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 = FXGMAC_INT_MODERATION_ENABLED;
pdata->crc_check = 1;
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;
pdata->support_10m_link = true;
pdata->expansion.pre_phy_speed = pdata->phy_speed;
pdata->expansion.pre_phy_duplex = pdata->phy_duplex;
pdata->expansion.pre_phy_autoneg = pdata->phy_autoeng;
pdata->expansion.recover_phy_state = 0;
// default to magic
pdata->expansion.wol = WAKE_MAGIC;
#ifdef FXGMAC_ASPM_ENABLED
pdata->expansion.recover_from_aspm = false;
pdata->expansion.aspm_en = false;
pdata->expansion.aspm_work_active = false;
#endif
#ifdef FXGMAC_SMART_SPEED_DISABLE
pdata->phy_disablesmartspeed = 1;
#else
pdata->phy_disablesmartspeed = 0;
#endif
strscpy(pdata->drv_name, FXGMAC_DRV_NAME, sizeof(pdata->drv_name));
strscpy(pdata->drv_ver, FXGMAC_DRV_VERSION, sizeof(pdata->drv_ver));
dev_info(pdata->dev, "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;
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;
ret = fxgmac_read_mac_addr(pdata);
if (ret < 0)
return ret;
#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);
/* Set the DMA mask */
ret = dma_set_mask_and_coherent(pdata->dev,
DMA_BIT_MASK(FXGMAC_DMA_BIT_MASK64));
if (ret) {
ret = dma_set_mask_and_coherent(pdata->dev,
DMA_BIT_MASK(FXGMAC_DMA_BIT_MASK32));
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;
ret = netif_set_real_num_tx_queues(netdev, pdata->tx_q_count);
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;
}
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->real_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_ENABLED
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
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,19,0))
netif_set_tso_max_size(netdev, NIC_MAX_TCP_OFFLOAD_SIZE);
#else
netdev->gso_max_size = NIC_MAX_TCP_OFFLOAD_SIZE;
#endif
/* 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;
mutex_init(&pdata->expansion.mutex);
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();
if(vectors >= FXGMAC_MAX_DMA_CHANNELS) {
// 0-3 for rx, 4 for tx, 5 for misc
req_vectors = FXGMAC_MSIX_INT_NUMS;
pdata->expansion.msix_entries = kcalloc(req_vectors,
sizeof(struct msix_entry),
GFP_KERNEL);
if (!pdata->expansion.msix_entries) {
dev_err(pdata->dev, "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;
#ifndef RHEL_MAJOR
rc = pci_enable_msix_range(pdata->pdev,
pdata->expansion.msix_entries,
req_vectors,
req_vectors);
#else
#if (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,0)) && (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(7,8))
rc = pci_enable_msix(pdata->pdev,
pdata->expansion.msix_entries,
req_vectors);
#else
rc = pci_enable_msix_range(pdata->pdev,
pdata->expansion.msix_entries,
req_vectors,
req_vectors);
#endif
#endif
if (rc < 0) {
dev_err(pdata->dev, "enable MSIx failed,%d.\n", rc);
req_vectors = 0; //indicate failure
} else {
req_vectors = rc;
}
if(req_vectors >= FXGMAC_MAX_DMA_CHANNELS_PLUS_1TX) {
dev_info(pdata->dev, "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;
#ifdef FXGMAC_MISC_ENABLED
pdata->expansion.misc_irq =
pdata->expansion.msix_entries[MSI_ID_PHY_OTHER].vector;
#endif
return;
}else if (req_vectors){
dev_err(pdata->dev, "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 {
dev_err(pdata->dev, "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);
dev_err(pdata->dev, "dev_err 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;
dev_info(pdata->dev, "enable MSI ok, cpu=%d, irq=%d.\n", vectors, pdata->pdev->irq);
}
#else
(void)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;
pdata->msg_enable = NETIF_MSG_DRV;
pdata->expansion.dev_state = FXGMAC_DEV_PROBE;
/* 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);
#ifdef FXGMAC_MISC_ENABLED
pdata->expansion.misc_irq = pdata->dev_irq;
#endif
fxgmac_init_interrupt_scheme(pdata);
pdata->mac_regs = res->addr;
pdata->base_mem = res->addr;
pdata->mac_regs = pdata->mac_regs + FXGMAC_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->real_num_tx_queues);
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;
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 ("Mac ver=%#x\n", hw_feat->version);
/* 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");
}
yt6801-dkms-1.0.31/src/fuxi-gmac-desc.c 0000664 0000000 0000000 00000136336 15126421535 0017252 0 ustar 00root root 0000000 0000000 // SPDX-License-Identifier: GPL-2.0+
/* Copyright (c) 2021 Motor-comm Corporation. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "fuxi-gmac.h"
#include "fuxi-gmac-reg.h"
#ifdef FXGMAC_USE_ADAPTER_HANDLE
#include "fuxi-mp.h"
#endif
static void fxgmac_unmap_desc_data(struct fxgmac_pdata* pdata,
struct fxgmac_desc_data* desc_data)
{
#ifndef LINUX
(void)pdata;
(void)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;
}
#ifdef FXGMAC_NOT_USE_PAGE_MAPPING
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;
}
#else
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
if (desc_data->skb) {
dev_kfree_skb_any(desc_data->skb);
desc_data->skb = NULL;
}
memset(&desc_data->tx, 0, sizeof(desc_data->tx));
memset(&desc_data->rx, 0, sizeof(desc_data->rx));
desc_data->mapped_as_page = 0;
#endif
}
static void fxgmac_free_ring(struct fxgmac_pdata* pdata,
struct fxgmac_ring* ring)
{
#ifndef LINUX
(void)pdata;
if (!ring)
return;
#else
struct fxgmac_desc_data* desc_data;
unsigned int i;
if (!ring)
return;
#ifndef FXGMAC_USE_STATIC_ALLOC
if (ring->desc_data_head) {
#endif
for (i = 0; i < ring->dma_desc_count; i++) {
desc_data = FXGMAC_GET_DESC_DATA(ring, i);
fxgmac_unmap_desc_data(pdata, desc_data);
}
#ifndef FXGMAC_USE_STATIC_ALLOC
kfree(ring->desc_data_head);
ring->desc_data_head = NULL;
}
#endif
#ifndef FXGMAC_NOT_USE_PAGE_MAPPING
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
(void)pdata;
(void)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;
#ifndef FXGMAC_USE_STATIC_ALLOC
/* 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;
#endif
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,", i);
if (i < pdata->tx_ring_count)
DPRINTK(" tx_desc_cnt=%u,", pdata->tx_desc_count);
DPRINTK(" rx_desc_cnt=%u.\n", pdata->rx_desc_count);
}
}
if(netif_msg_drv(pdata)) {
DPRINTK("alloc_rings callout ok ch=%u\n", i);
}
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 ,rx_ring=%p ,channel=%p\n", pdata->channel_head->tx_ring, pdata->channel_head->rx_ring, pdata->channel_head);
#ifndef FXGMAC_USE_STATIC_ALLOC
kfree(pdata->channel_head->tx_ring);
kfree(pdata->channel_head->rx_ring);
kfree(pdata->channel_head);
#endif
pdata->channel_head->tx_ring = NULL;
pdata->channel_head->rx_ring = NULL;
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;
UINT64 vir_addr;
UINT64 cache_sz = CACHE_ALIGN_SZ;
PADAPTER adpt = (PADAPTER)pdata->pAdapter;
DEBUGPRINT(INIT, "[%a,%a,%d]:MemoryChannelPtr=%llx\n",__FILE__, __func__,__LINE__,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;
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, *channel_head;
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
#ifdef FXGMAC_USE_STATIC_ALLOC
channel_head = pdata->channel;
tx_ring = &pdata->ring[0];
rx_ring = &pdata->ring[1];
if (netif_msg_drv(pdata)) DPRINTK("static_alloc_channels,channel_head=%p,tx_ring=%p,rx_ring=%p\n", channel_head, tx_ring, rx_ring);
#else
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*%d\n", channel_head, pdata->channel_count,(u32)sizeof(struct fxgmac_channel));
if (!channel_head)
return ret;
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*%d\n", tx_ring, pdata->tx_ring_count,(u32)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*%d\n", rx_ring, pdata->rx_ring_count,(u32)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);
#endif
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 0
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;
}
#endif
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++;
}
pdata->channel_head = channel_head;
if(netif_msg_drv(pdata)) DPRINTK("alloc_channels callout ok\n");
return 0;
err_irq:
#ifndef FXGMAC_USE_STATIC_ALLOC
kfree(rx_ring);
err_rx_ring:
kfree(tx_ring);
err_tx_ring:
kfree(channel_head);
#endif
DPRINTK("fxgmac alloc_channels callout err,%d\n",ret);
return ret;
}
#elif defined(UBOOT) || defined(KDNET) || defined(PXE)
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;
}
#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;
}
#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 !(defined(UEFI) || defined(UBOOT) || defined(PXE) || defined(FXGMAC_NOT_USE_PAGE_MAPPING))
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
#if (defined(LINUX) && !defined(FXGMAC_NOT_USE_PAGE_MAPPING))
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
static int fxgmac_map_rx_buffer(struct fxgmac_pdata* pdata,
struct fxgmac_ring* ring,
struct fxgmac_desc_data* desc_data)
{
#ifndef LINUX
(void)pdata;
(void)ring;
(void)desc_data;
#else
#ifdef FXGMAC_NOT_USE_PAGE_MAPPING
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;
}
#else
int ret;
int order;
if (!ring->rx_hdr_pa.pages) {
if (pdata->jumbo)
order = max_t(int, PAGE_ALLOC_COSTLY_ORDER - 1, 0);
else
order = 0;
ret = fxgmac_alloc_pages(pdata, &ring->rx_hdr_pa,
GFP_ATOMIC, order);
if (ret)
return ret;
}
#if 0
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;
}
#endif
/* Set up the header page info */
fxgmac_set_buffer_data(&desc_data->rx.hdr, &ring->rx_hdr_pa,
pdata->rx_buf_size);
#if 0
/* Set up the buffer page info */
fxgmac_set_buffer_data(&desc_data->rx.buf, &ring->rx_buf_pa,
pdata->rx_buf_size);
#endif
#endif
#endif
return 0;
}
#ifdef UBOOT
static void fxgmac_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_tx_desc_init(struct fxgmac_pdata* pdata)
{
struct fxgmac_channel *channel = pdata->expansion.tx_channel;
struct fxgmac_dma_desc *desc_data;
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 */
fxgmac_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 int fxgmac_rx_desc_init(struct fxgmac_pdata* pdata)
{
struct fxgmac_channel * channel = pdata->expansion.rx_channel;
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 */
fxgmac_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));
return 0;
}
#else
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_channel(struct fxgmac_channel* channel)
{
#ifndef KDNET
struct fxgmac_ring* ring = channel->tx_ring;
struct fxgmac_desc_data* desc_data;
int start_index = ring->cur;
unsigned int i;
(void)start_index;
/* 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);
}
#endif
///* Update the total number of Tx descriptors */
//writereg(ring->dma_desc_count - 1, FXGMAC_DMA_REG(channel, DMA_CH_TDRLR));
#ifndef PXE
writereg(channel->pdata->pAdapter, channel->pdata->tx_desc_count - 1, FXGMAC_DMA_REG(channel, DMA_CH_TDRLR));
#endif
/* 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)
#elif defined(KDNET)
writereg(channel->pdata->pAdapter, upper_32_bits(((PMOTORCOMM_ADAPTER)channel->pdata->pAdapter)->TbdPhyAddr),
FXGMAC_DMA_REG(channel, DMA_CH_TDLR_HI));
writereg(channel->pdata->pAdapter, lower_32_bits(((PMOTORCOMM_ADAPTER)channel->pdata->pAdapter)->TbdPhyAddr),
FXGMAC_DMA_REG(channel, DMA_CH_TDLR_LO));
#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_tx_desc_init(struct fxgmac_pdata* pdata)
{
#ifndef LINUX
struct fxgmac_channel* channel;
channel = pdata->channel_head;
fxgmac_tx_desc_init_channel(channel);
#else
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));
fxgmac_tx_desc_init_channel(channel);
}
#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;
dma_addr_t buf_dma;
/* 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
*/
#ifdef FXGMAC_NOT_USE_PAGE_MAPPING
buf_dma = desc_data->rx.buf.dma_base;
#else
buf_dma = desc_data->rx.hdr.dma_base + desc_data->rx.hdr.dma_off;
#endif
dma_desc->desc0 = cpu_to_le32(lower_32_bits(buf_dma));
dma_desc->desc1 = cpu_to_le32(upper_32_bits(buf_dma));
dma_desc->desc2 = 0;
dma_desc->desc3 = 0;
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
(void)pdata;
(void)desc_data;
(void)index;
#endif
}
static void fxgmac_rx_desc_init_channel(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(KDNET)
PHYSICAL_ADDRESS HwRbdPa;
#elif defined(_WIN64) || defined(_WIN32)
unsigned int Qid;
NDIS_PHYSICAL_ADDRESS HwRbdPa;
HwRbdPa.QuadPart = 0;
#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)
#elif defined(KDNET)
writereg(channel->pdata->pAdapter, channel->pdata->rx_desc_count - 1,
FXGMAC_DMA_REG(channel, DMA_CH_RDRLR));
/* Update the starting address of descriptor ring */
writereg(channel->pdata->pAdapter, upper_32_bits(((PMOTORCOMM_ADAPTER)channel->pdata->pAdapter)->RdbPhyAddr),
FXGMAC_DMA_REG(channel, DMA_CH_RDLR_HI));
writereg(channel->pdata->pAdapter, lower_32_bits(((PMOTORCOMM_ADAPTER)channel->pdata->pAdapter)->RdbPhyAddr),
FXGMAC_DMA_REG(channel, DMA_CH_RDLR_LO));
HwRbdPa.QuadPart = ((PMOTORCOMM_ADAPTER)channel->pdata->pAdapter)->RdbPhyAddr.QuadPart
+ (channel->pdata->rx_desc_count - 1) * sizeof(HW_RBD);
writereg(channel->pdata->pAdapter, HwRbdPa.LowPart, FXGMAC_DMA_REG(channel, DMA_CH_RDTR_LO));
#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 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_rx_desc_init(struct fxgmac_pdata* pdata)
{
#ifndef LINUX
struct fxgmac_channel* channel;
int Qid = 0;
channel = pdata->channel_head;
for (Qid = 0; Qid < RSS_Q_COUNT; Qid++)
{
fxgmac_rx_desc_init_channel(channel + Qid);
}
#else
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;
int ret;
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;
ret = fxgmac_map_rx_buffer(pdata, ring, desc_data);
if (ret)
return ret;
dma_desc++;
dma_desc_addr += sizeof(struct fxgmac_dma_desc);
}
ring->cur = 0;
ring->dirty = 0;
fxgmac_rx_desc_init_channel(channel);
}
#endif
return 0;
}
#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;
skb_frag_t *frag;
unsigned int tso, vlan;
dma_addr_t skb_dma;
unsigned int i;
#ifdef FXGMAC_TX_DMA_MAP_SINGLE
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);
#ifdef FXGMAC_TX_DMA_MAP_SINGLE
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);
#ifdef FXGMAC_TX_DMA_MAP_SINGLE
skb_dma = dma_map_single(pdata->dev, addr + offset, len, DMA_TO_DEVICE);
#else
skb_dma = skb_frag_dma_map(pdata->dev, frag, 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;
#ifdef FXGMAC_TX_DMA_MAP_SINGLE
desc_data->mapped_as_page = 0;
#else
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_channels_and_rings = fxgmac_alloc_channels;
#else
desc_ops->alloc_channels_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;
#ifndef UBOOT
desc_ops->tx_desc_init_channel = fxgmac_tx_desc_init_channel;
desc_ops->rx_desc_init_channel = fxgmac_rx_desc_init_channel;
desc_ops->tx_desc_reset = fxgmac_tx_desc_reset;
desc_ops->rx_desc_reset = fxgmac_rx_desc_reset;
#endif
}
yt6801-dkms-1.0.31/src/fuxi-gmac-ethtool.c 0000664 0000000 0000000 00000131251 15126421535 0020001 0 ustar 00root root 0000000 0000000 // SPDX-License-Identifier: GPL-2.0+
/* Copyright (c) 2021 Motor-comm Corporation. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#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;
strscpy(drvinfo->driver, pdata->drv_name, sizeof(drvinfo->driver));
strscpy(drvinfo->version, pdata->drv_ver, sizeof(drvinfo->version));
strscpy(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);
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) ||\
RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(9,1) )
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) ||\
RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(9,1) )
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)
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,16,0))
static u32 fxgmac_get_rxfh_key_size(struct net_device *netdev)
{
return FXGMAC_RSS_HASH_KEY_SIZE;
}
#endif
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_CHANNEL
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;
}
#if ( LINUX_VERSION_CODE >= KERNEL_VERSION(6,8,0) )
static int fxgmac_get_rxfh(struct net_device *netdev,struct ethtool_rxfh_param *rxfh)
{
struct fxgmac_pdata *pdata = netdev_priv(netdev);
if (rxfh->hfunc)
{
rxfh->hfunc = ETH_RSS_HASH_TOP;
DPRINTK("fxmac, get_rxfh for hash function\n");
}
if (rxfh->indir)
{
fxgmac_get_reta(pdata, rxfh->indir);
DPRINTK("fxmac, get_rxfh for indirection tab\n");
}
if (rxfh->key)
{
memcpy(rxfh->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, struct ethtool_rxfh_param *rxfh, struct netlink_ext_ack *ack)
{
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)rxfh->indir, (unsigned long)rxfh->key, rxfh->hfunc);
if (rxfh->hfunc)
return -EINVAL;
/* Fill out the redirection table */
if (rxfh->indir) {
#if FXGMAC_MSIX_CH0RXDIS_ENABLED
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 (rxfh->indir[i] >= max_queues)
return -EINVAL;
for (i = 0; i < reta_entries; i++)
pdata->rss_table[i] = rxfh->indir[i];
hw_ops->write_rss_lookup_table(pdata);
#endif
}
/* Fill out the rss hash key */
if (FXGMAC_RSS_HASH_KEY_LINUX && rxfh->key) {
hw_ops->set_rss_hash_key(pdata, rxfh->key);
}
return 0;
}
#else
static int fxgmac_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
u8 *hfunc)
{
struct fxgmac_pdata *pdata = netdev_priv(netdev);
if (hfunc)
{
*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 = 0;
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_ENABLED
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;
}
#endif
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;
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;
}
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;
hw_ops->set_rss_options(pdata);
}
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:
DPRINTK("set_rxnfc for rx cls rule insert-n\\a\n");
break;
case ETHTOOL_SRXCLSRLDEL:
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) ||\
RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(9,1) )
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) ||\
RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(9,1) )
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;
if (pdata->expansion.dev_state != FXGMAC_DEV_START)
return 0;
fxgmac_lock(pdata);
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_channels_and_rings(pdata);
fxgmac_start(pdata);
fxgmac_unlock(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);
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;
}
wol->wolopts = pdata->expansion.wol;
}
// only supports four patterns, and patterns will be cleared on every call
static void fxgmac_set_pattern_data(struct fxgmac_pdata *pdata)
{
struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops;
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++;
}
hw_ops->set_wake_pattern(pdata, pattern, i);
}
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.
*/
struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops;
if (!pdata->hw_feat.rwk) {
netdev_err(pdata->netdev, "error configuring WOL - not supported.\n");
return;
}
hw_ops->disable_wake_magic_pattern(pdata);
hw_ops->disable_wake_pattern(pdata);
hw_ops->disable_wake_link_change(pdata);
if(en) {
/* config mac address for rx of magic or ucast */
hw_ops->set_mac_address(pdata, (u8*)(pdata->netdev->dev_addr));
/* Enable Magic packet */
if (pdata->expansion.wol & WAKE_MAGIC) {
hw_ops->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) {
hw_ops->enable_wake_pattern(pdata);
}
/* Enable ephy link change */
if ((FXGMAC_WOL_UPON_EPHY_LINK) && (pdata->expansion.wol & WAKE_PHY)) {
hw_ops->enable_wake_link_change(pdata);
}
}
device_set_wakeup_enable(/*pci_dev_to_dev*/(pdata->dev), en);
DPRINTK("config_wol callout\n");
}
static int fxgmac_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
{
struct fxgmac_pdata *pdata = netdev_priv(netdev);
//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);
}
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;
fxgmac_set_pattern_data(pdata);
fxgmac_config_wol(pdata, (!!(pdata->expansion.wol)));
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];
}
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,6,0))
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;
int ret;
#if 0
ret = fxgmac_ephy_autoneg_ability_get(pdata, &adv);
if (ret < 0)
return -ETIMEDOUT;
#endif
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);
ret = hw_ops->read_ephy_reg(pdata, REG_MII_ADVERTISE, ®val);
if (ret < 0)
return ret;
if (FXGMAC_GET_REG_BITS(regval, PHY_MII_ADVERTISE_PAUSE_POS, PHY_MII_ADVERTISE_PAUSE_LEN))
ethtool_link_ksettings_add_link_mode(cmd, advertising, Pause);
if (FXGMAC_GET_REG_BITS(regval, PHY_MII_ADVERTISE_ASYPAUSE_POS, PHY_MII_ADVERTISE_ASYPAUSE_LEN))
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);
ret = hw_ops->read_ephy_reg(pdata, REG_MII_BMCR, ®val);
if (ret < 0)
return ret;
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
goto FORCE_MODE;
//clear_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, cmd->link_modes.advertising);
ret = hw_ops->read_ephy_reg(pdata, REG_MII_ADVERTISE, &adv);
if (ret < 0)
return ret;
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);
ret = hw_ops->read_ephy_reg(pdata, REG_MII_CTRL1000, &adv);
if (ret < 0)
return ret;
if (adv & FXGMAC_ADVERTISE_1000FULL)
ethtool_link_ksettings_add_link_mode(cmd, advertising, 1000baseT_Full);
}
else {
FORCE_MODE:
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;
regval = 0;
ret = hw_ops->read_ephy_reg(pdata, REG_MII_SPEC_STATUS, ®val);
if (ret < 0)
return ret;
link_status = regval & (BIT(FXGMAC_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;
struct fxgmac_pdata *pdata = netdev_priv(netdev);
struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops;
int ret;
if (cmd->base.speed == SPEED_1000 && cmd->base.duplex == DUPLEX_HALF)
return -EINVAL;
pdata->phy_autoeng = cmd->base.autoneg;
pdata->phy_duplex = cmd->base.duplex;
pdata->phy_speed = cmd->base.speed;
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->phy_config(pdata);
if (ret < 0)
return ret;
} else {
fxgmac_phy_force_mode(pdata);
}
/* Save speed is used to restore it when resuming */
pdata->expansion.pre_phy_speed = cmd->base.speed;
pdata->expansion.pre_phy_autoneg = cmd->base.autoneg;
pdata->expansion.pre_phy_duplex = cmd->base.duplex;
return 0;
}
#endif
#if FXGMAC_PAUSE_FEATURE_ENABLED
static void fxgmac_get_pauseparam(struct net_device *netdev,
struct ethtool_pauseparam *pause)
{
struct fxgmac_pdata *pdata = netdev_priv(netdev);
pause->autoneg = pdata->phy_autoeng;
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;
u32 adv;
int ret;
int enable_pause = 0;
pdata->rx_pause = pause->rx_pause;
pdata->tx_pause = pause->tx_pause;
if (pdata->rx_pause || pdata->tx_pause)
enable_pause = 1;
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 (pause->autoneg) {
ret = hw_ops->read_ephy_reg(pdata, REG_MII_ADVERTISE, &adv);
if (ret < 0)
return ret;
adv = FXGMAC_SET_REG_BITS(adv, PHY_MII_ADVERTISE_PAUSE_POS,
PHY_MII_ADVERTISE_PAUSE_LEN,
enable_pause);
adv = FXGMAC_SET_REG_BITS(adv, PHY_MII_ADVERTISE_ASYPAUSE_POS,
PHY_MII_ADVERTISE_ASYPAUSE_LEN,
enable_pause);
ret = hw_ops->write_ephy_reg(pdata, REG_MII_ADVERTISE, adv);
if (ret < 0) {
return ret;
}
ret = hw_ops->read_ephy_reg(pdata, REG_MII_BMCR, &adv);
if (ret < 0)
return ret;
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 ret;
}else {
DPRINTK("Can't set phy pause because autoneg is off.\n");
}
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*/
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
if(!test_bit(FXGMAC_POWER_STATE_DOWN, &pdata->expansion.powerstate))
#endif
{
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;
}
}
#if 0
static inline bool fxgmac_removed(void __iomem *addr)
{
return unlikely(!addr);
}
#endif
static int fxgmac_ethtool_reset(struct net_device *netdev, u32 *flag)
{
struct fxgmac_pdata *pdata = netdev_priv(netdev);
struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops;
u32 val;
int ret = 0;
val = (*flag & ETH_RESET_ALL) || (*flag & ETH_RESET_PHY);
if (!val) {
DPRINTK("Operation not support.\n");
return -EINVAL;
}
switch(*flag) {
case ETH_RESET_ALL:
fxgmac_restart_dev(pdata);
*flag = 0;
break;
case ETH_RESET_PHY:
/*
* power off and on the phy in order to properly
* configure the MAC timing
*/
hw_ops->read_ephy_reg(pdata, REG_MII_BMCR, &val);
val = FXGMAC_SET_REG_BITS(val, PHY_CR_POWER_POS,
PHY_CR_POWER_LEN,
PHY_POWER_DOWN);
ret = hw_ops->write_ephy_reg(pdata, REG_MII_BMCR, val);
if(ret < 0)
return ret;
usleep_range_ex(pdata->pAdapter, 9000, 10000);
val = FXGMAC_SET_REG_BITS(val, PHY_CR_POWER_POS,
PHY_CR_POWER_LEN,
PHY_POWER_UP);
ret = hw_ops->write_ephy_reg(pdata, REG_MII_BMCR, val);
if(ret < 0)
return ret;
*flag = 0;
break;
default:
break;
}
return 0;
}
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,
.reset = fxgmac_ethtool_reset,
#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,
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,16,0))
.get_rxfh_key_size = fxgmac_get_rxfh_key_size,
#endif
.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)
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,6,0))
.get_link_ksettings = fxgmac_get_link_ksettings,
.set_link_ksettings = fxgmac_set_link_ksettings,
#endif
.get_pauseparam = fxgmac_get_pauseparam,
.set_pauseparam = fxgmac_set_pauseparam,
#endif
};
const struct ethtool_ops *fxgmac_get_ethtool_ops(void)
{
return &fxgmac_ethtool_ops;
}
yt6801-dkms-1.0.31/src/fuxi-gmac-hw.c 0000664 0000000 0000000 00000657553 15126421535 0016763 0 ustar 00root root 0000000 0000000 // SPDX-License-Identifier: GPL-2.0+
/* Copyright (c) 2021 Motor-comm Corporation. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "fuxi-gmac.h"
#include "fuxi-gmac-reg.h"
#include "fuxi-efuse.h"
#ifdef FXGMAC_USE_ADAPTER_HANDLE
#include "fuxi-mp.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)
{
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, set val = %x.\n", regval);
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, set val = %x.\n", regval);
return 0;
}
static int fxgmac_set_mac_address(struct fxgmac_pdata *pdata, u8 *addr)
{
u32 mac_addr_hi, mac_addr_lo;
mac_addr_hi = (((u32)(addr[5]) << 8) | ((u32)(addr[4]) << 0));
mac_addr_lo = (((u32)(addr[3]) << 24) | ((u32)(addr[2]) << 16) |
((u32)(addr[1]) << 8) | ((u32)(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 __far*mac_reg)
{
u32 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\n",
ha->addr);
netif_dbg(pdata, drv, pdata->netdev,
"adding mac addredd at %#x\n",
*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 , set val = %x\n", regval);
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, set val = %x\n", regval);
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, "promiscuous mode=%d", enable);
DbgPrintF(MP_TRACE, "set val = %x", regval);
DbgPrintF(MP_TRACE, "note, vlan filter is called when set promiscuous mode=%d", enable);
/* Hardware will still perform VLAN filtering in promiscuous mode */
if (enable) {
fxgmac_disable_rx_vlan_filtering(pdata);
} else {
if (FXGMAC_RX_VLAN_FILTERING_ENABLED)
{
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, "bcast en=%d", enable);
DbgPrintF(MP_TRACE, "bit-val=%d", val);
DbgPrintF(MP_TRACE, "reg=%x", 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, "Enable all Multicast=%d", enable);
DbgPrintF(MP_TRACE, "set val = %#x.", 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
u32 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)
#ifndef CRC32_POLY_LE
#define CRC32_POLY_LE 0xedb88320
#endif
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 ^= CRC32_POLY_LE;
}
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)
{
u32 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", FXGMAC_MAC_REGS_OFFSET + hash_reg, readreg(pdata->mac_regs + hash_reg)));
}
DBGPRINT(MP_TRACE, ("fxgmac_config_mcast_mac_hash_table, clear all mcast mac hash table size %d", j));
return;
}
crc = fxgmac_crc32 (pmc_mac, ETH_ALEN);
/* reverse the crc */
for(j = 0, reversal_crc = 0; j < 32; j++)
{
if(crc & ((u32)1 << j)) reversal_crc |= ((u32)1 << (31 - j));
}
GET_REG_AND_BIT_POS((reversal_crc>>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);
}
static void fxgmac_set_mac_hash_table(struct fxgmac_pdata *pdata)
{
#ifndef DPDK
#if FXGMAC_MAC_HASH_TABLE
struct net_device *netdev = pdata->netdev;
struct netdev_hw_addr *ha;
fxgmac_config_multicast_mac_hash_table(pdata, (unsigned char *)0, 1);
netdev_for_each_mc_addr(ha, netdev)
{
fxgmac_config_multicast_mac_hash_table(pdata, ha->addr, 1);
}
#else
(void)pdata;
#endif
#else
(void)pdata;
#endif
}
static int fxgmac_set_mc_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_set_multicast_mode(struct fxgmac_pdata *pdata,
unsigned int enable)
{
if (enable)
fxgmac_set_mc_addresses(pdata);
else
fxgmac_config_multicast_mac_hash_table(pdata, (unsigned char *)0, 1);
}
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 FXGMAC_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)
{
if (FXGMAC_RX_CHECKSUM_ENABLED)
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)
{
unsigned int pr_mode, am_mode, mu_mode, bd_mode;
#ifndef FXGMAC_NETDEV_MU_MODE_ENABLED
#define FXGMAC_NETDEV_MU_MODE_ENABLED 0
#endif
#ifndef FXGMAC_NETDEV_BD_MODE_ENABLED
#define FXGMAC_NETDEV_BD_MODE_ENABLED 0
#endif
pr_mode = FXGMAC_NETDEV_PR_MODE_ENABLED;
am_mode = FXGMAC_NETDEV_AM_MODE_ENABLED;
mu_mode = FXGMAC_NETDEV_MU_MODE_ENABLED;
bd_mode = FXGMAC_NETDEV_BD_MODE_ENABLED;
fxgmac_enable_rx_broadcast(pdata, bd_mode);
fxgmac_set_promiscuous_mode(pdata, pr_mode);
fxgmac_set_all_multicast_mode(pdata, am_mode);
fxgmac_set_multicast_mode(pdata, mu_mode);
return 0;
}
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_ENABLED
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];
if (!txq) {
DPRINTK("Tx queue not setup for port %d\n",
pdata->expansion.eth_dev->data->port_id);
return;
}
/* 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++) {
#if FXGMAC_FAKE_4_TX_QUEUE_ENABLED
if (i>0)
break;
#endif
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;
#ifdef DPDK
PMD_INIT_FUNC_TRACE();
struct fxgmac_tx_queue *txq;
struct rte_eth_dev *dev = pdata->expansion.eth_dev;
#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];
if (!txq) {
DPRINTK("Tx queue not setup for port %d\n",
dev->data->port_id);
return;
}
FXGMAC_DMA_IOWRITE_BITS(txq, DMA_CH_TCR, ST, 0);
}
#endif
}
static void fxgmac_enable_rx(struct fxgmac_pdata *pdata)
{
#ifndef DPDK
struct fxgmac_channel *channel;
#endif
unsigned int i;
u32 regval;
/* 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];
if (!rxq) {
DPRINTK("Rx queue not setup for port %d\n",
dev->data->port_id);
return;
}
/* 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;
u32 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);
#ifdef DPDK
PMD_INIT_FUNC_TRACE();
struct fxgmac_rx_queue *rxq;
struct rte_eth_dev *dev = pdata->expansion.eth_dev;
#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];
if (!rxq) {
DPRINTK("Rx queue not setup for port %d\n",
dev->data->port_id);
return;
}
FXGMAC_DMA_IOWRITE_BITS(rxq, DMA_CH_RCR, SR, 0);
}
#endif
}
static int fxgmac_is_context_desc(struct fxgmac_dma_desc *dma_desc)
{
/* Rx and Tx share CTXT bit, so check TDES3.CTXT bit */
int regval;
regval = (int)FXGMAC_GET_REG_BITS_LE(dma_desc->desc3,
TX_NORMAL_DESC3_CTXT_POS,
TX_NORMAL_DESC3_CTXT_LEN);
return regval;
}
static int fxgmac_is_last_desc(struct fxgmac_dma_desc *dma_desc)
{
/* Rx and Tx share LD bit, so check TDES3.LD bit */
int regval;
regval = (int)FXGMAC_GET_REG_BITS_LE(dma_desc->desc3,
TX_NORMAL_DESC3_LD_POS,
TX_NORMAL_DESC3_LD_LEN);
return regval;
}
static int fxgmac_disable_tx_flow_control(struct fxgmac_pdata *pdata)
{
unsigned int max_q_count, q_count;
unsigned int reg;
unsigned int i;
u32 regval;
/* 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;
unsigned int i;
u32 regval;
/* 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];
if (!rxq) {
DPRINTK("Rx queue not setup for port %d\n",
pdata->expansion.eth_dev->data->port_id);
return -1;
}
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)
{
(void)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];
if (!rxq) {
DPRINTK("Rx queue not setup for port %d\n",
pdata->expansion.eth_dev->data->port_id);
return;
}
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)
{
u32 tso;
#ifndef DPDK
struct fxgmac_channel *channel;
unsigned int i;
u32 regval;
tso = pdata->hw_feat.tso;
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_TSE_POS,
DMA_CH_TCR_TSE_LEN, tso);
writereg(pdata->pAdapter, regval, FXGMAC_DMA_REG(channel, DMA_CH_TCR));
}
#else
struct fxgmac_tx_queue *txq;
unsigned int i;
tso = pdata->hw_feat.tso;
for (i = 0; i < pdata->expansion.eth_dev->data->nb_tx_queues; i++) {
txq = pdata->expansion.eth_dev->data->tx_queues[i];
if (!txq) {
DPRINTK("Tx queue not setup for port %d\n",
pdata->expansion.eth_dev->data->port_id);
return;
}
FXGMAC_DMA_IOWRITE_BITS(txq, DMA_CH_TCR, TSE, tso);
}
#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];
if (!rxq) {
DPRINTK("Rx queue not setup for port %d\n",
pdata->expansion.eth_dev->data->port_id);
return;
}
FXGMAC_DMA_IOWRITE_BITS(rxq, DMA_CH_CR, SPH, 0);
}
#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 long fxgmac_usec_to_riwt(struct fxgmac_pdata *pdata,
unsigned int usec)
{
unsigned long rate;
unsigned long 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 long fxgmac_riwt_to_usec(struct fxgmac_pdata *pdata,
unsigned int riwt)
{
unsigned long rate;
unsigned long 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 reg;
unsigned int mask;
unsigned int i, j;
u32 regval;
/* Map the MTL Tx Queues to Traffic Classes
* Note: Tx Queues >= Traffic Classes
*/
#if 0
unsigned int queue;
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,", prio);
netif_dbg(pdata, drv, pdata->netdev,
" mapped to RXq%u\n", i);
mask |= (1 << prio);
prio++;
}
if (i < ppq_extra) {
netif_dbg(pdata, drv, pdata->netdev,
"PRIO%u.", i);
netif_dbg(pdata, drv, pdata->netdev,
" mapped to Rxq%u", 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 u32 fxgmac_calculate_per_queue_fifo(
unsigned long fifo_size,
unsigned int queue_count)
{
unsigned long q_fifo_size;
unsigned long 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 u32 fxgmac_calculate_max_checksum_size(struct fxgmac_pdata* pdata)
{
u32 fifo_size;
fifo_size = fxgmac_calculate_per_queue_fifo(
pdata->hw_feat.tx_fifo_size,
pdata->tx_q_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.
*/
fifo_size = (fifo_size + 1) * 256;
/* Packet size < TxQSize - (PBL + N)*(DATAWIDTH/8),
* Datawidth = 128
* If Datawidth = 32, N = 7, elseif Datawidth != 32, N = 5.
* TxQSize is indicated by TQS field of MTL_TxQ#_Operation_Mode register
* PBL = TxPBL field in the DMA_CH#_TX_Control register in all DMA configurations.
*/
fifo_size -= (pdata->tx_pbl * (pdata->pblx8 ? 8 : 1) + 5) * (FXGMAC_DATA_WIDTH / 8);
fifo_size -= 256;
return fifo_size;
}
static void fxgmac_config_tx_fifo_size(struct fxgmac_pdata *pdata)
{
u32 fifo_size;
unsigned int i;
u32 regval;
fifo_size = fxgmac_calculate_per_queue_fifo(
pdata->hw_feat.tx_fifo_size,
#if FXGMAC_FAKE_4_TX_QUEUE_ENABLED
1);//force to 1 queue
#else
pdata->tx_q_count);
#endif
for (i = 0; i < pdata->tx_q_count; i++) {
#if FXGMAC_FAKE_4_TX_QUEUE_ENABLED
//DPRINTK("Tx idx > 0,break\n");
if (i>0)
break;
#endif
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,",
pdata->tx_q_count);
netif_info(pdata, drv, pdata->netdev,
" %d byte fifo per queue\n",
((fifo_size + 1) * 256));
}
static void fxgmac_config_rx_fifo_size(struct fxgmac_pdata *pdata)
{
u32 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,",
pdata->rx_q_count);
netif_info(pdata, drv, pdata->netdev,
" %d byte fifo per queue\n",
((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 4k left in fifo */
regval = FXGMAC_SET_REG_BITS(regval, MTL_Q_RQOMR_RFA_POS, MTL_Q_RQOMR_RFA_LEN, 6);
/* De-activate flow control when more than 6k 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];
if (!txq) {
DPRINTK("Tx queue not setup for port %d\n",
pdata->expansion.eth_dev->data->port_id);
return -1;
}
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];
if (!txq) {
DPRINTK("Tx queue not setup for port %d\n",
pdata->expansion.eth_dev->data->port_id);
return -1;
}
FXGMAC_DMA_IOWRITE_BITS(txq, DMA_CH_CR, PBLX8, pdata->pblx8);
}
#endif
return 0;
}
static u32 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];
if (!txq) {
DPRINTK("Tx queue not setup for port %d\n",
pdata->expansion.eth_dev->data->port_id);
return -1;
}
FXGMAC_DMA_IOWRITE_BITS(txq, DMA_CH_TCR, PBL, pdata->tx_pbl);
}
#endif
return 0;
}
static u32 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];
if (!rxq) {
DPRINTK("Rx queue not setup for port %d\n",
pdata->expansion.eth_dev->data->port_id);
return -1;
}
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)
{
u32 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)
{
u32 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;
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);
}
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 !(FXGMAC_MISC_INT_HANDLE_FEATURE_ENABLED)
//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, u32 val)
{
int ret = 0;
(void)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;
}
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;
}
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, (unsigned int)FXGMAC_RSS_HASH_KEY_TYPE,
(unsigned int)(MGMT_RSS_KEY0 + key_regs * MGMT_RSS_KEY_REG_INC), (unsigned int)(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, (void*)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_ENABLED
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 FXGMAC_USE_DEFAULT_RSS_KEY_TBALE
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_ENABLED
/* 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, set val = 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_ENABLED
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, set val = 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)
DPRINTK("fxgmac_config_rss: error configuring RSS\n");
}
#if defined(FXGMAC_POWER_MANAGEMENT)
//
static 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 FXGMAC_AOE_FEATURE_ENABLED
/* 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));
}
}
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 FXGMAC_NS_OFFLOAD_ENABLED
static 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;
(void)ptdata;
(void)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 FXGMAC_PM_WPI_READ_FEATURE_ENABLED
/*
* 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 & ((u32)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 /* FXGMAC_PM_WPI_READ_FEATURE_ENABLED */
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 // FXGMAC_POWER_MANAGEMENT
static u32 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
u32 dma_ch_isr, dma_ch_ier;
u32 regval;
struct fxgmac_channel *channel;
unsigned int i;
//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, DMA_MA_INTM_LEVLE_ENHANCE);
regval = FXGMAC_SET_REG_BITS(regval, DMA_MR_QUREAD_POS, DMA_MR_QUREAD_LEN, DMA_MR_QUREAD_EN);
writereg(pdata->pAdapter, regval, pdata->mac_regs + DMA_MR);
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];
if (!txq) {
DPRINTK("Tx queue not setup for port %d\n",
pdata->expansion.eth_dev->data->port_id);
return;
}
/* 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 i;
u32 mtl_q_isr, q_count;
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)
{
u32 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);
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, FXGMAC_MMC_IER_ALL_DEFAULT);
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, FXGMAC_MMC_IER_ALL_DEFAULT);
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)
{
u16 link_reg = 0;
(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
/*
* 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 link reg %d.\n", link_reg);
return -1;
}
}else {
DPRINTK("fxgmac_check_phy_link null base addr err link reg %d\n", link_reg);
return -1;
}
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,", reg_id);
DPRINTK(" %s,", (regval & 0x1)?"err" : "ok");
DPRINTK(" ctrl=0x%08x,", regval);
DPRINTK(" data=0x%08x\n", data);
return (regval & MAC_MDIO_ADDRESS_BUSY) ? -ETIMEDOUT : 0; //-1 indicates err
}
static int fxgmac_read_ephy_reg(struct fxgmac_pdata* pdata, u32 reg_id, u32 __far* 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 0;
}else {
return -ENOBUFS;
}
}
DPRINTK("fxgmac_read_ephy_reg id=0x%02x err,", reg_id);
DPRINTK(" busy=%d,", busy);
DPRINTK(" ctrl=0x%08x\n", regval);
return -ETIMEDOUT;
}
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,", reg_id);
DPRINTK(" mmd %d,", mmd);
DPRINTK(" %s,", (regval & 0x1) ? "err" : "ok");
DPRINTK(" ctrl=0x%08x,", regval);
DPRINTK(" data=0x%08x\n", 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 FXGMAC_NOT_REPORT_PHY_FC_CAPABILITY
u32 regval = 0;
#endif
fxgmac_config_tx_flow_control(pdata);
fxgmac_config_rx_flow_control(pdata);
#ifndef FXGMAC_NOT_REPORT_PHY_FC_CAPABILITY
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);
#endif
}
static int fxgmac_set_ephy_autoneg_advertise(struct fxgmac_pdata* pdata, struct fxphy_ag_adv phy_ag_adv)
{
u32 regval = 0;
int ret = 0;
ret = fxgmac_read_ephy_reg(pdata, REG_MII_BMCR, ®val);
if (ret < 0)
return ret;
if (phy_ag_adv.auto_neg_en) {
regval = FXGMAC_SET_REG_BITS(regval, PHY_CR_AUTOENG_POS, PHY_CR_AUTOENG_LEN, 1);
} else {
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);
if (ret < 0)
return ret;
ret = fxgmac_read_ephy_reg(pdata, REG_MII_CTRL1000, ®val);
if (ret < 0)
return ret;
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);
if (ret < 0)
return ret;
ret = fxgmac_read_ephy_reg(pdata, REG_MII_ADVERTISE, ®val);
if (ret < 0)
return ret;
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);
if (ret < 0)
return ret;
//after change the auto negotiation advertisement need to soft reset
ret = fxgmac_read_ephy_reg(pdata, REG_MII_BMCR, ®val);
if (ret < 0)
return ret;
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 void fxgmac_phy_green_ethernet(struct fxgmac_pdata* pdata)
{
if(pdata->phy_green_ethernet){
//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);
}
}
static void fxgmac_phy_eee_feature(struct fxgmac_pdata* pdata)
{
u32 regval = 0;
if(pdata->phy_eee){
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);
}
}
static void fxgmac_phy_disable_smartspeed_feature(struct fxgmac_pdata* pdata)
{
u32 regval = 0;
if (pdata->phy_disablesmartspeed) {
fxgmac_read_ephy_reg(pdata, REG_MII_DOWNG_CTRL, ®val);
regval = FXGMAC_SET_REG_BITS(regval, REG_SMART_SPEED_POS, REG_SMART_SPEED_LEN, 0);
fxgmac_write_ephy_reg(pdata, REG_MII_DOWNG_CTRL, regval);
}
}
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 = (pdata->phy_speed == SPEED_1000M) ? 1 : 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;
}
fxgmac_phy_green_ethernet(pdata);
fxgmac_phy_eee_feature(pdata);
fxgmac_phy_disable_smartspeed_feature(pdata);
return fxgmac_set_ephy_autoneg_advertise(pdata, phy_ag_adv);
}
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 ASIC_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_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_VALUE);
cfg_r32(pdata, REG_PCI_SUB_VENDOR_ID, &value);
if (AISTONEID_137D1D05_ADJUST_SI == 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_137D1D05_VALUE);
} else {
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_VALUE);
}
//http://redmine.motor-comm.com/issues/17830
fxgmac_write_ephy_reg(pdata, REG_MII_EXT_ADDR, REG_MII_EXT_AFE_CONTROL_REGISTER3);
fxgmac_read_ephy_reg(pdata, REG_MII_EXT_DATA, &value);
value = FXGMAC_SET_REG_BITS(value, REG_MII_EXT_AFE_CONTROL_CLKDAC_AON_POS, REG_MII_EXT_AFE_CONTROL_CLKDAC_AON_LEN, REG_MII_EXT_AFE_CONTROL_CLKDAC_AON_ON);
fxgmac_write_ephy_reg(pdata, REG_MII_EXT_DATA, value);
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);
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
}
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);
}
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 fxgmac_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);
}
}
static int fxgmac_enable_int(struct fxgmac_channel *channel,
enum fxgmac_int int_id)
{
u32 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)
{
u32 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;
}
static void fxgmac_enable_rx_tx_ints(struct fxgmac_pdata *pdata)
{
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;
fxgmac_enable_int(channel, int_id);
}
}
static void fxgmac_disable_rx_tx_ints(struct fxgmac_pdata *pdata)
{
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;
fxgmac_disable_int(channel, int_id);
}
}
static int fxgmac_dismiss_DMA_int(struct fxgmac_channel *channel, int int_id)
{
u32 dma_ch_ier;
(void)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 i;
u32 mtl_q_isr, q_count;
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);
(void)regval;
(void)regErrVal;
#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);
(void)regval;
#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);
(void)regval;
#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;
}
static int fxgmac_dismiss_all_int(struct fxgmac_pdata *pdata)
{
struct fxgmac_channel *channel;
unsigned int i;
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);
if (netif_msg_drv(pdata)) { DPRINTK("fxgmac_dismiss_all_int callin %d\n", i); }
return 0;
}
static void fxgmac_set_interrupt_moderation(struct fxgmac_pdata* pdata)
{
u32 value = 0, time;
#if defined(FXGMAC_INTERRUPT_MODERATION_EXTERN)
// the Windows driver initializes it somewhere else
pdata->intr_mod_timer = pdata->intr_mod_timer;
#else
pdata->intr_mod_timer = INT_MOD_IN_US;
#endif
#if defined(FXGMAC_INTERRUPT_TX_INTERVAL)
time = (pdata->intr_mod) ? pdata->tx_usecs : 0;
#else
time = (pdata->intr_mod) ? pdata->intr_mod_timer : 0;
#endif
value = FXGMAC_SET_REG_BITS(value, INT_MOD_TX_POS, INT_MOD_TX_LEN, time);
#if defined(FXGMAC_INTERRUPT_RX_INTERVAL)
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 int fxgmac_enable_msix_rxtxphyinterrupt(struct fxgmac_pdata* pdata)
{
u32 intid, regval = 0;
int ret = 0;
#if !(FXGMAC_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 !(FXGMAC_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);
ret = hw_ops->write_ephy_reg(pdata, REG_MII_INT_MASK, regval);//enable phy interrupt ASIC bit10 linkup bit11 linkdown
return ret;
#else
return 0;
#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)
{
#ifdef FXGMAC_MISC_ENABLED
writereg(pdata->pAdapter, 0xf0000000, pdata->base_mem + MGMT_INT_CTRL0);
#else
writereg(pdata->pAdapter, 0x00200000, pdata->base_mem + MGMT_INT_CTRL0);
#endif
return true;
}
static bool fxgmac_enable_source_interrupt(struct fxgmac_pdata* pdata)
{
u32 regval;
#ifdef FXGMAC_MISC_ENABLED
writereg(pdata->pAdapter, 0xf0000000, pdata->base_mem + MGMT_INT_CTRL0);
#else
writereg(pdata->pAdapter, 0x00200000, pdata->base_mem + MGMT_INT_CTRL0);
#endif
regval = 0;
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
fxgmac_enable_rx_tx_ints(pdata);
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 bool fxgmac_disable_source_interrupt(struct fxgmac_pdata* pdata)
{
unsigned int i, ti, ri, dma_ch_isr;
unsigned int dma_channel_status = 0, regval = 0;
struct fxgmac_channel* channel;
for (i = 0; i < pdata->channel_count; i++) {
channel = pdata->channel_head + i;
dma_ch_isr = readreg(pdata->pAdapter, FXGMAC_DMA_REG(channel, DMA_CH_SR));
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)) {
dma_channel_status |= (1 << i);
}
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++;
/* for legacy interrupt, check rx buffer interrupt status, 20210923,yzhang */
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++;
}
}
fxgmac_read_ephy_reg(pdata, REG_MII_INT_STATUS, &pdata->mgmt_phy_val);
if (!(dma_channel_status & 0x0f) && !(pdata->mgmt_phy_val & ((1 << PHY_INT_STAT_LINK_UP_POS) | (1 << PHY_INT_MASK_LINK_DOWN_POS))))
{
return false;
}
fxgmac_disable_rx_tx_ints(pdata);
regval = 0;
fxgmac_write_ephy_reg(pdata, REG_MII_INT_MASK, regval);//disable phy interrupt
channel = pdata->channel_head;
for (i = 0; i < pdata->channel_count; i++, channel++) {
regval = readreg(pdata->pAdapter, FXGMAC_DMA_REG(channel, DMA_CH_SR));
writereg(pdata->pAdapter, regval, FXGMAC_DMA_REG(channel, DMA_CH_SR));
}
readreg(pdata->pAdapter, 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,", FXGMAC_MTL_REG(pdata, i, MTL_Q_TQOMR));
DPRINTK(" val=0x%08x\n", 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,", FXGMAC_MTL_REG(pdata, i, MTL_Q_TQOMR));
DPRINTK(" ... val=0x%08x\n", regval);
if (regval) {/*(!count)*/
return -EBUSY;
}
}
return 0;
}
static void fxgmac_config_dma_bus(struct fxgmac_pdata *pdata)
{
u32 regval;
//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);
/* Out standing read/write requests*/
regval = FXGMAC_SET_REG_BITS(regval, DMA_SBMR_RD_OSR_LMT_POS,
DMA_SBMR_RD_OSR_LMT_LEN, 0x7);
regval = FXGMAC_SET_REG_BITS(regval, DMA_SBMR_WR_OSR_LMT_POS,
DMA_SBMR_WR_OSR_LMT_LEN, 0x7);
/* 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);
}
static void fxgmac_legacy_link_speed_setting(struct fxgmac_pdata* pdata)
{
unsigned int i = 0;
u32 regval = 0;
#ifdef FXGMAC_LINK_SPEED_CHECK_PHY_LINK
u8 link = 0;
regval = fxgmac_get_ephy_state(pdata);
link = FXGMAC_GET_REG_BITS(regval, MGMT_EPHY_CTRL_STA_EPHY_LINKUP_POS, MGMT_EPHY_CTRL_STA_EPHY_LINKUP_LEN);
#endif
fxgmac_phy_config(pdata);
#ifdef FXGMAC_LINK_SPEED_CHECK_PHY_LINK
//no need to wait for link up again if link is down before
if (!link)
return;
#endif
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.
}
#if defined(FXGMAC_FIX_SHUT_DOWN_ISSUE)
static void fxgmac_link_speed_down_fix_shutdown_issue(struct fxgmac_pdata* pdata)
{
LONGLONG tick_interval;
ULONG tick_inc;
LARGE_INTEGER tick_count;
unsigned int i = 0;
unsigned int regval = 0;
if ((ULONG)pdata->phy_speed != ((PMP_ADAPTER)pdata->pAdapter)->usLinkSpeed)
{
DbgPrintF(MP_TRACE, "%s change phy speed", __FUNCTION__);
pdata->phy_speed = ((PMP_ADAPTER)pdata->pAdapter)->usLinkSpeed;
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);
DbgPrintF(MP_TRACE, "regval is 0x%x", regval);*/
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))
)
{
fxgmac_legacy_link_speed_setting(pdata);
}
}
}
}
#endif
static void fxgmac_pre_powerdown(struct fxgmac_pdata* pdata, bool phyloopback)
{
u32 regval = 0;
int speed = SPEED_10;
(void)speed;
fxgmac_disable_rx(pdata);
/* HERE, WE NEED TO CONSIDER PHY CONFIG...TBD */
DPRINTK("fxgmac_config_powerdown, phy and mac status update speed %d\n", speed);
//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) {
if (!pdata->support_10m_link) {
#if defined(FXGMAC_LINK_SPEED_NOT_USE_LOCAL_VARIABLE)
if (SPEED_10 == ((PMP_ADAPTER)pdata->pAdapter)->usLinkSpeed) {
((PMP_ADAPTER)pdata->pAdapter)->usLinkSpeed = SPEED_100;
}
#else
speed = SPEED_100;
#endif
}
#if defined(FXGMAC_FIX_SHUT_DOWN_ISSUE)
fxgmac_link_speed_down_fix_shutdown_issue(pdata);
#elif defined(FXGMAC_LINK_SPEED_CHECK_PHY_LINK)
pdata->phy_autoeng = AUTONEG_ENABLE;
pdata->phy_speed = speed;
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);
}
#ifdef FXGMAC_WOL_INTEGRATED_WOL_PARAMETER
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 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
#if FXGMAC_PM_WPI_READ_FEATURE_ENABLED
fxgmac_enable_wake_packet_indication(pdata, 1);
#endif
/* Enable MAC Rx TX */
#ifdef FXGMAC_WOL_INTEGRATED_WOL_PARAMETER
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(FXGMAC_AOE_FEATURE_ENABLED) || defined(FXGMAC_NS_OFFLOAD_ENABLED)
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);
DPRINTK("fxgmac_config_powerdown callout, reg=0x%08x\n", regval);
}
static void fxgmac_config_powerup(struct fxgmac_pdata* pdata)
{
u32 regval = 0;
/* 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);
/* whether 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 FXGMAC_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 FXGMAC_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;
/* 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, (" disable channel %d tx dma", i));
}
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 regval %x\n", regval);
return -1;
}
busy = 15;
/* 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);
/* 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, (" disable channel %d rx dma", i));
}
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 FXGMAC_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 void fxgmac_config_wol_wait_time(struct fxgmac_pdata *pdata)
{
u32 regval;
regval = readreg(pdata->pAdapter, pdata->base_mem + WOL_CTL);
regval = FXGMAC_SET_REG_BITS(regval, WOL_WAIT_TIME_POS, WOL_WAIT_TIME_LEN,
FXGMAC_WOL_WAIT_TIME);
writereg(pdata->pAdapter, regval, pdata->base_mem + WOL_CTL);
}
static int fxgmac_hw_init(struct fxgmac_pdata *pdata)
{
struct fxgmac_desc_ops *desc_ops = &pdata->desc_ops;
int ret;
if (netif_msg_drv(pdata)) { DPRINTK("fxgmac hw init call in\n"); }
/* Flush Tx queues */
ret = fxgmac_flush_tx_queues(pdata);
if (ret) {
#ifdef FXGMAC_FLUSH_TX_CHECK_ENABLED
dev_err(pdata->dev, "fxgmac_hw_init call flush tx queue err.\n");
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);
desc_ops->tx_desc_init(pdata);
ret = desc_ops->rx_desc_init(pdata);
if (ret) {
#ifdef FXGMAC_RX_DESC_INIT_CHECK_ENABLED
dev_err(pdata->dev, "rx_desc_init err.\n");
return ret;
#endif
}
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);
fxgmac_config_wol_wait_time(pdata);
/* enable EPhy link change interrupt */
fxgmac_read_ephy_reg(pdata, REG_MII_INT_STATUS, NULL);// clear phy interrupt
ret = FXGMAC_SET_REG_BITS(0, PHY_INT_MASK_LINK_UP_POS, PHY_INT_MASK_LINK_UP_LEN, 1);
ret = FXGMAC_SET_REG_BITS(ret, PHY_INT_MASK_LINK_DOWN_POS, PHY_INT_MASK_LINK_DOWN_LEN, 1);
fxgmac_write_ephy_reg(pdata, REG_MII_INT_MASK, ret);//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) && !defined(KDNET)
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(FXGMAC_ESD_RESTORE_PCIE_CFG)
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)
{
#ifndef UEFI
u32 regval;
u32 value = 0;
#ifdef FXGMAC_CHECK_DEV_STATE
if (pdata->expansion.dev_state == FXGMAC_DEV_OPEN) {
#endif
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);
}
#ifdef FXGMAC_CHECK_DEV_STATE
}
#endif
/* 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);
/* bypass pcie reset */
regval = readreg(pdata->pAdapter, pdata->base_mem + SYS_RESET_REG);
regval = FXGMAC_SET_REG_BITS(regval, SYS_RESET_BYPASS_POS, SYS_RESET_BYPASS_LEN, 0);
regval = FXGMAC_SET_REG_BITS(regval, SYS_RESET_POS, SYS_RESET_LEN, 0);
writereg(pdata->pAdapter, regval, pdata->base_mem + SYS_RESET_REG);
/* 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
unsigned int count = 2000;
u32 regval;
/* 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;
}
static int fxgmac_set_gmac_register(struct fxgmac_pdata* pdata, IOMEM address, unsigned int data)
{
if (address < pdata->base_mem)
{
return -1;
}
writereg(pdata->pAdapter, data, address);
return 0;
}
static u32 fxgmac_get_gmac_register(struct fxgmac_pdata* pdata, IOMEM address)
{
u32 regval = 0;
if(address > pdata->base_mem)
{
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_1MS);
regval = FXGMAC_SET_REG_BITS(regval, LTR_IDLE_ENTER_POS, LTR_IDLE_ENTER_LEN, LTR_IDLE_ENTER_VAL);
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_1US);
regval = FXGMAC_SET_REG_BITS(regval, LTR_IDLE_EXIT_POS, LTR_IDLE_EXIT_LEN, LTR_IDLE_EXIT_VAL);
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 (YT6801_NTO_VER == 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);
regval = readreg(pdata->pAdapter, pdata->base_mem + MGMT_SIGDET_DEGLITCH);
regval = FXGMAC_SET_REG_BITS(regval, MGMT_SIGDET_DEGLITCH_DISABLE_POS, MGMT_SIGDET_DEGLITCH_DISABLE_LEN, 1);
writereg(pdata->pAdapter, regval, pdata->base_mem + MGMT_SIGDET_DEGLITCH);
}
cfg_r16(pdata, REG_DEVICE_CTRL1, ®val);
if (PCI_DEVICE_ID_FUXI == deviceid &&
(FXGMAC_GET_REG_BITS(regval, DEVICE_CTRL1_MPS_POS, DEVICE_CTRL1_MPS_LEN) > DEVICE_CTRL1_MPS_128B)) {
regval = FXGMAC_SET_REG_BITS(regval, DEVICE_CTRL1_MPS_POS, DEVICE_CTRL1_MPS_LEN, DEVICE_CTRL1_MPS_128B);
cfg_w16(pdata, REG_DEVICE_CTRL1, regval);
}
cfg_r32(pdata, REG_ACK_LATENCY_RELAY_TIMER, ®val);
regval = FXGMAC_SET_REG_BITS(regval, REG_ACK_LATENCY_TIMER_POS, REG_ACK_LATENCY_TIMER_LEN, REG_ACK_LATENCY_TIMER_VAL);
cfg_w32(pdata, REG_ACK_LATENCY_RELAY_TIMER, regval);
#ifdef ASIC_MODE
// close AER
cfg_r32(pdata, REG_CORRECTABLE_ERROR_MASK_REG, ®val);
regval = FXGMAC_SET_REG_BITS(regval, REG_CORRECTABLE_ERROR_MASK_POS, REG_CORRECTABLE_ERROR_MASK_LEN, 0xFFFF);
cfg_w32(pdata, REG_CORRECTABLE_ERROR_MASK_REG, regval);
#endif
// close L1 sub timeout
cfg_r32(pdata, REG_L1SUB_TIMING, ®val);
regval = FXGMAC_SET_REG_BITS(regval, L1SUB_T_PCLKACK_LOW_POS, L1SUB_T_PCLKACK_LOW_LEN, 0x0);
regval = FXGMAC_SET_REG_BITS(regval, L1SUB_T_PCLKACK_HIGH_POS, L1SUB_T_PCLKACK_HIGH_LEN, 0x0);
cfg_w32(pdata, REG_L1SUB_TIMING, regval);
return 0;
}
static void fxgmac_clear_misc_int_status(struct fxgmac_pdata *pdata)
{
struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops;
u32 regval, i, q_count;
/* clear phy interrupt status */
hw_ops->read_ephy_reg(pdata, REG_MII_INT_STATUS, NULL);
hw_ops->read_ephy_reg(pdata, REG_MII_INT_STATUS, NULL);
/* clear other interrupt status of misc interrupt */
regval = pdata->hw_ops.get_gmac_register(pdata, pdata->mac_regs + MAC_ISR);
if(regval) {
if(regval & (1 << MGMT_MAC_PHYIF_STA_POS))
pdata->hw_ops.get_gmac_register(pdata, pdata->mac_regs + MAC_PHYIF_STA);
if((regval & (1 << MGMT_MAC_AN_SR0_POS)) ||
(regval & (1 << MGMT_MAC_AN_SR1_POS)) ||
(regval & (1 << MGMT_MAC_AN_SR2_POS)))
pdata->hw_ops.get_gmac_register(pdata, pdata->mac_regs + MAC_AN_SR);
if(regval & (1 << MGMT_MAC_PMT_STA_POS))
pdata->hw_ops.get_gmac_register(pdata, pdata->mac_regs + MAC_PMT_STA);
if(regval & (1 << MGMT_MAC_LPI_STA_POS))
pdata->hw_ops.get_gmac_register(pdata, pdata->mac_regs + MAC_LPI_STA);
if(regval & (1 << MGMT_MAC_MMC_STA_POS)) {
if(regval & (1 << MGMT_MAC_RX_MMC_STA_POS))
hw_ops->rx_mmc_int(pdata);
if(regval & (1 << MGMT_MAC_TX_MMC_STA_POS))
hw_ops->tx_mmc_int(pdata);
if(regval & (1 << MGMT_MMC_IPCRXINT_POS))
pdata->hw_ops.get_gmac_register(pdata, pdata->mac_regs + MMC_IPCRXINT);
}
if((regval & (1 << MGMT_MAC_TX_RX_STA0_POS)) || (regval & (1 << MGMT_MAC_TX_RX_STA1_POS)))
pdata->hw_ops.get_gmac_register(pdata, pdata->mac_regs + MAC_TX_RX_STA);
if(regval & (1 << MGMT_MAC_GPIO_SR_POS))
pdata->hw_ops.get_gmac_register(pdata, pdata->mac_regs + MAC_GPIO_SR);
}
/* MTL_Interrupt_Status, write 1 clear */
regval = pdata->hw_ops.get_gmac_register(pdata, pdata->mac_regs + MTL_INT_SR);
pdata->hw_ops.set_gmac_register(pdata, pdata->mac_regs + MTL_INT_SR, regval);
/* MTL_Q(#i)_Interrupt_Control_Status, write 1 clear */
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 */
regval = pdata->hw_ops.get_gmac_register(pdata, pdata->mac_regs + MTL_Q_INT_CTL_SR + i * MTL_Q_INC);
pdata->hw_ops.set_gmac_register(pdata, pdata->mac_regs + MTL_Q_INT_CTL_SR + i * MTL_Q_INC, regval);
}
/* MTL_ECC_Interrupt_Status, write 1 clear */
regval = pdata->hw_ops.get_gmac_register(pdata, pdata->mac_regs + MTL_ECC_INT_SR);
pdata->hw_ops.set_gmac_register(pdata, pdata->mac_regs + MTL_ECC_INT_SR, regval);
/* DMA_ECC_Interrupt_Status, write 1 clear */
regval = pdata->hw_ops.get_gmac_register(pdata, pdata->mac_regs + DMA_ECC_INT_SR);
pdata->hw_ops.set_gmac_register(pdata, pdata->mac_regs + DMA_ECC_INT_SR, regval);
}
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(FXGMAC_ESD_RESTORE_PCIE_CFG)
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;
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->enable_source_interrupt = fxgmac_enable_source_interrupt;
hw_ops->disable_source_interrupt = fxgmac_disable_source_interrupt;
hw_ops->dismiss_all_int = fxgmac_dismiss_all_int;
hw_ops->clear_misc_int_status = fxgmac_clear_misc_int_status;
hw_ops->enable_rx_tx_ints = fxgmac_enable_rx_tx_ints;
hw_ops->disable_rx_tx_ints = fxgmac_disable_rx_tx_ints;
hw_ops->set_mac_address = fxgmac_set_mac_address;
hw_ops->set_mac_hash = fxgmac_set_mc_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->is_last_desc = fxgmac_is_last_desc;
hw_ops->is_context_desc = fxgmac_is_context_desc;
hw_ops->config_tso = fxgmac_config_tso_mode;
#if FXGMAC_SANITY_CHECK_ENABLED
hw_ops->diag_sanity_check = fxgmac_diag_sanity_check;
#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;
hw_ops->calculate_max_checksum_size = fxgmac_calculate_max_checksum_size;
/* 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;
/* 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;
hw_ops->get_rss_hash_key = fxgmac_read_rss_hash_key;
hw_ops->write_rss_lookup_table = fxgmac_write_rss_lookup_table;
/*For Power Management*/
#if defined(FXGMAC_POWER_MANAGEMENT)
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 FXGMAC_PM_WPI_READ_FEATURE_ENABLED
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 = fxgmac_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;
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;
/* 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_mac_subsys_from_efuse = fxgmac_read_mac_subsys_from_efuse;
hw_ops->read_efuse_data = fxgmac_efuse_read_data;
#ifndef COMMENT_UNUSED_CODE_TO_REDUCE_SIZE
hw_ops->read_patch_from_efuse = fxgmac_read_patch_from_efuse;
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->write_mac_subsys_to_efuse = fxgmac_write_mac_subsys_to_efuse;
hw_ops->efuse_load = fxgmac_efuse_load;
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;
#endif
/* */
hw_ops->pcie_init = fxgmac_pcie_init;
hw_ops->trigger_pcie = fxgmac_trigger_pcie;
}
yt6801-dkms-1.0.31/src/fuxi-gmac-ioctl.c 0000664 0000000 0000000 00000051667 15126421535 0017451 0 ustar 00root root 0000000 0000000 // SPDX-License-Identifier: GPL-2.0+
/* Copyright (c) 2021 Motor-comm Corporation. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "fuxi-gmac.h"
#include "fuxi-gmac-reg.h"
static void fxgmac_dbg_tx_pkt(struct fxgmac_pdata *pdata, u8 *pcmd_data)
{
unsigned int pkt_len = 0;
struct sk_buff *skb;
pfxgmac_test_packet pkt;
u8 *tx_data = NULL;
u8 *skb_data = NULL;
u32 offload_len = 0;
u8 ip_head_len, tcp_head_len, head_total_len;
static u32 last_gso_size = 806;//initial default value
//int i = 0;
/* get fxgmac_test_packet */
pkt = (pfxgmac_test_packet)(pcmd_data + sizeof(struct ext_ioctl_data));
pkt_len = pkt->length;
/* get pkt data */
tx_data = (u8 *)pkt + sizeof(fxgmac_test_packet);
/* alloc sk_buff */
skb = alloc_skb(pkt_len, GFP_ATOMIC);
if (!skb){
DPRINTK("alloc skb fail\n");
return;
}
/* copy data to skb */
skb_data = skb_put(skb, pkt_len);
memset(skb_data, 0, pkt_len);
memcpy(skb_data, tx_data, pkt_len);
/* 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 */
ip_head_len = (skb_data[TEST_MAC_HEAD] & 0xF) * 4;
tcp_head_len = (skb_data[TEST_MAC_HEAD + ip_head_len + TEST_TCP_HEAD_LEN_OFFSET] >> 4 & 0xF) * 4;
head_total_len = TEST_MAC_HEAD + ip_head_len + tcp_head_len;
offload_len = (skb_data[TEST_TCP_OFFLOAD_LEN_OFFSET] << 8 |
skb_data[TEST_TCP_OFFLOAD_LEN_OFFSET + 1]) & 0xFFFF;
/* set tso skb parameters */
//skb->ip_summed = CHECKSUM_PARTIAL;
skb->transport_header = ip_head_len + 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(tcp_head_len > TEST_TCP_FIX_HEAD_LEN){
skb_shinfo(skb)->gso_size = (skb_data[TEST_TCP_MSS_OFFSET] << 8 |
skb_data[TEST_TCP_MSS_OFFSET + 1]) & 0xFFFF;
}else{
skb_shinfo(skb)->gso_size = 0;
}
if(skb_shinfo(skb)->gso_size != 0){
last_gso_size = skb_shinfo(skb)->gso_size;
}else{
skb_shinfo(skb)->gso_size = last_gso_size;
}
//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 + head_total_len;
}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 + head_total_len;
}
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 + ip_head_len;
skb->csum_offset = skb->len - TEST_MAC_HEAD - ip_head_len;
pdata->expansion.fxgmac_test_packet_len = skb_shinfo(skb)->gso_size + head_total_len;
}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 total_len = 0;
struct sk_buff *rx_skb;
struct ext_ioctl_data *pcmd;
fxgmac_test_packet pkt;
void* addr = 0;
u8 *rx_data = 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) + total_len < 64000){
pkt.length = rx_skb->len;
pkt.type = 0x80;
pkt.buf[0].offset = total_len + 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 + total_len + sizeof(fxgmac_test_packet) + pkt.length);
}
/* copy data to user space */
if(copy_to_user((void *)(addr + total_len), (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 + total_len + sizeof(fxgmac_test_packet)), (void*)rx_data, rx_skb->len))
{
DPRINTK("cppy data to user fail...");
}
/* update total length */
total_len += (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
pkt = (pfxgmac_test_packet)buf;
DPRINTK("FXG: pkt->Length is %d", pkt->length);
DPRINTK("FXG: pkt->Length is %d", pkt->length);
DPRINTK("pkt: %p, buf is %lx",pkt, pcmd->cmd_buf.buf);
for(i = 0; i < 30; i++){
DPRINTK("%x",*(((u8*)pkt + 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_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 number [%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 FXGMAC_DFS_IOCTL_DIAG_BEGIN:
DPRINTK("Debugfs received diag begin command.\n");
#ifdef FXGMAC_EPHY_LOOPBACK_DETECT_ENABLED
pdata->expansion.lb_test_flag = 1;
#endif
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 FXGMAC_DFS_IOCTL_DIAG_END:
DPRINTK("Debugfs received diag end command.\n");
if (netif_running(pdata->netdev)){
fxgmac_restart_dev(pdata);
}
#ifdef FXGMAC_EPHY_LOOPBACK_DETECT_ENABLED
pdata->expansion.lb_test_flag = 0;
#endif
break;
/* ioctl diag tx pkt */
case FXGMAC_DFS_IOCTL_DIAG_TX_PKT:
fxgmac_dbg_tx_pkt(pdata, buf);
break;
/* ioctl diag rx pkt */
case FXGMAC_DFS_IOCTL_DIAG_RX_PKT:
fxgmac_dbg_rx_pkt(pdata, buf);
break;
/* ioctl device reset */
case FXGMAC_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_REG:
memcpy(&ex_data, data, sizeof(CMD_DATA));
ex_data.val1 = hw_ops->get_gmac_register(pdata,
(u8*)(pdata->base_mem + 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_REG:
memcpy(&ex_data, data, sizeof(CMD_DATA));
regval = hw_ops->set_gmac_register(pdata,
(u8*)(pdata->base_mem + 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;
}
yt6801-dkms-1.0.31/src/fuxi-gmac-net.c 0000664 0000000 0000000 00000367451 15126421535 0017126 0 ustar 00root root 0000000 0000000 // SPDX-License-Identifier: GPL-2.0+
/* Copyright (c) 2021 Motor-comm Corporation. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#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);
static int fxgmac_dev_read(struct fxgmac_channel *channel);
/* define for centos 7.0 */
#if (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,0)) && (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(7,8))
static inline void ____napi_schedule(struct softnet_data *sd,
struct napi_struct *napi)
{
list_add_tail(&napi->poll_list, &sd->poll_list);
//__raise_softirq_irqoff(NET_RX_SOFTIRQ);
or_softirq_pending(1UL << NET_RX_SOFTIRQ);
}
/**
* __napi_schedule_irqoff - schedule for receive
* @n: entry to schedule
*
* Variant of __napi_schedule() assuming hard irqs are masked
*/
void __napi_schedule_irqoff(struct napi_struct *n)
{
____napi_schedule(this_cpu_ptr(&softnet_data), n);
}
/**
* napi_schedule_irqoff - schedule NAPI poll
* @n: napi context
*
* Variant of napi_schedule(), assuming hard irqs are masked.
*/
static inline void napi_schedule_irqoff(struct napi_struct *n)
{
if (napi_schedule_prep(n))
__napi_schedule_irqoff(n);
}
#endif
void fxgmac_lock(struct fxgmac_pdata *pdata)
{
mutex_lock(&pdata->expansion.mutex);
}
void fxgmac_unlock(struct fxgmac_pdata *pdata)
{
mutex_unlock(&pdata->expansion.mutex);
}
#ifdef FXGMAC_ESD_CHECK_ENABLED
static void fxgmac_schedule_esd_work(struct fxgmac_pdata *pdata)
{
set_bit(FXGMAC_FLAG_TASK_ESD_CHECK_PENDING, pdata->expansion.task_flags);
schedule_delayed_work(&pdata->expansion.esd_work, FXGMAC_ESD_INTERVAL);
}
static void fxgmac_update_esd_stats(struct fxgmac_pdata *pdata)
{
u32 value;
value = readreg(pdata->pAdapter, pdata->mac_regs + MMC_TXEXCESSIVECOLLSIONFRAMES);
pdata->expansion.esd_stats.tx_abort_excess_collisions += value;
value = readreg(pdata->pAdapter, pdata->mac_regs + MMC_TXUNDERFLOWERROR_LO);
pdata->expansion.esd_stats.tx_dma_underrun += value;
value = readreg(pdata->pAdapter, pdata->mac_regs + MMC_TXCARRIERERRORFRAMES);
pdata->expansion.esd_stats.tx_lost_crs += value;
value = readreg(pdata->pAdapter, pdata->mac_regs + MMC_TXLATECOLLISIONFRAMES);
pdata->expansion.esd_stats.tx_late_collisions += value;
value = readreg(pdata->pAdapter, pdata->mac_regs + MMC_RXCRCERROR_LO);
pdata->expansion.esd_stats.rx_crc_errors += value;
value = readreg(pdata->pAdapter, pdata->mac_regs + MMC_RXALIGNERROR);
pdata->expansion.esd_stats.rx_align_errors += value;
value = readreg(pdata->pAdapter, pdata->mac_regs + MMC_RXRUNTERROR);
pdata->expansion.esd_stats.rx_runt_errors += value;
value = readreg(pdata->pAdapter, pdata->mac_regs + MMC_TXSINGLECOLLISION_G);
pdata->expansion.esd_stats.single_collisions += value;
value = readreg(pdata->pAdapter, pdata->mac_regs + MMC_TXMULTIPLECOLLISION_G);
pdata->expansion.esd_stats.multi_collisions += value;
value = readreg(pdata->pAdapter, pdata->mac_regs + MMC_TXDEFERREDFRAMES);
pdata->expansion.esd_stats.tx_deferred_frames += value;
}
static void fxgmac_check_esd_work(struct fxgmac_pdata *pdata)
{
FXGMAC_ESD_STATS *stats = &pdata->expansion.esd_stats;
int i = 0;
u32 regval;
/* ESD test will make recv crc errors more than 4,294,967,xxx in one second. */
if (stats->rx_crc_errors > FXGMAC_ESD_ERROR_THRESHOLD ||
stats->rx_align_errors > FXGMAC_ESD_ERROR_THRESHOLD ||
stats->rx_runt_errors > FXGMAC_ESD_ERROR_THRESHOLD ||
stats->tx_abort_excess_collisions > FXGMAC_ESD_ERROR_THRESHOLD ||
stats->tx_dma_underrun > FXGMAC_ESD_ERROR_THRESHOLD ||
stats->tx_lost_crs > FXGMAC_ESD_ERROR_THRESHOLD ||
stats->tx_late_collisions > FXGMAC_ESD_ERROR_THRESHOLD ||
stats->single_collisions > FXGMAC_ESD_ERROR_THRESHOLD ||
stats->multi_collisions > FXGMAC_ESD_ERROR_THRESHOLD ||
stats->tx_deferred_frames > FXGMAC_ESD_ERROR_THRESHOLD) {
dev_info(pdata->dev, "%s - Error:\n", __func__);
dev_info(pdata->dev, "rx_crc_errors %ul.\n", stats->rx_crc_errors);
dev_info(pdata->dev, "rx_align_errors %ul.\n", stats->rx_align_errors);
dev_info(pdata->dev, "rx_runt_errors %ul.\n", stats->rx_runt_errors);
dev_info(pdata->dev, "tx_abort_excess_collisions %ul.\n", stats->tx_abort_excess_collisions);
dev_info(pdata->dev, "tx_dma_underrun %ul.\n", stats->tx_dma_underrun);
dev_info(pdata->dev, "tx_lost_crs %ul.\n", stats->tx_lost_crs);
dev_info(pdata->dev, "tx_late_collisions %ul.\n", stats->tx_late_collisions);
dev_info(pdata->dev, "single_collisions %ul.\n", stats->single_collisions);
dev_info(pdata->dev, "multi_collisions %ul.\n", stats->multi_collisions);
dev_info(pdata->dev, "tx_deferred_frames %ul.\n", stats->tx_deferred_frames);
dev_info(pdata->dev, "esd error triggered, restart NIC...\n");
cfg_r32(pdata, REG_PCI_COMMAND, ®val);
while ((regval == FXGMAC_PCIE_LINK_DOWN) && (i++ < FXGMAC_PCIE_RECOVER_TIMES)) {
usleep_range_ex(pdata->pAdapter, 200, 200);
cfg_r32(pdata, REG_PCI_COMMAND, ®val);
dev_info(pdata->dev, "pcie recovery link cost %d(200us)\n", i);
}
if (regval == FXGMAC_PCIE_LINK_DOWN) {
dev_info(pdata->dev, "pcie link down, recovery failed.\n");
return;
}
if (regval & FXGMAC_PCIE_IO_MEM_MASTER_ENABLE) {
pdata->hw_ops.esd_restore_pcie_cfg(pdata);
cfg_r32(pdata, REG_PCI_COMMAND, ®val);
dev_info(pdata->dev, "pci command reg is %x after restoration.\n", regval);
fxgmac_restart_dev(pdata);
}
}
memset(stats, 0, sizeof(FXGMAC_ESD_STATS));
}
static void fxgmac_esd_work(struct work_struct *work)
{
struct fxgmac_pdata *pdata = container_of(work,
struct fxgmac_pdata,
expansion.esd_work.work);
rtnl_lock();
if (!netif_running(pdata->netdev) ||
!test_and_clear_bit(FXGMAC_FLAG_TASK_ESD_CHECK_PENDING, pdata->expansion.task_flags))
goto out_unlock;
fxgmac_update_esd_stats(pdata);
fxgmac_check_esd_work(pdata);
fxgmac_schedule_esd_work(pdata);
out_unlock:
rtnl_unlock();
}
static void fxgmac_cancel_esd_work(struct fxgmac_pdata *pdata)
{
struct work_struct *work = &pdata->expansion.esd_work.work;
if (!work->func) {
dev_info(pdata->dev, "work func is NULL.\n");
return;
}
cancel_delayed_work_sync(&pdata->expansion.esd_work);
}
#endif
#ifdef FXGMAC_EPHY_LOOPBACK_DETECT_ENABLED
static void fxgmac_schedule_loopback_work(struct fxgmac_pdata *pdata)
{
schedule_delayed_work(&pdata->expansion.loopback_work, FXGMAC_LOOPBACK_CHECK_INTERVAL);
}
static void fxgmac_loopback_work(struct work_struct *work)
{
int ret;
u32 regval;
struct fxgmac_pdata *pdata = container_of(work,
struct fxgmac_pdata,
expansion.loopback_work.work);
if (pdata->expansion.lb_test_flag || pdata->expansion.phy_link)
goto reschedule;
if (!pdata->expansion.lb_cable_flag) {
ret = pdata->hw_ops.read_ephy_reg(pdata, REG_MII_STAT1000, ®val);
if (ret < 0) {
printk("%s:read ephy failed\n", __func__);
goto reschedule;
}
// printk("%s: regval = 0x%x\n", __func__, regval);
regval = FXGMAC_GET_REG_BITS(regval, PHY_MII_STAT1000_CFG_ERROR_POS,
PHY_MII_STAT1000_CFG_ERROR_LEN);
if (regval == 1) {
pdata->expansion.lb_cable_detect_count++;
if (pdata->expansion.lb_cable_detect_count == FXGMAC_PHY_LOOPBACK_DETECT_THRESOLD) {
pdata->expansion.lb_cable_flag = 1;
pdata->hw_ops.setup_cable_loopback(pdata);
pdata->expansion.lb_cable_detect_count = 0;
}
}
}
reschedule:
fxgmac_schedule_loopback_work(pdata);
}
static void fxgmac_cancel_loopback_work(struct fxgmac_pdata *pdata)
{
struct work_struct *work = &pdata->expansion.loopback_work.work;
if (!work->func) {
dev_info(pdata->dev, "work func is NULL.\n");
return;
}
cancel_delayed_work_sync(&pdata->expansion.loopback_work);
}
#endif
#ifdef FXGMAC_ASPM_ENABLED
void fxgmac_schedule_aspm_config_work(struct fxgmac_pdata *pdata)
{
if (!pdata->expansion.aspm_work_active &&
!pdata->expansion.aspm_en &&
pdata->expansion.dev_state != FXGMAC_DEV_CLOSE) {
schedule_delayed_work(&pdata->expansion.aspm_config_work, FXGMAC_ASPM_INTERVAL);
pdata->expansion.aspm_work_active = true;
}
}
static void fxgmac_aspm_config_work(struct work_struct *work)
{
u32 pcie_low_power = PCIE_LP_ASPM_LTR | PCIE_LP_ASPM_L1SS | PCIE_LP_ASPM_L1;
struct fxgmac_pdata *pdata = container_of(work,
struct fxgmac_pdata,
expansion.aspm_config_work.work);
struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops;
if (pdata->expansion.aspm_work_active) {
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->set_pwr_clock_gate(pdata);
pdata->expansion.aspm_en = true;
printk("NIC set aspm at link down\n");
}
pdata->expansion.aspm_work_active = false;
}
void fxgmac_cancel_aspm_config_work(struct fxgmac_pdata *pdata)
{
struct work_struct *work = &pdata->expansion.aspm_config_work.work;
if (!work->func) {
dev_info(pdata->dev, "work func is NULL.\n");
return;
}
cancel_delayed_work_sync(&pdata->expansion.aspm_config_work);
}
bool fxgmac_aspm_action_linkup(struct fxgmac_pdata *pdata)
{
if ((pdata->expansion.aspm_work_active || pdata->expansion.aspm_en)) {
printk("cancel aspm work.\n");
pdata->expansion.aspm_work_active = false;
fxgmac_cancel_aspm_config_work(pdata);
if (pdata->expansion.aspm_en) {
printk("reset from aspm.\n");
pdata->expansion.aspm_en = false;
pdata->expansion.recover_from_aspm = true;
schedule_work(&pdata->expansion.restart_work);
return true;
}
pdata->expansion.aspm_en = false;
}
return false;
}
#endif
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 netdev_tx_t 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)) {
if(netif_msg_tx_done(pdata)) {
netif_info(pdata, drv, pdata->netdev,
"Tx queue stopped, not enough descriptors available\n");
}
/* Avoid wrongly optimistic queue wake-up: tx poll thread must
* not miss a ring update when it notices a stopped queue.
*/
smp_wmb();
netif_stop_subqueue(pdata->netdev, channel->queue_index);
ring->tx.queue_stopped = 1;
/* Sync with tx poll:
* - publish queue status and cur ring index (write barrier)
* - refresh dirty ring index (read barrier).
* May the current thread have a pessimistic view of the ring
* status and forget to wake up queue, a racing tx poll thread
* can't.
*/
smp_mb();
if (count <= fxgmac_tx_avail_desc(ring)) {
ring->tx.queue_stopped = 0;
netif_start_subqueue(pdata->netdev, channel->queue_index);
fxgmac_tx_start_xmit(channel, ring);
} else {
/* If we haven't notified the hardware because of xmit_more
* support, tell it now
*/
if (ring->tx.xmit_more)
fxgmac_tx_start_xmit(channel, ring);
if(netif_msg_tx_done(pdata)) DPRINTK("about stop tx q, ret BUSY\n");
return NETDEV_TX_BUSY;
}
}
return NETDEV_TX_OK;
}
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)
{
skb_frag_t *frag;
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;
unsigned int max_mtu;
/* On the Linux platform, the MTU size does not include the length
* of the MAC address and the length of the Type, but FXGMAC_JUMBO_PACKET_MTU include them.
*/
max_mtu = FXGMAC_JUMBO_PACKET_MTU - ETH_HLEN;
if (mtu > max_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;
}
#ifdef FXGMAC_MISC_ENABLED
static int fxgmac_misc_poll(struct napi_struct *napi, int budget)
{
struct fxgmac_pdata *pdata = container_of(napi,
struct fxgmac_pdata,
expansion.napi_misc);
struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops;
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0))
if (napi_complete_done(napi, 0))
hw_ops->enable_msix_one_interrupt(pdata, MSI_ID_PHY_OTHER);
#else
napi_complete(napi);
hw_ops->enable_msix_one_interrupt(pdata, MSI_ID_PHY_OTHER);
#endif
return 0;
}
static irqreturn_t fxgmac_misc_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_MISC))
return IRQ_HANDLED;
hw_ops->disable_msix_one_interrupt(pdata, MSI_ID_PHY_OTHER);
hw_ops->clear_misc_int_status(pdata);
napi_schedule_irqoff(&pdata->expansion.napi_misc);
return IRQ_HANDLED;
}
#endif
static irqreturn_t fxgmac_isr(int irq, void *data)
{
unsigned int dma_ch_isr, dma_isr, mac_isr;
struct fxgmac_pdata *pdata = data;
struct fxgmac_channel *channel;
struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops;
unsigned int i;
u32 val;
val = readreg(pdata->pAdapter, pdata->base_mem + MGMT_INT_CTRL0);
if (!(val & MGMT_INT_CTRL0_INT_STATUS_RXTX_MASK))
return IRQ_NONE;
dma_isr = readreg(pdata->pAdapter, pdata->mac_regs + DMA_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));
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);
#ifdef FXGMAC_MISC_ENABLED
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);
#endif
/* Clear all interrupt signals */
writel(mac_isr, (pdata->mac_regs + MAC_ISR));
}
hw_ops->disable_mgm_interrupt(pdata);
pdata->stats.mgmt_int_isr++;
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));
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));
napi_schedule_irqoff(&channel->expansion.napi_rx);
}
return IRQ_HANDLED;
}
#if FXGMAC_TX_HANG_TIMER_ENABLED
#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_ENABLED
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_ENABLED
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;
u32 tx_napi = 0, rx_napi = 0;
#ifdef FXGMAC_MISC_ENABLED
u32 misc_napi = 0;
misc_napi = FXGMAC_GET_REG_BITS(pdata->expansion.int_flags,
FXGMAC_FLAG_MISC_NAPI_FREE_POS,
FXGMAC_FLAG_MISC_NAPI_FREE_LEN);
#endif
tx_napi = FXGMAC_GET_REG_BITS(pdata->expansion.int_flags,
FXGMAC_FLAG_TX_NAPI_FREE_POS,
FXGMAC_FLAG_TX_NAPI_FREE_LEN);
rx_napi = FXGMAC_GET_REG_BITS(pdata->expansion.int_flags,
FXGMAC_FLAG_RX_NAPI_FREE_POS,
FXGMAC_FLAG_RX_NAPI_FREE_LEN);
if (pdata->per_channel_irq) {
channel = pdata->channel_head;
for (i = 0; i < pdata->channel_count; i++, channel++) {
if (!FXGMAC_GET_REG_BITS(rx_napi,
i, FXGMAC_FLAG_PER_CHAN_RX_NAPI_FREE_LEN)) {
if (add) {
#if ( LINUX_VERSION_CODE >= KERNEL_VERSION(5,19,0) ||\
RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(9,2) )
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);
pdata->expansion.int_flags =
FXGMAC_SET_REG_BITS(pdata->expansion.int_flags,
FXGMAC_FLAG_RX_NAPI_FREE_POS + i,
FXGMAC_FLAG_PER_CHAN_RX_NAPI_FREE_LEN,
FXGMAC_NAPI_ENABLE);
}
if (FXGMAC_IS_CHANNEL_WITH_TX_IRQ(i) && !tx_napi) {
#if ( LINUX_VERSION_CODE >= KERNEL_VERSION(5,19,0) ||\
RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(9,2) )
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);
pdata->expansion.int_flags =
FXGMAC_SET_REG_BITS(pdata->expansion.int_flags,
FXGMAC_FLAG_TX_NAPI_FREE_POS,
FXGMAC_FLAG_TX_NAPI_FREE_LEN,
FXGMAC_NAPI_ENABLE);
}
if(netif_msg_drv(pdata)) DPRINTK("napi_enable, msix ch%d napi enabled done,add=%d\n", i, add);
}
#ifdef FXGMAC_MISC_ENABLED
/* for misc */
if (!misc_napi) {
#if ( LINUX_VERSION_CODE >= KERNEL_VERSION(5,19,0) ||\
RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(9,2) )
netif_napi_add_weight(pdata->netdev, &pdata->expansion.napi_misc,
fxgmac_misc_poll, NAPI_POLL_WEIGHT);
#else
netif_napi_add(pdata->netdev, &pdata->expansion.napi_misc,
fxgmac_misc_poll, NAPI_POLL_WEIGHT);
#endif
napi_enable(&pdata->expansion.napi_misc);
pdata->expansion.int_flags =
FXGMAC_SET_REG_BITS(pdata->expansion.int_flags,
FXGMAC_FLAG_MISC_NAPI_FREE_POS,
FXGMAC_FLAG_MISC_NAPI_FREE_LEN,
FXGMAC_NAPI_ENABLE);
}
#endif
} 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(5,19,0) ||\
RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(9,2) )
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,
FXGMAC_NAPI_ENABLE);
}
}
}
static void fxgmac_napi_disable(struct fxgmac_pdata *pdata, unsigned int del)
{
struct fxgmac_channel *channel;
unsigned int i;
u32 tx_napi = 0, rx_napi = 0;
#ifdef FXGMAC_MISC_ENABLED
u32 misc_napi = 0;
#endif
if (pdata->per_channel_irq) {
#ifdef FXGMAC_MISC_ENABLED
misc_napi = FXGMAC_GET_REG_BITS(pdata->expansion.int_flags,
FXGMAC_FLAG_MISC_NAPI_FREE_POS,
FXGMAC_FLAG_MISC_NAPI_FREE_LEN);
#endif
tx_napi = FXGMAC_GET_REG_BITS(pdata->expansion.int_flags,
FXGMAC_FLAG_TX_NAPI_FREE_POS,
FXGMAC_FLAG_TX_NAPI_FREE_LEN);
rx_napi = FXGMAC_GET_REG_BITS(pdata->expansion.int_flags,
FXGMAC_FLAG_RX_NAPI_FREE_POS,
FXGMAC_FLAG_RX_NAPI_FREE_LEN);
channel = pdata->channel_head;
if (channel != NULL) {
for (i = 0; i < pdata->channel_count; i++, channel++) {
if (FXGMAC_GET_REG_BITS(rx_napi,
i, FXGMAC_FLAG_PER_CHAN_RX_NAPI_FREE_LEN)) {
napi_disable(&channel->expansion.napi_rx);
if (del) {
netif_napi_del(&channel->expansion.napi_rx);
}
pdata->expansion.int_flags =
FXGMAC_SET_REG_BITS(pdata->expansion.int_flags,
FXGMAC_FLAG_RX_NAPI_FREE_POS + i,
FXGMAC_FLAG_PER_CHAN_RX_NAPI_FREE_LEN,
FXGMAC_NAPI_DISABLE);
}
if (FXGMAC_IS_CHANNEL_WITH_TX_IRQ(i) && tx_napi) {
napi_disable(&channel->expansion.napi_tx);
netif_napi_del(&channel->expansion.napi_tx);
pdata->expansion.int_flags =
FXGMAC_SET_REG_BITS(pdata->expansion.int_flags,
FXGMAC_FLAG_TX_NAPI_FREE_POS,
FXGMAC_FLAG_TX_NAPI_FREE_LEN,
FXGMAC_NAPI_DISABLE);
}
if(netif_msg_drv(pdata)) DPRINTK("napi_disable, msix ch%d napi disabled done,del=%d\n", i, del);
}
#ifdef FXGMAC_MISC_ENABLED
if (misc_napi) {
napi_disable(&pdata->expansion.napi_misc);
netif_napi_del(&pdata->expansion.napi_misc);
pdata->expansion.int_flags =
FXGMAC_SET_REG_BITS(pdata->expansion.int_flags,
FXGMAC_FLAG_MISC_NAPI_FREE_POS,
FXGMAC_FLAG_MISC_NAPI_FREE_LEN,
FXGMAC_NAPI_DISABLE);
}
#endif
}
} 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,
FXGMAC_NAPI_DISABLE);
}
}
}
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;
u32 tx = 0, rx = 0;
#ifdef FXGMAC_MISC_ENABLED
u32 misc = 0;
#endif
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,
FXGMAC_IRQ_ENABLE);
}
}
if (!pdata->per_channel_irq) {
return 0;
}
tx = FXGMAC_GET_REG_BITS(pdata->expansion.int_flags,
FXGMAC_FLAG_TX_IRQ_FREE_POS,
FXGMAC_FLAG_TX_IRQ_FREE_LEN);
rx = FXGMAC_GET_REG_BITS(pdata->expansion.int_flags,
FXGMAC_FLAG_RX_IRQ_FREE_POS,
FXGMAC_FLAG_RX_IRQ_FREE_LEN);
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) && !tx) {
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) {
netdev_alert(netdev, "fxgmac_req_irqs, err with MSIx irq \
request for ch %d tx, ret=%d\n", i, ret);
goto err_irq;
}
pdata->expansion.int_flags = FXGMAC_SET_REG_BITS(pdata->expansion.int_flags,
FXGMAC_FLAG_TX_IRQ_FREE_POS,
FXGMAC_FLAG_TX_IRQ_FREE_LEN,
FXGMAC_IRQ_ENABLE);
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);
}
if (!FXGMAC_GET_REG_BITS(rx, i, FXGMAC_FLAG_PER_CHAN_RX_IRQ_FREE_LEN)) {
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;
}
pdata->expansion.int_flags = FXGMAC_SET_REG_BITS(pdata->expansion.int_flags,
FXGMAC_FLAG_RX_IRQ_FREE_POS + i,
FXGMAC_FLAG_PER_CHAN_RX_IRQ_FREE_LEN,
FXGMAC_IRQ_ENABLE);
}
}
#ifdef FXGMAC_MISC_ENABLED
misc = FXGMAC_GET_REG_BITS(pdata->expansion.int_flags,
FXGMAC_FLAG_MISC_IRQ_FREE_POS,
FXGMAC_FLAG_MISC_IRQ_FREE_LEN);
if (!misc) {
snprintf(pdata->expansion.misc_irq_name,
sizeof(pdata->expansion.misc_irq_name) - 1,
"%s-misc", netdev_name(netdev));
ret = devm_request_irq(pdata->dev,
pdata->expansion.misc_irq,
fxgmac_misc_isr,
0,
pdata->expansion.misc_irq_name,
pdata);
if (ret) {
netdev_alert(netdev,
"error requesting misc irq %d, ret = %d\n",
pdata->expansion.misc_irq,
ret);
goto err_irq;
}
pdata->expansion.int_flags = FXGMAC_SET_REG_BITS(pdata->expansion.int_flags,
FXGMAC_FLAG_MISC_IRQ_FREE_POS,
FXGMAC_FLAG_MISC_IRQ_FREE_LEN,
FXGMAC_IRQ_ENABLE);
}
#endif
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:
netdev_alert(netdev, "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) && tx) {
pdata->expansion.int_flags=
FXGMAC_SET_REG_BITS(pdata->expansion.int_flags,
FXGMAC_FLAG_TX_IRQ_FREE_POS,
FXGMAC_FLAG_TX_IRQ_FREE_LEN,
FXGMAC_IRQ_DISABLE);
devm_free_irq(pdata->dev, channel->expansion.dma_irq_tx, channel);
}
if (FXGMAC_GET_REG_BITS(rx, i, FXGMAC_FLAG_PER_CHAN_RX_IRQ_FREE_LEN)) {
pdata->expansion.int_flags=
FXGMAC_SET_REG_BITS(pdata->expansion.int_flags,
FXGMAC_FLAG_RX_IRQ_FREE_POS + i,
FXGMAC_FLAG_PER_CHAN_RX_IRQ_FREE_LEN,
FXGMAC_IRQ_DISABLE);
devm_free_irq(pdata->dev, channel->dma_irq, channel);
}
}
#ifdef FXGMAC_MISC_ENABLED
if (misc) {
pdata->expansion.int_flags=
FXGMAC_SET_REG_BITS(pdata->expansion.int_flags,
FXGMAC_FLAG_MISC_IRQ_FREE_POS,
FXGMAC_FLAG_MISC_IRQ_FREE_LEN,
FXGMAC_IRQ_DISABLE);
devm_free_irq(pdata->dev, pdata->expansion.misc_irq, pdata);
}
#endif
}
return ret;
}
static void fxgmac_free_irqs(struct fxgmac_pdata *pdata)
{
struct fxgmac_channel *channel;
unsigned int i = 0;
u32 need_free, msix;
u32 tx = 0, rx = 0;
#ifdef FXGMAC_MISC_ENABLED
u32 misc = 0;
#endif
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,
FXGMAC_IRQ_DISABLE);
}
}
if (!pdata->per_channel_irq)
return;
#ifdef FXGMAC_MISC_ENABLED
misc = FXGMAC_GET_REG_BITS(pdata->expansion.int_flags,
FXGMAC_FLAG_MISC_IRQ_FREE_POS,
FXGMAC_FLAG_MISC_IRQ_FREE_LEN);
#endif
tx = FXGMAC_GET_REG_BITS(pdata->expansion.int_flags,
FXGMAC_FLAG_TX_IRQ_FREE_POS,
FXGMAC_FLAG_TX_IRQ_FREE_LEN);
rx = FXGMAC_GET_REG_BITS(pdata->expansion.int_flags,
FXGMAC_FLAG_RX_IRQ_FREE_POS,
FXGMAC_FLAG_RX_IRQ_FREE_LEN);
channel = pdata->channel_head;
if (channel != NULL) {
for (i = 0; i < pdata->channel_count; i++, channel++) {
if(FXGMAC_IS_CHANNEL_WITH_TX_IRQ(i) && tx) {
pdata->expansion.int_flags=
FXGMAC_SET_REG_BITS(pdata->expansion.int_flags,
FXGMAC_FLAG_TX_IRQ_FREE_POS,
FXGMAC_FLAG_TX_IRQ_FREE_LEN,
FXGMAC_IRQ_DISABLE);
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);
}
if (FXGMAC_GET_REG_BITS(rx, i, FXGMAC_FLAG_PER_CHAN_RX_IRQ_FREE_LEN)) {
pdata->expansion.int_flags=
FXGMAC_SET_REG_BITS(pdata->expansion.int_flags,
FXGMAC_FLAG_RX_IRQ_FREE_POS + i,
FXGMAC_FLAG_PER_CHAN_RX_IRQ_FREE_LEN,
FXGMAC_IRQ_DISABLE);
devm_free_irq(pdata->dev, channel->dma_irq, channel);
}
}
#ifdef FXGMAC_MISC_ENABLED
if (misc) {
pdata->expansion.int_flags=
FXGMAC_SET_REG_BITS(pdata->expansion.int_flags,
FXGMAC_FLAG_MISC_IRQ_FREE_POS,
FXGMAC_FLAG_MISC_IRQ_FREE_LEN,
FXGMAC_IRQ_DISABLE);
devm_free_irq(pdata->dev, pdata->expansion.misc_irq, pdata);
}
#endif
}
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 = 0;
u32 pcie_msi_mask_bits = 0;
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) {
DPRINTK(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) {
DPRINTK(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 = 0;
u32 pcie_msi_mask_bits = 0;
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) {
DPRINTK(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) {
DPRINTK(KERN_ERR "write pci config space MSIX mask failed, %d\n", ret);
ret = -EFAULT;
}
return ret;
}
int fxgmac_start(struct fxgmac_pdata *pdata)
{
struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops;
unsigned int pcie_low_power = PCIE_LP_ASPM_LTR;
u8 deviceid;
int ret;
if(netif_msg_drv(pdata)) DPRINTK("fxgmac start callin here.\n");
if (pdata->expansion.dev_state != FXGMAC_DEV_OPEN &&
pdata->expansion.dev_state != FXGMAC_DEV_STOP &&
pdata->expansion.dev_state != FXGMAC_DEV_RESUME)
return 0;
/* 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);
cfg_r8(pdata, REG_PCI_REVID, &deviceid);
hw_ops->pcie_init(pdata,
pcie_low_power & PCIE_LP_ASPM_LTR,
pcie_low_power & PCIE_LP_ASPM_L1SS,
(YT6801_NTO_VER != deviceid) ? true : (pcie_low_power & PCIE_LP_ASPM_L1),
pcie_low_power & PCIE_LP_ASPM_L0S);
#ifdef FXGMAC_ASPM_ENABLED
if (pdata->expansion.aspm_work_active || pdata->expansion.aspm_en) {
printk("cancle aspm work.\n");
fxgmac_cancel_aspm_config_work(pdata);
pdata->expansion.aspm_en = false;
pdata->expansion.aspm_work_active = false;
}
#endif
hw_ops->config_power_up(pdata);
hw_ops->dismiss_all_int(pdata);
ret = hw_ops->init(pdata);
if (ret) {
DPRINTK("fxgmac hw init error.\n");
return ret;
}
#ifdef FXGMAC_PHY_SLEEP_ENABLE
hw_ops->enable_phy_sleep(pdata);
#endif
fxgmac_napi_enable(pdata, 1);
ret = fxgmac_request_irqs(pdata);
if (ret)
goto err_napi;
hw_ops->enable_mgm_interrupt(pdata);
#if FXGMAC_INT_MODERATION_ENABLED
hw_ops->set_interrupt_moderation(pdata);
#endif
if (pdata->per_channel_irq)
hw_ops->enable_msix_rxtxinterrupt(pdata);
#ifdef FXGMAC_ESD_CHECK_ENABLED
fxgmac_schedule_esd_work(pdata);
#endif
#ifdef FXGMAC_EPHY_LOOPBACK_DETECT_ENABLED
pdata->expansion.lb_cable_flag = 0;
fxgmac_schedule_loopback_work(pdata);
#endif
if (pdata->expansion.recover_phy_state)
fxgmac_set_phy_link_ksettings(pdata);
hw_ops->led_under_active(pdata);
pdata->expansion.dev_state = FXGMAC_DEV_START;
if (!pdata->expansion.recover_from_aspm) {
#ifdef FXGMAC_ASPM_ENABLED
printk("start aspm work and phy timer.\n");
fxgmac_schedule_aspm_config_work(pdata);
pdata->expansion.aspm_work_active = true;
#endif
fxgmac_phy_timer_init(pdata);
}
pdata->expansion.recover_from_aspm = false;
return 0;
err_napi:
if (!pdata->expansion.recover_from_aspm)
fxgmac_phy_timer_destroy(pdata);
fxgmac_napi_disable(pdata, 1);
hw_ops->exit(pdata);
dev_err(pdata->dev, "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->expansion.dev_state != FXGMAC_DEV_START)
return;
pdata->expansion.dev_state = FXGMAC_DEV_STOP;
netif_carrier_off(netdev);
netif_tx_stop_all_queues(netdev);
if (!pdata->expansion.recover_from_aspm)
fxgmac_phy_timer_destroy(pdata);
#ifdef FXGMAC_EPHY_LOOPBACK_DETECT_ENABLED
fxgmac_cancel_loopback_work(pdata);
#endif
#ifdef FXGMAC_ESD_CHECK_ENABLED
fxgmac_cancel_esd_work(pdata);
#endif
hw_ops->disable_tx(pdata);
hw_ops->disable_rx(pdata);
if (pdata->per_channel_irq) {
hw_ops->disable_msix_interrupt(pdata);
}
else {
hw_ops->disable_mgm_interrupt(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);
}
}
}
void fxgmac_restart_dev(struct fxgmac_pdata *pdata)
{
struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops;
int ret;
/* If not running, "restart" will happen on open */
if (!netif_running(pdata->netdev) &&
pdata->expansion.dev_state != FXGMAC_DEV_START)
return;
fxgmac_lock(pdata);
fxgmac_stop(pdata);
hw_ops->led_under_shutdown(pdata);
fxgmac_free_tx_data(pdata);
fxgmac_free_rx_data(pdata);
ret = fxgmac_start(pdata);
if (ret) {
DPRINTK("fxgmac_restart_dev: fxgmac_start failed.\n");
}
fxgmac_unlock(pdata);
}
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) {
DPRINTK("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;
u32 val;
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);
/* 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
#ifdef FXGMAC_EPHY_LOOPBACK_DETECT_ENABLED
val = pdata->expansion.lb_cable_flag;
#else
val = 0;
#endif
// must call it after software reset
hw_ops->pre_power_down(pdata, val);
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);
}
/* 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
//Close the phy when not enable any wakeup
if(!wol)
hw_ops->reset_phy(pdata);
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");
fxgmac_lock(pdata);
pdata->expansion.dev_state = FXGMAC_DEV_OPEN;
desc_ops = &pdata->desc_ops;
/* 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)
goto unlock;
pdata->rx_buf_size = ret;
/* Allocate the channels and rings */
ret = desc_ops->alloc_channels_and_rings(pdata);
if (ret)
goto unlock;
INIT_WORK(&pdata->expansion.restart_work, fxgmac_restart);
#ifdef FXGMAC_ESD_CHECK_ENABLED
INIT_DELAYED_WORK(&pdata->expansion.esd_work, fxgmac_esd_work);
#endif
#ifdef FXGMAC_EPHY_LOOPBACK_DETECT_ENABLED
INIT_DELAYED_WORK(&pdata->expansion.loopback_work, fxgmac_loopback_work);
#endif
#ifdef FXGMAC_ASPM_ENABLED
INIT_DELAYED_WORK(&pdata->expansion.aspm_config_work, fxgmac_aspm_config_work);
#endif
ret = fxgmac_start(pdata);
if (ret)
goto err_channels_and_rings;
if(netif_msg_drv(pdata)) DPRINTK("fxgmac_open callout\n");
fxgmac_unlock(pdata);
return 0;
err_channels_and_rings:
desc_ops->free_channels_and_rings(pdata);
DPRINTK("fxgmac_open callout with channel alloc err\n");
unlock:
fxgmac_unlock(pdata);
return ret;
}
static int fxgmac_close(struct net_device *netdev)
{
struct fxgmac_pdata *pdata = netdev_priv(netdev);
struct fxgmac_desc_ops *desc_ops = &pdata->desc_ops;
if(netif_msg_drv(pdata)) DPRINTK("fxgmac_close callin\n");
fxgmac_lock(pdata);
/* Stop the device */
fxgmac_stop(pdata);
pdata->expansion.dev_state = FXGMAC_DEV_CLOSE;
/* Free the channels and rings */
desc_ops->free_channels_and_rings(pdata);
pdata->hw_ops.reset_phy(pdata);
fxgmac_phy_update_link(netdev);
#ifdef FXGMAC_ASPM_ENABLED
fxgmac_cancel_aspm_config_work(pdata);
pdata->expansion.aspm_work_active = false;
pdata->expansion.recover_from_aspm = false;
pdata->expansion.aspm_en = false;
pdata->hw_ops.pcie_init(pdata, true, true, true, false);
#endif
if(netif_msg_drv(pdata)) DPRINTK("fxgmac_close callout\n");
fxgmac_unlock(pdata);
return 0;
}
static void fxgmac_dump_state(struct fxgmac_pdata *pdata)
{
struct fxgmac_channel *channel = pdata->channel_head;
struct fxgmac_stats *pstats = &pdata->stats;
struct fxgmac_ring *ring;
u32 i;
ring = channel->tx_ring;
DPRINTK( "Tx descriptor info:\n");
DPRINTK( "Tx cur = 0x%x\n", ring->cur);
DPRINTK( "Tx dirty = 0x%x\n", ring->dirty);
DPRINTK( "Tx dma_desc_head = %pad\n", &ring->dma_desc_head);
DPRINTK( "Tx desc_data_head = %pad\n", &ring->desc_data_head);
for (i = 0; i < pdata->channel_count; i++, channel++) {
ring = channel->rx_ring;
DPRINTK( "Rx[%d] descriptor info:\n", i);
DPRINTK( "Rx cur = 0x%x\n", ring->cur);
DPRINTK( "Rx dirty = 0x%x\n", ring->dirty);
DPRINTK( "Rx dma_desc_head = %pad\n",
&ring->dma_desc_head);
DPRINTK( "Rx desc_data_head = %pad\n",
&ring->desc_data_head);
}
DPRINTK( "Device Registers:\n");
DPRINTK( "MAC_ISR = %08x\n", readreg(pdata->pAdapter, pdata->mac_regs + MAC_ISR));
DPRINTK( "MAC_IER = %08x\n", readreg(pdata->pAdapter, pdata->mac_regs + MAC_IER));
DPRINTK( "MMC_RISR = %08x\n", readreg(pdata->pAdapter, pdata->mac_regs + MMC_RISR));
DPRINTK( "MMC_RIER = %08x\n", readreg(pdata->pAdapter, pdata->mac_regs + MMC_RIER));
DPRINTK( "MMC_TISR = %08x\n", readreg(pdata->pAdapter, pdata->mac_regs + MMC_TISR));
DPRINTK( "MMC_TIER = %08x\n", readreg(pdata->pAdapter, pdata->mac_regs + MMC_TIER));
DPRINTK( "EPHY_CTRL = %04x\n", readreg(pdata->pAdapter, pdata->base_mem + MGMT_EPHY_CTRL));
DPRINTK( "MGMT_INT_CTRL0 = %04x\n",
readreg(pdata->pAdapter, pdata->base_mem + MGMT_INT_CTRL0));
DPRINTK( "LPW_CTRL = %04x\n", readreg(pdata->pAdapter, pdata->base_mem + LPW_CTRL));
DPRINTK( "MSIX_TBL_MASK = %04x\n", readreg(pdata->pAdapter, pdata->base_mem + MSIX_TBL_BASE_ADDR + MSIX_TBL_MASK_OFFSET));
DPRINTK( "Dump nonstick regs:\n");
for ( i = REG_PCIE_TRIGGER; i < MSI_PBA_REG; i += 4)
DPRINTK( "[%d] = %04x\n", i / 4, readreg(pdata->pAdapter, pdata->base_mem + i));
pdata->hw_ops.read_mmc_stats(pdata);
DPRINTK( "Dump TX counters:\n");
DPRINTK( "tx_packets %lld\n", pstats->txframecount_gb);
DPRINTK( "tx_errors %lld\n",
pstats->txframecount_gb - pstats->txframecount_g);
DPRINTK( "tx_multicastframes_errors %lld\n",
pstats->txmulticastframes_gb - pstats->txmulticastframes_g);
DPRINTK( "tx_broadcastframes_errors %lld\n",
pstats->txbroadcastframes_gb - pstats->txbroadcastframes_g);
DPRINTK( "txunderflowerror %lld\n", pstats->txunderflowerror);
DPRINTK( "txdeferredframes %lld\n",
pstats->txdeferredframes);
DPRINTK( "txlatecollisionframes %lld\n",
pstats->txlatecollisionframes);
DPRINTK( "txexcessivecollisionframes %lld\n",
pstats->txexcessivecollisionframes);
DPRINTK( "txcarriererrorframes %lld\n",
pstats->txcarriererrorframes);
DPRINTK( "txexcessivedeferralerror %lld\n",
pstats->txexcessivedeferralerror);
DPRINTK( "txsinglecollision_g %lld\n",
pstats->txsinglecollision_g);
DPRINTK( "txmultiplecollision_g %lld\n",
pstats->txmultiplecollision_g);
DPRINTK( "txoversize_g %lld\n", pstats->txoversize_g);
DPRINTK( "Dump RX counters:\n");
DPRINTK( "rx_packets %lld\n", pstats->rxframecount_gb);
DPRINTK( "rx_errors %lld\n",
pstats->rxframecount_gb - pstats->rxbroadcastframes_g -
pstats->rxmulticastframes_g - pstats->rxunicastframes_g);
DPRINTK( "rx_crc_errors %lld\n", pstats->rxcrcerror);
DPRINTK( "rxalignerror %lld\n", pstats->rxalignerror);
DPRINTK( "rxrunterror %lld\n", pstats->rxrunterror);
DPRINTK( "rxjabbererror %lld\n", pstats->rxjabbererror);
DPRINTK( "rx_length_errors %lld\n", pstats->rxlengtherror);
DPRINTK( "rxoutofrangetype %lld\n", pstats->rxoutofrangetype);
DPRINTK( "rx_fifo_errors %lld\n", pstats->rxfifooverflow);
DPRINTK( "rxwatchdogerror %lld\n", pstats->rxwatchdogerror);
DPRINTK( "rxreceiveerrorframe %lld\n",
pstats->rxreceiveerrorframe);
DPRINTK( "rxbroadcastframes_g %lld\n",
pstats->rxbroadcastframes_g);
DPRINTK( "rxmulticastframes_g %lld\n",
pstats->rxmulticastframes_g);
DPRINTK( "rxundersize_g %lld\n", pstats->rxundersize_g);
DPRINTK( "rxoversize_g %lld\n", pstats->rxoversize_g);
DPRINTK( "rxunicastframes_g %lld\n", pstats->rxunicastframes_g);
DPRINTK( "rxcontrolframe_g %lld\n", pstats->rxcontrolframe_g);
DPRINTK( "Dump Extra counters:\n");
DPRINTK( "tx_tso_packets %lld\n", pstats->tx_tso_packets);
DPRINTK( "rx_split_header_packets %lld\n",
pstats->rx_split_header_packets);
DPRINTK( "tx_process_stopped %lld\n", pstats->tx_process_stopped);
DPRINTK( "rx_process_stopped %lld\n", pstats->rx_process_stopped);
DPRINTK( "tx_buffer_unavailable %lld\n",
pstats->tx_buffer_unavailable);
DPRINTK( "rx_buffer_unavailable %lld\n",
pstats->rx_buffer_unavailable);
DPRINTK( "fatal_bus_error %lld\n", pstats->fatal_bus_error);
DPRINTK( "napi_poll_isr %lld\n", pstats->napi_poll_isr);
DPRINTK( "napi_poll_txtimer %lld\n", pstats->napi_poll_txtimer);
DPRINTK( "ephy_poll_timer_cnt %lld\n",
pstats->ephy_poll_timer_cnt);
DPRINTK( "mgmt_int_isr %lld\n", pstats->mgmt_int_isr);
}
#if ((LINUX_VERSION_CODE > KERNEL_VERSION(4,0,0)) && (LINUX_VERSION_CODE < KERNEL_VERSION(5,6,0) || (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,8))))
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");
fxgmac_dump_state(pdata);
#if FXGMAC_TX_HANG_TIMER_ENABLED
if(!pdata->tx_hang_restart_queuing)
schedule_work(&pdata->expansion.restart_work);
#else
schedule_work(&pdata->expansion.restart_work);
#endif
}
static netdev_tx_t 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 netdev_queue *txq;
struct fxgmac_ring *ring;
int ret;
desc_ops = &pdata->desc_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 (skb->len == 0) {
netif_err(pdata, tx_err, netdev, "empty skb received from stack\n");
dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
/* 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");
dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
fxgmac_prep_vlan(skb, tx_pkt_info);
if (!desc_ops->map_tx_skb(channel, skb)) {
dev_kfree_skb_any(skb);
netif_err(pdata, tx_err, netdev, "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 */
fxgmac_dev_xmit(channel);
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) || (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,8)))
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->rxcrcerror + pstats->rxalignerror + pstats->rxrunterror + pstats->rxjabbererror +
pstats->rxlengtherror + pstats->rxwatchdogerror + pstats->rxreceiveerrorframe;
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->txunderflowerror + pstats->txlatecollisionframes + pstats->txexcessivecollisionframes +
pstats->txcarriererrorframes + pstats->txexcessivedeferralerror;
s->tx_dropped = netdev->stats.tx_dropped;
}
#if (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,8))
return;
#elif (LINUX_VERSION_CODE < KERNEL_VERSION(4,12,0))
return s;
#else
return;
#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]
* When using it, we must pay attention to the thread synchronization
* of this interface. Because it's an external call that isn't
* initiated by the OS.
*/
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) ||
pdata->expansion.dev_state != FXGMAC_DEV_START)
return -ENODEV;
f.private_data = pdata;
switch (cmd) {
case FXGMAC_DEV_CMD:
ret = fxgmac_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, max_mtu;
#ifdef FXGMAC_DEBUG
int old_mtu = netdev->mtu;
#endif
/* On the Linux platform, the MTU size does not include the length
* of the MAC address and the length of the Type, but FXGMAC_JUMBO_PACKET_MTU include them.
*/
max_mtu = FXGMAC_JUMBO_PACKET_MTU - ETH_HLEN;
if (mtu > max_mtu) {
netdev_alert(netdev, "MTU exceeds maximum supported value\n");
return -EINVAL;
}
/*
* 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
*/
ret = fxgmac_calc_rx_buf_size(netdev, mtu);
if (ret < 0) {
return ret;
}
pdata->rx_buf_size = ret;
pdata->jumbo = mtu > ETH_DATA_LEN ? 1 : 0;
netdev->mtu = mtu;
if (netif_running(netdev)) {
fxgmac_restart_dev(pdata);
netdev_update_features(netdev);
}
#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 netdev_features_t fxgmac_fix_features(struct net_device *netdev,
netdev_features_t features)
{
u32 fifo_size;
struct fxgmac_pdata* pdata = netdev_priv(netdev);
struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops;
fifo_size = hw_ops->calculate_max_checksum_size(pdata);
if (netdev->mtu > fifo_size) {
features &= ~NETIF_F_IP_CSUM;
features &= ~NETIF_F_IPV6_CSUM;
}
return features;
}
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) {
DPRINTK("enable tso.\n");
pdata->hw_feat.tso = 1;
hw_ops->config_tso(pdata);
} else if (!(features & (NETIF_F_TSO | NETIF_F_TSO6)) && tso) {
DPRINTK("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,
#if(RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(9,0))
.ndo_change_mtu = fxgmac_change_mtu,
#elif (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,8))
.ndo_change_mtu_rh74 = fxgmac_change_mtu,
#else
.ndo_change_mtu = fxgmac_change_mtu,
#endif
.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_fix_features = fxgmac_fix_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;
struct fxgmac_desc_ops *desc_ops = &pdata->desc_ops;
#if 0
struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops;
#endif
while (ring->dirty != ring->cur) {
desc_data = FXGMAC_GET_DESC_DATA(ring, ring->dirty);
#ifdef FXGMAC_ZERO_COPY
/* Reset desc_data values */
desc_ops->unmap_desc_data(pdata, desc_data);
if (desc_ops->map_rx_buffer(pdata, ring, desc_data))
break;
#endif
desc_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)
{
struct sk_buff *skb;
#ifndef FXGMAC_NOT_USE_PAGE_MAPPING
unsigned int copy_len;
u8 *packet;
#endif
#if (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,0)) && (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(7,8))
/* just add fot compile
* centos 7.0 not support napi_alloc_skb, and porting it is hard
*/
#define napi_alloc_skb(a,b) NULL
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;
#endif
#ifdef FXGMAC_NOT_USE_PAGE_MAPPING
#ifdef FXGMAC_ZERO_COPY
dma_sync_single_for_cpu(pdata->dev, desc_data->rx.buf.dma_base, len, DMA_FROM_DEVICE);
skb = desc_data->skb;
desc_data->skb = NULL;
skb_put(skb, len);
dma_sync_single_for_device(pdata->dev, desc_data->rx.buf.dma_base, len, DMA_FROM_DEVICE);
#else
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);
#endif
return skb;
#else
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 = 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);
return skb;
#endif
}
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;
(void) reg_cur_pre;
(void) change_cnt;
(void) fxgmac_restart_need;
#if FXGMAC_TX_HANG_TIMER_ENABLED
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_ENABLED
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);
desc_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);
smp_wmb();
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;
}
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, max_len;
unsigned int context_next, context;
struct fxgmac_desc_data *desc_data;
struct fxgmac_pkt_info *pkt_info;
unsigned int incomplete;
struct napi_struct *napi;
struct sk_buff *skb;
int packet_count = 0;
/* 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 (fxgmac_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);
pdata->netdev->stats.rx_dropped++;
goto next_packet;
}
if (!context) {
len = desc_data->rx.len;
if (len == 0) {
if (net_ratelimit())
netif_err(pdata, rx_err, netdev,
"A packet of length 0 was received\n");
pdata->netdev->stats.rx_length_errors++;
pdata->netdev->stats.rx_dropped++;
goto next_packet;
}
if (len && !skb) {
skb = fxgmac_create_skb(pdata, napi, desc_data, len);
if (unlikely(!skb)) {
if (net_ratelimit())
netif_err(pdata, rx_err, netdev, "create skb failed\n");
pdata->netdev->stats.rx_dropped++;
goto next_packet;
}
}
max_len = netdev->mtu + ETH_HLEN;
if (!(netdev->features & NETIF_F_HW_VLAN_CTAG_RX) &&
skb->protocol == htons(ETH_P_8021Q))
max_len += VLAN_HLEN;
if (len > max_len) {
if (net_ratelimit())
netif_err(pdata, rx_err, netdev,
"len %d larger than max size %d\n",
len, max_len);
pdata->netdev->stats.rx_length_errors++;
pdata->netdev->stats.rx_dropped++;
dev_kfree_skb(skb);
goto next_packet;
}
}
if (!skb) {
pdata->netdev->stats.rx_dropped++;
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)
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);
struct fxgmac_pdata *pdata = channel->pdata;
struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops;
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 occurred 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 occurred 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);
/* If we processed everything, we are done */
if (processed < budget) {
/* Turn off polling */
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0))
if (napi_complete_done(napi, processed))
hw_ops->enable_mgm_interrupt(pdata);
#else
napi_complete(napi);
hw_ops->enable_mgm_interrupt(pdata);
#endif
}
if((processed) && (netif_msg_rx_status(pdata))) { //yzhang for debug
DPRINTK("rx all_poll callout received = %d\n", processed);
}
return processed;
}
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);
writereg(pdata->pAdapter, lower_32_bits(desc_data->dma_desc_addr),
FXGMAC_DMA_REG(channel, DMA_CH_TDTR_LO));
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;
}
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;
if (tso_context || vlan_context)
i += 1;
}
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);
/* 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));
}
}
extern void fxgmac_diag_get_rx_info(struct fxgmac_channel *channel);
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);
}
//}
}
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;
u32 ipce, iphe, rxparser;
unsigned int err, etlt;
//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++;
}
#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) {
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 (!ipce && !iphe)
pkt_info->attributes = FXGMAC_SET_REG_BITS(
pkt_info->attributes,
RX_PACKET_ATTRIBUTES_CSUM_DONE_POS,
RX_PACKET_ATTRIBUTES_CSUM_DONE_LEN,
1);
else
return 0;
}
/* 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);
/* b111: Incomplete parsing due to ECC error */
rxparser = FXGMAC_GET_REG_BITS_LE(desc_data->dma_desc->desc2,
RX_NORMAL_DESC2_WB_RAPARSER_POS,
RX_NORMAL_DESC2_WB_RAPARSER_LEN);
if (err || rxparser == 0x7) {
pkt_info->errors = FXGMAC_SET_REG_BITS(pkt_info->errors,
RX_PACKET_ERRORS_FRAME_POS,
RX_PACKET_ERRORS_FRAME_LEN, 1);
return 0;
}
etlt = FXGMAC_GET_REG_BITS_LE(dma_desc->desc3,
RX_NORMAL_DESC3_ETLT_POS,
RX_NORMAL_DESC3_ETLT_LEN);
if ((etlt == 0x4) &&
(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);
}
return 0;
}
yt6801-dkms-1.0.31/src/fuxi-gmac-pci.c 0000664 0000000 0000000 00000016306 15126421535 0017101 0 ustar 00root root 0000000 0000000 // SPDX-License-Identifier: GPL-2.0+
/* Copyright (c) 2021 Motor-comm Corporation. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "fuxi-gmac.h"
#include "fuxi-gmac-reg.h"
/* declarations */
static void fxgmac_shutdown(struct pci_dev *pdev);
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)
{
dev_err(dev, "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];
return fxgmac_drv_probe(&pcidev->dev, &res);
}
static void fxgmac_remove(struct pci_dev *pcidev)
{
struct net_device *netdev;
struct fxgmac_pdata *pdata;
(void)pdata;
netdev = dev_get_drvdata(&pcidev->dev);
pdata = netdev_priv(netdev);
fxgmac_drv_remove(&pcidev->dev);
#ifdef CONFIG_PCI_MSI
if(FXGMAC_GET_REG_BITS(pdata->expansion.int_flags, FXGMAC_FLAG_MSIX_POS,
FXGMAC_FLAG_MSIX_LEN)){
pci_disable_msix(pcidev);
kfree(pdata->expansion.msix_entries);
pdata->expansion.msix_entries = NULL;
}
#endif
DPRINTK("%s has been removed\n", netdev->name);
}
/* 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");
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");
pci_wake_from_d3(pdev, !!wufc);
*enable_wake = !!wufc;
pci_disable_device(pdev);
DPRINTK("fxpm,_fxgmac_shutdown callout, enable wake=%d.\n", *enable_wake);
return 0;
}
static void fxgmac_shutdown(struct pci_dev *pdev)
{
struct net_device *netdev = dev_get_drvdata(&pdev->dev);
struct fxgmac_pdata *pdata = netdev_priv(netdev);
struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops;
bool wake;
DPRINTK("fxpm, fxgmac_shutdown callin\n");
fxgmac_lock(pdata);
__fxgmac_shutdown(pdev, &wake);
hw_ops->led_under_shutdown(pdata);
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_unlock(pdata);
}
#ifdef CONFIG_PM
/* yzhang, 20210628 for PM */
static int fxgmac_suspend(struct pci_dev *pdev,
pm_message_t __always_unused state)
{
struct net_device *netdev = dev_get_drvdata(&pdev->dev);
struct fxgmac_pdata *pdata = netdev_priv(netdev);
struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops;
int retval = 0;
bool wake;
DPRINTK("fxpm, fxgmac_suspend callin\n");
fxgmac_lock(pdata);
if (pdata->expansion.dev_state != FXGMAC_DEV_START)
goto unlock;
if (netif_running(netdev)) {
#ifdef FXGMAC_ASPM_ENABLED
fxgmac_cancel_aspm_config_work(pdata);
pdata->expansion.aspm_en = false;
pdata->expansion.aspm_work_active = false;
pdata->expansion.recover_from_aspm = false;
#endif
retval = __fxgmac_shutdown(pdev, &wake);
if (retval)
goto unlock;
} else {
wake = !!(pdata->expansion.wol);
}
hw_ops->led_under_sleep(pdata);
if (wake) {
pci_prepare_to_sleep(pdev);
} else {
pci_wake_from_d3(pdev, false);
pci_set_power_state(pdev, PCI_D3hot);
}
pdata->expansion.recover_phy_state = 1;
pdata->expansion.dev_state = FXGMAC_DEV_SUSPEND;
DPRINTK("fxpm, fxgmac_suspend callout to %s\n", wake ? "sleep" : "D3hot");
unlock:
fxgmac_unlock(pdata);
return retval;
}
static int fxgmac_resume(struct pci_dev *pdev)
{
struct net_device *netdev = dev_get_drvdata(&pdev->dev);
struct fxgmac_pdata *pdata = netdev_priv(netdev);
u32 err = 0;
DPRINTK("fxpm, fxgmac_resume callin\n");
fxgmac_lock(pdata);
if (pdata->expansion.dev_state != FXGMAC_DEV_SUSPEND)
goto unlock;
pdata->expansion.dev_state = FXGMAC_DEV_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");
goto unlock;
}
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;
if (!err && netif_running(netdev))
fxgmac_net_powerup(pdata);
if (!err)
netif_device_attach(netdev);
rtnl_unlock();
DPRINTK("fxpm, fxgmac_resume callout\n");
unlock:
fxgmac_unlock(pdata);
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("Motorcomm Electronic Tech. Co., Ltd.");
MODULE_LICENSE("GPL");
yt6801-dkms-1.0.31/src/fuxi-gmac-phy.c 0000664 0000000 0000000 00000030656 15126421535 0017132 0 ustar 00root root 0000000 0000000 // SPDX-License-Identifier: GPL-2.0+
/* Copyright (c) 2021 Motor-comm Corporation. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "fuxi-gmac.h"
#include "fuxi-gmac-reg.h"
/*
* When in forced mode, set the speed, duplex, and auto-negotiation of the PHY
* all at once to avoid the problems caused by individual settings
* on some machines
*/
int fxgmac_phy_force_mode(struct fxgmac_pdata *pdata)
{
struct fxgmac_hw_ops* hw_ops = &pdata->hw_ops;
u32 regval = 0;
unsigned int high_bit = 0, low_bit = 0;
int ret = 0;
switch (pdata->phy_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;
}
hw_ops->read_ephy_reg(pdata, REG_MII_BMCR, ®val);
regval = FXGMAC_SET_REG_BITS(regval, PHY_CR_AUTOENG_POS, PHY_CR_AUTOENG_LEN, pdata->phy_autoeng);
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);
regval = FXGMAC_SET_REG_BITS(regval, PHY_CR_DUPLEX_POS, PHY_CR_DUPLEX_LEN, pdata->phy_duplex);
regval = FXGMAC_SET_REG_BITS(regval, PHY_CR_RESET_POS, PHY_CR_RESET_LEN, 1);
ret = hw_ops->write_ephy_reg(pdata, REG_MII_BMCR, regval);
return ret;
}
int 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;
int ret = 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;
}
hw_ops->read_ephy_reg(pdata, REG_MII_BMCR, ®val);
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);
ret = hw_ops->write_ephy_reg(pdata, REG_MII_BMCR, regval);
return ret;
}
int fxgmac_phy_force_duplex(struct fxgmac_pdata *pdata, int duplex)
{
struct fxgmac_hw_ops* hw_ops = &pdata->hw_ops;
u32 regval = 0;
int ret = 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);
return ret;
}
int fxgmac_phy_force_autoneg(struct fxgmac_pdata *pdata, int autoneg)
{
struct fxgmac_hw_ops* hw_ops = &pdata->hw_ops;
u32 regval = 0;
int ret = 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));
ret = hw_ops->write_ephy_reg(pdata, REG_MII_BMCR, regval);
return ret;
}
void fxgmac_set_phy_link_ksettings(struct fxgmac_pdata *pdata)
{
struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops;
pdata->phy_speed = pdata->expansion.pre_phy_speed;
pdata->phy_duplex = pdata->expansion.pre_phy_duplex;
pdata->phy_autoeng = pdata->expansion.pre_phy_autoneg;
if (pdata->phy_autoeng || (!pdata->phy_autoeng && pdata->phy_speed == SPEED_1000))
hw_ops->phy_config(pdata);
else
fxgmac_phy_force_mode(pdata);
}
/* 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(FXGMAC_EPHY_DUPLEX_BIT)) >> FXGMAC_EPHY_DUPLEX_BIT;
speed_mode = (val & FXGMAC_EPHY_SPEED_MODE) >> FXGMAC_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;
}
#if 0
static int fxgmac_ephy_soft_reset(struct fxgmac_pdata* pdata)
{
struct fxgmac_hw_ops* hw_ops = &pdata->hw_ops;
int ret;
volatile u32 val;
int busy = 15;
ret = hw_ops->read_ephy_reg(pdata, REG_MII_BMCR, (u32*)&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, (u32*)&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;
}
#endif
/*
* 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(FXGMAC_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 = (FXGMAC_EPHY_SMI_SEL_PHY + 1);
if(link_fiber) *media = (FXGMAC_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;
}
/*
* fxgmac_phy_update_link - update the phy link status
* @adapter: pointer to the device adapter structure
*/
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;
u32 regval, cur_link, cur_speed;
regval = hw_ops->get_ephy_state(pdata);
// We should make sure that PHY is done with the reset
if (!(regval & BIT(MGMT_EPHY_CTRL_RESET_POS)) &&
(pdata->expansion.dev_state != FXGMAC_DEV_CLOSE)) {
pdata->expansion.phy_link = false;
return;
}
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);
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) {
hw_ops->read_ephy_reg(pdata, REG_MII_INT_STATUS, NULL);
hw_ops->read_ephy_reg(pdata, REG_MII_INT_STATUS, NULL);
if (cur_link) {
#ifdef FXGMAC_ASPM_ENABLED
if (fxgmac_aspm_action_linkup(pdata))
return;
#endif
hw_ops->config_mac_speed(pdata);
hw_ops->enable_rx(pdata);
hw_ops->enable_tx(pdata);
hw_ops->read_ephy_reg(pdata, REG_MII_LPA, ®val);
if (FXGMAC_GET_REG_BITS(regval, PHY_MII_LINK_PARNTNER_10FULL_POS, PHY_MII_LINK_PARNTNER_10FULL_LEN)
|| FXGMAC_GET_REG_BITS(regval, PHY_MII_LINK_PARNTNER_10HALF_POS, PHY_MII_LINK_PARNTNER_10HALF_LEN))
{
pdata->support_10m_link = true;
}
else {
pdata->support_10m_link = false;
}
pdata->expansion.pre_phy_speed = pdata->phy_speed;
pdata->expansion.pre_phy_duplex = pdata->phy_duplex;
pdata->expansion.pre_phy_autoneg = pdata->phy_autoeng;
netif_carrier_on(pdata->netdev);
if (netif_running(pdata->netdev))
{
netif_tx_wake_all_queues(pdata->netdev);
dev_info(pdata->dev, "%s now is link up, mac_speed=%d.\n",
netdev_name(pdata->netdev),
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);
#ifdef FXGMAC_EPHY_LOOPBACK_DETECT_ENABLED
if (pdata->expansion.lb_cable_flag) {
hw_ops->clean_cable_loopback(pdata);
pdata->expansion.lb_cable_flag = 0;
}
#endif
#ifdef FXGMAC_ASPM_ENABLED
fxgmac_schedule_aspm_config_work(pdata);
#endif
dev_info(pdata->dev, "%s now is link down\n", netdev_name(pdata->netdev));
}
pdata->expansion.phy_link = cur_link;
}
}
#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("fxgmac_phy_timer polling with NULL netdev %lx\n",(unsigned long)(pdata->netdev));
return;
}
pdata->stats.ephy_poll_timer_cnt++;
#if FXGMAC_PM_FEATURE_ENABLED
if(!test_bit(FXGMAC_POWER_STATE_DOWN, &pdata->expansion.powerstate))
#endif
{
mod_timer(&pdata->expansion.phy_poll_tm,jiffies + HZ / 2);
fxgmac_phy_update_link(pdata->netdev);
}else {
DPRINTK("fxgmac_phy_timer polling, powerstate changed, %ld, netdev=%lx, tm=%lx\n", pdata->expansion.powerstate, (unsigned long)(pdata->netdev), (unsigned long)&pdata->expansion.phy_poll_tm);
}
//DPRINTK("fxgmac_phy_timer polled,%d\n",cnt_polling);
}
int fxgmac_phy_timer_init(struct fxgmac_pdata *pdata)
{
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,15,0))
init_timer_key(&pdata->expansion.phy_poll_tm, NULL, 0, "fuxi_phy_link_update_timer", NULL);
#else
init_timer_key(&pdata->expansion.phy_poll_tm, 0, "fuxi_phy_link_update_timer", NULL);
#endif
pdata->expansion.phy_poll_tm.expires = jiffies + HZ / 2;
pdata->expansion.phy_poll_tm.function = (void *)(fxgmac_phy_link_poll);
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,15,0))
pdata->expansion.phy_poll_tm.data = (unsigned long)pdata;
#endif
add_timer(&pdata->expansion.phy_poll_tm);
DPRINTK("fxgmac_phy_timer started, %lx\n", jiffies);
return 0;
}
void fxgmac_phy_timer_destroy(struct fxgmac_pdata *pdata)
{
del_timer_sync(&pdata->expansion.phy_poll_tm);
DPRINTK("fxgmac_phy_timer removed\n");
}
yt6801-dkms-1.0.31/src/fuxi-gmac-reg.h 0000664 0000000 0000000 00000265301 15126421535 0017111 0 ustar 00root root 0000000 0000000 /* SPDX-License-Identifier: GPL-2.0+ */
/* Copyright (c) 2021 Motor-comm Corporation. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifndef __FXGMAC_GMAC_REG_H__
#define __FXGMAC_GMAC_REG_H__
#define ASIC_MODE
#define YT6801_NTO_VER 0x01 // The first NTO version.
#define YT6801_ECO1_VER 0x03 // ECO1 back on 07/2023.
#define YT6801_ECO2_VER 0x04 // ECO2 back on 01/2026.
/* 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_WTR 0x000c
#define MAC_HTR0 0x0010
#define MAC_VLANTR 0x0050
#define MAC_VLANHTR 0x0058
#define MAC_VLANIR 0x0060
#define MAC_IVLANIR 0x0064
#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 writing.
#define MAC_LPI_STA 0x00d0
#define MAC_LPI_CONTROL 0x00d4
#define MAC_LPI_TIMER 0x00d8
#define MAC_MS_TIC_COUNTER 0x00dc
#define MAC_AN_CR 0x00e0
#define MAC_AN_SR 0x00e4
#define MAC_AN_ADV 0x00e8
#define MAC_AN_LPA 0x00ec
#define MAC_AN_EXP 0x00f0
#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_GPIOCR 0x0208
#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 28
#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 28
#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_FDCR 0x0c08
#define MTL_FDSR 0x0c0c
#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_TQUR 0x04
#define MTL_Q_RQOMR 0x30
#define MTL_Q_RQMPOCR 0x34
#define MTL_Q_RQDR 0x38
#define MTL_Q_RQCR 0x3c
#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_TQDR 0x08
#define MTL_TC_ETSCR 0x10
#define MTL_TC_ETSSR 0x14
#define MTL_TC_QWR 0x18
/* The Queue 0 Transmit Debug register gives the debug status of various blocks
* related to the Transmit queue
*/
#define MTL_TC_TQDR_TRCSTS_POS 1
#define MTL_TC_TQDR_TRCSTS_LEN 2
#define MTL_TC_TQDR_TXQSTS_POS 4
#define MTL_TC_TQDR_TXQSTS_LEN 1
/* 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_AXIARCR 0x1020
#define DMA_AXIAWCR 0x1024
#define DMA_AXIAWRCR 0x1028
#define DMA_SAFE_ISR 0x1080
#define DMA_ECC_IE 0x1084
#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_TXPR_POS 11
#define DMA_MR_TXPR_LEN 1
#define DMA_MR_INTM_POS 16
#define DMA_MR_INTM_LEN 2
#define DMA_MA_INTM_EDGE 0
#define DMA_MA_INTM_LEVEL 1
#define DMA_MA_INTM_LEVLE_ENHANCE 2
#define DMA_MR_QUREAD_POS 19
#define DMA_MR_QUREAD_LEN 1
#define DMA_MR_QUREAD_EN 1
#define DMA_MR_TNDF_POS 20
#define DMA_MR_TNDF_LEN 2
#define DMA_MR_RNDF_POS 22
#define DMA_MR_RNDF_LEN 2
#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_AAL_POS 12
#define DMA_SBMR_AAL_LEN 1
#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_CATDR_LO 0x44
#define DMA_CH_CARDR_LO 0x4c
#define DMA_CH_CATBR_HI 0x50
#define DMA_CH_CATBR_LO 0x54
#define DMA_CH_CARBR_HI 0x58
#define DMA_CH_CARBR_LO 0x5c
#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_RSV_POS 26
#define RX_NORMAL_DESC3_RSV_LEN 1
#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_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
/* 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_POS 17
#define RX_NORMAL_DESC2_WB_DAF_LEN 1
#define RX_NORMAL_DESC2_WB_RAPARSER_POS 11
#define RX_NORMAL_DESC2_WB_RAPARSER_LEN 3
#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
/* 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_POS 24
#define RX_NORMAL_DESC3_WB_CE_LEN 1
/*
* When this bit is set, it indicates that the packet length exceeds the specified maximum
* Ethernet size of 1518, 1522, or 2000 bytes (9018 or 9022 bytes if jumbo packet enable is set).
* Note: Giant packet indicates only the packet length. It does not cause any packet truncation.
*/
#define RX_NORMAL_DESC3_WB_GP_POS 23
#define RX_NORMAL_DESC3_WB_GP_LEN 1
/*
* When this bit is set, it indicates that the Receive Watchdog Timer has expired while receiving
* the current packet. The current packet is truncated after watchdog timeout.
*/
#define RX_NORMAL_DESC3_WB_RWT_POS 22
#define RX_NORMAL_DESC3_WB_RWT_LEN 1
/*
* When this bit is set, it indicates that the received packet is damaged because of buffer
* overflow in Rx FIFO.
* Note: This bit is set only when the DMA transfers a partial packet to the application. This
* happens only when the Rx FIFO is operating in the threshold mode. In the store-and-forward
* mode, all partial packets are dropped completely in Rx FIFO.
*/
#define RX_NORMAL_DESC3_WB_OE_POS 21
#define RX_NORMAL_DESC3_WB_OE_LEN 1
/*
* When this bit is set, it indicates that the gmii_rxer_i signal is asserted while the gmii_rxdv_i
* signal is asserted during packet reception. This error also includes carrier extension error in
* the GMII and half-duplex mode. Error can be of less or no extension, or error (rxd!= 0f) during
* extension
*/
#define RX_NORMAL_DESC3_WB_RE_POS 20
#define RX_NORMAL_DESC3_WB_RE_LEN 1
/*
* When this bit is set, it indicates that the received packet has a non-integer multiple of bytes
* (odd nibbles). This bit is valid only in the MII Mode
*/
#define RX_NORMAL_DESC3_WB_DE_POS 19
#define RX_NORMAL_DESC3_WB_DE_LEN 1
/*
* When this bit is set, it indicates the logical OR of the following bits:
* RDES3[24]: CRC Error
* RDES3[19]: Dribble Error
* RDES3[20]: Receive Error
* RDES3[22]: Watchdog Timeout
* RDES3[21]: Overflow Error
* RDES3[23]: Giant Packet
* RDES2[17]: Destination Address Filter Fail, when Flexible RX Parser is enabled
* RDES2[16]: SA Address Filter Fail, when Flexible RX Parser is enabled
* This field is valid only when the LD bit of RDES3 is set
*/
#define RX_NORMAL_DESC3_WB_ES_POS 15
#define RX_NORMAL_DESC3_WB_ES_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_POWER_POS 11
#define PHY_CR_POWER_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 PHY_MII_LINK_PARNTNER_10FULL_POS 6
#define PHY_MII_LINK_PARNTNER_10FULL_LEN 1
#define PHY_MII_LINK_PARNTNER_10HALF_POS 5
#define PHY_MII_LINK_PARNTNER_10HALF_LEN 1
#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 ASIC_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 */
#ifdef ASIC_MODE
#define PHY_INT_STAT_LINK_UP_POS 10
#define PHY_INT_STAT_LINK_UP_LEN 1
#define PHY_INT_STAT_LINK_DOWN_POS 11
#define PHY_INT_STAT_LINK_DOWN_LEN 1
#else
#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
#endif
#define REG_MII_DOWNG_CTRL 0x14 /* Speed auto downgrade control*/
#define REG_SMART_SPEED_POS 5
#define REG_SMART_SPEED_LEN 1
#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)
*/
#define FXGMAC_ADVERTISE_SLCT 0x001f /* Selector bits */
#define FXGMAC_ADVERTISE_CSMA 0x0001 /* Only selector supported */
//#define FXGMAC_ADVERTISE_1000FULL 0x0004 /* Try for 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 asymmetric 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 FXGMAC_ADVERTISE_1000FULL 0x0200 /* Advertise 1000BASE-T full duplex */
#define FXGMAC_ADVERTISE_1000HALF 0x0100 /* Advertise 1000BASE-T half duplex */
#define REG_BIT_ADVERTISE_1000_CAP (FXGMAC_ADVERTISE_1000FULL | FXGMAC_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 FXGMAC_EPHY_SPEED_MODE_BIT
#define FXGMAC_EPHY_SPEED_MODE 0xc000
#define FXGMAC_EPHY_DUPLEX 0x2000
#define FXGMAC_EPHY_SPEED_MODE_BIT 14
#define FXGMAC_EPHY_DUPLEX_BIT 13
#define FXGMAC_EPHY_LINK_STATUS_BIT 10
#endif
#define FXGMAC_EPHY_SMI_SEL_PHY 0x0
#define FXGMAC_EPHY_SMI_SEL_SDS_QSGMII 0x02
#define FXGMAC_EPHY_SMI_SEL_SDS_SGMII 0x03
#define REG_MII_EXT_AFE_CONTROL_REGISTER3 0x12
#define REG_MII_EXT_AFE_CONTROL_CLKDAC_AON_POS 13
#define REG_MII_EXT_AFE_CONTROL_CLKDAC_AON_LEN 1
#define REG_MII_EXT_AFE_CONTROL_CLKDAC_AON_ON 1
#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_VALUE 0x4a9
#define REG_MII_EXT_ANALOG_CFG8 0x57
#define REG_MII_EXT_ANALOG_CFG8_VALUE 0x274c
#define REG_MII_EXT_ANALOG_CFG8_137D1D05_VALUE 0x264c
#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_VALUE 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 WOL_WAIT_TIME_POS 2
#define WOL_WAIT_TIME_LEN 13
#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_INT_CTRL0_INT_STATUS_TX_INVERSE 0xffef
#define MGMT_INT_CTRL0_INT_STATUS_MISC_INVERSE 0xffdf
#define MGMT_INT_CTRL0_INT_STATUS_MISC 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_RXTXMISC_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
#define MGMT_MAC_PHYIF_STA_POS 0
#define MGMT_MAC_AN_SR0_POS 1
#define MGMT_MAC_AN_SR1_POS 2
#define MGMT_MAC_AN_SR2_POS 3
#define MGMT_MAC_PMT_STA_POS 4
#define MGMT_MAC_LPI_STA_POS 5
#define MGMT_MAC_MMC_STA_POS 8
#define MGMT_MAC_RX_MMC_STA_POS 9
#define MGMT_MAC_TX_MMC_STA_POS 10
#define MGMT_MMC_IPCRXINT_POS 11
#define MGMT_MAC_TX_RX_STA0_POS 13
#define MGMT_MAC_TX_RX_STA1_POS 14
#define MGMT_MAC_GPIO_SR_POS 15
/* 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
#ifndef INT_MOD_IN_US
#define INT_MOD_IN_US 200 /*in us*/
#endif
/* 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 initialization 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_VAL 1
#define LTR_IDLE_ENTER_SCALE_POS 10
#define LTR_IDLE_ENTER_SCALE_LEN 5
#define LTR_IDLE_ENTER_SCALE_1US 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_SCALE_32US 3
#define LTR_IDLE_ENTER_SCALE_1MS 4
#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_VAL 288
#define LTR_IDLE_EXIT_SCALE_POS 10
#define LTR_IDLE_EXIT_SCALE_LEN 5
#define LTR_IDLE_EXIT_SCALE_1US 2
#define LTR_IDLE_EXIT_SCALE_32US 3
#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 SYS_RESET_BYPASS_POS 0
#define SYS_RESET_BYPASS_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_IP2TE_POS 1
#define MAC_RSSCR_IP2TE_LEN 1
#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
#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_DEGLITCH 0x17f0
#define MGMT_SIGDET_DEGLITCH_DISABLE_POS 2 //sigdet deglitch disable ,active low
#define MGMT_SIGDET_DEGLITCH_DISABLE_LEN 1
#define MGMT_SIGDET_DEGLITCH_TIME_WIN_POS 3 //sigdet deglitch time windows filter seltion
#define MGMT_SIGDET_DEGLITCH_TIME_WIN_LEN 2
#define MGMT_SIGDET_DEGLITCH_TIME_WIN_10ns 0
#define MGMT_SIGDET_DEGLITCH_TIME_WIN_20ns 1
#define MGMT_SIGDET_DEGLITCH_TIME_WIN_30ns 2
#define MGMT_SIGDET_DEGLITCH_TIME_WIN_40ns 3
#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 FXGMAC_EFUSE_MAX_ENTRY 39
#define FXGMAC_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_MPS_POS 5 //MPS: max payload size
#define DEVICE_CTRL1_MPS_LEN 3
#define DEVICE_CTRL1_MPS_128B 0
#define DEVICE_CTRL1_MPS_256B 1
#define DEVICE_CTRL1_MPS_512B 2
#define DEVICE_CTRL1_MPS_1024B 3
#define DEVICE_CTRL1_MPS_2048B 4
#define DEVICE_CTRL1_MPS_4096B 5
#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
#define REG_ACK_LATENCY_RELAY_TIMER 0x700
#define REG_ACK_LATENCY_TIMER_POS 0
#define REG_ACK_LATENCY_TIMER_LEN 16
#define REG_ACK_LATENCY_TIMER_VAL 0x20
#define REG_L1SUB_TIMING 0xb44
#define L1SUB_T_PCLKACK_LOW_POS 6
#define L1SUB_T_PCLKACK_LOW_LEN 2
#define L1SUB_T_PCLKACK_HIGH_POS 9
#define L1SUB_T_PCLKACK_HIGH_LEN 5
#define REG_CORRECTABLE_ERROR_MASK_REG 0x114
#define REG_CORRECTABLE_ERROR_MASK_POS 0
#define REG_CORRECTABLE_ERROR_MASK_LEN 16
#define AISTONEID_137D1D05_ADJUST_SI 0x137d1d05
#define KX_SERIAL_CPU_TX_PATCH 0x00011F0A
#endif /* __FXGMAC_GMAC_REG_H__ */
yt6801-dkms-1.0.31/src/fuxi-gmac.h 0000664 0000000 0000000 00000106362 15126421535 0016337 0 ustar 00root root 0000000 0000000 /* SPDX-License-Identifier: GPL-2.0+ */
/* Copyright (c) 2021 Motor-comm Corporation. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifndef __FXGMAC_GMAC_H__
#define __FXGMAC_GMAC_H__
#include "fuxi-os.h"
#include "fuxi-errno.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 YT6801 Gigabit Ethernet Driver"
#define FXGMAC_MAC_REGS_OFFSET 0x2000
#define FXGMAC_EPHY_INTERRUPT_D0_OFF 0 //1: in normal D0 state, turn off ephy link change interrupt.
#define FXGMAC_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 initialized 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_ENABLED
#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_ENABLED 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
#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 */
#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 /* 30 */
#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
#define FXGMAC_DATA_WIDTH 128
#define FXGMAC_WOL_WAIT_TIME 0 // unit 1ms
// 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;
#if 0
/* 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;
#endif
};
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)
*/
#ifdef FXGMAC_USE_STATIC_ALLOC
struct fxgmac_desc_data desc_data_head[FXGMAC_RX_DESC_CNT];
#else
struct fxgmac_desc_data *desc_data_head;
#endif
/* 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;
u32 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_channels_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);
int (*rx_desc_init)(struct fxgmac_pdata* pdata);
/* For descriptor related operation */
void (*tx_desc_init_channel)(struct fxgmac_channel* channel);
void (*rx_desc_init_channel)(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);
};
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);
int (*set_gmac_register)(struct fxgmac_pdata* pdata, IOMEM address, unsigned int data);
u32 (*get_gmac_register)(struct fxgmac_pdata* pdata, IOMEM address);
void (*esd_restore_pcie_cfg)(struct fxgmac_pdata* pdata);
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);
void (*enable_rx_tx_ints)(struct fxgmac_pdata* pdata);
void (*disable_rx_tx_ints)(struct fxgmac_pdata* pdata);
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);
int (*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);
bool (*enable_source_interrupt)(struct fxgmac_pdata* pdata);
bool (*disable_source_interrupt)(struct fxgmac_pdata* pdata);
int (*dismiss_all_int)(struct fxgmac_pdata* pdata);
void (*clear_misc_int_status)(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 (*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);
/* 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 long (*usec_to_riwt)(struct fxgmac_pdata* pdata,
unsigned int usec);
unsigned long (*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 */
u32 (*calculate_max_checksum_size)(struct fxgmac_pdata* pdata);
int (*config_rx_pbl_val)(struct fxgmac_pdata* pdata);
u32 (*get_rx_pbl_val)(struct fxgmac_pdata* pdata);
int (*config_tx_pbl_val)(struct fxgmac_pdata* pdata);
u32 (*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*/
#ifdef FXGMAC_POWER_MANAGEMENT
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 FXGMAC_PM_WPI_READ_FEATURE_ENABLED
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);
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);
u32 (*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 __far* 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);
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);
#ifdef FXGMAC_WOL_INTEGRATED_WOL_PARAMETER
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_per_index)(struct fxgmac_pdata* pdata, u8 index, u32 __far* offset, u32 __far* value); /* read patch per index. */
bool (*read_mac_subsys_from_efuse)(struct fxgmac_pdata* pdata, u8* mac_addr, u32* subsys, u32* revid);
bool (*read_efuse_data)(struct fxgmac_pdata* pdata, u32 offset, u32 __far* value);
#ifndef COMMENT_UNUSED_CODE_TO_REDUCE_SIZE
bool (*read_patch_from_efuse)(struct fxgmac_pdata* pdata, 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 (*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 (*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);
#endif
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.
};
/* This structure contains flags that indicate what hardware features
* or configurations are present in the device.
*/
struct fxgmac_hw_features {
/* HW Version */
u32 version;
/* HW Feature Register0 */
u32 phyifsel; /* PHY interface support */
u32 vlhash; /* VLAN Hash Filter */
u32 sma; /* SMA(MDIO) Interface */
u32 rwk; /* PMT remote wake-up packet */
u32 mgk; /* PMT magic packet */
u32 mmc; /* RMON module */
u32 aoe; /* ARP Offload */
u32 ts; /* IEEE 1588-2008 Advanced Timestamp */
u32 eee; /* Energy Efficient Ethernet */
u32 tx_coe; /* Tx Checksum Offload */
u32 rx_coe; /* Rx Checksum Offload */
u32 addn_mac; /* Additional MAC Addresses */
u32 ts_src; /* Timestamp Source */
u32 sa_vlan_ins;/* Source Address or VLAN Insertion */
/* HW Feature Register1 */
u32 rx_fifo_size; /* MTL Receive FIFO Size */
u32 tx_fifo_size; /* MTL Transmit FIFO Size */
u32 adv_ts_hi; /* Advance Timestamping High Word */
u32 dma_width; /* DMA width */
u32 dcb; /* DCB Feature */
u32 sph; /* Split Header Feature */
u32 tso; /* TCP Segmentation Offload */
u32 dma_debug; /* DMA Debug Registers */
u32 rss; /* Receive Side Scaling */
u32 tc_cnt; /* Number of Traffic Classes */
u32 avsel; /* AV Feature Enable */
u32 ravsel; /* Rx Side Only AV Feature Enable */
u32 hash_table_size;/* Hash Table Size */
u32 l3l4_filter_num;/* Number of L3-L4 Filters */
/* HW Feature Register2 */
u32 rx_q_cnt; /* Number of MTL Receive Queues */
u32 tx_q_cnt; /* Number of MTL Transmit Queues */
u32 rx_ch_cnt; /* Number of DMA Receive Channels */
u32 tx_ch_cnt; /* Number of DMA Transmit Channels */
u32 pps_out_num; /* Number of PPS outputs */
u32 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;
#ifdef FXGMAC_USE_STATIC_ALLOC
struct fxgmac_channel channel[FXGMAC_MAX_DMA_CHANNELS];
struct fxgmac_ring ring[FXGMAC_MAX_DMA_CHANNELS_PLUS_1TX];
#endif
/* 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_ENABLED
/* 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 long 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;
int phy_green_ethernet;
int phy_eee;
int phy_disablesmartspeed;
#ifndef COMMENT_UNUSED_CODE_TO_REDUCE_SIZE
char drv_name[32];
char drv_ver[32];
struct wol_bitmap_pattern pattern[MAX_PATTERN_COUNT];
#endif
struct led_setting led;
struct led_setting ledconfig;
FXGMAC_PDATA_OF_PLATFORM expansion;
u32 pcie_link_status;
u32 mgmt_phy_val;
u32 support_10m_link;
};
#if 1
#define FXGMAC_FLAG_MSI_CAPABLE (u32)(1 << 0)
#define FXGMAC_FLAG_MSI_ENABLED (u32)(1 << 1)
#define FXGMAC_FLAG_MSIX_CAPABLE (u32)(1 << 2)
#define FXGMAC_FLAG_MSIX_ENABLED (u32)(1 << 3)
#define FXGMAC_FLAG_LEGACY_ENABLED (u32)(1 << 4)
#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
#define FXGMAC_FLAG_LEGACY_IRQ_FREE_LEN 1
#define FXGMAC_FLAG_LEGACY_NAPI_FREE_POS 30
#define FXGMAC_FLAG_LEGACY_NAPI_FREE_LEN 1
#define FXGMAC_FLAG_MISC_IRQ_FREE_POS 29
#define FXGMAC_FLAG_MISC_IRQ_FREE_LEN 1
#define FXGMAC_FLAG_MISC_NAPI_FREE_POS 28
#define FXGMAC_FLAG_MISC_NAPI_FREE_LEN 1
#define FXGMAC_FLAG_TX_IRQ_FREE_POS 27
#define FXGMAC_FLAG_TX_IRQ_FREE_LEN 1
#define FXGMAC_FLAG_TX_NAPI_FREE_POS 26
#define FXGMAC_FLAG_TX_NAPI_FREE_LEN 1
#define FXGMAC_FLAG_RX_IRQ_FREE_POS 22
#define FXGMAC_FLAG_RX_IRQ_FREE_LEN 4
#define FXGMAC_FLAG_PER_CHAN_RX_IRQ_FREE_LEN 1
#define FXGMAC_FLAG_RX_NAPI_FREE_POS 18
#define FXGMAC_FLAG_RX_NAPI_FREE_LEN 4
#define FXGMAC_FLAG_PER_CHAN_RX_NAPI_FREE_LEN 1
#endif
#ifndef FXGMAC_FAKE_4_TX_QUEUE_ENABLED
#define FXGMAC_FAKE_4_TX_QUEUE_ENABLED 0
#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 /* __FXGMAC_GMAC_H__ */
yt6801-dkms-1.0.31/src/fuxi-os.h 0000664 0000000 0000000 00000065162 15126421535 0016053 0 ustar 00root root 0000000 0000000 /* SPDX-License-Identifier: GPL-2.0+ */
/* Copyright (c) 2021 Motor-comm Corporation. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifndef __FXGMAC_OS_H__
#define __FXGMAC_OS_H__
#include
//#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifdef CONFIG_PCI_MSI
#include
#endif
#define LINUX
#ifndef LINUX_VERSION_CODE
#include
#else
#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
#endif
#ifndef RHEL_MAJOR
//must used like : if ( RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(a,b) )
#ifndef RHEL_RELEASE_VERSION
#define RHEL_RELEASE_VERSION(a,b) (((a) << 8) + (b))
#define RHEL_RELEASE_CODE (0)
#endif
#include
#else
#if (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,8))
#include
#endif
#endif
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,19,0))
#include
#endif
#include "fuxi-dbg.h"
struct fxgmac_ring;
struct fxgmac_pdata;
struct fxgmac_channel;
#define FXGMAC_DRV_VERSION "1.0.31"
#ifdef CONFIG_PCI_MSI
/* undefined for legacy interrupt mode */
/* #undef CONFIG_PCI_MSI */
#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 FXGMAC_PM_WPI_READ_FEATURE_ENABLED 1
#define RSS_Q_COUNT 4
/* #define FXGMAC_TX_INTERRUPT_ENABLED 1 */
#define FXGMAC_TX_HANG_TIMER_ENABLED 0
/* 1 to trigger(write reg 0x1000) for sniffer stop */
#define FXGMAC_TRIGGER_TX_HANG 0
/* driver feature configuration */
#if FXGMAC_TX_HANG_TIMER_ENABLED
/* 0: check hw current desc; 1: check software dirty */
#define FXGMAC_TX_HANG_CHECH_DIRTY 0
#endif
#define FXGMAC_DMA_BIT_MASK64 64
#define FXGMAC_DMA_BIT_MASK32 32
#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_ENABLED 0 //set to 1 for ch0 unbalance fix;
#define FXGMAC_MSIX_INTCTRL_EN 1
#ifdef FXGMAC_MISC_ENABLED
#define FXGMAC_MISC_INT_NUM 1
#else
#define FXGMAC_MISC_INT_NUM 0
#endif
#define FXGMAC_MSIX_INT_NUMS (FXGMAC_MAX_MSIX_Q_VECTORS + FXGMAC_MISC_INT_NUM)
#else
#define FXGMAC_MSIX_CH0RXDIS_ENABLED 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 0
/* 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 FXGMAC_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 FXGMAC_MISC_INT_HANDLE_FEATURE_ENABLED 0
#define FXGMAC_ESD_RESTORE_PCIE_CFG
#define FXGMAC_WOL_INTEGRATED_WOL_PARAMETER
#define FXGMAC_LINK_SPEED_CHECK_PHY_LINK
#define FXGMAC_FLUSH_TX_CHECK_ENABLED
#define FXGMAC_POWER_MANAGEMENT
#define FXGMAC_INTERRUPT_TX_INTERVAL
#define FXGMAC_INTERRUPT_RX_INTERVAL
#define FXGMAC_WAIT_TX_STOP
#define FXGMAC_WAIT_RX_STOP_BY_PRXQ_RXQSTS
#define FXGMAC_USE_DEFAULT_RSS_KEY_TBALE
//#define FXGMAC_MISC_ENABLED
#define FXGMAC_RX_VLAN_FILTERING_ENABLED (pdata->netdev->features & NETIF_F_HW_VLAN_CTAG_FILTER)
#define FXGMAC_NETDEV_PR_MODE_ENABLED ((pdata->netdev->flags & IFF_PROMISC) != 0)
#define FXGMAC_NETDEV_AM_MODE_ENABLED ((pdata->netdev->flags & IFF_ALLMULTI) != 0)
#define FXGMAC_NETDEV_MU_MODE_ENABLED ((pdata->netdev->flags & IFF_MULTICAST) != 0)
#define FXGMAC_NETDEV_BD_MODE_ENABLED ((pdata->netdev->flags & IFF_BROADCAST) != 0)
#define FXGMAC_RX_CHECKSUM_ENABLED (pdata->netdev->features & NETIF_F_RXCSUM)
#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
#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)))
/* centos 7 define start */
#ifndef dma_rmb
#define dma_rmb() barrier()
#endif
#ifndef dma_wmb
#define dma_wmb() barrier()
#endif
#ifndef smp_mb__before_atomic
#define smp_mb__before_atomic() barrier()
#endif
#ifndef smp_mb__after_atomic
#define smp_mb__after_atomic() barrier()
#endif
#ifndef skb_vlan_tag_present
#define skb_vlan_tag_present(__skb) ((__skb)->vlan_tci & VLAN_TAG_PRESENT)
#endif
#ifndef skb_vlan_tag_get
#define skb_vlan_tag_get(__skb) ((__skb)->vlan_tci & ~VLAN_TAG_PRESENT)
#endif
#ifndef GENMASK
/* Create a contiguous bitmask starting at bit position @l and ending at
* position @h. For example
* GENMASK_ULL(39, 21) gives us the 64bit vector 0x000000ffffe00000.
*/
#define GENMASK(h, l) \
(((~0UL) << (l)) & (~0UL >> (BITS_PER_LONG - 1 - (h))))
#endif
#ifndef ETH_RSS_HASH_TOP
#define __ETH_RSS_HASH_BIT(bit) ((u32)1 << (bit))
#define __ETH_RSS_HASH(name) __ETH_RSS_HASH_BIT(ETH_RSS_HASH_##name##_BIT)
#define ETH_RSS_HASH_TOP __ETH_RSS_HASH(TOP)
#endif
/* centos 7 needs set these definitions to 0
* 1. FXGMAC_RSS_FEATURE_ENABLED
* 2. FXGMAC_RSS_HASH_KEY_LINUX
* 3. FXGMAC_PAUSE_FEATURE_ENABLED
* #undef CONFIG_PCI_MSI
*/
#if (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,0)) && (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(7,8))
#define strscpy strlcpy
#undef FXGMAC_RSS_FEATURE_ENABLED
#define FXGMAC_RSS_FEATURE_ENABLED 0
#undef FXGMAC_RSS_HASH_KEY_LINUX
#define FXGMAC_RSS_HASH_KEY_LINUX 0
#undef FXGMAC_PAUSE_FEATURE_ENABLED
#define FXGMAC_PAUSE_FEATURE_ENABLED 0
#undef CONFIG_PCI_MSI
#endif
/* centos 7 define end */
/* 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 __far
#define __far
#endif
#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)
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,9,0))
/*
* If you want to continue a line, you NEED to use KERN_CONT.
* That has always been true. It hasn't always been enforced, though.
* If you do two printk's and the second one doesn't say "I'm a continuation",
* the printk logic assumes you're just confused and wanted two lines.
*/
#define DPRINTK(fmt, args...) \
printk(KERN_CONT fmt, ## args)
#else
#define DPRINTK printk
#endif
#else
#define FXGMAC_PR(x...) do { } while (0)
#define DPRINTK(x...) do { } while (0)
#endif
#define IOC_MAGIC 'M'
#define IOC_MAXNR (0x80 + 5)
#define FXGMAC_DFS_IOCTL_DEVICE_INACTIVE 0x10001
#define FXGMAC_DFS_IOCTL_DEVICE_RESET 0x10002
#define FXGMAC_DFS_IOCTL_DIAG_BEGIN 0x10003
#define FXGMAC_DFS_IOCTL_DIAG_END 0x10004
#define FXGMAC_DFS_IOCTL_DIAG_TX_PKT 0x10005
#define FXGMAC_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_REG 0x10015
#define FXGMAC_SET_REG 0x10016
#define FXGMAC_GET_PHY_REG 0x10017
#define FXGMAC_SET_PHY_REG 0x10018
#define FXGMAC_EPHY_STATISTICS 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
#define FXGMAC_IRQ_ENABLE 0x1
#define FXGMAC_IRQ_DISABLE 0x0
#define FXGMAC_NAPI_ENABLE 0x1
#define FXGMAC_NAPI_DISABLE 0x0
#ifndef fallthrough
#ifdef __has_attribute
#if __has_attribute(__fallthrough__)
# define fallthrough __attribute__((__fallthrough__))
#else
# define fallthrough do {} while (0) /* fallthrough */
#endif
#else
# define fallthrough do {} while (0) /* fallthrough */
#endif
#endif
#define PHY_POWER_DOWN 1
#define PHY_POWER_UP 0
#define FXGMAC_MMC_IER_ALL_DEFAULT 0
#define FXGMAC_RX_DESC_INIT_CHECK_ENABLED
/* #define FXGMAC_ESD_CHECK_ENABLED */
#ifdef FXGMAC_ESD_CHECK_ENABLED
#define FXGMAC_ESD_INTERVAL (5 * HZ)
#define FXGMAC_ESD_ERROR_THRESHOLD (u64)4000000000
#define FXGMAC_PCIE_LINK_DOWN 0xFFFFFFFF
#define FXGMAC_PCIE_RECOVER_TIMES 5000
#define FXGMAC_PCIE_IO_MEM_MASTER_ENABLE 0x7
#endif
//#define FXGMAC_EPHY_LOOPBACK_DETECT_ENABLED
#ifdef FXGMAC_EPHY_LOOPBACK_DETECT_ENABLED
#define FXGMAC_LOOPBACK_CHECK_INTERVAL (5 * HZ)
#define FXGMAC_PHY_LOOPBACK_DETECT_THRESOLD 2
#endif
//#define FXGMAC_ASPM_ENABLED
#ifdef FXGMAC_ASPM_ENABLED
#define FXGMAC_CHECK_DEV_STATE
#define FXGMAC_ASPM_INTERVAL (20 * HZ)
#endif
#ifndef BIT
#define BIT(n) (0x1<<(n))
#endif
#define UDP_RSS_FLAGS (BIT(MAC_RSSCR_UDP4TE_POS) | \
BIT(MAC_RSSCR_UDP6TE_POS))
#define MF90_SUB_VENTOR_ID 0x17aa
#define MF90_SUB_DEVICE_ID 0x3509
#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 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_ENABLED
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;
enum fxgmac_task_flag {
FXGMAC_FLAG_TASK_DOWN = 0,
FXGMAC_FLAG_TASK_RESET_PENDING,
FXGMAC_FLAG_TASK_ESD_CHECK_PENDING,
FXGMAC_FLAG_TASK_LINKCHG_CHECK_PENDING,
FXGMAC_FLAG_TASK_MAX
};
typedef struct fxgmac_esd_stats {
u32 tx_abort_excess_collisions;
u32 tx_dma_underrun;
u32 tx_lost_crs;
u32 tx_late_collisions;
u32 rx_crc_errors;
u32 rx_align_errors;
u32 rx_runt_errors;
u32 single_collisions;
u32 multi_collisions;
u32 tx_deferred_frames;
}FXGMAC_ESD_STATS;
typedef enum fxgmac_dev_state {
FXGMAC_DEV_OPEN = 0x0,
FXGMAC_DEV_CLOSE = 0x1,
FXGMAC_DEV_STOP = 0x2,
FXGMAC_DEV_START = 0x3,
FXGMAC_DEV_SUSPEND = 0x4,
FXGMAC_DEV_RESUME = 0x5,
FXGMAC_DEV_PROBE = 0xFF,
}DEV_STATE;
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;
int pre_phy_speed;
int pre_phy_duplex;
int pre_phy_autoneg;
struct work_struct restart_work;
#ifdef FXGMAC_ESD_CHECK_ENABLED
struct delayed_work esd_work;
FXGMAC_ESD_STATS esd_stats;
DECLARE_BITMAP(task_flags, FXGMAC_FLAG_TASK_MAX);
#endif
#ifdef FXGMAC_EPHY_LOOPBACK_DETECT_ENABLED
struct delayed_work loopback_work;
u32 lb_test_flag; // for tool
u32 lb_cable_flag; // for driver
u32 lb_cable_detect_count; // for driver
#endif
#ifdef FXGMAC_ASPM_ENABLED
struct delayed_work aspm_config_work;
bool aspm_en;
bool aspm_work_active;
#endif
bool recover_from_aspm;
u32 int_flags; /* legacy, msi or msix */
#ifdef CONFIG_PCI_MSI
struct msix_entry *msix_entries;
#endif
/* power management and wol*/
u32 wol;
unsigned long powerstate;
/*for ns-offload table. 2 entries supported. */
unsigned int ns_offload_tab_idx;
netdev_features_t netdev_features;
struct napi_struct napi;
#ifdef FXGMAC_MISC_ENABLED
struct napi_struct napi_misc;
int misc_irq;
#endif
u8 recover_phy_state;
char misc_irq_name[IFNAMSIZ + 32];
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];
DEV_STATE dev_state;
struct mutex mutex;
struct timer_list phy_poll_tm;
}FXGMAC_PDATA_OF_PLATFORM;
void fxgmac_restart_dev(struct fxgmac_pdata *pdata);
long fxgmac_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 */
#if 0
int fxgmac_ephy_autoneg_ability_get(struct fxgmac_pdata *pdata,
unsigned int *cap_mask);
#endif
int fxgmac_ephy_status_get(struct fxgmac_pdata *pdata, int* speed,
int* duplex, int* ret_link, int *media);
int fxgmac_phy_force_mode(struct fxgmac_pdata *pdata);
int fxgmac_phy_force_speed(struct fxgmac_pdata *pdata, int speed);
int fxgmac_phy_force_duplex(struct fxgmac_pdata *pdata, int duplex);
int fxgmac_phy_force_autoneg(struct fxgmac_pdata *pdata, int autoneg);
//void fxgmac_act_phy_link(struct fxgmac_pdata *pdata);
int fxgmac_phy_timer_init(struct fxgmac_pdata *pdata);
void fxgmac_phy_timer_destroy(struct fxgmac_pdata *pdata);
void fxgmac_phy_update_link(struct net_device *netdev);
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);
void fxgmac_tx_start_xmit(struct fxgmac_channel *channel, struct fxgmac_ring *ring);
void fxgmac_dev_xmit(struct fxgmac_channel *channel);
void fxgmac_config_wol(struct fxgmac_pdata *pdata, int en);
void fxgmac_print_pkt(struct net_device *netdev, struct sk_buff *skb, bool tx_rx);
void fxgmac_lock(struct fxgmac_pdata * pdata);
void fxgmac_unlock(struct fxgmac_pdata * pdata);
void fxgmac_set_phy_link_ksettings(struct fxgmac_pdata *pdata);
#ifdef FXGMAC_ASPM_ENABLED
void fxgmac_schedule_aspm_config_work(struct fxgmac_pdata *pdata);
void fxgmac_cancel_aspm_config_work(struct fxgmac_pdata *pdata);
bool fxgmac_aspm_action_linkup(struct fxgmac_pdata *pdata);
#endif
#endif /* __FXGMAC_OS_H__ */
yt6801-dkms-1.0.31/src/motorcomm 0000664 0000000 0000000 00000001434 15126421535 0016237 0 ustar 00root root 0000000 0000000 #!/bin/sh
#
# yt6801 initramfs-tools hook script
#
# Installs copies of firmware files for the yt6801 driver
# to the early initramfs
PREREQ=""
prereqs()
{
echo "$PREREQ"
}
case $1 in
prereqs)
prereqs
exit 0
;;
esac
. /usr/share/initramfs-tools/hook-functions
#
# Copy yt6801 driver to /lib/modules/ to be seen
# by mkinitramfs tool during initrd.img creation
#
copy_yt6801_driver() {
local dir="/lib/modules/$version/kernel/kylin/yt6801"
mkdir -p $dir
cp -a $dir/yt6801.ko $dir
}
#
# Remove yt6801 driver at /lib/modules/ location
#
clean_yt6801_driver() {
local dir="/lib/modules/$version/kernel/kylin/yt6801"
rm -rf $dir
# if [ -z "$(ls -A $dir)" ]; then
# rm -rf $dir
# fi
}
copy_yt6801_driver
manual_add_modules yt6801
#clean_yt6801_driver