net: ethernet: motorcomm: Update to 1.0.27

This commit is contained in:
baiywt 2024-05-07 17:10:38 +08:00
parent 338a0b10ac
commit 652868bbf1
19 changed files with 19045 additions and 19326 deletions

View File

@ -1,40 +1,40 @@
# SUBARCH tells the usermode build what the underlying arch is. That is set
# first, and if a usermode build is happening, the "ARCH=um" on the command
# line overrides the setting of ARCH below. If a native build is happening,
# then ARCH is assigned, getting whatever value it gets normally, and
# SUBARCH is subsequently ignored.
# eg:
# x86(make modules or make)
# arm(make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- modules)
SUBARCH := $(shell uname -m | sed -e s/i.86/x86/ -e s/x86_64/x86/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/ -e s/s390x/s390/ -e s/parisc64/parisc/ -e s/ppc.*/powerpc/ -e s/mips.*/mips/ -e s/sh[234].*/sh/ -e s/aarch64.*/arm64/ -e s/riscv.*/riscv/)
CURARCH ?= $(SUBARCH)
ARCH ?= $(SUBARCH)
CROSS_COMPILE ?=
CONFIG_MODULE_SIG=n
EXTRA_CFLAGS = -Wall -g -I$(CURDIR) -I$(subst fuxi-linux-release-package/module_fuxi/src,common,$(PWD)) -I$(PWD)
EXTRA_CFLAGS += -DFXGMAC_DEBUG
KSRC = /lib/modules/`uname -r`/build
KDST = /lib/modules/`uname -r`/kernel/drivers/net/ethernet/motorcomm/
KFILE = yt6801.ko
ifneq ($(filter arm arm64, $(ARCH)),)
ifeq ($(CURARCH), x86)
# if you want to compile driver with linux kernel source code,you should specify the source path(KSRC), such as:
# KSRC = /home/mxl/ti-processor-sdk-linux-am57xx-evm-06.03.00.106/board-support/linux-4.19.94+gitAUTOINC+be5389fd85-gbe5389fd85
endif
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-dbg.o fuxi-gmac-debugfs.o
obj-m += yt6801.o
modules:
make -C $(KSRC) M=$(PWD) modules
install:
sudo install -d $(KDST)
sudo install $(KFILE) $(KDST)
sudo depmod -a
@file $(KDST)$(KFILE)
@echo install done.
uninstall:
sudo rm $(KDST)$(KFILE)
sudo ls -l $(KDST)
clean:
make -C $(KSRC) M=$(PWD) clean
.PHONY:modules install uninstall clean
# SUBARCH tells the usermode build what the underlying arch is. That is set
# first, and if a usermode build is happening, the "ARCH=um" on the command
# line overrides the setting of ARCH below. If a native build is happening,
# then ARCH is assigned, getting whatever value it gets normally, and
# SUBARCH is subsequently ignored.
# eg:
# x86(make modules or make)
# arm(make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- modules)
SUBARCH := $(shell uname -m | sed -e s/i.86/x86/ -e s/x86_64/x86/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/ -e s/s390x/s390/ -e s/parisc64/parisc/ -e s/ppc.*/powerpc/ -e s/mips.*/mips/ -e s/sh[234].*/sh/ -e s/aarch64.*/arm64/ -e s/riscv.*/riscv/)
CURARCH ?= $(SUBARCH)
ARCH ?= $(SUBARCH)
CROSS_COMPILE ?=
CONFIG_MODULE_SIG=n
EXTRA_CFLAGS = -Wall -g -I$(CURDIR) -I$(subst fuxi-linux-release-package/module_fuxi/src,common,$(PWD)) -I$(PWD)
EXTRA_CFLAGS += -DFXGMAC_DEBUG -Wno-self-assign -Wno-unused-but-set-variable -Wno-sometimes-uninitialized
KSRC = /lib/modules/`uname -r`/build
KDST = /lib/modules/`uname -r`/kernel/drivers/net/ethernet/motorcomm/
KFILE = yt6801.ko
ifneq ($(filter arm arm64, $(ARCH)),)
ifeq ($(CURARCH), x86)
# if you want to compile driver with linux kernel source code,you should specify the source path(KSRC), such as:
# KSRC = /home/mxl/ti-processor-sdk-linux-am57xx-evm-06.03.00.106/board-support/linux-4.19.94+gitAUTOINC+be5389fd85-gbe5389fd85
endif
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-dbg.o fuxi-gmac-debugfs.o
obj-m += yt6801.o
modules:
make -C $(KSRC) M=$(PWD) modules
install:
sudo install -d $(KDST)
sudo install $(KFILE) $(KDST)
sudo depmod -a
@file $(KDST)$(KFILE)
@echo install done.
uninstall:
sudo rm $(KDST)$(KFILE)
sudo ls -l $(KDST)
clean:
make -C $(KSRC) M=$(PWD) clean
.PHONY:modules install uninstall clean

View File

@ -1,4 +1,4 @@
obj-$(CONFIG_FUXI) += fuxi.o
fuxi-objs := fuxi-gmac-common.o fuxi-gmac-desc.o fuxi-gmac-ethtool.o fuxi-gmac-hw.o \
fuxi-gmac-net.o fuxi-gmac-pci.o fuxi-gmac-phy.o fuxi-efuse.o fuxi-dbg.o \
fuxi-gmac-debugfs.o
obj-$(CONFIG_FUXI) += fuxi.o
fuxi-objs := fuxi-gmac-common.o fuxi-gmac-desc.o fuxi-gmac-ethtool.o fuxi-gmac-hw.o \
fuxi-gmac-net.o fuxi-gmac-pci.o fuxi-gmac-phy.o fuxi-efuse.o fuxi-dbg.o \
fuxi-gmac-debugfs.o

View File

@ -1,30 +1,30 @@
=============================================================================
This file contains certain notices of software components included with
the software that Motorcomm, Inc. ("Motorcomm") is required to
provide you. Except where prohibited by the open source license, the
content of this file is provided solely to satisfy Motorcomm's attribution
and notice requirement; your use of these software components
together with the Motorcomm software ("Software") is subject to the terms
of your license from Motorcomm. Compliance with all copyright laws and
software license agreements included in the notice section of this
file are the responsibility of the user. Except as may be granted by
separate express written agreement, this file provides no license to
any patents, trademarks, copyrights, or other intellectual property
of Motorcomm or any of its subsidiaries.
Software provided with this notice is NOT A CONTRIBUTION to any open
source project. If alternative licensing is available for any of the
components with licenses or attributions provided below, a license
choice is made for receiving such code by Motorcomm.
Copyright (c) 2021 Motorcomm, Inc. All rights reserved.
Motorcomm is a trademark of Motorcomm Incorporated, registered in China
and other countries. All Motorcomm Incorporated trademarks
are used with permission. Other products and brand names may be
trademarks or registered trademarks of their respective owners.
=============================================================================
=============================================================================
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.
=============================================================================

View File

@ -1,7 +1,7 @@
PACKAGE_NAME="yt6801"
PACKAGE_VERSION="1.0.21"
CLEAN="make clean"
MAKE[0]="make"
BUILT_MODULE_NAME[0]="yt6801"
DEST_MODULE_LOCATION[0]="/kernel/drivers/motorcomm"
AUTOINSTALL="yes"
PACKAGE_NAME="yt6801"
PACKAGE_VERSION="1.0.27"
CLEAN="make clean"
MAKE[0]="make"
BUILT_MODULE_NAME[0]="yt6801"
DEST_MODULE_LOCATION[0]="/kernel/drivers/net/ethernet/motorcomm"
AUTOINSTALL="yes"

File diff suppressed because it is too large Load Diff

View File

