mirror of
https://github.com/torvalds/linux.git
synced 2024-10-27 07:16:27 +00:00
NVMe: Add a character device for each nvme device
Registers a miscellaneous device for each nvme controller probed. This creates character device files as /dev/nvmeN, where N is the device instance, and supports nvme admin ioctl commands so devices without namespaces can be managed. Signed-off-by: Keith Busch <keith.busch@intel.com> Signed-off-by: Matthew Wilcox <matthew.r.wilcox@intel.com>
This commit is contained in:
parent
1c9b52651d
commit
5e82e952f0
|
@ -1647,6 +1647,56 @@ static void nvme_release_instance(struct nvme_dev *dev)
|
||||||
spin_unlock(&dev_list_lock);
|
spin_unlock(&dev_list_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void nvme_free_dev(struct kref *kref)
|
||||||
|
{
|
||||||
|
struct nvme_dev *dev = container_of(kref, struct nvme_dev, kref);
|
||||||
|
nvme_dev_remove(dev);
|
||||||
|
pci_disable_msix(dev->pci_dev);
|
||||||
|
iounmap(dev->bar);
|
||||||
|
nvme_release_instance(dev);
|
||||||
|
nvme_release_prp_pools(dev);
|
||||||
|
pci_disable_device(dev->pci_dev);
|
||||||
|
pci_release_regions(dev->pci_dev);
|
||||||
|
kfree(dev->queues);
|
||||||
|
kfree(dev->entry);
|
||||||
|
kfree(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nvme_dev_open(struct inode *inode, struct file *f)
|
||||||
|
{
|
||||||
|
struct nvme_dev *dev = container_of(f->private_data, struct nvme_dev,
|
||||||
|
miscdev);
|
||||||
|
kref_get(&dev->kref);
|
||||||
|
f->private_data = dev;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nvme_dev_release(struct inode *inode, struct file *f)
|
||||||
|
{
|
||||||
|
struct nvme_dev *dev = f->private_data;
|
||||||
|
kref_put(&dev->kref, nvme_free_dev);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static long nvme_dev_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
|
||||||
|
{
|
||||||
|
struct nvme_dev *dev = f->private_data;
|
||||||
|
switch (cmd) {
|
||||||
|
case NVME_IOCTL_ADMIN_CMD:
|
||||||
|
return nvme_user_admin_cmd(dev, (void __user *)arg);
|
||||||
|
default:
|
||||||
|
return -ENOTTY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
};
|
||||||
|
|
||||||
static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||||
{
|
{
|
||||||
int bars, result = -ENOMEM;
|
int bars, result = -ENOMEM;
|
||||||
|
@ -1705,8 +1755,20 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||||
if (result)
|
if (result)
|
||||||
goto delete;
|
goto delete;
|
||||||
|
|
||||||
|
scnprintf(dev->name, sizeof(dev->name), "nvme%d", dev->instance);
|
||||||
|
dev->miscdev.minor = MISC_DYNAMIC_MINOR;
|
||||||
|
dev->miscdev.parent = &pdev->dev;
|
||||||
|
dev->miscdev.name = dev->name;
|
||||||
|
dev->miscdev.fops = &nvme_dev_fops;
|
||||||
|
result = misc_register(&dev->miscdev);
|
||||||
|
if (result)
|
||||||
|
goto remove;
|
||||||
|
|
||||||
|
kref_init(&dev->kref);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
remove:
|
||||||
|
nvme_dev_remove(dev);
|
||||||
delete:
|
delete:
|
||||||
spin_lock(&dev_list_lock);
|
spin_lock(&dev_list_lock);
|
||||||
list_del(&dev->node);
|
list_del(&dev->node);
|
||||||
|
@ -1732,16 +1794,8 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||||
static void nvme_remove(struct pci_dev *pdev)
|
static void nvme_remove(struct pci_dev *pdev)
|
||||||
{
|
{
|
||||||
struct nvme_dev *dev = pci_get_drvdata(pdev);
|
struct nvme_dev *dev = pci_get_drvdata(pdev);
|
||||||
nvme_dev_remove(dev);
|
misc_deregister(&dev->miscdev);
|
||||||
pci_disable_msix(pdev);
|
kref_put(&dev->kref, nvme_free_dev);
|
||||||
iounmap(dev->bar);
|
|
||||||
nvme_release_instance(dev);
|
|
||||||
nvme_release_prp_pools(dev);
|
|
||||||
pci_disable_device(pdev);
|
|
||||||
pci_release_regions(pdev);
|
|
||||||
kfree(dev->queues);
|
|
||||||
kfree(dev->entry);
|
|
||||||
kfree(dev);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* These functions are yet to be implemented */
|
/* These functions are yet to be implemented */
|
||||||
|
|
|
@ -507,6 +507,8 @@ struct nvme_admin_cmd {
|
||||||
|
|
||||||
#ifdef __KERNEL__
|
#ifdef __KERNEL__
|
||||||
#include <linux/pci.h>
|
#include <linux/pci.h>
|
||||||
|
#include <linux/miscdevice.h>
|
||||||
|
#include <linux/kref.h>
|
||||||
|
|
||||||
#define NVME_IO_TIMEOUT (5 * HZ)
|
#define NVME_IO_TIMEOUT (5 * HZ)
|
||||||
|
|
||||||
|
@ -527,6 +529,9 @@ struct nvme_dev {
|
||||||
struct msix_entry *entry;
|
struct msix_entry *entry;
|
||||||
struct nvme_bar __iomem *bar;
|
struct nvme_bar __iomem *bar;
|
||||||
struct list_head namespaces;
|
struct list_head namespaces;
|
||||||
|
struct kref kref;
|
||||||
|
struct miscdevice miscdev;
|
||||||
|
char name[12];
|
||||||
char serial[20];
|
char serial[20];
|
||||||
char model[40];
|
char model[40];
|
||||||
char firmware_rev[8];
|
char firmware_rev[8];
|
||||||
|
|
Loading…
Reference in New Issue
Block a user