概述
文章目录
- 背景
- 手动测试RX TX的延时值
- 节点确认
- 使用方法
- 扫描delayline窗口效果图
- 代码解析
- 设备树配置
- 相关结构体
- 自动扫描延时
- 驱动代码解析
- 扫描函数解析
背景
最近在调试RK系列的网口,出现网口丢包很严重,或者获取不到IP(手动获取ip也无法ping通外网和内网)等。出现这类问题很大可能是MAC或PHY的延时出现问题,造成收发数据丢包。这时手动调整PHY芯片寄存器收发延时值或者MAC延时值(设备树节点里TX/RX值)很麻烦。我在测试过程中出现由于PCB的原因造成每块板子的延时值不同,需要按照每块板子进行网口延时调整,这样工作量就很大。
为了解决这类问题,RK代码添加回环测试进行手动测试RX/TX延时值,并且集成自动扫描延时值的功能,大大方便调试。(原理:固定PHY芯片的延时(可以将收发延时关掉),调整MAC延时)接下来讲解下相关代码以及使用方法。
手动测试RX TX的延时值
代码实现部分都在 drivers/net/ethernet/stmicro/stmmac/dwmac-rk-tool.c 文件
Kernel-4.4 和 Kernel-3.10版本,测试RX TX 补丁
调整延时值TX/RX补丁资料
Kernel-4.19和之后的版本本身已经包含这部分代码
注:代码需要根据实际的phy进行调整(不通用),不通用的地方代码里有解析
节点确认
新固件(内核)会生成几个sysfs节点,在/sys/devices/platform/fe010000.ethernet/目录下生成几个节点:
使用方法
测试前需要拔掉网线
扫描delayline窗口效果图
代码解析
设备树配置
gmac0: ethernet@fe2a0000 {
compatible = "rockchip,rk3568-gmac", "snps,dwmac-4.20a";
reg = <0x0 0xfe2a0000 0x0 0x10000>;
interrupts = <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "macirq", "eth_wake_irq";
rockchip,grf = <&grf>;
clocks = <&cru SCLK_GMAC0>, <&cru SCLK_GMAC0_RX_TX>,
<&cru SCLK_GMAC0_RX_TX>, <&cru CLK_MAC0_REFOUT>,
<&cru ACLK_GMAC0>, <&cru PCLK_GMAC0>,
<&cru SCLK_GMAC0_RX_TX>, <&cru CLK_GMAC0_PTP_REF>,
<&cru PCLK_XPCS>;
clock-names = "stmmaceth", "mac_clk_rx",
"mac_clk_tx", "clk_mac_refout",
"aclk_mac", "pclk_mac",
"clk_mac_speed", "ptp_ref",
"pclk_xpcs";
resets = <&cru SRST_A_GMAC0>;
reset-names = "stmmaceth";
snps,mixed-burst;
snps,tso;
snps,axi-config = <&gmac0_stmmac_axi_setup>;
snps,mtl-rx-config = <&gmac0_mtl_rx_setup>;
snps,mtl-tx-config = <&gmac0_mtl_tx_setup>;
status = "disabled";
mdio0: mdio {
compatible = "snps,dwmac-mdio";
#address-cells = <0x1>;
#size-cells = <0x0>;
};
gmac0_stmmac_axi_setup: stmmac-axi-config {
snps,wr_osr_lmt = <4>;
snps,rd_osr_lmt = <8>;
snps,blen = <0 0 0 0 16 8 4>;
};
gmac0_mtl_rx_setup: rx-queues-config {
snps,rx-queues-to-use = <1>;
queue0 {};
};
gmac0_mtl_tx_setup: tx-queues-config {
snps,tx-queues-to-use = <1>;
queue0 {};
};
};
&gmac0 {
phy-mode = "rgmii";
clock_in_out = "output";
snps,reset-gpio = <&gpio2 RK_PC5 GPIO_ACTIVE_LOW>; //RK_PB1 RK_PC5
snps,reset-active-low;
snps,reset-delays-us = <0 30000 150000>;
assigned-clocks = <&cru SCLK_GMAC0_RX_TX>, <&cru SCLK_GMAC0>;
assigned-clock-parents = <&cru SCLK_GMAC0_RGMII_SPEED>, <&cru CLK_MAC0_2TOP>;
assigned-clock-rates = <0>, <125000000>;
pinctrl-names = "default";
pinctrl-0 = <&gmac0_miim
&gmac0_tx_bus2
&gmac0_rx_bus2
&gmac0_rgmii_clk
&gmac0_rgmii_bus>;
tx_delay = <0x00>; // TX 发送延时,便于测试
rx_delay = <0x00>; // RX 接受延时,便于测试
phy-handle = <&rgmii_phy0>;
status = "disabled";
};
相关结构体
路径:drivers/net/ethernet/stmicro/stmmac/dwmac-rk-tool.c
// lb私有数据
struct dwmac_rk_lb_priv {
struct dma_desc *dma_tx;
dma_addr_t dma_tx_phy;
struct sk_buff *tx_skbuff;
dma_addr_t tx_skbuff_dma;
unsigned int tx_skbuff_dma_len;
struct dma_desc *dma_rx ____cacheline_aligned_in_smp;
dma_addr_t dma_rx_phy;
struct sk_buff *rx_skbuff;
dma_addr_t rx_skbuff_dma;
u32 rx_tail_addr;
u32 tx_tail_addr;
unsigned int dma_buf_sz; // dma mtu大小
unsigned int buf_sz; // RX 接受FIFO大小
int type; // 回环测试类型(LOOPBACK_TYPE_GMAC LOOPBACK_TYPE_PHY) drivers/net/ethernet/stmicro/stmmac/dwmac-rk-tool.c phy_lb_scan_store
int speed; // 测试速度(10 100 1000) drivers/net/ethernet/stmicro/stmmac/dwmac-rk-tool.c phy_lb_scan_store
struct dwmac_rk_packet_attrs *packet;
unsigned int actual_size;
int scan; // 扫描标志位 drivers/net/ethernet/stmicro/stmmac/dwmac-rk-tool.c phy_lb_scan_store
int sysfs; // 系统文件标志位 drivers/net/ethernet/stmicro/stmmac/dwmac-rk-tool.c phy_lb_scan_store
u32 id;
int tx;
int rx;
int final_tx;
int final_rx;
};
// 接口模式设置 根据设备树phy-mode = "rgmii"定义
typedef enum {
PHY_INTERFACE_MODE_NA,
PHY_INTERFACE_MODE_INTERNAL,
PHY_INTERFACE_MODE_MII,
PHY_INTERFACE_MODE_GMII,
PHY_INTERFACE_MODE_SGMII,
PHY_INTERFACE_MODE_TBI,
PHY_INTERFACE_MODE_REVMII,
PHY_INTERFACE_MODE_RMII,
PHY_INTERFACE_MODE_RGMII,
PHY_INTERFACE_MODE_RGMII_ID,
PHY_INTERFACE_MODE_RGMII_RXID,
PHY_INTERFACE_MODE_RGMII_TXID,
PHY_INTERFACE_MODE_RTBI,
PHY_INTERFACE_MODE_SMII,
PHY_INTERFACE_MODE_XGMII,
PHY_INTERFACE_MODE_MOCA,
PHY_INTERFACE_MODE_QSGMII,
PHY_INTERFACE_MODE_TRGMII,
PHY_INTERFACE_MODE_1000BASEX,
PHY_INTERFACE_MODE_2500BASEX,
PHY_INTERFACE_MODE_RXAUI,
PHY_INTERFACE_MODE_XAUI,
/* 10GBASE-KR, XFI, SFI - single lane 10G Serdes */
PHY_INTERFACE_MODE_10GKR,
PHY_INTERFACE_MODE_MAX,
} phy_interface_t;
路径:drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
static const struct of_device_id rk_gmac_dwmac_match[] = {
{ .compatible = "rockchip,px30-gmac", .data = &px30_ops },
{ .compatible = "rockchip,rk1808-gmac", .data = &rk1808_ops },
{ .compatible = "rockchip,rk3128-gmac", .data = &rk3128_ops },
{ .compatible = "rockchip,rk3228-gmac", .data = &rk3228_ops },
{ .compatible = "rockchip,rk3288-gmac", .data = &rk3288_ops },
{ .compatible = "rockchip,rk3308-mac", .data = &rk3308_ops },
{ .compatible = "rockchip,rk3328-gmac", .data = &rk3328_ops },
{ .compatible = "rockchip,rk3366-gmac", .data = &rk3366_ops },
{ .compatible = "rockchip,rk3368-gmac", .data = &rk3368_ops },
{ .compatible = "rockchip,rk3399-gmac", .data = &rk3399_ops },
{ .compatible = "rockchip,rk3568-gmac", .data = &rk3568_ops },
{ .compatible = "rockchip,rv1108-gmac", .data = &rv1108_ops },
{ .compatible = "rockchip,rv1126-gmac", .data = &rv1126_ops },
{ }
};
MODULE_DEVICE_TABLE(of, rk_gmac_dwmac_match);
static struct platform_driver rk_gmac_dwmac_driver = {
.probe = rk_gmac_probe, // 匹配后调用
.remove = rk_gmac_remove,
.driver = {
.name = "rk_gmac-dwmac",
.pm = &rk_gmac_pm_ops,
.of_match_table = rk_gmac_dwmac_match,
},
};
static const struct net_device_ops stmmac_netdev_ops = {
.ndo_open = stmmac_open,
.ndo_start_xmit = stmmac_xmit,
.ndo_stop = stmmac_release,
.ndo_change_mtu = stmmac_change_mtu,
.ndo_fix_features = stmmac_fix_features,
.ndo_set_features = stmmac_set_features,
.ndo_set_rx_mode = stmmac_set_rx_mode,
.ndo_tx_timeout = stmmac_tx_timeout,
.ndo_do_ioctl = stmmac_ioctl,
.ndo_setup_tc = stmmac_setup_tc,
.ndo_select_queue = stmmac_select_queue,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = stmmac_poll_controller,
#endif
.ndo_set_mac_address = stmmac_set_mac_address,
};
// include/linux/device.h
#define DEVICE_ATTR_RW(_name)
struct device_attribute dev_attr_##_name = __ATTR_RW(_name)
#define DEVICE_ATTR_RO(_name)
struct device_attribute dev_attr_##_name = __ATTR_RO(_name)
#define DEVICE_ATTR_WO(_name)
struct device_attribute dev_attr_##_name = __ATTR_WO(_name)
// include/linux/sysfs.h
#define __ATTR_RO(_name) {
.attr = { .name = __stringify(_name), .mode = 0444 },
.show = _name##_show,
}
#define __ATTR_WO(_name) {
.attr = { .name = __stringify(_name), .mode = 0200 },
.store = _name##_store,
}
#define __ATTR_RW(_name) __ATTR(_name, 0644, _name##_show, _name##_store)
// drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
rk_gmac_probe
-> stmmac_dvr_probe
-> ndev->netdev_ops = &stmmac_netdev_ops; // 网络设备的操作函数
-> dwmac_rk_create_loopback_sysfs // 初始化系统下的文件创建
-> device_create_file(device, &dev_attr_rgmii_delayline); // 创建rgmii_delayline
-> static DEVICE_ATTR_RW(rgmii_delayline);
-> device_create_file(device, &dev_attr_mac_lb); // 创建mac_lb
-> static DEVICE_ATTR_WO(mac_lb);
-> device_create_file(device, &dev_attr_phy_lb); // 创建phy_lb
-> static DEVICE_ATTR_WO(phy_lb);
-> device_create_file(device, &dev_attr_phy_lb_scan); // 创建phy_lb_scan
-> static DEVICE_ATTR_WO(phy_lb_scan);
// drivers/net/ethernet/stmicro/stmmac/dwmac-rk-tool.c
// echo 1000 > phy_lb_scan
phy_lb_scan_store
-> struct net_device *ndev = dev_get_drvdata(dev); // 网络设备
-> struct dwmac_rk_lb_priv *lb_priv; // lb私有数据
-> lb_priv = kzalloc(sizeof(*lb_priv), GFP_KERNEL); // 申请dwmac_rk_lb_priv结构体大小的空间
-> ret = kstrtoint(buf, 0, &speed); // echo 1000 > phy_lb_scan (1000赋值speed)
-> lb_priv->sysfs = 1; // 系统文件标志位为1
-> lb_priv->type = LOOPBACK_TYPE_PHY; // 类型回环PHY
-> lb_priv->speed = speed; // 速度设置1000
-> lb_priv->scan = 1; // 扫描
-> dwmac_rk_loopback_run(priv, lb_priv);
-> phy_iface = dwmac_rk_get_phy_interface(priv); // 获取phy接口 设备树phy-mode = "rgmii" phy_iface=8 "PHY_INTERFACE_MODE_RGMII"
-> ndev_up = ndev->flags & IFF_UP; // 查看网络设备是否正常
-> ndev->netdev_ops->ndo_stop(ndev); // stmmac_release 关闭驱动的入口节点
-> priv->plat->stmmac_rst
-> priv->mii->reset
-> priv->plat->stmmac_rst
-> usleep_range(100000, 200000); // 等待phy和控制器准备
-> dwmac_rk_init // 设置DMA FIFO
-> lb_priv->dma_buf_sz = 1536; // mtu大小 1500
-> lb_priv->buf_sz // rx fifo大小
-> dwmac_rk_alloc_dma_desc_resources // dma描述符申请
-> dwmac_rk_init_dma_desc_rings // 初始化dma描述符
-> dwmac_rk_init_dma_engine // dma配置、TX通道配置、RX通道配置
-> dwmac_rk_set_loopback // 设置回环参数以及使能
-> dwmac_rk_set_phy_loopback // type = LOOPBACK_TYPE_PHY
-> dwmac_rk_enable_phy_loopback // enable = 1 根据传输速度写mac寄存器
-> val = mdiobus_read(priv->mii, 2, MII_BMCR); // 读phy地址2的寄存器0 所有寄存器存在mii.h里,注意:phy的硬件地址一定要对
-> mdiobus_write(priv->mii, 2, MII_BMCR, val); // 设置phy寄存器0为回环模式,写入,这部分每块phy芯片回环值不同需看手册确定是否写入正确
-> dwmac_rk_loopback_delayline_scan(priv, lb_priv); // lb_priv->scan=1
-> dwmac_rk_delayline_scan // delayline窗口扫描
-> 循环发送数据
-> kfree(lb_priv); // 释放结构体
注:代码里提到的回环测试里val值可以参考AR8035芯片解析
循环发送解析
static int dwmac_rk_loopback_delayline_scan(struct stmmac_priv *priv,
struct dwmac_rk_lb_priv *lb_priv)
{
if (lb_priv->sysfs)
return dwmac_rk_delayline_scan(priv, lb_priv);
else
return dwmac_rk_delayline_scan_cross(priv, lb_priv);
}
// lb_priv->sysfs = 1
#define MAX_DELAYLINE 0x7f
static int dwmac_rk_delayline_scan(struct stmmac_priv *priv,
struct dwmac_rk_lb_priv *lb_priv)
{
int tx, rx, tx_sum, rx_sum, count;
int tx_mid, rx_mid;
int ret = -ENXIO;
tx_sum = 0;
rx_sum = 0;
count = 0;
// MAX_DELAYLINE = 0x7f;窗口扫描打印,具体扫描dwmac_rk_loopback_with_identify
// 在循环过程中tx范围0x00-0x7f,rx范围0x00-0x7f,组合循环测试
// mac发数据给phy芯片,phy芯片回复回来的值进行检测对比
// 根据延时发送接收数据无误成功,则返回0
// 具体过程会再开篇分析整个循环过程
for (rx = 0x0; rx <= MAX_DELAYLINE; rx++) {
printk(KERN_CONT "RX(0x%02x):", rx);
for (tx = 0x0; tx <= MAX_DELAYLINE; tx++) {
if (!dwmac_rk_loopback_with_identify(priv,
lb_priv, tx, rx)) {
tx_sum += tx;
rx_sum += rx;
count++;
printk(KERN_CONT "O");
} else {
printk(KERN_CONT " ");
}
}
printk(KERN_CONT "n");
}
// 将所有回环测试成功的延时值相加取平均值,作为最后确定的延时值
if (tx_sum && rx_sum && count) {
tx_mid = tx_sum / count;
rx_mid = rx_sum / count;
if (dwmac_rk_delayline_is_valid(tx_mid, rx_mid)) {
lb_priv->final_tx = tx_mid;
lb_priv->final_rx = rx_mid;
ret = 0;
}
}
if (ret)
pr_err("nCan't find suitable delaylinen");
else
pr_info("nFind suitable tx_delay = 0x%02x, rx_delay = 0x%02xn",
lb_priv->final_tx, lb_priv->final_rx);
return ret;
}
自动扫描延时
补丁(通用,在kernel:4.19.194测试okay )
自动扫描延时值补丁资料
注:该补丁重点针对内核版本为4.19和4.19之后的内核,没有CONFIG_DWMAC_RK_AUTO_DELAYLINE自动扫描配置项。可参考此补丁。
开启自动扫描CONFIG_DWMAC_RK_AUTO_DELAYLINE=y
开辟两个空间用于存放TX/RX延时
驱动代码解析
// arch/arm64/configs/rockchip_linux_defconfig
CONFIG_DWMAC_RK_AUTO_DELAYLINE=y
// drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
// 烧写的时候判断值有没有效,无效扫描,有效跳过扫描
#ifdef CONFIG_DWMAC_RK_AUTO_DELAYLINE
if (!priv->delayline_scanned) {
if (dwmac_rk_get_rgmii_delayline_from_vendor(priv)){
priv->delayline_scanned = true;
schedule_delayed_work(&priv->scan_dwork, msecs_to_jiffies(8000));
}else{
// TX/RX值有效
priv->delayline_scanned = true;
}
}
#endif
// 任务
#ifdef CONFIG_DWMAC_RK_AUTO_DELAYLINE
INIT_DELAYED_WORK(&priv->scan_dwork, stmmac_scan_delayline_dwork);
#endif
// 扫描delayline窗口得到延时值
#ifdef CONFIG_DWMAC_RK_AUTO_DELAYLINE
static void stmmac_scan_delayline_dwork(struct work_struct *work)
{
struct stmmac_priv *priv = container_of(work, struct stmmac_priv,
scan_dwork.work);
dwmac_rk_search_rgmii_delayline(priv);
};
#endif
// include/linux/soc/rockchip/rk_vendor_storage.h
// 用RKDevInfoWriteTool工具新开两个空间
#define LAN_RGMII_DL_ID 16 // eth0 mac地址
#define EINK_VCOM_ID 17 // eth1 mac地址
#define ETH0_DELAY_ID 18 // 用于存放eth0 TX/RX延时值
#define ETH1_DELAY_ID 19 // 用于存放eth1 TX/RX延时值
#ifdef CONFIG_DWMAC_RK_AUTO_DELAYLINE
// 从vendor区获取延时值设置到对应的rgmii中
int dwmac_rk_get_rgmii_delayline_from_vendor(struct stmmac_priv *priv)
{
int phy_iface = dwmac_rk_get_phy_interface(priv); // 获取phy接口类型
unsigned char delayline[2];
int ret;
int vendor_id;
if(!strcmp(priv->dev->name , "eth0")) // 获取传进来的phy是哪一个,赋值对应的vendor_id
vendor_id = ETH0_DELAY_ID;
else if(!strcmp(priv->dev->name , "eth1"))
vendor_id = ETH1_DELAY_ID;
if (phy_iface != PHY_INTERFACE_MODE_RGMII &&
phy_iface != PHY_INTERFACE_MODE_RGMII_ID)
return 0;
memset(delayline, 0x0, sizeof(delayline)); // 为delayline窗口申请空间
ret = rk_vendor_read(vendor_id, delayline, 2); // 读vendor_id 里delayline[0], delayline[1]值
if (ret == 2 &&
dwmac_rk_delayline_is_valid(delayline[0], delayline[1])) { // 判断TX/RX值有效,有效范围00-7f
pr_info("damac rk: read rgmii dl from vendor tx = 0x%02x, rx = 0x%02xn",
delayline[0], delayline[1]);
dwmac_rk_set_rgmii_delayline(priv, delayline[0], delayline[1]); // 写入对应的phy的延时值 bsp_priv->tx_delay = tx_delay; bsp_priv->rx_delay = rx_delay;
return 0;
}
return -ERANGE;
}
int dwmac_rk_search_rgmii_delayline(struct stmmac_priv *priv)
{
struct dwmac_rk_lb_priv *lb_priv;
unsigned char delayline[2];
int ret;
int vendor_id;
lb_priv = kzalloc(sizeof(*lb_priv), GFP_KERNEL);
if (!lb_priv)
return -ENOMEM;
if(!strcmp(priv->dev->name , "eth0"))
vendor_id = ETH0_DELAY_ID;
else if(!strcmp(priv->dev->name , "eth1"))
vendor_id = ETH1_DELAY_ID;
lb_priv->sysfs = 0; // 不以文件系统形式扫描
lb_priv->type = LOOPBACK_TYPE_PHY;
lb_priv->speed = LOOPBACK_SPEED1000;
lb_priv->scan = 1;
ret = dwmac_rk_loopback_run(priv, lb_priv); // 循环测试
if (!ret) {
delayline[0] = lb_priv->final_tx;
delayline[1] = lb_priv->final_rx;
if (rk_vendor_write(vendor_id, delayline, 2)) // 将测试后的值写入vendor区,保存
pr_err("damac rk: write rgmii delayline to vendor failedn");
/* write tx/rx delayline back if loopback okay */
dwmac_rk_set_rgmii_delayline(priv, lb_priv->final_tx, // 回环ok后写入phy延时 bsp_priv->tx_delay = tx_delay; bsp_priv->rx_delay = rx_delay;
lb_priv->final_rx);
}
kfree(lb_priv); // 释放lb_priv结构体
return ret;
}
#endif
扫描函数解析
static int dwmac_rk_loopback_delayline_scan(struct stmmac_priv *priv,
struct dwmac_rk_lb_priv *lb_priv)
{
if (lb_priv->sysfs)
return dwmac_rk_delayline_scan(priv, lb_priv);
else
return dwmac_rk_delayline_scan_cross(priv, lb_priv);
}
// lb_priv->sysfs =0
#define SCAN_STEP 0x1 // 扫描步长为1
#define MAX_DELAYLINE 0x7f
#define SCAN_VALID_RANGE 0xA
static int dwmac_rk_delayline_scan_cross(struct stmmac_priv *priv,
struct dwmac_rk_lb_priv *lb_priv)
{
int tx_left, tx_right, rx_up, rx_down;
int i, j, tx_index, rx_index;
int tx_mid, rx_mid;
/* initiation */
tx_index = SCAN_STEP;
rx_index = SCAN_STEP;
re_scan:
/* start from rx based on the experience */
for (i = rx_index; i <= (MAX_DELAYLINE - SCAN_STEP); i += SCAN_STEP) {
tx_left = 0;
tx_right = 0;
tx_mid = 0;
for (j = tx_index; j <= (MAX_DELAYLINE - SCAN_STEP);
j += SCAN_STEP) {
if (!dwmac_rk_loopback_with_identify(priv,
lb_priv, j, i)) {
if (!tx_left)
tx_left = j;
tx_right = j;
}
}
/* look for tx_mid */
if ((tx_right - tx_left) > SCAN_VALID_RANGE) {
tx_mid = (tx_right + tx_left) / 2;
break;
}
}
/* Worst case: reach the end */
if (i >= (MAX_DELAYLINE - SCAN_STEP))
goto end;
rx_up = 0;
rx_down = 0;
/* look for rx_mid base on the tx_mid */
for (i = SCAN_STEP; i <= (MAX_DELAYLINE - SCAN_STEP);
i += SCAN_STEP) {
if (!dwmac_rk_loopback_with_identify(priv, lb_priv,
tx_mid, i)) {
if (!rx_up)
rx_up = i;
rx_down = i;
}
}
if ((rx_down - rx_up) > SCAN_VALID_RANGE) {
/* Now get the rx_mid */
rx_mid = (rx_up + rx_down) / 2;
} else {
rx_index += SCAN_STEP;
rx_mid = 0;
goto re_scan;
}
if (dwmac_rk_delayline_is_valid(tx_mid, rx_mid)) {
lb_priv->final_tx = tx_mid;
lb_priv->final_rx = rx_mid;
pr_info("Find suitable tx_delay = 0x%02x, rx_delay = 0x%02xn",
lb_priv->final_tx, lb_priv->final_rx);
return 0;
}
end:
pr_err("Can't find suitable delaylinen");
return -ENXIO;
}
注:
1、遇到手动扫描可以使用(网络性能好),但是自动扫描失败,报没有合适的延时值匹配,可以调整步长#define SCAN_STEP 0x5
2、该自动扫描也可以不用RK工具去烧写,只要在vendor区ID分配没有用的区间即可
3、自动扫描只能在emmc全部擦除之后才能用,在使用的过程中不能插网线。(RK一般是将emmc全部擦除,第一次加载固件时不能插网线,后续可以插网线烧写单个镜像)
4、关于vendor分区,为什么要讲扫描出来的值保存在这里?后续文章会更新
最后
以上就是无限洋葱为你收集整理的Linux内核(六)[ RK3568 ] 手动/自动调整千兆网口延时TX RX的全部内容,希望文章能够帮你解决Linux内核(六)[ RK3568 ] 手动/自动调整千兆网口延时TX RX所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复