t113i不查网线启动,内核[ cut here ]崩溃问题解决

前言

环境介绍:

1.编译环境

Ubuntu 18.04.5 LTS

2.SDK

T113-i_v1.0

3.单板

迅龙TLT113-EVM-A1.1-000 + 自制底板


# 一、现象

插上网线启动,内核打印信息正常
t113i不查网线启动,内核[ cut here ]崩溃问题解决_第1张图片
不插网线启动,内核存在CPU崩溃打印[ cut here ]
t113i不查网线启动,内核[ cut here ]崩溃问题解决_第2张图片

二、问题根因

根据错误提示找到
/home/zfeng/T113- v1.8/kernel/linux-5.4/drivers/net/phy/phy.c:839 phy stop
phy_stop用于中止soc的gmac与phy的链接。

/**
 * phy_stop - Bring down the PHY link, and stop checking the status
 * @phydev: target phy_device struct
 */
void phy_stop(struct phy_device *phydev)
{
	if (!phy_is_started(phydev)) {
		WARN(1, "called from state %s\n",
		     phy_state_to_str(phydev->state));
		return;
	}

	mutex_lock(&phydev->lock);

	phydev->state = PHY_HALTED;

	mutex_unlock(&phydev->lock);

	phy_state_machine(&phydev->state_queue.work);
	phy_stop_machine(phydev);

	/* Cannot call flush_scheduled_work() here as desired because
	 * of rtnl_lock(), but PHY_HALTED shall guarantee irq handler
	 * will not reenable interrupts.
	 */
}
EXPORT_SYMBOL(phy_stop);

phy_stop该函数在
/home/zfeng/T113-i_v1.0/kernel/linux-5.4/drivers/net/ethernet/allwinner/sunxi-gmac.c→geth_phy_release引用

static int geth_phy_release(struct net_device *ndev)
{
... ...
	/* Stop and disconnect the PHY */
	if (phydev)
		phy_stop(phydev);
... ...
}

而函数geth_phy_release 在static int geth_stop(struct net_device *ndev)、static int geth_open(struct net_device *ndev)都有被引用。

static int geth_stop(struct net_device *ndev)
{
... ...
	/* Release PHY resources */
	geth_phy_release(ndev);
... ...
}
static int geth_open(struct net_device *ndev)
{
... ...
if (!priv->is_suspend) {
	ret = geth_dma_desc_init(ndev);
	if (ret) {
		ret = -EINVAL;
		goto desc_err;//当没插入网线,会执行desc_err 中断网络配置
	}
}
... ...
//该内容被跳过了
if (ndev->phydev)
	phy_start(ndev->phydev);
... ...
desc_err:
geth_phy_release(ndev);
... ...
}

从geth_open函数可以看到,当没插入网线,会执行desc_err 中断网络配置,跳过 phy_start(ndev->phydev),直接执行geth_phy_release的phy_stop(phydev),导致cpu执行了空指针或是空函数出错。
如果从启动正常把网线插入,geth_open将正常执行完,phy_start(ndev->phydev)也会正常执行,这样当将网络down,geth_stop可以正常执行phy_stop不会报错。

三、问题解决

根据上述,只要在geth_phy_release将phy_start(ndev->phydev)有没有正常执行区分开来,就可以轻松把问题解决,增加phy_start_flag标志位。
修改如下:

static int geth_open(struct net_device *ndev)
{	
	... ...
	int phy_start_flag = 0;
	... ... 
	if (ndev->phydev)
	{
		phy_start(ndev->phydev);
		phy_start_flag = 1;
	}
	... ...
desc_err:
	geth_phy_release(ndev, phy_start_flag);
	... ...
}

static int geth_phy_release(struct net_device *ndev, int phy_start_flag)
{
	... ... 
	// /* Stop and disconnect the PHY */
	if (phydev && phy_start_flag)
		phy_stop(phydev);
	 ... ...
}

你可能感兴趣的:(linux,驱动,linux,网络)