[Armadillo:09315] Re: Armadillo-440のLINK/ACTIVITYランプ挙動について

Yanagihara, Kosaku email@hidden
2013年 11月 26日 (火) 19:56:51 JST


柳原です。
古いメールへの自己レスで恐縮ですが、自分としての結論を出しましたので・・・。


仕様か不具合かは判断がつきかねますが、
 ・初めての活性化前 (dev_open()前)
 ・活性化状態 (dev_open()後)
 ・明示的な非活性状態 (dev_close()後)
でランプ挙動が異なるのは、
 ・誤改造ではない (そんとこいじってない)
 ・故障ではない (新品もそうなる)
 ・現状はそういうドライバ実装になっている (以下参照)
と理解し、それを前提にした作り込みにしました。


以下にその根拠を示します。


----------------------------------------------------------------------
ログ出力準備
----------------------------------------------------------------------
以下のようにprintk()を仕込んでビルドします。

-> /linux-2.6.26-at16/net/core/dev.c
int dev_open(struct net_device *dev)
{
		:
	/*
	 *	Call device private open method
	 */
	set_bit(__LINK_STATE_START, &dev->state);
	printk("set_bit(__LINK_STATE_START, &dev->state);\n");
		:
}

->/linux-2.6.26-at16/drivers/net/mx25_fec.c
static void fec_phy_update_linkmode(struct net_device *ndev)
{
		:
	/* check current and old link status */
	old_carrier = netif_carrier_ok(mii->dev) ? 1 : 0;
	new_carrier = (unsigned int) mii_link_ok(mii);
	printk("netif_running=%d old_carrier=%d new_carrier=%d\n",
	       netif_running(mii->dev), old_carrier, new_carrier);

	if (old_carrier == new_carrier)
		return;

	if (old_carrier && !new_carrier) {
		netif_carrier_off(mii->dev);
		fec_priv->link = 0;
		gpio_link_led_inactive();

		pr_info("%s: link down\n", mii->dev->name);

		return;
	}

		:
}


----------------------------------------------------------------------
ログ取り
----------------------------------------------------------------------
1. Linuxを起動して最初のNIC活性化(ip link set eth0 up)の前段階で止める
2. 以下を実行してprintk()の出力を眺める。

# ip link set eth0 up ; sleep 3s ; ip link set eth0 down
set_bit(__LINK_STATE_START, &dev->state);
netif_running=1 old_carrier=1 new_carrier=0
eth0: link down
netif_running=1 old_carrier=0 new_carrier=0
	: (同じ出力のため省略)
netif_running=1 old_carrier=0 new_carrier=0
netif_running=1 old_carrier=0 new_carrier=1
eth0: link up, 100Mbps, full-duplex
netif_running=1 old_carrier=1 new_carrier=1
	: (同じ出力のため省略)
netif_running=1 old_carrier=1 new_carrier=1
clear_bit(__LINK_STATE_START, &dev->state);

ここから分かる事は、
 ・dev_open()以前は、そもそもfec_phy_update_linkmode()は呼ばれない
 ・dev_close()直前のfec_phy_update_linkmode()結果で貼り付く
という点です。

gpio_link_led_inactive()はfec_phy_update_linkmode()以外からは呼ばれない
ことから、
	『明示的にNIC非活性(netドライバがクローズ)状態にした後の
	LINKランプは、非活性化(dev_close())直前の状態に貼り付く』
と理解し、
	『実際の製品でランプ表示したいなら現状を踏まえた作り込みが必要』
という結論に至りました。

なお、ACTIVITYランプはPHYがドライブしているようで、精査していませんが、
少なくとも
 ・初めての活性化(dev_open())前
 ・明示的な非活性化(dev_close())後
を比較すると、
 ・前者はケーブル挿抜に関係なく消灯のまま
 ・後者はケーブル挿抜でトグル
と、明らかに挙動が異なることから、LINK同様、dev_close()に対応した状態変
更処理が『無い』と推測しています。

蛇足ですが、dev_open()・dev_close()近傍ではnew_・old_の関係は逆転してい
るっぽいですね。


----------------------------------------------------------------------
対策例
----------------------------------------------------------------------
C言語プログラムにおいては、ioctl()でIFF_UPフラグで活性状態を確認、
シェルスクリプトでは/sys/class/net/eth0/carrierのリード・エラー有無
で非活性状態を取得するといった対応が考えられます。

/sys/class/net/eth0/carrierについては、以下のようにドライバがオープンさ
れていない時に読み出すと、EINVALが返されるため、例えばcatコマンドは
	# cat /sys/class/net/eth0/carrier
	cat: Read error: Invalid argument
の様なエラーになります。(残念なことにこの時の$?は1になりませんが。)

-> /linux-2.6.26-at16/net/core/net-sysfs.c
static ssize_t show_carrier(struct device *dev,
			    struct device_attribute *attr, char *buf)
{
	struct net_device *netdev = to_net_dev(dev);
	if (netif_running(netdev)) {
		return sprintf(buf, fmt_dec, !!netif_carrier_ok(netdev));
	}
	return -EINVAL;
}

-> /linux-2.6.26-at16/include/linux/netdevice.h
static inline int netif_running(const struct net_device *dev)
{
	return test_bit(__LINK_STATE_START, &dev->state);
}

またまた蛇足ですが、「!!」という書き方は初めて見ました。真値を1に規格化
する手法のようですね。


以上、よろしくお願いします。



armadillo メーリングリストの案内