net: ethernet: motorcomm: Add yt6801 driver

This commit is contained in:
baiywt
2023-11-30 16:36:39 +08:00
committed by Igor
parent 08eb04cd9d
commit d601b058f9
22 changed files with 19349 additions and 0 deletions

View File

@@ -43,6 +43,7 @@ source "drivers/net/ethernet/chelsio/Kconfig"
source "drivers/net/ethernet/cirrus/Kconfig"
source "drivers/net/ethernet/cisco/Kconfig"
source "drivers/net/ethernet/cortina/Kconfig"
source "drivers/net/ethernet/motorcomm/Kconfig"
config CX_ECAT
tristate "Beckhoff CX5020 EtherCAT master support"

View File

@@ -95,3 +95,4 @@ obj-$(CONFIG_NET_VENDOR_XILINX) += xilinx/
obj-$(CONFIG_NET_VENDOR_XIRCOM) += xircom/
obj-$(CONFIG_NET_VENDOR_SYNOPSYS) += synopsys/
obj-$(CONFIG_NET_VENDOR_PENSANDO) += pensando/
obj-$(CONFIG_NET_VENDOR_MOTORCOMM) += motorcomm/

View File

@@ -0,0 +1,18 @@
# SPDX-License-Identifier: GPL-2.0-only
config NET_VENDOR_MOTORCOMM
bool "Motorcomm devices"
default y
help
If you have a network (Ethernet) device belonging to this class, say Y.
Note that the answer to this question doesn't directly affect the
kernel: saying N will just cause the configurator to skip all
the questions about motorcomm devices. If you say Y, you will be asked
for your specific device in the following questions.
if NET_VENDOR_MOTORCOMM
config FUXI
tristate "motorcomm fuxi Ethernet support"
endif #NET_VENDOR_MOTORCOMM

View File

@@ -0,0 +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

View File

@@ -0,0 +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

View File

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

View File

@@ -0,0 +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"

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,271 @@
/*++
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.
#endif // _MP_DBG_H

File diff suppressed because it is too large Load Diff

View File

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

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

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,428 @@
/*++
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");
}

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More