nvme_core_init

从drivers/nvme/host/kconfig中可以看到,要使用nvme的话,只需要打开CONFIG_BLK_DEV_NVME即可,当选择这个时,默认会选择CONFIG_NVME_CORE
config BLK_DEV_NVME
    tristate "NVM Express block device"
    depends on PCI && BLOCK
    select NVME_CORE
    ---help---
      The NVM Express driver is for solid state drives directly
      connected to the PCI or PCI Express bus.  If you know you
      don't have one of these, it is safe to answer N.

      To compile this driver as a module, choose M here: the
      module will be called nvme.
这时可以看看core.c 中都做了什么事情
int __init nvme_core_init(void)
{
    int result;

    result = __register_chrdev(nvme_char_major, 0, NVME_MINORS, "nvme",
                            &nvme_dev_fops);
    if (result < 0)
        return result;
    else if (result > 0)
        nvme_char_major = result;

    nvme_class = class_create(THIS_MODULE, "nvme");
    if (IS_ERR(nvme_class)) {
        result = PTR_ERR(nvme_class);
        goto unregister_chrdev;
    }

    return 0;

 unregister_chrdev:
    __unregister_chrdev(nvme_char_major, 0, NVME_MINORS, "nvme");
    return result;
}
module_init(nvme_core_init);
nvme_core_init 首先注册了一个名为nvme的字符设备,然后在sys/class下新建一个nvme的class。
这个字符设备的的ops为nvme_dev_fops
static const struct file_operations nvme_dev_fops = {
    .owner        = THIS_MODULE,
    .open        = nvme_dev_open,
    .release    = nvme_dev_release,
    .unlocked_ioctl    = nvme_dev_ioctl,
    .compat_ioctl    = nvme_dev_ioctl,
};
先看看nvme_dev_open
static int nvme_dev_open(struct inode *inode, struct file *file)
{
    struct nvme_ctrl *ctrl;
//从inode 拿到instance。
    int instance = iminor(inode);
    int ret = -ENODEV;

    spin_lock(&dev_list_lock);
之前在nvme_probe 中讲到过,所有的nave都会加到nvme_ctrl_list 这个list中,因此这里遍历nvme_ctrl_list,找到和instance相同的nvme controller.其次检查ctrl->admin_q和ctrl->kref 不能为null,并把找到的nvme controller 当到private_data 中.
    list_for_each_entry(ctrl, &nvme_ctrl_list, node) {
        if (ctrl->instance != instance)
            continue;

        if (!ctrl->admin_q) {
            ret = -EWOULDBLOCK;
            break;
        }
        if (!kref_get_unless_zero(&ctrl->kref))
            break;
        file->private_data = ctrl;
        ret = 0;
        break;
    }
    spin_unlock(&dev_list_lock);

    return ret;
}
这里的ioctl有两个unlocked_ioctl和compat_ioctl,如果这两个同时存在的话,优先调用unlocked_ioctl,对于compat_ioctl只有打来了CONFIG_COMPAT 才会调用compat_ioctl。obj-$(CONFIG_COMPAT) += compat.o compat_ioctl.o
针对nvme这两个unlocked_ioctl和compat_ioctl的实现是一样的,都是nvme_dev_ioctl。
static long nvme_dev_ioctl(struct file *file, unsigned int cmd,
        unsigned long arg)
{
    struct nvme_ctrl *ctrl = file->private_data;
    void __user *argp = (void __user *)arg;

    switch (cmd) {
    case NVME_IOCTL_ADMIN_CMD:
        return nvme_user_cmd(ctrl, NULL, argp);
    case NVME_IOCTL_IO_CMD:
        return nvme_dev_user_cmd(ctrl, argp);
    case NVME_IOCTL_RESET:
        dev_warn(ctrl->device, "resetting controller\n");
        return ctrl->ops->reset_ctrl(ctrl);
    case NVME_IOCTL_SUBSYS_RESET:
        return nvme_reset_subsystem(ctrl);
    case NVME_IOCTL_RESCAN:
        nvme_queue_scan(ctrl);
        return 0;
    default:
        return -ENOTTY;
    }
}
在nvme_dev_ioctl 中总共实现了五个命令
其中NVME_IOCTL_ADMIN_CMD和NVME_IOCTL_IO_CMD 都是发送command给nvme controller,也就是user space可以直接通过nvme这个字符设备直接发送command给nvme controller
这两个命令的区别是NVME_IOCTL_ADMIN_CMD需要admin 权限:
    if (!capable(CAP_SYS_ADMIN))
        return -EACCES;
而NVME_IOCTL_IO_CMD 则是说系统中如果只有一个nvme controller有多个name space的话,则不能发送命令。判断如下:
    ns = list_first_entry(&ctrl->namespaces, struct nvme_ns, list);
    if (ns != list_last_entry(&ctrl->namespaces, struct nvme_ns, list)) {
        dev_warn(ctrl->device,
            "NVME_IOCTL_IO_CMD not supported when multiple namespaces present!\n");
        ret = -EINVAL;
        goto out_unlock;
    }

而NVME_IOCTL_RESET和NVME_IOCTL_SUBSYS_RESET 命令则是通过nvme的ops直接写register来reset io和subsys
    case NVME_IOCTL_RESET:
        dev_warn(ctrl->device, "resetting controller\n");
        return ctrl->ops->reset_ctrl(ctrl);

    case NVME_IOCTL_SUBSYS_RESET:
        return nvme_reset_subsystem(ctrl);
static inline int nvme_reset_subsystem(struct nvme_ctrl *ctrl)
{
    if (!ctrl->subsystem)
        return -ENOTTY;
    return ctrl->ops->reg_write32(ctrl, NVME_REG_NSSR, 0x4E564D65);
}
可见一个是调用reset_ctrl,一个调用reg_write32。这个ops是在nvme_probe->nvme_init_ctrl的时候赋值为nvme_pci_ctrl_ops的
明白这些后,我们先看reset_ctrl的实现nvme_pci_reset_ctrl
static int nvme_pci_reset_ctrl(struct nvme_ctrl *ctrl)
{
//通过to_nvme_dev从nvme_ctrl得到nvme_dev,然后调用nvme_reset 来reset,ret为零的话表示执行成功,如果执行成功后通过flush_work 来flash work.
    struct nvme_dev *dev = to_nvme_dev(ctrl);
    int ret = nvme_reset(dev);

    if (!ret)
        flush_work(&dev->reset_work);
    return ret;
}
nvme_reset的实现如下:
static int nvme_reset(struct nvme_dev *dev)
{
    if (!dev->ctrl.admin_q || blk_queue_dying(dev->ctrl.admin_q))
        return -ENODEV;
    if (work_busy(&dev->reset_work))
        return -ENODEV;
    if (!queue_work(nvme_workq, &dev->reset_work))
        return -EBUSY;
    return 0;
}
可见如果当前work 是busy的话,则reset失败,也就是reset的时候nvme controller 必须处于空闲状态,如果处于空闲状态,则调用dev->reset_work 来reset nvme controller,这个函数之前已经分析过了.
再看reg_write32的实现函数nvme_pci_reg_write32
static int nvme_pci_reg_write32(struct nvme_ctrl *ctrl, u32 off, u32 val)
{
    writel(val, to_nvme_dev(ctrl)->bar + off);
    return 0;
}
其实就是往bar寄存器里面写0x4E564D65





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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值