stmmac probe 过程

本文以海思3535的stmmac驱动注册过程为例,介绍网络驱动探测、网络设备探测过程。原文地址  http://blog.csdn.net/linchuanzhi_886/article/details/44458713

1.由于我们使用的是以太网,直接用alloc_etherdev()函数返回一个struct net_device的地址ndev。 
在alloc_ether的过程中,会把ndev->dev->name赋值为“eth%” 
2. 第一步成功后,获取STMMAC的资源,包括内存、中断。 
3. 初始化mac信息。主要是根据mac控制器的能力,给mac_device_info结果体成员赋值。如全/半双工模式、10/100/1000Mbps,并且读取mac地址,如果mac地址无效,自动分配一个mac地址。里面有DMA操作函数。 
4. `static int stmmac_mac_device_setup(struct net_device *dev) 

struct stmmac_priv *priv = netdev_priv(dev);

struct mac_device_info *device;

if (priv->plat->has_gmac)
    device = dwmac1000_setup(priv->ioaddr);
else
    device = dwmac100_setup(priv->ioaddr);

if (!device)
    return -ENOMEM;

if (priv->plat->enh_desc) {
    device->desc = &enh_desc_ops;
    pr_info("\tEnhanced descriptor structure\n");
} else
    device->desc = &ndesc_ops;

****priv->hw = device;****

return 0;


`

struct mac_device_info *dwmac1000_setup(void __iomem *ioaddr)
{
    struct mac_device_info *mac;
    u32 uid = readl(ioaddr + GMAC_VERSION);

    printk("\tDWMAC1000 - user ID: 0x%x, Synopsys ID: 0x%x\n",
        ((uid & 0x0000ff00) >> 8), (uid & 0x000000ff));

    mac = kzalloc(sizeof(const struct mac_device_info), GFP_KERNEL);
    if (!mac)
        return NULL;

    mac->mac = &dwmac1000_ops;
    mac->dma = &dwmac1000_dma_ops;
    mac->link.port = GMAC_CONTROL_PS;
    mac->link.duplex = GMAC_CONTROL_DM;
    mac->link.speed = GMAC_CONTROL_FES;
    mac->mii.addr = GMAC_MII_ADDR;
    mac->mii.data = GMAC_MII_DATA;
    return mac;
}

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
const struct stmmac_dma_ops dwmac1000_dma_ops = {
    .init = dwmac1000_dma_init,
    .dump_regs = dwmac1000_dump_dma_regs,
    .dma_mode = dwmac1000_dma_operation_mode,
    .enable_dma_transmission = dwmac_enable_dma_transmission,
    .enable_dma_irq = dwmac_enable_dma_irq,
    .disable_dma_irq = dwmac_disable_dma_irq,
    .start_tx = dwmac_dma_start_tx,
    .stop_tx = dwmac_dma_stop_tx,
    .start_rx = dwmac_dma_start_rx,
    .stop_rx = dwmac_dma_stop_rx,
    .dma_interrupt = dwmac_dma_interrupt,
    .get_hw_feature = dwmac1000_get_hw_feature,
};
static const struct stmmac_ops dwmac1000_ops = {
    .core_init = dwmac1000_core_init,
    .rx_coe = dwmac1000_rx_coe_supported,
    .dump_regs = dwmac1000_dump_regs,
    .host_irq_status = dwmac1000_irq_status,
    .set_filter = dwmac1000_set_filter,
    .flow_ctrl = dwmac1000_flow_ctrl,
    .pmt = dwmac1000_pmt,
    .set_umac_addr = dwmac1000_set_umac_addr,
    .get_umac_addr = dwmac1000_get_umac_addr,
};

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

4.ether_setup(dev);设置ndev的头部信息:

void ether_setup(struct net_device *dev)
{
    dev->header_ops     = &eth_header_ops;
    dev->type       = ARPHRD_ETHER;//1
    dev->hard_header_len    = ETH_HLEN;//14
    dev->mtu        = ETH_DATA_LEN;//1500
    dev->addr_len       = ETH_ALEN;//6
    dev->tx_queue_len   = 1000; /* Ethernet wants good queues */
    dev->flags      = IFF_BROADCAST|IFF_MULTICAST;
    dev->priv_flags     |= IFF_TX_SKB_SHARING;

    memset(dev->broadcast, 0xFF, ETH_ALEN);

}

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

