8139too (2)

先頭を 32-byte 境界にアワせる根拠は未だナゾのまま。
kernel の ML なのかどうか分かりませんが、cache line (64 byte) にアワせるべきかそうでないか、というスレッドは見つけたんですが、32 byte な根拠は微妙。以下が根拠なんですか??

The reason it's 32 is that old drivers depended on the
struct being at least 32-byte aligned because they would
embed structures DMA'd to/from the card in their private
area and just assumed that would be aligned enough for
the card's restrictions.

http://www.mail-archive.com/netdev@vger.kernel.org/msg12380.html より引用

ま、いいや。とりあえず 32 byte な境界整列させてマス、というのは分かったので、もう少し alloc_netdev() を観察。基本的には

  • 確保が必要な領域サイズを計算
  • 領域確保
  • 0 で初期化
  • 先頭を確定して、先頭のパディングな領域サイズを退避
  • priv な領域の確定 (ここも 32-byte で境界整列)
  • setup 呼び出し

最後の strcpy が意味分からんがとりあえずスルー。setup で何してるのか、というと。領域確保した struct net_device な領域を初期化してるんですが具体的にどうか、というと、まず関数ポインタなメンバについて

	dev->change_mtu		= eth_change_mtu;
	dev->hard_header	= eth_header;
	dev->rebuild_header 	= eth_rebuild_header;
	dev->set_mac_address 	= eth_mac_addr;
	dev->hard_header_cache	= eth_header_cache;
	dev->header_cache_update= eth_header_cache_update;
	dev->hard_header_parse	= eth_header_parse;

上記のおそらく同一ソース (net/ethernet/eth.c) な関数を登録している模様。以降の処理は以下。

	dev->type		= ARPHRD_ETHER;
	dev->hard_header_len 	= ETH_HLEN;
	dev->mtu		= 1500; /* eth_mtu */
	dev->addr_len		= ETH_ALEN;
	dev->tx_queue_len	= 1000;	/* Ethernet wants good queues */
	dev->flags		= IFF_BROADCAST|IFF_MULTICAST;
	
	memset(dev->broadcast,0xFF, ETH_ALEN);

なんとなく耳に入るコトが多いソレが列挙されているような気が。とりあえず ethernet な NIC だったら alloc_etherdev() 使えば net_device やドライバ固有の構造体のスペースを確保して ethernet なデフォが設定される訳ですな。
で、alloc_etherdev() を呼び出して戻りをチェックした後に、マクロが二つ。

	SET_MODULE_OWNER(dev);
	SET_NETDEV_DEV(dev, &pdev->dev);

定義元は include/linux/netdevice.h の netdev_priv() 関数が定義されている直下。

#define SET_MODULE_OWNER(dev) do { } while (0)
/* Set the sysfs physical device reference for the network logical device
 * if set prior to registration will cause a symlink during initialization.
 */
#define SET_NETDEV_DEV(net, pdev)	((net)->class_dev.dev = (pdev))

dev->class_dev.dev に pdev->dev のアドレスが設定される模様。
で、多分更新が放置されているんだと思いますが、再度 netdev_priv() が呼び出され、件のドライバ固有の構造体 (ここでは rtl8139_private 型) の pci_dev メンバに引数で受け取った struct pci_dev 型のソレが設定されている。

「PCI デバイス」の有効化

テキスト p.258 な部分に突入。コメントによると

	/* enable device (incl. PCI PM wakeup and hotplug setup) */

との事。テキスト p.259 によれば

「PCI デバイス」の「電源ステータス」を「D0」(フル・パワー) にして、「PCI コンフィグレーション空間」の「コマンド」レジスタに「メモリ空間イネーブル・ビット」および「I/O 空間イネーブル・ビット」を立ます。

amazon: Linux カーネル解析入門 より引用

となっている。現在、関数が定義されている箇所をサーチ中 (ETAGS は NG)。発見された模様。drivers/pci/pci.c か。

/**
 * pci_enable_device - Initialize device before it's used by a driver.
 * @dev: PCI device to be initialized
 *
 *  Initialize device before it's used by a driver. Ask low-level code
 *  to enable I/O and memory. Wake up the device if it was suspended.
 *  Beware, this function can fail.
 */
int
pci_enable_device(struct pci_dev *dev)
{
	int err;

	if ((err = pci_enable_device_bars(dev, (1 << PCI_NUM_RESOURCES) - 1)))
		return err;
	pci_fixup_device(pci_fixup_enable, dev);
	dev->is_enabled = 1;
	return 0;
}

失敗する事もあるから注意せえ、との事。テキストにも戻り値のチェックはしなさい、と書いてあります。で、エラーが戻ってくるかもしれない pci_enable_device_bars() の先を見ていく内に PCI コンフィグレーション空間読み書きな関数が pci_set_power_state() の中で出てきた。
ちょっと一旦停止して pci_*_config_*() な関数色々チェキ予定。