NVMe: Switch to use DMA Pool API

Calling dma_free_coherent from interrupt context causes warnings.
Using the DMA pools delays freeing until pool destruction, so avoids
the problem.

Signed-off-by: Matthew Wilcox <matthew.r.wilcox@intel.com>
This commit is contained in:
Matthew Wilcox 2011-02-10 09:56:01 -05:00
parent d534df3c73
commit 091b609258

View File

@ -57,6 +57,7 @@ struct nvme_dev {
struct nvme_queue **queues; struct nvme_queue **queues;
u32 __iomem *dbs; u32 __iomem *dbs;
struct pci_dev *pci_dev; struct pci_dev *pci_dev;
struct dma_pool *prp_page_pool;
int instance; int instance;
int queue_count; int queue_count;
u32 ctrl_config; u32 ctrl_config;
@ -88,6 +89,7 @@ struct nvme_ns {
*/ */
struct nvme_queue { struct nvme_queue {
struct device *q_dmadev; struct device *q_dmadev;
struct nvme_dev *dev;
spinlock_t q_lock; spinlock_t q_lock;
struct nvme_command *sq_cmds; struct nvme_command *sq_cmds;
volatile struct nvme_completion *cqes; volatile struct nvme_completion *cqes;
@ -247,10 +249,9 @@ static int nvme_submit_cmd(struct nvme_queue *nvmeq, struct nvme_command *cmd)
return 0; return 0;
} }
static __le64 *alloc_prp_list(struct nvme_queue *nvmeq, int length, static __le64 *alloc_prp_list(struct nvme_dev *dev, dma_addr_t *addr)
dma_addr_t *addr)
{ {
return dma_alloc_coherent(nvmeq->q_dmadev, PAGE_SIZE, addr, GFP_ATOMIC); return dma_pool_alloc(dev->prp_page_pool, GFP_ATOMIC, addr);
} }
struct nvme_prps { struct nvme_prps {
@ -262,6 +263,7 @@ struct nvme_prps {
static void nvme_free_prps(struct nvme_queue *nvmeq, struct nvme_prps *prps) static void nvme_free_prps(struct nvme_queue *nvmeq, struct nvme_prps *prps)
{ {
const int last_prp = PAGE_SIZE / 8 - 1; const int last_prp = PAGE_SIZE / 8 - 1;
struct nvme_dev *dev = nvmeq->dev;
int i; int i;
dma_addr_t prp_dma; dma_addr_t prp_dma;
@ -272,8 +274,7 @@ static void nvme_free_prps(struct nvme_queue *nvmeq, struct nvme_prps *prps)
for (i = 0; i < prps->npages; i++) { for (i = 0; i < prps->npages; i++) {
__le64 *prp_list = prps->list[i]; __le64 *prp_list = prps->list[i];
dma_addr_t next_prp_dma = le64_to_cpu(prp_list[last_prp]); dma_addr_t next_prp_dma = le64_to_cpu(prp_list[last_prp]);
dma_free_coherent(nvmeq->q_dmadev, PAGE_SIZE, prp_list, dma_pool_free(dev->prp_page_pool, prp_list, prp_dma);
prp_dma);
prp_dma = next_prp_dma; prp_dma = next_prp_dma;
} }
kfree(prps); kfree(prps);
@ -320,6 +321,7 @@ static struct nvme_prps *nvme_setup_prps(struct nvme_queue *nvmeq,
struct nvme_common_command *cmd, struct nvme_common_command *cmd,
struct scatterlist *sg, int length) struct scatterlist *sg, int length)
{ {
struct nvme_dev *dev = nvmeq->dev;
int dma_len = sg_dma_len(sg); int dma_len = sg_dma_len(sg);
u64 dma_addr = sg_dma_address(sg); u64 dma_addr = sg_dma_address(sg);
int offset = offset_in_page(dma_addr); int offset = offset_in_page(dma_addr);
@ -352,7 +354,7 @@ static struct nvme_prps *nvme_setup_prps(struct nvme_queue *nvmeq,
prps = kmalloc(sizeof(*prps) + sizeof(__le64 *) * npages, GFP_ATOMIC); prps = kmalloc(sizeof(*prps) + sizeof(__le64 *) * npages, GFP_ATOMIC);
prps->npages = npages; prps->npages = npages;
prp_page = 0; prp_page = 0;
prp_list = alloc_prp_list(nvmeq, length, &prp_dma); prp_list = alloc_prp_list(dev, &prp_dma);
prps->list[prp_page++] = prp_list; prps->list[prp_page++] = prp_list;
prps->first_dma = prp_dma; prps->first_dma = prp_dma;
cmd->prp2 = cpu_to_le64(prp_dma); cmd->prp2 = cpu_to_le64(prp_dma);
@ -360,7 +362,7 @@ static struct nvme_prps *nvme_setup_prps(struct nvme_queue *nvmeq,
for (;;) { for (;;) {
if (i == PAGE_SIZE / 8 - 1) { if (i == PAGE_SIZE / 8 - 1) {
__le64 *old_prp_list = prp_list; __le64 *old_prp_list = prp_list;
prp_list = alloc_prp_list(nvmeq, length, &prp_dma); prp_list = alloc_prp_list(dev, &prp_dma);
prps->list[prp_page++] = prp_list; prps->list[prp_page++] = prp_list;
old_prp_list[i] = cpu_to_le64(prp_dma); old_prp_list[i] = cpu_to_le64(prp_dma);
i = 0; i = 0;
@ -752,6 +754,7 @@ static struct nvme_queue *nvme_alloc_queue(struct nvme_dev *dev, int qid,
goto free_cqdma; goto free_cqdma;
nvmeq->q_dmadev = dmadev; nvmeq->q_dmadev = dmadev;
nvmeq->dev = dev;
spin_lock_init(&nvmeq->q_lock); spin_lock_init(&nvmeq->q_lock);
nvmeq->cq_head = 0; nvmeq->cq_head = 0;
nvmeq->cq_phase = 1; nvmeq->cq_phase = 1;
@ -1302,6 +1305,22 @@ static int nvme_dev_remove(struct nvme_dev *dev)
return 0; return 0;
} }
static int nvme_setup_prp_pools(struct nvme_dev *dev)
{
struct device *dmadev = &dev->pci_dev->dev;
dev->prp_page_pool = dma_pool_create("prp list page", dmadev,
PAGE_SIZE, PAGE_SIZE, 0);
if (!dev->prp_page_pool)
return -ENOMEM;
return 0;
}
static void nvme_release_prp_pools(struct nvme_dev *dev)
{
dma_pool_destroy(dev->prp_page_pool);
}
/* XXX: Use an ida or something to let remove / add work correctly */ /* XXX: Use an ida or something to let remove / add work correctly */
static void nvme_set_instance(struct nvme_dev *dev) static void nvme_set_instance(struct nvme_dev *dev)
{ {
@ -1346,6 +1365,10 @@ static int __devinit nvme_probe(struct pci_dev *pdev,
nvme_set_instance(dev); nvme_set_instance(dev);
dev->entry[0].vector = pdev->irq; dev->entry[0].vector = pdev->irq;
result = nvme_setup_prp_pools(dev);
if (result)
goto disable_msix;
dev->bar = ioremap(pci_resource_start(pdev, 0), 8192); dev->bar = ioremap(pci_resource_start(pdev, 0), 8192);
if (!dev->bar) { if (!dev->bar) {
result = -ENOMEM; result = -ENOMEM;
@ -1369,6 +1392,7 @@ static int __devinit nvme_probe(struct pci_dev *pdev,
disable_msix: disable_msix:
pci_disable_msix(pdev); pci_disable_msix(pdev);
nvme_release_instance(dev); nvme_release_instance(dev);
nvme_release_prp_pools(dev);
disable: disable:
pci_disable_device(pdev); pci_disable_device(pdev);
pci_release_regions(pdev); pci_release_regions(pdev);
@ -1386,6 +1410,7 @@ static void __devexit nvme_remove(struct pci_dev *pdev)
pci_disable_msix(pdev); pci_disable_msix(pdev);
iounmap(dev->bar); iounmap(dev->bar);
nvme_release_instance(dev); nvme_release_instance(dev);
nvme_release_prp_pools(dev);
pci_disable_device(pdev); pci_disable_device(pdev);
pci_release_regions(pdev); pci_release_regions(pdev);
kfree(dev->queues); kfree(dev->queues);