填充ndev的netdev_ops,实现网络设备的open、发生,停止,超时处理函数,ioctl调用。 
`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_set_rx_mode = stmmac_multicast_list, 
.ndo_tx_timeout = stmmac_tx_timeout, 
.ndo_do_ioctl = stmmac_ioctl, 
.ndo_set_config = stmmac_config,

ifdef STMMAC_VLAN_TAG_USED

.ndo_vlan_rx_register = stmmac_vlan_rx_register,

endif

ifdef CONFIG_NET_POLL_CONTROLLER

.ndo_poll_controller = stmmac_poll_controller,

endif

.ndo_set_mac_address = stmmac_eth_mac_addr,

};`

  1. 现在内核基本都支持ETHTOOL,填充ndev的ethtooll_ops。 
    ( (netdev)->ethtool_ops = (ops)
static struct ethtool_ops stmmac_ethtool_ops = {
    .begin = stmmac_check_if_running,
    .get_drvinfo = stmmac_ethtool_getdrvinfo,
    .get_settings = stmmac_ethtool_getsettings,
    .set_settings = stmmac_ethtool_setsettings,
    .get_msglevel = stmmac_ethtool_getmsglevel,
    .set_msglevel = stmmac_ethtool_setmsglevel,
    .get_regs = stmmac_ethtool_gregs,
    .get_regs_len = stmmac_ethtool_get_regs_len,
    .get_link = ethtool_op_get_link,
    .get_pauseparam = stmmac_get_pauseparam,
    .set_pauseparam = stmmac_set_pauseparam,
    .get_ethtool_stats = stmmac_get_ethtool_stats,
    .get_strings = stmmac_get_strings,
    .get_wol = stmmac_get_wol,
    .set_wol = stmmac_set_wol,
    .get_sset_count = stmmac_get_sset_count,
};

6.设置watchdog_timeo时间
在前5步,也可以初始化mac_device_info,并实现其mdio_bus总线的度磁轭
7.register_netdev(ndev)注册到内核。产生eth0/1/2节点。

8.初始化mdiobus读写函数,并注册bus->dev,接着探测mii总线上的phy。发现有效的phy之后,执行phy_device_create、phydev_register.

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

static struct mii_bus *stmmac_mii_bus; 
int stmmac_mdio_register(struct net_device *ndev) 

……. 
stmmac_mii_bus->name = “STMMAC MII Bus”; 
stmmac_mii_bus->read = &stmmac_mdio_read; 
stmmac_mii_bus->write = &stmmac_mdio_write; 
stmmac_mii_bus->reset = &stmmac_mdio_reset; 
snprintf(stmmac_mii_bus->id, MII_BUS_ID_SIZE, “%x”, 
priv->plat->bus_id); 
stmmac_mii_bus->priv = ndev; 
stmmac_mii_bus->irq = irqlist; 
stmmac_mii_bus->phy_mask = priv->phy_mask; 
stmmac_mii_bus->parent = priv->device; 
err = mdiobus_register(stmmac_mii_bus); 
…… 

int mdiobus_register(struct mii_bus *bus) 

int i, err;

if (NULL == bus || NULL == bus->name ||
        NULL == bus->read ||
        NULL == bus->write)
    return -EINVAL;

BUG_ON(bus->state != MDIOBUS_ALLOCATED &&
       bus->state != MDIOBUS_UNREGISTERED);

bus->dev.parent = bus->parent;
bus->dev.class = &mdio_bus_class;
bus->dev.groups = NULL;
dev_set_name(&bus->dev, "%s", bus->id);

err = device_register(&bus->dev);
if (err) {
    printk(KERN_ERR "mii_bus %s failed to register\n", bus->id);
    return -EINVAL;
}

mutex_init(&bus->mdio_lock);

if (bus->reset)
    bus->reset(bus);

for (i = 0; i < PHY_MAX_ADDR; i++) {
    if ((bus->phy_mask & (1 << i)) == 0) {
        struct phy_device *phydev;

        phydev = mdiobus_scan(bus, i);
        if (IS_ERR(phydev)) {
            err = PTR_ERR(phydev);
            goto error;
        }
    }
}

bus->state = MDIOBUS_REGISTERED;
pr_info("%s: probed\n", bus->name);
return 0;

error: 
while (–i >= 0) { 
if (bus->phy_map[i]) 
device_unregister(&bus->phy_map[i]->dev); 

device_del(&bus->dev); 
return err; 
}


 
 
  • 1
  • 1

struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr) 

struct phy_device *phydev; 
int err;

phydev = get_phy_device(bus, addr);
if (IS_ERR(phydev) || phydev == NULL)
    return phydev;

err = phy_device_register(phydev);
if (err) {
    phy_device_free(phydev);
    return NULL;
}

return phydev;


struct phy_device * get_phy_device(struct mii_bus *bus, int addr) 

struct phy_device *dev = NULL; 
u32 phy_id; 
int r;

r = get_phy_id(bus, addr, &phy_id);
if (r)
    return ERR_PTR(r);

/* If the phy_id is mostly Fs, there is no device there */
if ((phy_id & 0x1fffffff) == 0x1fffffff)
    return NULL;

dev = phy_device_create(bus, addr, phy_id);

return dev;


int get_phy_id(struct mii_bus *bus, int addr, u32 *phy_id) 

int phy_reg;

/* Grab the bits from PHYIR1, and put them
 * in the upper half */
phy_reg = mdiobus_read(bus, addr, MII_PHYSID1);
printk(KERN_INFO "ID1 = 0x%x at %s \n",phy_reg,bus->name);
if (phy_reg < 0)
    return -EIO;

*phy_id = (phy_reg & 0xffff) << 16;

/* Grab the bits from PHYIR2, and put them in the lower half */
phy_reg = mdiobus_read(bus, addr, MII_PHYSID2);
printk(KERN_INFO "ID2 = 0x%x at %s \n",phy_reg,bus->name);

if (phy_reg < 0)
    return -EIO;

*phy_id |= (phy_reg & 0xffff);

return 0;

}

9.初始化sk_buff队列头,skb_queue_head_init。然后申请中断,开启中断。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值