Linux网络设备的系统调用

转自: http://www.tuicool.com/articles/QJfmUr


在用户层上的程序, 建立本地socket后,使用ioctl读取phy芯片的寄存器。

ioctl(sockfd, SIOCGMIIREG, &ifr);

下面是linux的网络设备驱动程序响应用户层的ioctl命令过程间各个阶段的函数调用。


ioclt 系统调用层:

fs/ioctl.c

SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd, unsigned long, arg)
{ 
...
	error = do_vfs_ioctl(filp, fd, cmd, arg);
...
}

int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd,                                                                    unsigned long arg)
{
	switch (cmd) {
...
	default:
       ...
            error = vfs_ioctl(filp, cmd, arg);

		
...
}

static long vfs_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg)
{ 
...
	*如果文件操作方法--无锁的的ioctl有对应实现函数(函数指针unlock_ioctl有被填充), 则调用unlcok_ioctl的实现函数
	*/
	if (filp->f_op->unlocked_ioctl) {
        error = filp->f_op->unlocked_ioctl(filp, cmd, arg);


...
}

unlock_ioctl 的实现层:


net/socket.c

static const struct file_operations socket_file_ops = {
...
    .unlocked_ioctl = sock_ioctl,
...
}

static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg)
{   
...
switch (cmd) {
...
 default:
            err = sock->ops->ioctl(sock, cmd, arg);
            if (err == -ENOIOCTLCMD)
                err = dev_ioctl(net, cmd, argp);

...
}


net/core/dev.c


//dev_ioctl :  network device ioctl
dev_ioctl(){
	switch (cmd) {
...
    case SIOCGMIIPHY:
    case SIOCGMIIREG:
    case SIOCSIFNAME:
        ret = dev_ifsioc(net, &ifr, cmd);



static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd)                                                             
{
	switch (cmd) {
...
    default:
            if (ops->ndo_do_ioctl) {
                if (netif_device_present(dev))
                    err = ops->ndo_do_ioctl(dev, ifr, cmd);

...
}

ndo_do_ioctl 的实现层:


drivers/net/octeon/octeon_mgmt.c


static int __init octeon_mgmt_mod_init(void)
{
    /* Force our mdiobus driver module to be loaded first. */
    octeon_mdiobus_force_mod_depencency();
    return platform_driver_register(&octeon_mgmt_driver);
}
 

static struct platform_driver octeon_mgmt_driver = {
    .driver = {
        .name       = "octeon_mgmt",
        .owner      = THIS_MODULE,
        .of_match_table = octeon_mgmt_match,
    },  
    .probe      = octeon_mgmt_probe,
    .remove     = __exit_p(octeon_mgmt_remove),
}; 


static struct of_device_id octeon_mgmt_match[] = {
    {
        .compatible = "cavium,octeon-5750-mix",

    },  
    {},  
};  
MODULE_DEVICE_TABLE(of, octeon_mgmt_match);

static int __init octeon_mgmt_probe(struct platform_device *pdev)
{  
 
...  
    netdev->netdev_ops = &octeon_mgmt_ops;
    netdev->ethtool_ops = &octeon_mgmt_ethtool_ops;
 ...   




static const struct net_device_ops octeon_mgmt_ops = {                                                                                         
    .ndo_open =         octeon_mgmt_open,
    .ndo_stop =         octeon_mgmt_stop,
    .ndo_start_xmit =       octeon_mgmt_xmit,
    .ndo_set_rx_mode =      octeon_mgmt_set_rx_filtering,
    .ndo_set_multicast_list =   octeon_mgmt_set_rx_filtering,
    .ndo_set_mac_address =      octeon_mgmt_set_mac_address,
    .ndo_do_ioctl =         octeon_mgmt_ioctl,
    .ndo_change_mtu =       octeon_mgmt_change_mtu,
#ifdef CONFIG_NET_POLL_CONTROLLER
    .ndo_poll_controller =      octeon_mgmt_poll_controller,
#endif
};
 
   
static int octeon_mgmt_ioctl(struct net_device *netdev,                                                                                        
                 struct ifreq *rq, int cmd)
{  
    default:
        if (p->phydev)
            return phy_mii_ioctl(p->phydev, if_mii(rq), cmd);

        return -EINVAL;
    }
}  


drivers/net/phy/phy.c

int phy_mii_ioctl(struct phy_device *phydev,
        struct mii_ioctl_data *mii_data, int cmd)
{  
    switch (cmd) {
    case SIOCGMIIPHY:
        mii_data->phy_id = phydev->addr;
    
    case SIOCGMIIREG:
        mii_data->val_out = phy_read(phydev, mii_data->reg_num);

        break;
    
...
}

include/linux/phy.h

static inline int phy_read(struct phy_device *phydev, u32 regnum)                                                                              
{
    return mdiobus_read(phydev->bus, phydev->addr, regnum);
}
  

drivers/net/phy/mdio_bus.c

int mdiobus_read(struct mii_bus *bus, int addr, u32 regnum)
{

    retval = bus->read(bus, addr, regnum);
...
}


bus->read 的实现层

drivers/net/phy/mdio-octeon.c

static int __init octeon_mdiobus_mod_init(void)
{  
    return platform_driver_register(&octeon_mdiobus_driver);
}  
  
   
static struct platform_driver octeon_mdiobus_driver = {
    .driver = {
        .name       = "mdio-octeon",
        .owner      = THIS_MODULE,
        .of_match_table = octeon_mdiobus_match,
    },
    .probe      = octeon_mdiobus_probe,

    .remove     = __exit_p(octeon_mdiobus_remove),
}; 
   
static struct of_device_id octeon_mdiobus_match[] = {
    {
        .compatible = "cavium,octeon-3860-mdio",

    },
    {},
};  
MODULE_DEVICE_TABLE(of, octeon_mdiobus_match);

static int __init octeon_mdiobus_probe(struct platform_device *pdev)
{  
...
    
    bus->mii_bus->read = octeon_mdiobus_read;

    bus->mii_bus->write = octeon_mdiobus_write;
 
...
}

octeon_mdiobus_read 是最底层的实现函数。

你可能感兴趣的:(kernel)