diff --git a/drivers/nvdimm/virtio_pmem.c b/drivers/nvdimm/virtio_pmem.c index 726c7354d465..ea9e111f3ea1 100644 --- a/drivers/nvdimm/virtio_pmem.c +++ b/drivers/nvdimm/virtio_pmem.c @@ -37,6 +37,8 @@ static int virtio_pmem_probe(struct virtio_device *vdev) struct virtio_pmem *vpmem; struct resource res; int err = 0; + bool have_shm_region; + struct virtio_shm_region pmem_region; if (!vdev->config->get) { dev_err(&vdev->dev, "%s failure: config access disabled\n", @@ -58,10 +60,21 @@ static int virtio_pmem_probe(struct virtio_device *vdev) goto out_err; } - virtio_cread_le(vpmem->vdev, struct virtio_pmem_config, - start, &vpmem->start); - virtio_cread_le(vpmem->vdev, struct virtio_pmem_config, - size, &vpmem->size); + /* Retrieve the pmem device's address and size. It may have been supplied + * as a PCI BAR-relative shared memory region, or as a guest absolute address. + */ + have_shm_region = virtio_get_shm_region(vpmem->vdev, &pmem_region, + VIRTIO_PMEM_SHMCAP_ID_PMEM_REGION); + + if (have_shm_region) { + vpmem->start = pmem_region.addr; + vpmem->size = pmem_region.len; + } else { + virtio_cread_le(vpmem->vdev, struct virtio_pmem_config, + start, &vpmem->start); + virtio_cread_le(vpmem->vdev, struct virtio_pmem_config, + size, &vpmem->size); + } res.start = vpmem->start; res.end = vpmem->start + vpmem->size - 1; @@ -78,6 +91,11 @@ static int virtio_pmem_probe(struct virtio_device *vdev) dev_set_drvdata(&vdev->dev, vpmem->nvdimm_bus); + /* Online the device prior to creating a pmem region, to ensure that + * the region is never touched while the device is offline. + */ + virtio_device_ready(vdev); + ndr_desc.res = &res; ndr_desc.numa_node = nid; ndr_desc.flush = async_pmem_flush; @@ -92,6 +110,7 @@ static int virtio_pmem_probe(struct virtio_device *vdev) nd_region->provider_data = dev_to_virtio(nd_region->dev.parent->parent); return 0; out_nd: + vdev->config->reset(vdev); nvdimm_bus_unregister(vpmem->nvdimm_bus); out_vq: vdev->config->del_vqs(vdev); diff --git a/drivers/nvdimm/virtio_pmem.h b/drivers/nvdimm/virtio_pmem.h index 0dddefe594c4..62bb564e81cb 100644 --- a/drivers/nvdimm/virtio_pmem.h +++ b/drivers/nvdimm/virtio_pmem.h @@ -50,6 +50,9 @@ struct virtio_pmem { __u64 size; }; +/* For the id field in virtio_pci_shm_cap */ +#define VIRTIO_PMEM_SHMCAP_ID_PMEM_REGION 0 + void virtio_pmem_host_ack(struct virtqueue *vq); int async_pmem_flush(struct nd_region *nd_region, struct bio *bio); #endif