@ -1,271 +1,24 @@
/*++
Copyright (c) 2021 Motorcomm Corporation.
Confidential and Proprietary. All rights reserved.
This is Motorcomm Corporation NIC driver relevant files. Please don't copy, modify,
distribute without commercial permission.
--*/
#ifndef _MP_DBG_H
#define _MP_DBG_H
#include "fuxi-os.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
#if defined(UEFI)
//#pragma warning(disable:4100) //warning C4100: 'xxx': unreferenced formal parameter
//#pragma warning(disable:4101) //warning C4101: 'xxx': unreferenced local variable
//#pragma warning(disable:4189) //warning C4189: 'xxx': local variable is initialized but not referenced
//#pragma warning(disable:4213) //warning C4213: nonstandard extension used: cast on l-value.
//#pragma warning(disable:4201) //warning C4201: nonstandard extension used: nameless struct/union
#define NIC_DBG_STRING "FUXI: "
#define STR_FORMAT "%a"
extern UINT32 MPDebugLevel;
#if DBG
#define DbgPrintF(level, ...) \
{ \
if (level <= MPDebugLevel) \
{ \
AsciiPrint(NIC_DBG_STRING ##__VA_ARGS__); \
AsciiPrint("\n"); \
} \
}
#define DBGPRINT(Level, Fmt) \
{ \
if (Level <= MPDebugLevel) \
{ \
/*DbgPrint(NIC_DBG_STRING);*/ \
AsciiPrint Fmt; \
} \
}
#else
#define DBGPRINT(Level, Fmt)
#define DbgPrintF(level, ...)
#endif
#define DBGPRINT_RAW(Level, Fmt)
#define DBGPRINT_S(Status, Fmt)
#define DBGPRINT_UNICODE(Level, UString)
#define Dump(p,cb,fAddress,ulGroup)
void fxgmac_dump_buffer(unsigned char *skb, unsigned int len, int tx_rx);
#elif defined(_WIN64) || defined(_WIN32)
//#pragma warning(disable:4100) //warning C4100: 'xxx': unreferenced formal parameter
//#pragma warning(disable:4101) //warning C4101: 'xxx': unreferenced local variable
//#pragma warning(disable:4189) //warning C4189: 'xxx': local variable is initialized but not referenced
//#pragma warning(disable:4213) //warning C4213: nonstandard extension used: cast on l-value.
#pragma warning(disable:4201) //warning C4201: nonstandard extension used: nameless struct/union
#define STR_FORMAT "%s"
// Define a macro so DbgPrint can work on win9x, 32-bit/64-bit NT's
#ifdef _WIN64
#define PTR_FORMAT "%p"
#else
#define PTR_FORMAT "%x"
#endif
#define NIC_TAG ((ULONG)'FUXI')
#define NIC_DBG_STRING "FUXI: "
#if DBG
extern ULONG MPDebugLevel;
extern BOOLEAN MPInitDone;
extern NDIS_SPIN_LOCK MPMemoryLock;
#define DbgPrintF(Level, ...) \
{ \
if (Level <= MPDebugLevel) \
{ \
DbgPrint(NIC_DBG_STRING ##__VA_ARGS__); \
DbgPrint("\n"); \
} \
}
#define DBGPRINT(Level, Fmt) \
{ \
if (Level <= MPDebugLevel) \
{ \
/*DbgPrint(NIC_DBG_STRING);*/ \
DbgPrint Fmt; \
} \
}
#define DBGPRINT_RAW(Level, Fmt) \
{ \
if (Level <= MPDebugLevel) \
{ \
DbgPrint Fmt; \
} \
}
#define DBGPRINT_S(Status, Fmt) \
{ \
ULONG dbglevel; \
if(Status == NDIS_STATUS_SUCCESS || Status == NDIS_STATUS_PENDING) dbglevel = MP_TRACE; \
else dbglevel = MP_ERROR; \
DBGPRINT(dbglevel, Fmt); \
}
#define DBGPRINT_UNICODE(Level, UString) \
{ \
if (Level <= MPDebugLevel) \
{ \
/* DbgPrint(NIC_DBG_STRING); */ \
mpDbgPrintUnicodeString(UString); \
} \
}
#undef ASSERT
#define ASSERT(x) if(!(x)) { \
DBGPRINT(MP_ERROR, ("Assertion failed: %s:%d %s\n", __FILE__, __LINE__, #x)); \
/*DbgBreakPoint();*/ }
VOID
DbgPrintOidName(
_In_ NDIS_OID Oid
);
VOID
DbgPrintAddress(
_In_reads_bytes_(ETH_LENGTH_OF_ADDRESS) PUCHAR Address)
;
#pragma pack(push)
#pragma pack(16)
//
// The MP_ALLOCATION structure stores all info about MPAuditAllocMemTag
//
typedef struct _MP_ALLOCATION
{
LIST_ENTRY List;
ULONG Signature;
CHAR* FileNumber;
ULONG LineNumber;
ULONG Size;
ULONGLONG dummy; // for 64 bit alignment
union {
ULONGLONG Alignment;
UCHAR UserData;
};
} MP_ALLOCATION, *PMP_ALLOCATION;
#pragma pack(pop)
PVOID
MPAuditAllocMemTag(
UINT Size,
CHAR* FileNumber,
ULONG LineNumber,
NDIS_HANDLE MiniportAdapterHandle
);
VOID MPAuditFreeMem(
PVOID Pointer
);
VOID mpDbgPrintUnicodeString(
IN PUNICODE_STRING UnicodeString);
VOID
Dump(
__in_bcount(cb) CHAR* p,
ULONG cb,
BOOLEAN fAddress,
ULONG ulGroup );
void fxgmac_dump_buffer(unsigned char* skb, unsigned int len, int tx_rx);
VOID
DumpLine(
__in_bcount(cb) CHAR* p,
ULONG cb,
BOOLEAN fAddress,
ULONG ulGroup);
#else // !DBG
#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 )
#endif // DBG
#elif defined(LINUX)
#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 )
#elif defined(UBOOT)
#ifdef UBOOT_DEBUG
extern u32 MPDebugLevel;
#define NIC_DBG_STRING "YT6801: "
#define STR_FORMAT "%s"
#define PTR_FORMAT "%x"
//#define DBGPRINT(Level, Fmt) printf Fmt
#define DbgPrintF(Level, fmt, args...) \
{ \
if (Level <= MPDebugLevel) \
{ \
printf(NIC_DBG_STRING fmt,##args); \
printf("\n"); \
} \
}
#else
#define DbgPrintF(Level, ...)
#endif
#else
//#pragma warning(disable:4100) //warning C4100: 'xxx': unreferenced formal parameter
//#pragma warning(disable:4101) //warning C4101: 'xxx': unreferenced local variable
//#pragma warning(disable:4189) //warning C4189: 'xxx': local variable is initialized but not referenced
//#pragma warning(disable:4213) //warning C4213: nonstandard extension used: cast on l-value.
#pragma warning(disable:4201) //warning C4201: nonstandard extension used: nameless struct/union
#pragma warning(disable:4002) //warning C4002: too many actual parameters for macro
#endif // ifdef UEFI.
/*++
Copyright (c) 2021 Motorcomm Corporation.
Confidential and Proprietary. All rights reserved.
This is Motorcomm Corporation NIC driver relevant files. Please don't copy, modify,
distribute without commercial permission.
--*/
#ifndef _MP_DBG_H
#define _MP_DBG_H
//
// Message verbosity: lower values indicate higher urgency
//
#define MP_OFF 0
#define MP_ERROR 1
#define MP_WARN 2
#define MP_TRACE 3
#define MP_INFO 4
#define MP_LOUD 5
#endif // _MP_DBG_H

File diff suppressed because it is too large Load Diff

View File

@ -1,33 +1,33 @@
/*++
Copyright (c) 2021 Motorcomm Corporation.
Confidential and Proprietary. All rights reserved.
This is Motorcomm Corporation NIC driver relevant files. Please don't copy, modify,
distribute without commercial permission.
--*/
#ifndef __FUXI_EFUSE_H__
#define __FUXI_EFUSE_H__
bool fxgmac_read_patch_from_efuse(struct fxgmac_pdata* pdata, u32 offset, u32* value); /* read patch per register offset. */
bool fxgmac_read_patch_from_efuse_per_index(struct fxgmac_pdata* pdata, u8 index, u32* offset, u32* value); /* read patch per 0-based index. */
bool fxgmac_write_patch_to_efuse(struct fxgmac_pdata* pdata, u32 offset, u32 value);
bool fxgmac_write_patch_to_efuse_per_index(struct fxgmac_pdata* pdata, u8 index, u32 offset, u32 value);
bool fxgmac_read_mac_subsys_from_efuse(struct fxgmac_pdata* pdata, u8* mac_addr, u32* subsys, u32* revid);
bool fxgmac_write_mac_subsys_to_efuse(struct fxgmac_pdata* pdata, u8* mac_addr, u32* subsys, u32* revid);
bool fxgmac_write_mac_addr_to_efuse(struct fxgmac_pdata* pdata, u8* mac_addr);
bool fxgmac_read_subsys_from_efuse(struct fxgmac_pdata* pdata, u32* subsys, u32* revid);
bool fxgmac_write_subsys_to_efuse(struct fxgmac_pdata* pdata, u32* subsys, u32* revid);
bool fxgmac_efuse_load(struct fxgmac_pdata* pdata);
bool fxgmac_efuse_read_data(struct fxgmac_pdata* pdata, u32 offset, u32* value);
bool fxgmac_efuse_write_data(struct fxgmac_pdata* pdata, u32 offset, u32 value);
bool fxgmac_efuse_write_oob(struct fxgmac_pdata* pdata);
bool fxgmac_efuse_write_led(struct fxgmac_pdata* pdata, u32 value);
bool fxgmac_read_led_setting_from_efuse(struct fxgmac_pdata* pdata);
bool fxgmac_write_led_setting_to_efuse(struct fxgmac_pdata* pdata);
/*++
Copyright (c) 2021 Motorcomm Corporation.
Confidential and Proprietary. All rights reserved.
This is Motorcomm Corporation NIC driver relevant files. Please don't copy, modify,
distribute without commercial permission.
--*/
#ifndef __FUXI_EFUSE_H__
#define __FUXI_EFUSE_H__
bool fxgmac_read_patch_from_efuse(struct fxgmac_pdata* pdata, u32 offset, u32* value); /* read patch per register offset. */
bool fxgmac_read_patch_from_efuse_per_index(struct fxgmac_pdata* pdata, u8 index, u32* offset, u32* value); /* read patch per 0-based index. */
bool fxgmac_write_patch_to_efuse(struct fxgmac_pdata* pdata, u32 offset, u32 value);
bool fxgmac_write_patch_to_efuse_per_index(struct fxgmac_pdata* pdata, u8 index, u32 offset, u32 value);
bool fxgmac_read_mac_subsys_from_efuse(struct fxgmac_pdata* pdata, u8* mac_addr, u32* subsys, u32* revid);
bool fxgmac_write_mac_subsys_to_efuse(struct fxgmac_pdata* pdata, u8* mac_addr, u32* subsys, u32* revid);
bool fxgmac_write_mac_addr_to_efuse(struct fxgmac_pdata* pdata, u8* mac_addr);
bool fxgmac_read_subsys_from_efuse(struct fxgmac_pdata* pdata, u32* subsys, u32* revid);
bool fxgmac_write_subsys_to_efuse(struct fxgmac_pdata* pdata, u32* subsys, u32* revid);
bool fxgmac_efuse_load(struct fxgmac_pdata* pdata);
bool fxgmac_efuse_read_data(struct fxgmac_pdata* pdata, u32 offset, u32* value);
bool fxgmac_efuse_write_data(struct fxgmac_pdata* pdata, u32 offset, u32 value);
bool fxgmac_efuse_write_oob(struct fxgmac_pdata* pdata);
bool fxgmac_efuse_write_led(struct fxgmac_pdata* pdata, u32 value);
bool fxgmac_read_led_setting_from_efuse(struct fxgmac_pdata* pdata);
bool fxgmac_write_led_setting_to_efuse(struct fxgmac_pdata* pdata);
#endif // __FUXI_EFUSE_H__

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,504 +1,365 @@
/*++
Copyright (c) 2021 Motor-comm Corporation.
Confidential and Proprietary. All rights reserved.
This is Motor-comm Corporation NIC driver relevant files. Please don't copy, modify,
distribute without commercial permission.
--*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
/* for file operation */
#include <linux/fs.h>
#include "fuxi-gmac.h"
#include "fuxi-gmac-reg.h"
#ifdef CONFIG_PCI_MSI
u32 pcidev_int_mode; // for msix
//for MSIx, 20210526
struct msix_entry *msix_entries = NULL;
int req_vectors = 0;
#endif
#define FXGMAC_DBG 0
/* for power state debug using, 20210629. */
#if FXGMAC_DBG
static struct file *dbg_file = NULL;
#define FXGMAC_DBG_BUF_SIZE 128
static char log_buf[FXGMAC_DBG_BUF_SIZE + 2];
#endif
#if FXGMAC_DBG
static char * file_name = "/home/fxgmac/fxgmac_dbg.log";
#endif
#if (LINUX_VERSION_CODE < KERNEL_VERSION(5,13,0))
#if FXGMAC_DBG
#define fxgmac_dbg_log(logstr, arg...) \
do { \
static struct kstat dbg_stat; \
static loff_t pos = 0; \
if (!(IS_ERR(dbg_file))) { \
mm_segment_t previous_fs; /*for address-space switch */ \
sprintf (&log_buf[0], (logstr), ##arg); \
previous_fs = get_fs(); \
set_fs(KERNEL_DS); \
vfs_stat(file_name, &dbg_stat); \
pos = (loff_t)dbg_stat.size; \
kernel_write(dbg_file, (const char*)log_buf, strlen(log_buf) > FXGMAC_DBG_BUF_SIZE ? FXGMAC_DBG_BUF_SIZE : strlen(log_buf), /*&dbg_file->f_pos*/&pos)/**/; \
/*DPRINTK("kernel write done, file size=%d, s=%s", (int)dbg_stat.size, log_buf)*/; \
set_fs(previous_fs); \
/*dbg_file->f_op->flush(dbg_file)*/; \
} \
}while(0)
#else
#define fxgmac_dbg_log(logstr, arg...) \
do { \
/*nothing*/; \
}while(0)
#endif
#else
#if FXGMAC_DBG
/* in kernel 5.14, get_fs/set_fs are removed. */
#define fxgmac_dbg_log(logstr, arg...) \
do { \
static struct kstat dbg_stat; \
static loff_t pos = 0; \
fxgmac_dbg_log_init(); \
if (!(IS_ERR(dbg_file))) { \
sprintf (&log_buf[0], (logstr), ##arg); \
vfs_getattr(&(dbg_file->f_path), &dbg_stat, 0, 0); \
pos = (loff_t)dbg_stat.size; \
kernel_write(dbg_file, (const char*)log_buf, strlen(log_buf) > FXGMAC_DBG_BUF_SIZE ? FXGMAC_DBG_BUF_SIZE : strlen(log_buf), /*&dbg_file->f_pos*/&pos)/**/; \
/*DPRINTK("kernel write done, file size=%d, s=%s", (int)dbg_stat.size, log_buf)*/; \
/*dbg_file->f_op->flush(dbg_file)*/; \
} \
fxgmac_dbg_log_uninit();\
}while(0)
#else
#define fxgmac_dbg_log(logstr, arg...) \
do { \
/*nothing*/; \
}while(0)
#endif
#endif
/* declarations */
static void fxgmac_shutdown(struct pci_dev *pdev);
/*
* functions definitions
*/
int fxgmac_dbg_log_init( void )
{
#if FXGMAC_DBG
dbg_file = filp_open(file_name, O_RDWR | O_CREAT, 0644);
if (IS_ERR(dbg_file))
{
DPRINTK("File fxgmac_dbg.log open or created failed.\n");
return PTR_ERR(dbg_file);
}
#endif
return 0;
}
int fxgmac_dbg_log_uninit( void )
{
#if FXGMAC_DBG
if(IS_ERR(dbg_file))
{
DPRINTK("Invalid fd for file fxgmac_dbg.log, %p.\n", dbg_file);
dbg_file= NULL;
return PTR_ERR(dbg_file);
}
filp_close(dbg_file, NULL);
dbg_file= NULL;
#endif
return 0;
}
/*
* since kernel does not clear the MSI mask bits and
* this function clear MSI mask bits when MSI is enabled.
*/
int fxgmac_pci_config_modify(struct pci_dev *pdev)
{
//struct net_device *netdev = dev_get_drvdata(&pdev->dev);
//struct fxgmac_pdata *pdata = netdev_priv(netdev);
u16 pcie_cap_offset;
u32 pcie_msi_mask_bits;
int ret;
pcie_cap_offset = pci_find_capability(pdev, 0x05 /*MSI Capability ID*/);
if (pcie_cap_offset) {
ret = pci_read_config_dword(pdev,
pcie_cap_offset + 0x10 /* MSI mask bits */,
&pcie_msi_mask_bits);
if (ret)
{
DPRINTK(KERN_ERR "fxgmac_pci_config_modify read pci config space MSI cap. failed, %d\n", ret);
return -EFAULT;
}
}
ret = pci_write_config_word(pdev, pcie_cap_offset + 0xc /* MSI data */, 0x1234/* random val */);
ret = pci_write_config_dword(pdev, pcie_cap_offset + 0x10 /* MSI mask bits */, (pcie_msi_mask_bits & 0xffff0000) /*clear mask bits*/);
if (ret)
{
DPRINTK(KERN_ERR "fxgmac_pci_config_modify write pci config space MSI mask failed, %d\n", ret);
}
return ret;
}
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;
#ifdef CONFIG_PCI_MSI
//for MSIx, 20210526
int vectors, rc;
#endif
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;
/*if (0x100 != pci_resource_len(pcidev, i))
continue;
*/
ret = pcim_iomap_regions(pcidev, BIT(i), FXGMAC_DRV_NAME);
if (ret)
{
DPRINTK(KERN_INFO "fxgmac_probe pcim_iomap_regions failed\n");
return ret;
}
DPRINTK(KERN_INFO "fxgmac_probe iomap_region i=%#x,ret=%#x\n",(int)i,(int)ret);
break;
}
pci_set_master(pcidev);
memset(&res, 0, sizeof(res));
res.irq = pcidev->irq;
res.addr = pcim_iomap_table(pcidev)[i];
DPRINTK(KERN_INFO "fxgmac_probe res.addr=%p,val=%#x\n",res.addr,/*(int)(*((int*)(res.addr)))*/0);
#ifdef CONFIG_PCI_MSI
/* added for MSIx feature, 20210526 */
pcidev_int_mode = 0; //init to legacy interrupt, and MSIx has the first priority
/* check cpu core number.
* since we have 4 channels, we must ensure the number of cpu core > 4
* otherwise, just roll back to legacy
*/
vectors = num_online_cpus();
DPRINTK("fxgmac_probe, num of cpu=%d\n", vectors);
if(vectors >= FXGMAC_MAX_DMA_CHANNELS) {
#if FXGMAC_TX_INTERRUPT_EN
req_vectors = FXGMAC_MAX_DMA_CHANNELS_PLUS_1TX;
#else
req_vectors = FXGMAC_MAX_DMA_CHANNELS;
#endif
msix_entries = kcalloc(/*vectors 20220211*/req_vectors,
sizeof(struct msix_entry),
GFP_KERNEL);
if (!msix_entries) {
DPRINTK("fxgmac_probe, MSIx, kcalloc err for msix entries, rollback to MSI..\n");
goto enable_msi_interrupt;
}else {
for (i = 0; i < /*vectors 20220211*/req_vectors; i++)
msix_entries[i].entry = i;
#if 0
/* follow the requirement from pci_enable_msix():
*
* Setup the MSI-X capability structure of device function with the number
* of requested irqs upon its software driver call to request for
* MSI-X mode enabled on its hardware device function. A return of zero
* indicates the successful configuration of MSI-X capability structure
* with new allocated MSI-X irqs. A return of < 0 indicates a failure.
* Or a return of > 0 indicates that driver request is exceeding the number
* of irqs or MSI-X vectors available. Driver should use the returned value to
* re-send its request.
*/
req_vectors = vectors;
do {
rc = pci_enable_msix(pcidev, msix_entries, req_vectors);
if (rc < 0) {
//failure
//DPRINTK("fxgmac_probe, enable MSIx failed,%d.\n", rc);
rc = 0; //stop the loop
req_vectors = 0; //indicate failure
} else if (rc > 0) {
//re-request with new number
req_vectors = rc;
}
} while (rc);
#else
rc = pci_enable_msix_range(pcidev, msix_entries, req_vectors, req_vectors);
if (rc < 0) {
//failure
DPRINTK("fxgmac_probe, enable MSIx failed,%d.\n", rc);
req_vectors = 0; //indicate failure
} else {
req_vectors = rc;
}
#endif
#if FXGMAC_TX_INTERRUPT_EN
if(req_vectors >= FXGMAC_MAX_DMA_CHANNELS_PLUS_1TX) {
#else
if(req_vectors >= FXGMAC_MAX_DMA_CHANNELS) {
#endif
DPRINTK("fxgmac_probe, enable MSIx ok, cpu=%d,vectors=%d.\n", vectors, req_vectors);
pcidev_int_mode = FXGMAC_FLAG_MSIX_CAPABLE | FXGMAC_FLAG_MSIX_ENABLED;
goto drv_probe;
}else if (req_vectors){
DPRINTK("fxgmac_probe, enable MSIx with only %d vector, while we need %d, rollback to MSI.\n", req_vectors, vectors);
//roll back to msi
pci_disable_msix(pcidev);
kfree(msix_entries);
msix_entries = NULL;
}else {
DPRINTK("fxgmac_probe, enable MSIx failure and clear msix entries.\n");
//roll back to msi
kfree(msix_entries);
msix_entries = NULL;
}
}
}
enable_msi_interrupt:
rc = pci_enable_msi(pcidev);
if (rc < 0)
DPRINTK("fxgmac_probe, enable MSI failure, rollback to LEGACY.\n");
else {
pcidev_int_mode = FXGMAC_FLAG_MSI_CAPABLE | FXGMAC_FLAG_MSI_ENABLED;
DPRINTK("fxgmac_probe, enable MSI ok, irq=%d.\n", pcidev->irq);
}
drv_probe:
#endif
//fxgmac_dbg_log_init();
fxgmac_dbg_log("fxpm,_fxgmac_probe\n");
return fxgmac_drv_probe(&pcidev->dev, &res);
}
static void fxgmac_remove(struct pci_dev *pcidev)
{
struct net_device *netdev = dev_get_drvdata(&pcidev->dev);
struct fxgmac_pdata * pdata = netdev_priv(netdev);
fxgmac_drv_remove(&pcidev->dev);
#ifdef CONFIG_PCI_MSI
//20210526
if(pcidev_int_mode & (FXGMAC_FLAG_MSIX_CAPABLE | FXGMAC_FLAG_MSIX_ENABLED)){
pci_disable_msix(pcidev);
kfree(msix_entries);
msix_entries = NULL;
req_vectors = 0;
}
pcidev_int_mode = 0;
#endif
fxgmac_dbg_log("fxpm,_fxgmac_remove\n");
#ifdef HAVE_FXGMAC_DEBUG_FS
fxgmac_dbg_exit(pdata);
#endif /* HAVE_FXGMAC_DEBUG_FS */
//fxgmac_dbg_log_uninit();
}
/* for Power management, 20210628 */
static int __fxgmac_shutdown(struct pci_dev *pdev, bool *enable_wake)
{
struct net_device *netdev = dev_get_drvdata(&pdev->dev);
struct fxgmac_pdata *pdata = netdev_priv(netdev);
u32 wufc = pdata->wol;
#ifdef CONFIG_PM
int retval = 0;
#endif
DPRINTK("fxpm,_fxgmac_shutdown, callin\n");
fxgmac_dbg_log("fxpm,_fxgmac_shutdown, callin.\n");
rtnl_lock();
/* for linux shutdown, we just treat it as power off wol can be ignored
* for suspend, we do need recovery by wol
*/
fxgmac_net_powerdown(pdata, (unsigned int)!!wufc);
netif_device_detach(netdev);
rtnl_unlock();
#ifdef CONFIG_PM
retval = pci_save_state(pdev);
if (retval) {
DPRINTK("fxpm,_fxgmac_shutdown, save pci state failed.\n");
return retval;
}
#endif
DPRINTK("fxpm,_fxgmac_shutdown, save pci state done.\n");
fxgmac_dbg_log("fxpm,_fxgmac_shutdown, save pci state done.\n");
pci_wake_from_d3(pdev, !!wufc);
*enable_wake = !!wufc;
pci_disable_device(pdev);
DPRINTK("fxpm,_fxgmac_shutdown callout, enable wake=%d.\n", *enable_wake);
fxgmac_dbg_log("fxpm,_fxgmac_shutdown callout, enable wake=%d.\n", *enable_wake);
return 0;
}
static void fxgmac_shutdown(struct pci_dev *pdev)
{
bool wake;
struct net_device *netdev = dev_get_drvdata(&pdev->dev);
struct fxgmac_pdata *pdata = netdev_priv(netdev);
DPRINTK("fxpm, fxgmac_shutdown callin\n");
fxgmac_dbg_log("fxpm, fxgmac_shutdown callin\n");
pdata->current_state = CURRENT_STATE_SHUTDOWN;
__fxgmac_shutdown(pdev, &wake);
if (system_state == SYSTEM_POWER_OFF) {
pci_wake_from_d3(pdev, wake);
pci_set_power_state(pdev, PCI_D3hot);
}
DPRINTK("fxpm, fxgmac_shutdown callout, system power off=%d\n", (system_state == SYSTEM_POWER_OFF)? 1 : 0);
fxgmac_dbg_log("fxpm, fxgmac_shutdown callout, system power off=%d\n", (system_state == SYSTEM_POWER_OFF)? 1 : 0);
}
#ifdef CONFIG_PM
/* yzhang, 20210628 for PM */
static int fxgmac_suspend(struct pci_dev *pdev,
pm_message_t __always_unused state)
{
int retval;
bool wake;
struct net_device *netdev = dev_get_drvdata(&pdev->dev);
struct fxgmac_pdata *pdata = netdev_priv(netdev);
DPRINTK("fxpm, fxgmac_suspend callin\n");
fxgmac_dbg_log("fxpm, fxgmac_suspend callin\n");
pdata->current_state = CURRENT_STATE_SUSPEND;
retval = __fxgmac_shutdown(pdev, &wake);
if (retval)
return retval;
if (wake) {
pci_prepare_to_sleep(pdev);
} else {
pci_wake_from_d3(pdev, false);
pci_set_power_state(pdev, PCI_D3hot);
}
DPRINTK("fxpm, fxgmac_suspend callout to %s\n", wake ? "sleep" : "D3hot");
fxgmac_dbg_log("fxpm, fxgmac_suspend callout to %s\n", wake ? "sleep" : "D3hot");
return 0;
}
static int fxgmac_resume(struct pci_dev *pdev)
{
struct fxgmac_pdata *pdata;
struct net_device *netdev;
u32 err;
DPRINTK("fxpm, fxgmac_resume callin\n");
fxgmac_dbg_log("fxpm, fxgmac_resume callin\n");
netdev = dev_get_drvdata(&pdev->dev);
pdata = netdev_priv(netdev);
pdata->current_state = CURRENT_STATE_RESUME;
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
/*
* pci_restore_state clears dev->state_saved so call
* pci_save_state to restore it.
*/
pci_save_state(pdev);
err = pci_enable_device_mem(pdev);
if (err) {
dev_err(pdata->dev, "fxgmac_resume, failed to enable PCI device from suspend\n");
return err;
}
smp_mb__before_atomic();
__clear_bit(FXGMAC_POWER_STATE_DOWN, &pdata->powerstate);
pci_set_master(pdev);
pci_wake_from_d3(pdev, false);
rtnl_lock();
err = 0;//ixgbe_init_interrupt_scheme(adapter);
if (!err && netif_running(netdev))
fxgmac_net_powerup(pdata);
if (!err)
netif_device_attach(netdev);
rtnl_unlock();
DPRINTK("fxpm, fxgmac_resume callout\n");
fxgmac_dbg_log("fxpm, fxgmac_resume callout\n");
return err;
}
#endif
static const struct pci_device_id fxgmac_pci_tbl[] = {
{ PCI_DEVICE(0x1f0a, 0x6801) },
{ 0 }
};
MODULE_DEVICE_TABLE(pci, fxgmac_pci_tbl);
static struct pci_driver fxgmac_pci_driver = {
.name = FXGMAC_DRV_NAME,
.id_table = fxgmac_pci_tbl,
.probe = fxgmac_probe,
.remove = fxgmac_remove,
#ifdef CONFIG_PM
/* currently, we only use USE_LEGACY_PM_SUPPORT */
.suspend = fxgmac_suspend,
.resume = fxgmac_resume,
#endif
.shutdown = fxgmac_shutdown,
};
module_pci_driver(fxgmac_pci_driver);
MODULE_DESCRIPTION(FXGMAC_DRV_DESC);
MODULE_VERSION(FXGMAC_DRV_VERSION);
MODULE_AUTHOR("Frank <Frank.Sae@motor-comm.com>");
MODULE_LICENSE("Dual BSD/GPL");
/*++
Copyright (c) 2021 Motor-comm Corporation.
Confidential and Proprietary. All rights reserved.
This is Motor-comm Corporation NIC driver relevant files. Please don't copy, modify,
distribute without commercial permission.
--*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
/* for file operation */
#include <linux/fs.h>
#include "fuxi-gmac.h"
#include "fuxi-gmac-reg.h"
#define FXGMAC_DBG 0
/* for power state debug using, 20210629. */
#if FXGMAC_DBG
static struct file *dbg_file = NULL;
#define FXGMAC_DBG_BUF_SIZE 128
static char log_buf[FXGMAC_DBG_BUF_SIZE + 2];
#endif
#if FXGMAC_DBG
static char * file_name = "/home/fxgmac/fxgmac_dbg.log";
#endif
#if (LINUX_VERSION_CODE < KERNEL_VERSION(5,13,0))
#if FXGMAC_DBG
#define fxgmac_dbg_log(logstr, arg...) \
do { \
static struct kstat dbg_stat; \
static loff_t pos = 0; \
if (!(IS_ERR(dbg_file))) { \
mm_segment_t previous_fs; /*for address-space switch */ \
sprintf (&log_buf[0], (logstr), ##arg); \
previous_fs = get_fs(); \
set_fs(KERNEL_DS); \
vfs_stat(file_name, &dbg_stat); \
pos = (loff_t)dbg_stat.size; \
kernel_write(dbg_file, (const char*)log_buf, strlen(log_buf) > FXGMAC_DBG_BUF_SIZE ? FXGMAC_DBG_BUF_SIZE : strlen(log_buf), /*&dbg_file->f_pos*/&pos)/**/; \
/*DPRINTK("kernel write done, file size=%d, s=%s", (int)dbg_stat.size, log_buf)*/; \
set_fs(previous_fs); \
/*dbg_file->f_op->flush(dbg_file)*/; \
} \
}while(0)
#else
#define fxgmac_dbg_log(logstr, arg...) \
do { \
/*nothing*/; \
}while(0)
#endif
#else
#if FXGMAC_DBG
/* in kernel 5.14, get_fs/set_fs are removed. */
#define fxgmac_dbg_log(logstr, arg...) \
do { \
static struct kstat dbg_stat; \
static loff_t pos = 0; \
fxgmac_dbg_log_init(); \
if (!(IS_ERR(dbg_file))) { \
sprintf (&log_buf[0], (logstr), ##arg); \
vfs_getattr(&(dbg_file->f_path), &dbg_stat, 0, 0); \
pos = (loff_t)dbg_stat.size; \
kernel_write(dbg_file, (const char*)log_buf, strlen(log_buf) > FXGMAC_DBG_BUF_SIZE ? FXGMAC_DBG_BUF_SIZE : strlen(log_buf), /*&dbg_file->f_pos*/&pos)/**/; \
/*DPRINTK("kernel write done, file size=%d, s=%s", (int)dbg_stat.size, log_buf)*/; \
/*dbg_file->f_op->flush(dbg_file)*/; \
} \
fxgmac_dbg_log_uninit();\
}while(0)
#else
#define fxgmac_dbg_log(logstr, arg...) \
do { \
/*nothing*/; \
}while(0)
#endif
#endif
/* declarations */
static void fxgmac_shutdown(struct pci_dev *pdev);
/*
* functions definitions
*/
int fxgmac_dbg_log_init( void )
{
#if FXGMAC_DBG
dbg_file = filp_open(file_name, O_RDWR | O_CREAT, 0644);
if (IS_ERR(dbg_file))
{
DPRINTK("File fxgmac_dbg.log open or created failed.\n");
return PTR_ERR(dbg_file);
}
#endif
return 0;
}
int fxgmac_dbg_log_uninit( void )
{
#if FXGMAC_DBG
if(IS_ERR(dbg_file))
{
DPRINTK("Invalid fd for file fxgmac_dbg.log, %p.\n", dbg_file);
dbg_file= NULL;
return PTR_ERR(dbg_file);
}
filp_close(dbg_file, NULL);
dbg_file= NULL;
#endif
return 0;
}
static int fxgmac_probe(struct pci_dev *pcidev, const struct pci_device_id *id)
{
struct device *dev = &pcidev->dev;
struct fxgmac_resources res;
int i, ret;
ret = pcim_enable_device(pcidev);
if (ret) {
dev_err(dev, "ERROR: fxgmac_probe failed to enable device\n");
return ret;
}
for (i = 0; i <= PCI_STD_RESOURCE_END; i++) {
if (pci_resource_len(pcidev, i) == 0)
continue;
ret = pcim_iomap_regions(pcidev, BIT(i), FXGMAC_DRV_NAME);
if (ret)
{
DPRINTK(KERN_INFO "fxgmac_probe pcim_iomap_regions failed\n");
return ret;
}
DPRINTK(KERN_INFO "fxgmac_probe iomap_region i=%#x,ret=%#x\n",(int)i,(int)ret);
break;
}
pci_set_master(pcidev);
memset(&res, 0, sizeof(res));
res.irq = pcidev->irq;
res.addr = pcim_iomap_table(pcidev)[i];
//fxgmac_dbg_log_init();
fxgmac_dbg_log("fxpm,_fxgmac_probe\n");
return fxgmac_drv_probe(&pcidev->dev, &res);
}
static void fxgmac_remove(struct pci_dev *pcidev)
{
struct net_device *netdev = dev_get_drvdata(&pcidev->dev);
struct fxgmac_pdata * pdata = netdev_priv(netdev);
#ifdef CONFIG_PCI_MSI
u32 msix = FXGMAC_GET_REG_BITS(pdata->expansion.int_flags,
FXGMAC_FLAG_MSIX_POS,
FXGMAC_FLAG_MSIX_LEN);
#endif
fxgmac_drv_remove(&pcidev->dev);
#ifdef CONFIG_PCI_MSI
if(msix){
pci_disable_msix(pcidev);
kfree(pdata->expansion.msix_entries);
pdata->expansion.msix_entries = NULL;
}
#endif
fxgmac_dbg_log("fxpm,_fxgmac_remove\n");
#ifdef HAVE_FXGMAC_DEBUG_FS
fxgmac_dbg_exit(pdata);
#endif /* HAVE_FXGMAC_DEBUG_FS */
//fxgmac_dbg_log_uninit();
}
/* for Power management, 20210628 */
static int __fxgmac_shutdown(struct pci_dev *pdev, bool *enable_wake)
{
struct net_device *netdev = dev_get_drvdata(&pdev->dev);
struct fxgmac_pdata *pdata = netdev_priv(netdev);
u32 wufc = pdata->expansion.wol;
#ifdef CONFIG_PM
int retval = 0;
#endif
DPRINTK("fxpm,_fxgmac_shutdown, callin\n");
fxgmac_dbg_log("fxpm,_fxgmac_shutdown, callin.\n");
rtnl_lock();
/* for linux shutdown, we just treat it as power off wol can be ignored
* for suspend, we do need recovery by wol
*/
fxgmac_net_powerdown(pdata, (unsigned int)!!wufc);
netif_device_detach(netdev);
rtnl_unlock();
#ifdef CONFIG_PM
retval = pci_save_state(pdev);
if (retval) {
DPRINTK("fxpm,_fxgmac_shutdown, save pci state failed.\n");
return retval;
}
#endif
DPRINTK("fxpm,_fxgmac_shutdown, save pci state done.\n");
fxgmac_dbg_log("fxpm,_fxgmac_shutdown, save pci state done.\n");
pci_wake_from_d3(pdev, !!wufc);
*enable_wake = !!wufc;
pci_disable_device(pdev);
DPRINTK("fxpm,_fxgmac_shutdown callout, enable wake=%d.\n", *enable_wake);
fxgmac_dbg_log("fxpm,_fxgmac_shutdown callout, enable wake=%d.\n", *enable_wake);
return 0;
}
static void fxgmac_shutdown(struct pci_dev *pdev)
{
bool wake;
struct net_device *netdev = dev_get_drvdata(&pdev->dev);
struct fxgmac_pdata *pdata = netdev_priv(netdev);
DPRINTK("fxpm, fxgmac_shutdown callin\n");
fxgmac_dbg_log("fxpm, fxgmac_shutdown callin\n");
pdata->expansion.current_state = CURRENT_STATE_SHUTDOWN;
__fxgmac_shutdown(pdev, &wake);
if (system_state == SYSTEM_POWER_OFF) {
pci_wake_from_d3(pdev, wake);
pci_set_power_state(pdev, PCI_D3hot);
}
DPRINTK("fxpm, fxgmac_shutdown callout, system power off=%d\n", (system_state == SYSTEM_POWER_OFF)? 1 : 0);
fxgmac_dbg_log("fxpm, fxgmac_shutdown callout, system power off=%d\n", (system_state == SYSTEM_POWER_OFF)? 1 : 0);
}
#ifdef CONFIG_PM
/* yzhang, 20210628 for PM */
static int fxgmac_suspend(struct pci_dev *pdev,
pm_message_t __always_unused state)
{
int retval;
bool wake;
struct net_device *netdev = dev_get_drvdata(&pdev->dev);
struct fxgmac_pdata *pdata = netdev_priv(netdev);
DPRINTK("fxpm, fxgmac_suspend callin\n");
fxgmac_dbg_log("fxpm, fxgmac_suspend callin\n");
pdata->expansion.current_state = CURRENT_STATE_SUSPEND;
if (netif_running(netdev)) {
retval = __fxgmac_shutdown(pdev, &wake);
if (retval)
return retval;
} else {
wake = !!(pdata->expansion.wol);
}
if (wake) {
pci_prepare_to_sleep(pdev);
} else {
pci_wake_from_d3(pdev, false);
pci_set_power_state(pdev, PCI_D3hot);
}
DPRINTK("fxpm, fxgmac_suspend callout to %s\n", wake ? "sleep" : "D3hot");
fxgmac_dbg_log("fxpm, fxgmac_suspend callout to %s\n", wake ? "sleep" : "D3hot");
return 0;
}
static int fxgmac_resume(struct pci_dev *pdev)
{
struct fxgmac_pdata *pdata;
struct net_device *netdev;
u32 err;
DPRINTK("fxpm, fxgmac_resume callin\n");
fxgmac_dbg_log("fxpm, fxgmac_resume callin\n");
netdev = dev_get_drvdata(&pdev->dev);
pdata = netdev_priv(netdev);
pdata->expansion.current_state = CURRENT_STATE_RESUME;
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
/*
* pci_restore_state clears dev->state_saved so call
* pci_save_state to restore it.
*/
pci_save_state(pdev);
err = pci_enable_device_mem(pdev);
if (err) {
dev_err(pdata->dev, "fxgmac_resume, failed to enable PCI device from suspend\n");
return err;
}
smp_mb__before_atomic();
__clear_bit(FXGMAC_POWER_STATE_DOWN, &pdata->expansion.powerstate);
pci_set_master(pdev);
pci_wake_from_d3(pdev, false);
rtnl_lock();
err = 0;//ixgbe_init_interrupt_scheme(adapter);
if (!err && netif_running(netdev))
fxgmac_net_powerup(pdata);
if (!err)
netif_device_attach(netdev);
rtnl_unlock();
DPRINTK("fxpm, fxgmac_resume callout\n");
fxgmac_dbg_log("fxpm, fxgmac_resume callout\n");
return err;
}
#endif
static const struct pci_device_id fxgmac_pci_tbl[] = {
{ PCI_DEVICE(0x1f0a, 0x6801) },
{ 0 }
};
MODULE_DEVICE_TABLE(pci, fxgmac_pci_tbl);
static struct pci_driver fxgmac_pci_driver = {
.name = FXGMAC_DRV_NAME,
.id_table = fxgmac_pci_tbl,
.probe = fxgmac_probe,
.remove = fxgmac_remove,
#ifdef CONFIG_PM
/* currently, we only use USE_LEGACY_PM_SUPPORT */
.suspend = fxgmac_suspend,
.resume = fxgmac_resume,
#endif
.shutdown = fxgmac_shutdown,
};
module_pci_driver(fxgmac_pci_driver);
MODULE_DESCRIPTION(FXGMAC_DRV_DESC);
MODULE_VERSION(FXGMAC_DRV_VERSION);
MODULE_AUTHOR("Frank <Frank.Sae@motor-comm.com>");
MODULE_LICENSE("Dual BSD/GPL");

View File

@ -1,428 +1,422 @@
/*++
Copyright (c) 2021 Motor-comm Corporation.
Confidential and Proprietary. All rights reserved.
This is Motor-comm Corporation NIC driver relevant files. Please don't copy, modify,
distribute without commercial permission.
--*/
#include <linux/timer.h>
#include <linux/module.h>
#include "fuxi-gmac.h"
#include "fuxi-gmac-reg.h"
void fxgmac_phy_force_speed(struct fxgmac_pdata *pdata, int speed)
{
struct fxgmac_hw_ops* hw_ops = &pdata->hw_ops;
u32 regval = 0;
unsigned int high_bit = 0, low_bit = 0;
switch (speed)
{
case SPEED_1000:
high_bit = 1, low_bit = 0;
break;
case SPEED_100:
high_bit = 0, low_bit = 1;
break;
case SPEED_10:
high_bit = 0, low_bit = 0;
break;
default:
break;
}
/* disable autoneg */
hw_ops->read_ephy_reg(pdata, REG_MII_BMCR, &regval);
regval = FXGMAC_SET_REG_BITS(regval, PHY_CR_AUTOENG_POS, PHY_CR_AUTOENG_LEN, 0);
regval = FXGMAC_SET_REG_BITS(regval, PHY_CR_SPEED_SEL_H_POS, PHY_CR_SPEED_SEL_H_LEN, high_bit);
regval = FXGMAC_SET_REG_BITS(regval, PHY_CR_SPEED_SEL_L_POS, PHY_CR_SPEED_SEL_L_LEN, low_bit);
hw_ops->write_ephy_reg(pdata, REG_MII_BMCR, regval);
}
void fxgmac_phy_force_duplex(struct fxgmac_pdata *pdata, int duplex)
{
struct fxgmac_hw_ops* hw_ops = &pdata->hw_ops;
u32 regval = 0;
hw_ops->read_ephy_reg(pdata, REG_MII_BMCR, &regval);
regval = FXGMAC_SET_REG_BITS(regval, PHY_CR_DUPLEX_POS, PHY_CR_DUPLEX_LEN, (duplex ? 1 : 0));
hw_ops->write_ephy_reg(pdata, REG_MII_BMCR, regval);
}
void fxgmac_phy_force_autoneg(struct fxgmac_pdata *pdata, int autoneg)
{
struct fxgmac_hw_ops* hw_ops = &pdata->hw_ops;
u32 regval = 0;
hw_ops->read_ephy_reg(pdata, REG_MII_BMCR, &regval);
regval = FXGMAC_SET_REG_BITS(regval, PHY_CR_AUTOENG_POS, PHY_CR_AUTOENG_LEN, (autoneg? 1 : 0));
hw_ops->write_ephy_reg(pdata, REG_MII_BMCR, regval);
}
/*
* input: lport
* output:
* cap_mask, bit definitions:
* pause capbility and 100/10 capbilitys follow the definition of mii reg4.
* for 1000M capability, bit0=1000M half; bit1=1000M full, refer to mii reg9.[9:8].
*/
int fxgmac_ephy_autoneg_ability_get(struct fxgmac_pdata *pdata, unsigned int *cap_mask)
{
struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops;
unsigned int val;
unsigned int reg;
if((!hw_ops->read_ephy_reg) || (!hw_ops->write_ephy_reg))
return -1;
reg = REG_MII_ADVERTISE;
if(hw_ops->read_ephy_reg(pdata, reg, &val) < 0)
goto busy_exit;
//DPRINTK("fxgmac_ephy_autoneg_ability_get, reg %d=0x%04x\n", reg, val);
if(FXGMAC_ADVERTISE_10HALF & val)
{
*cap_mask |= FXGMAC_ADVERTISE_10HALF;
}
else
{
*cap_mask &= ~FXGMAC_ADVERTISE_10HALF;
}
if(FXGMAC_ADVERTISE_10FULL & val)
{
*cap_mask |= FXGMAC_ADVERTISE_10FULL;
}
else
{
*cap_mask &= ~FXGMAC_ADVERTISE_10FULL;
}
if(FXGMAC_ADVERTISE_100HALF & val)
{
*cap_mask |= FXGMAC_ADVERTISE_100HALF;
}
else
{
*cap_mask &= ~FXGMAC_ADVERTISE_100HALF;
}
if(FXGMAC_ADVERTISE_100FULL & val)
{
*cap_mask |= FXGMAC_ADVERTISE_100FULL;
}
else
{
*cap_mask &= ~FXGMAC_ADVERTISE_100FULL;
}
if(FXGMAC_ADVERTISE_PAUSE_CAP & val)
{
*cap_mask |= FXGMAC_ADVERTISE_PAUSE_CAP;
}
else
{
*cap_mask &= ~FXGMAC_ADVERTISE_PAUSE_CAP;
}
if(FXGMAC_ADVERTISE_PAUSE_ASYM & val)
{
*cap_mask |= FXGMAC_ADVERTISE_PAUSE_ASYM;
}
else
{
*cap_mask &= ~FXGMAC_ADVERTISE_PAUSE_ASYM;
}
reg = REG_MII_CTRL1000;
if(hw_ops->read_ephy_reg(pdata, reg, &val) < 0)
goto busy_exit;
//DPRINTK("fxgmac_ephy_autoneg_ability_get, reg %d=0x%04x\n", reg, val);
if(REG_BIT_ADVERTISE_1000HALF & val )
{
*cap_mask |= FXGMAC_ADVERTISE_1000HALF;
}
else
{
*cap_mask &= ~FXGMAC_ADVERTISE_1000HALF;
}
if(REG_BIT_ADVERTISE_1000FULL & val )
{
*cap_mask |= FXGMAC_ADVERTISE_1000FULL;
}
else
{
*cap_mask &= ~FXGMAC_ADVERTISE_1000FULL;
}
//DPRINTK("fxgmac_ephy_autoneg_ability_get done, 0x%08x.\n", *cap_mask);
return 0;
busy_exit:
DPRINTK("fxgmac_ephy_autoneg_ability_get exit due to ephy reg access fail.\n");
return -1;
}
/* 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;
//DPRINTK ("8614 status adjust call in...\n");
*speed = -1;
*duplex = (val & BIT(FUXI_EPHY_DUPLEX_BIT)) >> FUXI_EPHY_DUPLEX_BIT;
speed_mode = (val & FUXI_EPHY_SPEED_MODE) >> FUXI_EPHY_SPEED_MODE_BIT;
switch (speed_mode) {
case 0:
if (is_utp)
*speed = SPEED_10M;
break;
case 1:
*speed = SPEED_100M;
break;
case 2:
*speed = SPEED_1000M;
break;
case 3:
break;
default:
break;
}
//DPRINTK (KERN_INFO "8521 status adjust call out,regval=0x%04x,mode=%s,speed=%dm...\n", val,is_utp?"utp":"fiber", phydev->speed);
return 0;
}
int fxgmac_ephy_soft_reset(struct fxgmac_pdata *pdata)
{
struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops;
int ret;
volatile unsigned int val;
int busy = 15;
ret = hw_ops->read_ephy_reg(pdata, REG_MII_BMCR, (unsigned int *)&val);
if (0 > ret)
goto busy_exit;
ret = hw_ops->write_ephy_reg(pdata, REG_MII_BMCR, (val | 0x8000));
if (0 > ret)
goto busy_exit;
do {
ret = hw_ops->read_ephy_reg(pdata, REG_MII_BMCR, (unsigned int *)&val);
busy--;
//DPRINTK("fxgmac_ephy_soft_reset, check busy=%d.\n", busy);
}while((ret >= 0) && (0 != (val & 0x8000)) && (busy));
if(0 == (val & 0x8000)) return 0;
DPRINTK("fxgmac_ephy_soft_reset, timeout, busy=%d.\n", busy);
return -EBUSY;
busy_exit:
DPRINTK("fxgmac_ephy_soft_reset exit due to ephy reg access fail.\n");
return ret;
}
/*
* this function for polling to get status of ephy link.
* output:
* speed: SPEED_10M, SPEED_100M, SPEED_1000M or -1;
* duplex: 0 or 1, see reg 0x11, bit YT8614_DUPLEX_BIT.
* ret_link: 0 or 1, link down or up.
* media: only valid when ret_link=1, (YT8614_SMI_SEL_SDS_SGMII + 1) for fiber; (YT8614_SMI_SEL_PHY + 1) for utp. -1 for link down.
*/
int fxgmac_ephy_status_get(struct fxgmac_pdata *pdata, int* speed, int* duplex, int* ret_link, int *media)
{
struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops;
int ret;
u16 reg;
volatile unsigned int val;
volatile int link;
int link_utp = 0, link_fiber = 0;
reg = REG_MII_SPEC_STATUS;
ret = hw_ops->read_ephy_reg(pdata, reg, (unsigned int *)&val);
if (0 > ret)
goto busy_exit;
link = val & (BIT(FUXI_EPHY_LINK_STATUS_BIT));
if (link) {
link_utp = 1;
fxgmac_ephy_adjust_status(0, val, 1, speed, duplex);
} else {
link_utp = 0;
}
if (link_utp || link_fiber) {
/* case of fiber of priority */
if(link_utp) *media = (FUXI_EPHY_SMI_SEL_PHY + 1);
if(link_fiber) *media = (FUXI_EPHY_SMI_SEL_SDS_SGMII + 1);
*ret_link = 1;
} else
{
*ret_link = 0;
*media = -1;
*speed= -1;
*duplex = -1;
}
//DPRINTK (KERN_INFO "8614 read status call out,link=%d,linkmode=%d\n", ret_link, link_mode_8614[lport] );
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
**/
static void fxgmac_phy_update_link(struct net_device *netdev)
{
struct fxgmac_pdata *pdata = netdev_priv(netdev);
struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops;
bool b_linkup = false;
u32 phy_speed = 0, ephy_val1, ephy_val2;
u32 pre_phy_speed = 0xff;
if (hw_ops->get_xlgmii_phy_status) {
hw_ops->get_xlgmii_phy_status(pdata, (u32*)&phy_speed, (bool *)&b_linkup, 0);
} else {
/* always assume link is down, if no check link function */
}
pre_phy_speed = ((SPEED_1000 == pdata->phy_speed) ? 2 : ((SPEED_100 == pdata->phy_speed) ? 1 : 0) );
if(pre_phy_speed != phy_speed)
{
DPRINTK("fuxi_phy link phy speed changed,%d->%d\n", pre_phy_speed, phy_speed);
switch(phy_speed){
case 2:
pdata->phy_speed = SPEED_1000;
break;
case 1:
pdata->phy_speed = SPEED_100;
break;
case 0:
pdata->phy_speed = SPEED_10;
break;
default:
pdata->phy_speed = SPEED_1000;
break;
}
fxgmac_config_mac_speed(pdata);
pre_phy_speed = phy_speed;
}
if(pdata->phy_link != b_linkup)
{
pdata->phy_link = b_linkup;
fxgmac_act_phy_link(pdata);
if(b_linkup && (hw_ops->read_ephy_reg))
{
hw_ops->read_ephy_reg(pdata, 0x1/* ephy latched status */, (unsigned int *)&ephy_val1);
hw_ops->read_ephy_reg(pdata, 0x1/* ephy latched status */, (unsigned int *)&ephy_val2);
DPRINTK("%s phy reg1=0x%04x, 0x%04x\n", __FUNCTION__, ephy_val1 & 0xffff, ephy_val2 & 0xffff);
/* phy reg 1 bit2: link state */
if((ephy_val1 & 0x4) != (ephy_val2 & 0x4))
{
pdata->stats.ephy_link_change_cnt++;
}
}
}
}
#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, phy_poll_tm);
#else
struct fxgmac_pdata *pdata = (struct fxgmac_pdata*)data;
#endif
if(NULL == pdata->netdev)
{
DPRINTK("fuxi_phy_timer polling with NULL netdev %lx\n",(unsigned long)(pdata->netdev));
return;
}
pdata->stats.ephy_poll_timer_cnt++;
#if FXGMAC_PM_FEATURE_ENABLED
/* 20210709 for net power down */
if(!test_bit(FXGMAC_POWER_STATE_DOWN, &pdata->powerstate))
#endif
{
//yzhang if(2 > pdata->stats.ephy_poll_timer_cnt)
{
mod_timer(&pdata->phy_poll_tm,jiffies + HZ / 2);
}
fxgmac_phy_update_link(pdata->netdev);
}else {
DPRINTK("fuxi_phy_timer polling, powerstate changed, %ld, netdev=%lx, tm=%lx\n", pdata->powerstate, (unsigned long)(pdata->netdev), (unsigned long)&pdata->phy_poll_tm);
}
//DPRINTK("fuxi_phy_timer polled,%d\n",cnt_polling);
}
/*
* used when fxgmac is powerdown and resume
* 20210709 for net power down
*/
void fxgmac_phy_timer_resume(struct fxgmac_pdata *pdata)
{
if(NULL == pdata->netdev)
{
DPRINTK("fxgmac_phy_timer_resume, failed due to NULL netdev %lx\n",(unsigned long)(pdata->netdev));
return;
}
mod_timer(&pdata->phy_poll_tm,jiffies + HZ / 2);
DPRINTK("fxgmac_phy_timer_resume ok, fxgmac powerstate=%ld, netdev=%lx, tm=%lx\n", pdata->powerstate, (unsigned long)(pdata->netdev), (unsigned long)&pdata->phy_poll_tm);
}
int fxgmac_phy_timer_init(struct fxgmac_pdata *pdata)
{
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,15,0))
init_timer_key(&pdata->phy_poll_tm,NULL/*function*/,0/*flags*/,"fuxi_phy_link_update_timer"/*name*/,NULL/*class lock key*/);
#else
init_timer_key(&pdata->phy_poll_tm,0/*flags*/,"fuxi_phy_link_update_timer"/*name*/,NULL/*class lock key*/);
#endif
pdata->phy_poll_tm.expires = jiffies + HZ / 2;
pdata->phy_poll_tm.function = (void *)(fxgmac_phy_link_poll);
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,15,0))
pdata->phy_poll_tm.data = (unsigned long)pdata;
#endif
add_timer(&pdata->phy_poll_tm);
DPRINTK("fuxi_phy_timer started, %lx\n", jiffies);
return 0;
}
void fxgmac_phy_timer_destroy(struct fxgmac_pdata *pdata)
{
del_timer_sync(&pdata->phy_poll_tm);
DPRINTK("fuxi_phy_timer removed\n");
}
/*++
Copyright (c) 2021 Motor-comm Corporation.
Confidential and Proprietary. All rights reserved.
This is Motor-comm Corporation NIC driver relevant files. Please don't copy, modify,
distribute without commercial permission.
--*/
#include <linux/timer.h>
#include <linux/module.h>
#include "fuxi-gmac.h"
#include "fuxi-gmac-reg.h"
void fxgmac_phy_force_speed(struct fxgmac_pdata *pdata, int speed)
{
struct fxgmac_hw_ops* hw_ops = &pdata->hw_ops;
u32 regval = 0;
unsigned int high_bit = 0, low_bit = 0;
switch (speed)
{
case SPEED_1000:
high_bit = 1, low_bit = 0;
break;
case SPEED_100:
high_bit = 0, low_bit = 1;
break;
case SPEED_10:
high_bit = 0, low_bit = 0;
break;
default:
break;
}
/* disable autoneg */
hw_ops->read_ephy_reg(pdata, REG_MII_BMCR, &regval);
regval = FXGMAC_SET_REG_BITS(regval, PHY_CR_AUTOENG_POS, PHY_CR_AUTOENG_LEN, 0);
regval = FXGMAC_SET_REG_BITS(regval, PHY_CR_SPEED_SEL_H_POS, PHY_CR_SPEED_SEL_H_LEN, high_bit);
regval = FXGMAC_SET_REG_BITS(regval, PHY_CR_SPEED_SEL_L_POS, PHY_CR_SPEED_SEL_L_LEN, low_bit);
hw_ops->write_ephy_reg(pdata, REG_MII_BMCR, regval);
}
void fxgmac_phy_force_duplex(struct fxgmac_pdata *pdata, int duplex)
{
struct fxgmac_hw_ops* hw_ops = &pdata->hw_ops;
u32 regval = 0;
hw_ops->read_ephy_reg(pdata, REG_MII_BMCR, &regval);
regval = FXGMAC_SET_REG_BITS(regval, PHY_CR_DUPLEX_POS, PHY_CR_DUPLEX_LEN, (duplex ? 1 : 0));
hw_ops->write_ephy_reg(pdata, REG_MII_BMCR, regval);
}
void fxgmac_phy_force_autoneg(struct fxgmac_pdata *pdata, int autoneg)
{
struct fxgmac_hw_ops* hw_ops = &pdata->hw_ops;
u32 regval = 0;
hw_ops->read_ephy_reg(pdata, REG_MII_BMCR, &regval);
regval = FXGMAC_SET_REG_BITS(regval, PHY_CR_AUTOENG_POS, PHY_CR_AUTOENG_LEN, (autoneg? 1 : 0));
hw_ops->write_ephy_reg(pdata, REG_MII_BMCR, regval);
}
/*
* input: lport
* output:
* cap_mask, bit definitions:
* pause capbility and 100/10 capbilitys follow the definition of mii reg4.
* for 1000M capability, bit0=1000M half; bit1=1000M full, refer to mii reg9.[9:8].
*/
int fxgmac_ephy_autoneg_ability_get(struct fxgmac_pdata *pdata, unsigned int *cap_mask)
{
struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops;
unsigned int val;
unsigned int reg;
if((!hw_ops->read_ephy_reg) || (!hw_ops->write_ephy_reg))
return -1;
reg = REG_MII_ADVERTISE;
if(hw_ops->read_ephy_reg(pdata, reg, &val) < 0)
goto busy_exit;
//DPRINTK("fxgmac_ephy_autoneg_ability_get, reg %d=0x%04x\n", reg, val);
if(FXGMAC_ADVERTISE_10HALF & val)
{
*cap_mask |= FXGMAC_ADVERTISE_10HALF;
}
else
{
*cap_mask &= ~FXGMAC_ADVERTISE_10HALF;
}
if(FXGMAC_ADVERTISE_10FULL & val)
{
*cap_mask |= FXGMAC_ADVERTISE_10FULL;
}
else
{
*cap_mask &= ~FXGMAC_ADVERTISE_10FULL;
}
if(FXGMAC_ADVERTISE_100HALF & val)
{
*cap_mask |= FXGMAC_ADVERTISE_100HALF;
}
else
{
*cap_mask &= ~FXGMAC_ADVERTISE_100HALF;
}
if(FXGMAC_ADVERTISE_100FULL & val)
{
*cap_mask |= FXGMAC_ADVERTISE_100FULL;
}
else
{
*cap_mask &= ~FXGMAC_ADVERTISE_100FULL;
}
if(FXGMAC_ADVERTISE_PAUSE_CAP & val)
{
*cap_mask |= FXGMAC_ADVERTISE_PAUSE_CAP;
}
else
{
*cap_mask &= ~FXGMAC_ADVERTISE_PAUSE_CAP;
}
if(FXGMAC_ADVERTISE_PAUSE_ASYM & val)
{
*cap_mask |= FXGMAC_ADVERTISE_PAUSE_ASYM;
}
else
{
*cap_mask &= ~FXGMAC_ADVERTISE_PAUSE_ASYM;
}
reg = REG_MII_CTRL1000;
if(hw_ops->read_ephy_reg(pdata, reg, &val) < 0)
goto busy_exit;
//DPRINTK("fxgmac_ephy_autoneg_ability_get, reg %d=0x%04x\n", reg, val);
if(REG_BIT_ADVERTISE_1000HALF & val )
{
*cap_mask |= FXGMAC_ADVERTISE_1000HALF;
}
else
{
*cap_mask &= ~FXGMAC_ADVERTISE_1000HALF;
}
if(REG_BIT_ADVERTISE_1000FULL & val )
{
*cap_mask |= FXGMAC_ADVERTISE_1000FULL;
}
else
{
*cap_mask &= ~FXGMAC_ADVERTISE_1000FULL;
}
//DPRINTK("fxgmac_ephy_autoneg_ability_get done, 0x%08x.\n", *cap_mask);
return 0;
busy_exit:
DPRINTK("fxgmac_ephy_autoneg_ability_get exit due to ephy reg access fail.\n");
return -1;
}
int fxgmac_ephy_soft_reset(struct fxgmac_pdata *pdata)
{
struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops;
int ret;
volatile unsigned int val;
int busy = 15;
ret = hw_ops->read_ephy_reg(pdata, REG_MII_BMCR, (unsigned int *)&val);
if (0 > ret)
goto busy_exit;
ret = hw_ops->write_ephy_reg(pdata, REG_MII_BMCR, (val | 0x8000));
if (0 > ret)
goto busy_exit;
do {
ret = hw_ops->read_ephy_reg(pdata, REG_MII_BMCR, (unsigned int *)&val);
busy--;
//DPRINTK("fxgmac_ephy_soft_reset, check busy=%d.\n", busy);
}while((ret >= 0) && (0 != (val & 0x8000)) && (busy));
if(0 == (val & 0x8000)) return 0;
DPRINTK("fxgmac_ephy_soft_reset, timeout, busy=%d.\n", busy);
return -EBUSY;
busy_exit:
DPRINTK("fxgmac_ephy_soft_reset exit due to ephy reg access fail.\n");
return ret;
}
/* this function used to double check the speed. for fiber, to correct there is no 10M */
static int fxgmac_ephy_adjust_status(u32 lport, int val, int is_utp, int* speed, int* duplex)
{
int speed_mode;
*speed = -1;
*duplex = (val & BIT(FUXI_EPHY_DUPLEX_BIT)) >> FUXI_EPHY_DUPLEX_BIT;
speed_mode = (val & FUXI_EPHY_SPEED_MODE) >> FUXI_EPHY_SPEED_MODE_BIT;
switch (speed_mode) {
case 0:
if (is_utp)
*speed = SPEED_10M;
break;
case 1:
*speed = SPEED_100M;
break;
case 2:
*speed = SPEED_1000M;
break;
case 3:
break;
default:
break;
}
return 0;
}
/*
* this function for polling to get status of ephy link.
* output:
* speed: SPEED_10M, SPEED_100M, SPEED_1000M or -1;
* duplex: 0 or 1, see reg 0x11, bit YT8614_DUPLEX_BIT.
* ret_link: 0 or 1, link down or up.
* media: only valid when ret_link=1, (YT8614_SMI_SEL_SDS_SGMII + 1) for fiber; (YT8614_SMI_SEL_PHY + 1) for utp. -1 for link down.
*/
int fxgmac_ephy_status_get(struct fxgmac_pdata *pdata, int* speed, int* duplex, int* ret_link, int *media)
{
struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops;
int ret;
u16 reg;
volatile unsigned int val;
volatile int link;
int link_utp = 0, link_fiber = 0;
reg = REG_MII_SPEC_STATUS;
ret = hw_ops->read_ephy_reg(pdata, reg, (unsigned int *)&val);
if (0 > ret)
goto busy_exit;
link = val & (BIT(FUXI_EPHY_LINK_STATUS_BIT));
if (link) {
link_utp = 1;
fxgmac_ephy_adjust_status(0, val, 1, speed, duplex);
} else {
link_utp = 0;
}
if (link_utp || link_fiber) {
/* case of fiber of priority */
if(link_utp) *media = (FUXI_EPHY_SMI_SEL_PHY + 1);
if(link_fiber) *media = (FUXI_EPHY_SMI_SEL_SDS_SGMII + 1);
*ret_link = 1;
} else
{
*ret_link = 0;
*media = -1;
*speed= -1;
*duplex = -1;
}
return 0;
busy_exit:
DPRINTK("fxgmac_ephy_status_get exit due to ephy reg access fail.\n");
return ret;
}
#if 0
/**
* fxgmac_phy_update_link - update the phy link status
* @adapter: pointer to the device adapter structure
**/
static void fxgmac_phy_update_link(struct net_device *netdev)
{
struct fxgmac_pdata *pdata = netdev_priv(netdev);
struct fxgmac_hw_ops *hw_ops = &pdata->hw_ops;
bool b_linkup = false;
u32 phy_speed = 0, ephy_val1, ephy_val2;
u32 pre_phy_speed = 0xff;
if (hw_ops->get_xlgmii_phy_status) {
hw_ops->get_xlgmii_phy_status(pdata, (u32*)&phy_speed, (bool *)&b_linkup, 0);
} else {
/* always assume link is down, if no check link function */
}
pre_phy_speed = ((SPEED_1000 == pdata->phy_speed) ? 2 : ((SPEED_100 == pdata->phy_speed) ? 1 : 0) );
if(pre_phy_speed != phy_speed)
{
DPRINTK("fuxi_phy link phy speed changed,%d->%d\n", pre_phy_speed, phy_speed);
switch(phy_speed){
case 2:
pdata->phy_speed = SPEED_1000;
break;
case 1:
pdata->phy_speed = SPEED_100;
break;
case 0:
pdata->phy_speed = SPEED_10;
break;
default:
pdata->phy_speed = SPEED_1000;
break;
}
fxgmac_config_mac_speed(pdata);
pre_phy_speed = phy_speed;
}
if(pdata->phy_link != b_linkup)
{
pdata->phy_link = b_linkup;
fxgmac_act_phy_link(pdata);
if(b_linkup && (hw_ops->read_ephy_reg))
{
hw_ops->read_ephy_reg(pdata, 0x1/* ephy latched status */, (unsigned int *)&ephy_val1);
hw_ops->read_ephy_reg(pdata, 0x1/* ephy latched status */, (unsigned int *)&ephy_val2);
DPRINTK("%s phy reg1=0x%04x, 0x%04x\n", __FUNCTION__, ephy_val1 & 0xffff, ephy_val2 & 0xffff);
}
}
}
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,15,0))
static void fxgmac_phy_link_poll(struct timer_list *t)
#else
static void fxgmac_phy_link_poll(unsigned long data)
#endif
{
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,15,0))
struct fxgmac_pdata *pdata = from_timer(pdata, t, expansion.phy_poll_tm);
#else
struct fxgmac_pdata *pdata = (struct fxgmac_pdata*)data;
#endif
if(NULL == pdata->netdev)
{
DPRINTK("fuxi_phy_timer polling with NULL netdev %lx\n",(unsigned long)(pdata->netdev));
return;
}
pdata->stats.ephy_poll_timer_cnt++;
#if FXGMAC_PM_FEATURE_ENABLED
/* 20210709 for net power down */
if(!test_bit(FXGMAC_POWER_STATE_DOWN, &pdata->expansion.powerstate))
#endif
{
//yzhang if(2 > pdata->stats.ephy_poll_timer_cnt)
{
mod_timer(&pdata->phy_poll_tm,jiffies + HZ / 2);
}
fxgmac_phy_update_link(pdata->netdev);
}else {
DPRINTK("fuxi_phy_timer polling, powerstate changed, %ld, netdev=%lx, tm=%lx\n", pdata->expansion.powerstate, (unsigned long)(pdata->netdev), (unsigned long)&pdata->phy_poll_tm);
}
//DPRINTK("fuxi_phy_timer polled,%d\n",cnt_polling);
}
/*
* used when fxgmac is powerdown and resume
* 20210709 for net power down
*/
void fxgmac_phy_timer_resume(struct fxgmac_pdata *pdata)
{
if(NULL == pdata->netdev)
{
DPRINTK("fxgmac_phy_timer_resume, failed due to NULL netdev %lx\n",(unsigned long)(pdata->netdev));
return;
}
mod_timer(&pdata->phy_poll_tm,jiffies + HZ / 2);
DPRINTK("fxgmac_phy_timer_resume ok, fxgmac powerstate=%ld, netdev=%lx, tm=%lx\n", pdata->expansion.powerstate, (unsigned long)(pdata->netdev), (unsigned long)&pdata->phy_poll_tm);
}
int fxgmac_phy_timer_init(struct fxgmac_pdata *pdata)
{
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,15,0))
init_timer_key(&pdata->phy_poll_tm,NULL/*function*/,0/*flags*/,"fuxi_phy_link_update_timer"/*name*/,NULL/*class lock key*/);
#else
init_timer_key(&pdata->phy_poll_tm,0/*flags*/,"fuxi_phy_link_update_timer"/*name*/,NULL/*class lock key*/);
#endif
pdata->phy_poll_tm.expires = jiffies + HZ / 2;
pdata->phy_poll_tm.function = (void *)(fxgmac_phy_link_poll);
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,15,0))
pdata->phy_poll_tm.data = (unsigned long)pdata;
#endif
add_timer(&pdata->phy_poll_tm);
DPRINTK("fuxi_phy_timer started, %lx\n", jiffies);
return 0;
}
void fxgmac_phy_timer_destroy(struct fxgmac_pdata *pdata)
{
del_timer_sync(&pdata->phy_poll_tm);
DPRINTK("fuxi_phy_timer removed\n");
}
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,24 +1,560 @@
/*++
Copyright (c) 2021 Motor-comm Corporation.
Confidential and Proprietary. All rights reserved.
This is Motor-comm Corporation NIC driver relevant files. Please don't copy, modify,
distribute without commercial permission.
--*/
#ifndef __FUXI_OS_H__
#define __FUXI_OS_H__
#define LINUX
#define PCIE_LP_ASPM_L0S 1
#define PCIE_LP_ASPM_L1 2
#define PCIE_LP_ASPM_L1SS 4
#define PCIE_LP_ASPM_LTR 8
#endif //__FUXI_OS_H__
/*++
Copyright (c) 2021 Motor-comm Corporation.
Confidential and Proprietary. All rights reserved.
This is Motor-comm Corporation NIC driver relevant files.
Please don't copy, modify,distribute without commercial permission.
--*/
#ifndef __FUXI_OS_H__
#define __FUXI_OS_H__
#include <linux/dma-mapping.h>
#include <linux/netdevice.h>
#include <linux/workqueue.h>
#include <linux/phy.h>
#include <linux/if_vlan.h>
#include <linux/bitops.h>
#include <linux/timecounter.h>
#ifdef CONFIG_PCI_MSI
#include <linux/pci.h>
#endif
#include <linux/pm_wakeup.h>
#include <linux/mdio.h>
#include <linux/clk.h>
#include <linux/bitrev.h>
#include <linux/crc32.h>
#include <linux/dcbnl.h>
#include <linux/inet.h>
#define LINUX
#ifndef LINUX_VERSION_CODE
#include <linux/version.h>
#else
#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
#endif
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,19,0))
#include <linux/crc32poly.h>
#endif
#include "fuxi-dbg.h"
struct fxgmac_ring;
struct fxgmac_pdata;
#define FXGMAC_DRV_VERSION "1.0.27"
#ifdef CONFIG_PCI_MSI
//#undef CONFIG_PCI_MSI //undefined for legacy interupt mode
#endif
#define PCIE_LP_ASPM_L0S 1
#define PCIE_LP_ASPM_L1 2
#define PCIE_LP_ASPM_L1SS 4
#define PCIE_LP_ASPM_LTR 8
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,19,0))
/*
* There are multiple 16-bit CRC polynomials in common use, but this is
* *the* standard CRC-32 polynomial, first popularized by Ethernet.
* x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x^1+x^0
*/
#define CRC32_POLY_LE 0xedb88320
#define CRC32_POLY_BE 0x04c11db7
/*
* This is the CRC32c polynomial, as outlined by Castagnoli.
* x^32+x^28+x^27+x^26+x^25+x^23+x^22+x^20+x^19+x^18+x^14+x^13+x^11+x^10+x^9+
* x^8+x^6+x^0
*/
#define CRC32C_POLY_LE 0x82F63B78
#endif
#define FXGMAC_FAIL -1
#define FXGMAC_SUCCESS 0
#define FXGMAC_DEV_CMD (SIOCDEVPRIVATE + 1)
#define FXGMAC_IOCTL_DFS_COMMAND _IOWR('M', 0x80, struct ext_ioctl_data)
#define FXGMAC_MAX_DBG_TEST_PKT 150
#define FXGMAC_MAX_DBG_BUF_LEN 64000
#define FXGMAC_MAX_DBG_RX_DATA 1600
#define FXGMAC_NETDEV_OPS_BUF_LEN 256
#define FXGMAC_TEST_MAC_HEAD_LEN 14
#define FUXI_PM_WPI_READ_FEATURE_EN 1
#define RSS_Q_COUNT 4
//#define FXGMAC_TX_INTERRUPT_EN 1
#define FXGMAC_TX_HANG_TIMER_EN 0
/* only for debug. for normal run, pls keep them both 0 */
//0: use default tx q; other: specify txq-1: 1 txq;
#define FXGMAC_NUM_OF_TX_Q_USED 0
//1 to enable a dummy tx,ie, no tail for gmac;
#define FXGMAC_DUMMY_TX_DEBUG 0
//1 to trigger(write reg 0x1000) for sniffer stop
#define FXGMAC_TRIGGER_TX_HANG 0
/* driver feature configuration */
#if FXGMAC_TX_HANG_TIMER_EN
//0: check hw current desc; 1: check software dirty
#define FXGMAC_TX_HANG_CHECH_DIRTY 0
#endif
// 1:poll tx of 4 channels; 0: since only 1 tx channel supported in this
// version, poll ch 0 always.
#define FXGMAC_FULL_TX_CHANNEL 0
#ifdef CONFIG_ARM64
// when you want to run this driver on 64bit arm,you should open this,otherwise
// dma's mask cannot be set successfully.
#define FUXI_DMA_BIT_MASK 64
#endif
#ifdef CONFIG_PCI_MSI
//should be same as FXGMAC_MAX_DMA_CHANNELS + 1 tx_irq
#define FXGMAC_MAX_MSIX_Q_VECTORS (FXGMAC_MSIX_Q_VECTORS + 1)
#define FXGMAC_MSIX_CH0RXDIS_EN 0 //set to 1 for ch0 unbalance fix;
#define FXGMAC_MSIX_INTCTRL_EN 1
#define FXGMAC_PHY_INT_NUM 1
#define FXGMAC_MSIX_INT_NUMS (FXGMAC_MAX_MSIX_Q_VECTORS + FXGMAC_PHY_INT_NUM)
#else //for case of no CONFIG_PCI_MSI
#define FXGMAC_MSIX_CH0RXDIS_EN 0 //NO modification needed! for non-MSI, set to 0 always
#define FXGMAC_MSIX_INTCTRL_EN 0
#endif
/*RSS features*/
#ifdef FXGMAC_ONE_CHANNEL
#define FXGMAC_RSS_FEATURE_ENABLED 0 // 1:enable rss ; 0: rss not included.
#else
#define FXGMAC_RSS_FEATURE_ENABLED 1 // 1:enable rss ; 0: rss not included.
#endif
#define FXGMAC_RSS_HASH_KEY_LINUX 1 // 0:hard to default rss key ;1: normal hash key process from Linux.
/*WOL features*/
#define FXGMAC_WOL_FEATURE_ENABLED 1 // 1:enable wol ; 0: wol not included.
/*since wol upon link will cause issue, disabled it always. */
#define FXGMAC_WOL_UPON_EPHY_LINK 1 // 1:enable ephy link change wol ; 0: ephy link change wol is not supported.
/*Pause features*/
#define FXGMAC_PAUSE_FEATURE_ENABLED 1 // 1:enable flow control/pause framce ; 0: flow control/pause frame not included.
/*ARP offload engine (AOE)*/
#define FXGMAC_AOE_FEATURE_ENABLED 1 // 1:enable arp offload engine ; 0: aoe is not included.
/*NS offload engine*/
#define FXGMAC_NS_OFFLOAD_ENABLED 1 // 1:enable NS offload for IPv6 ; 0: NS is not included.
/*for fpga ver after, which needs release phy before set of MAC tx/rx */
#define FXGMAC_TXRX_EN_AFTER_PHY_RELEASE 1 // 1:release ephy before mac tx/rx bits are set.
/*power management features*/
#define FXGMAC_PM_FEATURE_ENABLED 1 // 1:enable PM ; 0: PM not included.
/*sanity check*/
#define FXGMAC_SANITY_CHECK_ENABLED 0 // 1:enable health checking ;
/*vlan id filter*/
#define FXGMAC_FILTER_SINGLE_VLAN_ENABLED 1 // 1:enable health checking ;
//Linux driver implement VLAN HASH Table feature to support mutliple VLAN feautre
#define FXGMAC_FILTER_MULTIPLE_VLAN_ENABLED 1
//Linux driver implement MAC HASH Table feature
#define FUXI_MAC_HASH_TABLE 1
//Linux driver implement write multiple mac addr
#define FXGMAC_FILTER_MULTIPLE_MAC_ADDR_ENABLED 1
//Linux driver disable MISC Interrupt
#define FUXI_MISC_INT_HANDLE_FEATURE_EN 1
#define HAVE_FXGMAC_DEBUG_FS
#ifndef offsetof
#define offsetof(TYPE, MEMBER) ((size_t) &(((TYPE*)0)->MEMBER))
#endif
#define ETH_IS_ZEROADDRESS(Address) \
((((u8*)(Address))[0] == ((u8)0x00)) \
&& (((u8*)(Address))[1] == ((u8)0x00)) \
&& (((u8*)(Address))[2] == ((u8)0x00)) \
&& (((u8*)(Address))[3] == ((u8)0x00)) \
&& (((u8*)(Address))[4] == ((u8)0x00)) \
&& (((u8*)(Address))[5] == ((u8)0x00)))
/* read from 8bit register via pci config space */
#define cfg_r8(_pdata, reg, pdat) pci_read_config_byte((_pdata)->pdev, (reg), (u8 *)(pdat))
/* read from 16bit register via pci config space */
#define cfg_r16(_pdata, reg, pdat) pci_read_config_word((_pdata)->pdev, (reg), (u16 *)(pdat))
/* read from 32bit register via pci config space */
#define cfg_r32(_pdata, reg, pdat) pci_read_config_dword((_pdata)->pdev, (reg), (u32 *)(pdat))
/* write to 8bit register via pci config space */
#define cfg_w8(_pdata, reg, val) pci_write_config_byte((_pdata)->pdev, (reg), (u8)(val))
/* write to 16bit register via pci config space */
#define cfg_w16(_pdata, reg, val) pci_write_config_word((_pdata)->pdev, (reg), (u16)(val))
/* write to 32bit register via pci config space */
#define cfg_w32(_pdata, reg, val) pci_write_config_dword((_pdata)->pdev, (reg), (u32)(val))
#define readreg(pAdapter, addr) (readl(addr))
#define writereg(pAdapter, val, addr) (writel(val, addr))
#define usleep_range_ex(pAdapter, a, b) (usleep_range(a, b))
#define _CR(Record, TYPE, Field) ((TYPE *) ((char *) (Record) - (char *) &(((TYPE *) 0)->Field)))
#define FXGMAC_GET_REG_BITS(var, pos, len) ({ \
typeof(pos) _pos = (pos); \
typeof(len) _len = (len); \
((var) & GENMASK(_pos + _len - 1, _pos)) >> (_pos); \
})
#define FXGMAC_GET_REG_BITS_LE(var, pos, len) ({ \
typeof(pos) _pos = (pos); \
typeof(len) _len = (len); \
typeof(var) _var = le32_to_cpu((var)); \
((_var) & GENMASK(_pos + _len - 1, _pos)) >> (_pos); \
})
#define FXGMAC_SET_REG_BITS(var, pos, len, val) ({ \
typeof(var) _var = (var); \
typeof(pos) _pos = (pos); \
typeof(len) _len = (len); \
typeof(val) _val = (val); \
_val = (_val << _pos) & GENMASK(_pos + _len - 1, _pos); \
_var = (_var & ~GENMASK(_pos + _len - 1, _pos)) | _val; \
})
#define FXGMAC_SET_REG_BITS_LE(var, pos, len, val) ({ \
typeof(var) _var = (var); \
typeof(pos) _pos = (pos); \
typeof(len) _len = (len); \
typeof(val) _val = (val); \
_val = (_val << _pos) & GENMASK(_pos + _len - 1, _pos); \
_var = (_var & ~GENMASK(_pos + _len - 1, _pos)) | _val; \
cpu_to_le32(_var); \
})
#define STR_FORMAT "%s"
#define DbgPrintF(level, fmt, ...)
#define DBGPRINT(Level, Fmt)
#define DBGPRINT_RAW(Level, Fmt)
#define DBGPRINT_S(Status, Fmt)
#define DBGPRINT_UNICODE(Level, UString)
#define Dump(p,cb,fAddress,ulGroup)
#undef ASSERT
#define ASSERT(x)
#define DbgPrintOidName(_Oid)
#define DbgPrintAddress(_pAddress)
#define fxgmac_dump_buffer(_skb, _len, _tx_rx)
#define DumpLine(_p, _cbLine, _fAddress, _ulGroup )
#ifndef FXGMAC_DEBUG
#define FXGMAC_DEBUG
#endif
/* For debug prints */
#ifdef FXGMAC_DEBUG
#define FXGMAC_PR(fmt, args...) \
pr_alert("[%s,%d]:" fmt, __func__, __LINE__, ## args)
#define DPRINTK printk
#else
#define FXGMAC_PR(x...) do { } while (0)
#define DPRINTK(x...)
#endif
#define IOC_MAGIC 'M'
#define IOC_MAXNR (0x80 + 5)
#define FUXI_DFS_IOCTL_DEVICE_INACTIVE 0x10001
#define FUXI_DFS_IOCTL_DEVICE_RESET 0x10002
#define FUXI_DFS_IOCTL_DIAG_BEGIN 0x10003
#define FUXI_DFS_IOCTL_DIAG_END 0x10004
#define FUXI_DFS_IOCTL_DIAG_TX_PKT 0x10005
#define FUXI_DFS_IOCTL_DIAG_RX_PKT 0x10006
#define FXGMAC_EFUSE_UPDATE_LED_CFG 0x10007
#define FXGMAC_EFUSE_WRITE_LED 0x10008
#define FXGMAC_EFUSE_WRITE_PATCH_REG 0x10009
#define FXGMAC_EFUSE_WRITE_PATCH_PER_INDEX 0x1000A
#define FXGMAC_EFUSE_WRITE_OOB 0x1000B
#define FXGMAC_EFUSE_LOAD 0x1000C
#define FXGMAC_EFUSE_READ_REGIONABC 0x1000D
#define FXGMAC_EFUSE_READ_PATCH_REG 0x1000E
#define FXGMAC_EFUSE_READ_PATCH_PER_INDEX 0x1000F
#define FXGMAC_EFUSE_LED_TEST 0x10010
#define FXGMAC_GET_MAC_DATA 0x10011
#define FXGMAC_SET_MAC_DATA 0x10012
#define FXGMAC_GET_SUBSYS_ID 0x10013
#define FXGMAC_SET_SUBSYS_ID 0x10014
#define FXGMAC_GET_GMAC_REG 0x10015
#define FXGMAC_SET_GMAC_REG 0x10016
#define FXGMAC_GET_PHY_REG 0x10017
#define FXGMAC_SET_PHY_REG 0x10018
#define FXGMAC_EPHYSTATISTICS 0x10019
#define FXGMAC_GET_STATISTICS 0x1001A
#define FXGMAC_GET_PCIE_LOCATION 0x1001B
#define FXGMAC_GET_GSO_SIZE 0x1001C
#define FXGMAC_SET_GSO_SIZE 0x1001D
#define FXGMAC_SET_RX_MODERATION 0x1001E
#define FXGMAC_SET_TX_MODERATION 0x1001F
#define FXGMAC_GET_TXRX_MODERATION 0x10020
#define MAX_PKT_BUF 1
#define FXGAMC_MAX_DATA_SIZE (1024 * 4 + 16)
#ifndef PCI_CAP_ID_MSI
#define PCI_CAP_ID_MSI 0x05 /* Message Signalled Interrupts */
#endif
#ifndef PCI_CAP_ID_MSIX
#define PCI_CAP_ID_MSIX 0x11 /* MSI-X */
#endif
#define PCI_CAP_ID_MSI_ENABLE_POS 0x10
#define PCI_CAP_ID_MSI_ENABLE_LEN 0x1
#define PCI_CAP_ID_MSIX_ENABLE_POS 0x1F
#define PCI_CAP_ID_MSIX_ENABLE_LEN 0x1
#ifndef fallthrough
#if __has_attribute(__fallthrough__)
# define fallthrough __attribute__((__fallthrough__))
#else
# define fallthrough do {} while (0) /* fallthrough */
#endif
#endif
#pragma pack(1)
// it's better to make this struct's size to 128byte.
struct pattern_packet{
u8 ether_daddr[ETH_ALEN];
u8 ether_saddr[ETH_ALEN];
u16 ether_type;
__be16 ar_hrd; /* format of hardware address */
__be16 ar_pro; /* format of protocol */
unsigned char ar_hln; /* length of hardware address */
unsigned char ar_pln; /* length of protocol address */
__be16 ar_op; /* ARP opcode (command) */
unsigned char ar_sha[ETH_ALEN]; /* sender hardware address */
unsigned char ar_sip[4]; /* sender IP address */
unsigned char ar_tha[ETH_ALEN]; /* target hardware address */
unsigned char ar_tip[4]; /* target IP address */
u8 reverse[86];
};
#pragma pack()
typedef enum
{
CURRENT_STATE_SHUTDOWN = 0,
CURRENT_STATE_RESUME = 1,
CURRENT_STATE_INIT = 2,
CURRENT_STATE_SUSPEND = 3,
CURRENT_STATE_CLOSE = 4,
CURRENT_STATE_OPEN = 5,
CURRENT_STATE_RESTART = 6,
CURRENT_STATE_REMOVE = 7,
}CURRENT_STATE;
typedef dma_addr_t DMA_ADDR_T;
typedef enum pkt_hash_types RSS_HASH_TYPE;
typedef void __iomem* IOMEM;
typedef struct pci_dev PCI_DEV;
struct ext_command_buf {
void* buf;
u32 size_in;
u32 size_out;
};
struct ext_command_mac {
u32 num;
union {
u32 val32;
u16 val16;
u8 val8;
};
};
struct ext_command_mii {
u16 dev;
u16 num;
u16 val;
};
struct ext_ioctl_data {
u32 cmd_type;
struct ext_command_buf cmd_buf;
};
typedef struct _fxgmac_test_buf {
u8* addr;
u32 offset;
u32 length;
} fxgmac_test_buf, *pfxgmac_test_buf;
typedef struct _fxgmac_test_packet {
struct _fxgmac_test_packet * next;
u32 length; /* total length of the packet(buffers) */
u32 type; /* packet type, vlan, ip checksum, TSO, etc. */
fxgmac_test_buf buf[MAX_PKT_BUF];
fxgmac_test_buf sGList[MAX_PKT_BUF];
u16 vlanID;
u16 mss;
u32 hash;
u16 cpuNum;
u16 xsum; /* rx, ip-payload checksum */
u16 csumStart; /* custom checksum offset to the mac-header */
u16 csumPos; /* custom checksom position (to the mac_header) */
void* upLevelReserved[4];
void* lowLevelReserved[4];
} fxgmac_test_packet, *pfxgmac_test_packet;
typedef struct fxgmac_channel_of_platform
{
char dma_irq_name[IFNAMSIZ + 32];
u32 dma_irq_tx; //for MSIx to match the type of struct msix_entry.vector
char dma_irq_name_tx[IFNAMSIZ + 32];
/* Netdev related settings */
struct napi_struct napi_tx;
/* Netdev related settings */
struct napi_struct napi_rx;
struct timer_list tx_timer;
#if FXGMAC_TX_HANG_TIMER_EN
unsigned int tx_hang_timer_active;
struct timer_list tx_hang_timer;
unsigned int tx_hang_hw_cur;
#endif
}FXGMAC_CHANNEL_OF_PLATFORM;
typedef struct per_regisiter_info
{
unsigned int size;
unsigned int address;
unsigned int value;
unsigned char data[FXGAMC_MAX_DATA_SIZE];
}PER_REG_INFO;
// for FXGMAC_EFUSE_WRITE_PATCH_PER_INDEX,val0 is index, val1 is offset,
// val2 is value
typedef struct ext_command_data {
u32 val0;
u32 val1;
u32 val2;
}CMD_DATA;
typedef struct fxgmac_pdata_of_platform
{
u32 cfg_pci_cmd;
u32 cfg_cache_line_size;
u32 cfg_mem_base;
u32 cfg_mem_base_hi;
u32 cfg_io_base;
u32 cfg_int_line;
u32 cfg_device_ctrl1;
u32 cfg_pci_link_ctrl;
u32 cfg_device_ctrl2;
u32 cfg_msix_capability;
struct work_struct restart_work;
u32 int_flags; //legacy, msi or msix
int phy_irq;
#ifdef CONFIG_PCI_MSI
struct msix_entry *msix_entries;
#endif
/* power management and wol*/
u32 wol; //wol options
unsigned long powerstate; //power state
unsigned int ns_offload_tab_idx; //for ns-offload table. 2 entries supported.
CURRENT_STATE current_state;
netdev_features_t netdev_features;
struct napi_struct napi;
struct napi_struct napi_phy;
u32 mgm_intctrl_val;
bool phy_link;
bool fxgmac_test_tso_flag;
u32 fxgmac_test_tso_seg_num;
u32 fxgmac_test_last_tso_len;
u32 fxgmac_test_packet_len;
volatile u32 fxgmac_test_skb_arr_in_index;
volatile u32 fxgmac_test_skb_arr_out_index;
//CMD_DATA ex_cmd_data;
//PER_REG_INFO per_reg_data;
struct sk_buff *fxgmac_test_skb_array[FXGMAC_MAX_DBG_TEST_PKT];
#ifdef HAVE_FXGMAC_DEBUG_FS
struct dentry *dbg_adapter;
struct dentry *fxgmac_dbg_root;
char fxgmac_dbg_netdev_ops_buf[FXGMAC_NETDEV_OPS_BUF_LEN];
#endif
}FXGMAC_PDATA_OF_PLATFORM;
#ifdef HAVE_FXGMAC_DEBUG_FS
void fxgmac_dbg_adapter_init(struct fxgmac_pdata *pdata);
void fxgmac_dbg_adapter_exit(struct fxgmac_pdata *pdata);
void fxgmac_dbg_init(struct fxgmac_pdata *pdata);
void fxgmac_dbg_exit(struct fxgmac_pdata *pdata);
#endif /* HAVE_FXGMAC_DEBUG_FS */
void fxgmac_restart_dev(struct fxgmac_pdata *pdata);
long fxgmac_dbg_netdev_ops_ioctl(struct file *file, unsigned int cmd,
unsigned long arg);
int fxgmac_init(struct fxgmac_pdata *pdata, bool save_private_reg);
/* for phy interface */
int fxgmac_ephy_autoneg_ability_get(struct fxgmac_pdata *pdata,
unsigned int *cap_mask);
int fxgmac_ephy_status_get(struct fxgmac_pdata *pdata, int* speed,
int* duplex, int* ret_link, int *media);
int fxgmac_ephy_soft_reset(struct fxgmac_pdata *pdata);
void fxgmac_phy_force_speed(struct fxgmac_pdata *pdata, int speed);
void fxgmac_phy_force_duplex(struct fxgmac_pdata *pdata, int duplex);
void fxgmac_phy_force_autoneg(struct fxgmac_pdata *pdata, int autoneg);
unsigned int fxgmac_get_netdev_ip4addr(struct fxgmac_pdata *pdata);
unsigned char * fxgmac_get_netdev_ip6addr(struct fxgmac_pdata *pdata,
unsigned char *ipval,
unsigned char *ip6addr_solicited,
unsigned int ifa_flag);
#if FXGMAC_PM_FEATURE_ENABLED
void fxgmac_net_powerdown(struct fxgmac_pdata *pdata, unsigned int wol);
void fxgmac_net_powerup(struct fxgmac_pdata *pdata);
#endif
inline unsigned int fxgmac_tx_avail_desc(struct fxgmac_ring *ring);
inline unsigned int fxgmac_rx_dirty_desc(struct fxgmac_ring *ring);
int fxgmac_start(struct fxgmac_pdata *pdata);
void fxgmac_stop(struct fxgmac_pdata *pdata);
void fxgmac_free_rx_data(struct fxgmac_pdata *pdata);
void fxgmac_free_tx_data(struct fxgmac_pdata *pdata);
#endif //__FUXI_OS_H__