转自: 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 是最底层的实现函数。