1d6aca350SJuergen Gross // SPDX-License-Identifier: GPL-2.0-only 2d6aca350SJuergen Gross /* 3d6aca350SJuergen Gross * Xen grant DMA-mapping layer - contains special DMA-mapping routines 4d6aca350SJuergen Gross * for providing grant references as DMA addresses to be used by frontends 5d6aca350SJuergen Gross * (e.g. virtio) in Xen guests 6d6aca350SJuergen Gross * 7d6aca350SJuergen Gross * Copyright (c) 2021, Juergen Gross <jgross@suse.com> 8d6aca350SJuergen Gross */ 9d6aca350SJuergen Gross 10d6aca350SJuergen Gross #include <linux/module.h> 11d6aca350SJuergen Gross #include <linux/dma-map-ops.h> 12d6aca350SJuergen Gross #include <linux/of.h> 13ef8ae384SOleksandr Tyshchenko #include <linux/pci.h> 14d6aca350SJuergen Gross #include <linux/pfn.h> 15d6aca350SJuergen Gross #include <linux/xarray.h> 16251e90e7SJuergen Gross #include <linux/virtio_anchor.h> 17251e90e7SJuergen Gross #include <linux/virtio.h> 18d6aca350SJuergen Gross #include <xen/xen.h> 19d6aca350SJuergen Gross #include <xen/xen-ops.h> 20d6aca350SJuergen Gross #include <xen/grant_table.h> 21d6aca350SJuergen Gross 22d6aca350SJuergen Gross struct xen_grant_dma_data { 23d6aca350SJuergen Gross /* The ID of backend domain */ 24d6aca350SJuergen Gross domid_t backend_domid; 25d6aca350SJuergen Gross /* Is device behaving sane? */ 26d6aca350SJuergen Gross bool broken; 27d6aca350SJuergen Gross }; 28d6aca350SJuergen Gross 2977be00f1SOleksandr Tyshchenko static DEFINE_XARRAY_FLAGS(xen_grant_dma_devices, XA_FLAGS_LOCK_IRQ); 30d6aca350SJuergen Gross 31d6aca350SJuergen Gross #define XEN_GRANT_DMA_ADDR_OFF (1ULL << 63) 32d6aca350SJuergen Gross 33d6aca350SJuergen Gross static inline dma_addr_t grant_to_dma(grant_ref_t grant) 34d6aca350SJuergen Gross { 35a383dcb1SOleksandr Tyshchenko return XEN_GRANT_DMA_ADDR_OFF | ((dma_addr_t)grant << XEN_PAGE_SHIFT); 36d6aca350SJuergen Gross } 37d6aca350SJuergen Gross 38d6aca350SJuergen Gross static inline grant_ref_t dma_to_grant(dma_addr_t dma) 39d6aca350SJuergen Gross { 40a383dcb1SOleksandr Tyshchenko return (grant_ref_t)((dma & ~XEN_GRANT_DMA_ADDR_OFF) >> XEN_PAGE_SHIFT); 41d6aca350SJuergen Gross } 42d6aca350SJuergen Gross 43d6aca350SJuergen Gross static struct xen_grant_dma_data *find_xen_grant_dma_data(struct device *dev) 44d6aca350SJuergen Gross { 45d6aca350SJuergen Gross struct xen_grant_dma_data *data; 4677be00f1SOleksandr Tyshchenko unsigned long flags; 47d6aca350SJuergen Gross 4877be00f1SOleksandr Tyshchenko xa_lock_irqsave(&xen_grant_dma_devices, flags); 49d6aca350SJuergen Gross data = xa_load(&xen_grant_dma_devices, (unsigned long)dev); 5077be00f1SOleksandr Tyshchenko xa_unlock_irqrestore(&xen_grant_dma_devices, flags); 51d6aca350SJuergen Gross 52d6aca350SJuergen Gross return data; 53d6aca350SJuergen Gross } 54d6aca350SJuergen Gross 5577be00f1SOleksandr Tyshchenko static int store_xen_grant_dma_data(struct device *dev, 5677be00f1SOleksandr Tyshchenko struct xen_grant_dma_data *data) 5777be00f1SOleksandr Tyshchenko { 5877be00f1SOleksandr Tyshchenko unsigned long flags; 5977be00f1SOleksandr Tyshchenko int ret; 6077be00f1SOleksandr Tyshchenko 6177be00f1SOleksandr Tyshchenko xa_lock_irqsave(&xen_grant_dma_devices, flags); 6277be00f1SOleksandr Tyshchenko ret = xa_err(__xa_store(&xen_grant_dma_devices, (unsigned long)dev, data, 6377be00f1SOleksandr Tyshchenko GFP_ATOMIC)); 6477be00f1SOleksandr Tyshchenko xa_unlock_irqrestore(&xen_grant_dma_devices, flags); 6577be00f1SOleksandr Tyshchenko 6677be00f1SOleksandr Tyshchenko return ret; 6777be00f1SOleksandr Tyshchenko } 6877be00f1SOleksandr Tyshchenko 69d6aca350SJuergen Gross /* 70d6aca350SJuergen Gross * DMA ops for Xen frontends (e.g. virtio). 71d6aca350SJuergen Gross * 72d6aca350SJuergen Gross * Used to act as a kind of software IOMMU for Xen guests by using grants as 73d6aca350SJuergen Gross * DMA addresses. 74d6aca350SJuergen Gross * Such a DMA address is formed by using the grant reference as a frame 75d6aca350SJuergen Gross * number and setting the highest address bit (this bit is for the backend 76d6aca350SJuergen Gross * to be able to distinguish it from e.g. a mmio address). 77d6aca350SJuergen Gross */ 78d6aca350SJuergen Gross static void *xen_grant_dma_alloc(struct device *dev, size_t size, 79d6aca350SJuergen Gross dma_addr_t *dma_handle, gfp_t gfp, 80d6aca350SJuergen Gross unsigned long attrs) 81d6aca350SJuergen Gross { 82d6aca350SJuergen Gross struct xen_grant_dma_data *data; 83a383dcb1SOleksandr Tyshchenko unsigned int i, n_pages = XEN_PFN_UP(size); 84d6aca350SJuergen Gross unsigned long pfn; 85d6aca350SJuergen Gross grant_ref_t grant; 86d6aca350SJuergen Gross void *ret; 87d6aca350SJuergen Gross 88d6aca350SJuergen Gross data = find_xen_grant_dma_data(dev); 89d6aca350SJuergen Gross if (!data) 90d6aca350SJuergen Gross return NULL; 91d6aca350SJuergen Gross 92d6aca350SJuergen Gross if (unlikely(data->broken)) 93d6aca350SJuergen Gross return NULL; 94d6aca350SJuergen Gross 95a383dcb1SOleksandr Tyshchenko ret = alloc_pages_exact(n_pages * XEN_PAGE_SIZE, gfp); 96d6aca350SJuergen Gross if (!ret) 97d6aca350SJuergen Gross return NULL; 98d6aca350SJuergen Gross 99d6aca350SJuergen Gross pfn = virt_to_pfn(ret); 100d6aca350SJuergen Gross 101d6aca350SJuergen Gross if (gnttab_alloc_grant_reference_seq(n_pages, &grant)) { 102a383dcb1SOleksandr Tyshchenko free_pages_exact(ret, n_pages * XEN_PAGE_SIZE); 103d6aca350SJuergen Gross return NULL; 104d6aca350SJuergen Gross } 105d6aca350SJuergen Gross 106d6aca350SJuergen Gross for (i = 0; i < n_pages; i++) { 107d6aca350SJuergen Gross gnttab_grant_foreign_access_ref(grant + i, data->backend_domid, 108d6aca350SJuergen Gross pfn_to_gfn(pfn + i), 0); 109d6aca350SJuergen Gross } 110d6aca350SJuergen Gross 111d6aca350SJuergen Gross *dma_handle = grant_to_dma(grant); 112d6aca350SJuergen Gross 113d6aca350SJuergen Gross return ret; 114d6aca350SJuergen Gross } 115d6aca350SJuergen Gross 116d6aca350SJuergen Gross static void xen_grant_dma_free(struct device *dev, size_t size, void *vaddr, 117d6aca350SJuergen Gross dma_addr_t dma_handle, unsigned long attrs) 118d6aca350SJuergen Gross { 119d6aca350SJuergen Gross struct xen_grant_dma_data *data; 120a383dcb1SOleksandr Tyshchenko unsigned int i, n_pages = XEN_PFN_UP(size); 121d6aca350SJuergen Gross grant_ref_t grant; 122d6aca350SJuergen Gross 123d6aca350SJuergen Gross data = find_xen_grant_dma_data(dev); 124d6aca350SJuergen Gross if (!data) 125d6aca350SJuergen Gross return; 126d6aca350SJuergen Gross 127d6aca350SJuergen Gross if (unlikely(data->broken)) 128d6aca350SJuergen Gross return; 129d6aca350SJuergen Gross 130d6aca350SJuergen Gross grant = dma_to_grant(dma_handle); 131d6aca350SJuergen Gross 132d6aca350SJuergen Gross for (i = 0; i < n_pages; i++) { 133d6aca350SJuergen Gross if (unlikely(!gnttab_end_foreign_access_ref(grant + i))) { 134d6aca350SJuergen Gross dev_alert(dev, "Grant still in use by backend domain, disabled for further use\n"); 135d6aca350SJuergen Gross data->broken = true; 136d6aca350SJuergen Gross return; 137d6aca350SJuergen Gross } 138d6aca350SJuergen Gross } 139d6aca350SJuergen Gross 140d6aca350SJuergen Gross gnttab_free_grant_reference_seq(grant, n_pages); 141d6aca350SJuergen Gross 142a383dcb1SOleksandr Tyshchenko free_pages_exact(vaddr, n_pages * XEN_PAGE_SIZE); 143d6aca350SJuergen Gross } 144d6aca350SJuergen Gross 145d6aca350SJuergen Gross static struct page *xen_grant_dma_alloc_pages(struct device *dev, size_t size, 146d6aca350SJuergen Gross dma_addr_t *dma_handle, 147d6aca350SJuergen Gross enum dma_data_direction dir, 148d6aca350SJuergen Gross gfp_t gfp) 149d6aca350SJuergen Gross { 150d6aca350SJuergen Gross void *vaddr; 151d6aca350SJuergen Gross 152d6aca350SJuergen Gross vaddr = xen_grant_dma_alloc(dev, size, dma_handle, gfp, 0); 153d6aca350SJuergen Gross if (!vaddr) 154d6aca350SJuergen Gross return NULL; 155d6aca350SJuergen Gross 156d6aca350SJuergen Gross return virt_to_page(vaddr); 157d6aca350SJuergen Gross } 158d6aca350SJuergen Gross 159d6aca350SJuergen Gross static void xen_grant_dma_free_pages(struct device *dev, size_t size, 160d6aca350SJuergen Gross struct page *vaddr, dma_addr_t dma_handle, 161d6aca350SJuergen Gross enum dma_data_direction dir) 162d6aca350SJuergen Gross { 163d6aca350SJuergen Gross xen_grant_dma_free(dev, size, page_to_virt(vaddr), dma_handle, 0); 164d6aca350SJuergen Gross } 165d6aca350SJuergen Gross 166d6aca350SJuergen Gross static dma_addr_t xen_grant_dma_map_page(struct device *dev, struct page *page, 167d6aca350SJuergen Gross unsigned long offset, size_t size, 168d6aca350SJuergen Gross enum dma_data_direction dir, 169d6aca350SJuergen Gross unsigned long attrs) 170d6aca350SJuergen Gross { 171d6aca350SJuergen Gross struct xen_grant_dma_data *data; 172a383dcb1SOleksandr Tyshchenko unsigned long dma_offset = xen_offset_in_page(offset), 173a383dcb1SOleksandr Tyshchenko pfn_offset = XEN_PFN_DOWN(offset); 174a383dcb1SOleksandr Tyshchenko unsigned int i, n_pages = XEN_PFN_UP(dma_offset + size); 175d6aca350SJuergen Gross grant_ref_t grant; 176d6aca350SJuergen Gross dma_addr_t dma_handle; 177d6aca350SJuergen Gross 178d6aca350SJuergen Gross if (WARN_ON(dir == DMA_NONE)) 179d6aca350SJuergen Gross return DMA_MAPPING_ERROR; 180d6aca350SJuergen Gross 181d6aca350SJuergen Gross data = find_xen_grant_dma_data(dev); 182d6aca350SJuergen Gross if (!data) 183d6aca350SJuergen Gross return DMA_MAPPING_ERROR; 184d6aca350SJuergen Gross 185d6aca350SJuergen Gross if (unlikely(data->broken)) 186d6aca350SJuergen Gross return DMA_MAPPING_ERROR; 187d6aca350SJuergen Gross 188d6aca350SJuergen Gross if (gnttab_alloc_grant_reference_seq(n_pages, &grant)) 189d6aca350SJuergen Gross return DMA_MAPPING_ERROR; 190d6aca350SJuergen Gross 191d6aca350SJuergen Gross for (i = 0; i < n_pages; i++) { 192d6aca350SJuergen Gross gnttab_grant_foreign_access_ref(grant + i, data->backend_domid, 193875553e3SOleksandr Tyshchenko pfn_to_gfn(page_to_xen_pfn(page) + i + pfn_offset), 194875553e3SOleksandr Tyshchenko dir == DMA_TO_DEVICE); 195d6aca350SJuergen Gross } 196d6aca350SJuergen Gross 197875553e3SOleksandr Tyshchenko dma_handle = grant_to_dma(grant) + dma_offset; 198d6aca350SJuergen Gross 199d6aca350SJuergen Gross return dma_handle; 200d6aca350SJuergen Gross } 201d6aca350SJuergen Gross 202d6aca350SJuergen Gross static void xen_grant_dma_unmap_page(struct device *dev, dma_addr_t dma_handle, 203d6aca350SJuergen Gross size_t size, enum dma_data_direction dir, 204d6aca350SJuergen Gross unsigned long attrs) 205d6aca350SJuergen Gross { 206d6aca350SJuergen Gross struct xen_grant_dma_data *data; 207a383dcb1SOleksandr Tyshchenko unsigned long dma_offset = xen_offset_in_page(dma_handle); 208a383dcb1SOleksandr Tyshchenko unsigned int i, n_pages = XEN_PFN_UP(dma_offset + size); 209d6aca350SJuergen Gross grant_ref_t grant; 210d6aca350SJuergen Gross 211d6aca350SJuergen Gross if (WARN_ON(dir == DMA_NONE)) 212d6aca350SJuergen Gross return; 213d6aca350SJuergen Gross 214d6aca350SJuergen Gross data = find_xen_grant_dma_data(dev); 215d6aca350SJuergen Gross if (!data) 216d6aca350SJuergen Gross return; 217d6aca350SJuergen Gross 218d6aca350SJuergen Gross if (unlikely(data->broken)) 219d6aca350SJuergen Gross return; 220d6aca350SJuergen Gross 221d6aca350SJuergen Gross grant = dma_to_grant(dma_handle); 222d6aca350SJuergen Gross 223d6aca350SJuergen Gross for (i = 0; i < n_pages; i++) { 224d6aca350SJuergen Gross if (unlikely(!gnttab_end_foreign_access_ref(grant + i))) { 225d6aca350SJuergen Gross dev_alert(dev, "Grant still in use by backend domain, disabled for further use\n"); 226d6aca350SJuergen Gross data->broken = true; 227d6aca350SJuergen Gross return; 228d6aca350SJuergen Gross } 229d6aca350SJuergen Gross } 230d6aca350SJuergen Gross 231d6aca350SJuergen Gross gnttab_free_grant_reference_seq(grant, n_pages); 232d6aca350SJuergen Gross } 233d6aca350SJuergen Gross 234d6aca350SJuergen Gross static void xen_grant_dma_unmap_sg(struct device *dev, struct scatterlist *sg, 235d6aca350SJuergen Gross int nents, enum dma_data_direction dir, 236d6aca350SJuergen Gross unsigned long attrs) 237d6aca350SJuergen Gross { 238d6aca350SJuergen Gross struct scatterlist *s; 239d6aca350SJuergen Gross unsigned int i; 240d6aca350SJuergen Gross 241d6aca350SJuergen Gross if (WARN_ON(dir == DMA_NONE)) 242d6aca350SJuergen Gross return; 243d6aca350SJuergen Gross 244d6aca350SJuergen Gross for_each_sg(sg, s, nents, i) 245d6aca350SJuergen Gross xen_grant_dma_unmap_page(dev, s->dma_address, sg_dma_len(s), dir, 246d6aca350SJuergen Gross attrs); 247d6aca350SJuergen Gross } 248d6aca350SJuergen Gross 249d6aca350SJuergen Gross static int xen_grant_dma_map_sg(struct device *dev, struct scatterlist *sg, 250d6aca350SJuergen Gross int nents, enum dma_data_direction dir, 251d6aca350SJuergen Gross unsigned long attrs) 252d6aca350SJuergen Gross { 253d6aca350SJuergen Gross struct scatterlist *s; 254d6aca350SJuergen Gross unsigned int i; 255d6aca350SJuergen Gross 256d6aca350SJuergen Gross if (WARN_ON(dir == DMA_NONE)) 257d6aca350SJuergen Gross return -EINVAL; 258d6aca350SJuergen Gross 259d6aca350SJuergen Gross for_each_sg(sg, s, nents, i) { 260d6aca350SJuergen Gross s->dma_address = xen_grant_dma_map_page(dev, sg_page(s), s->offset, 261d6aca350SJuergen Gross s->length, dir, attrs); 262d6aca350SJuergen Gross if (s->dma_address == DMA_MAPPING_ERROR) 263d6aca350SJuergen Gross goto out; 264d6aca350SJuergen Gross 265d6aca350SJuergen Gross sg_dma_len(s) = s->length; 266d6aca350SJuergen Gross } 267d6aca350SJuergen Gross 268d6aca350SJuergen Gross return nents; 269d6aca350SJuergen Gross 270d6aca350SJuergen Gross out: 271d6aca350SJuergen Gross xen_grant_dma_unmap_sg(dev, sg, i, dir, attrs | DMA_ATTR_SKIP_CPU_SYNC); 272d6aca350SJuergen Gross sg_dma_len(sg) = 0; 273d6aca350SJuergen Gross 274d6aca350SJuergen Gross return -EIO; 275d6aca350SJuergen Gross } 276d6aca350SJuergen Gross 277d6aca350SJuergen Gross static int xen_grant_dma_supported(struct device *dev, u64 mask) 278d6aca350SJuergen Gross { 279d6aca350SJuergen Gross return mask == DMA_BIT_MASK(64); 280d6aca350SJuergen Gross } 281d6aca350SJuergen Gross 282d6aca350SJuergen Gross static const struct dma_map_ops xen_grant_dma_ops = { 283d6aca350SJuergen Gross .alloc = xen_grant_dma_alloc, 284d6aca350SJuergen Gross .free = xen_grant_dma_free, 285d6aca350SJuergen Gross .alloc_pages = xen_grant_dma_alloc_pages, 286d6aca350SJuergen Gross .free_pages = xen_grant_dma_free_pages, 287d6aca350SJuergen Gross .mmap = dma_common_mmap, 288d6aca350SJuergen Gross .get_sgtable = dma_common_get_sgtable, 289d6aca350SJuergen Gross .map_page = xen_grant_dma_map_page, 290d6aca350SJuergen Gross .unmap_page = xen_grant_dma_unmap_page, 291d6aca350SJuergen Gross .map_sg = xen_grant_dma_map_sg, 292d6aca350SJuergen Gross .unmap_sg = xen_grant_dma_unmap_sg, 293d6aca350SJuergen Gross .dma_supported = xen_grant_dma_supported, 294d6aca350SJuergen Gross }; 295d6aca350SJuergen Gross 296ef8ae384SOleksandr Tyshchenko static struct device_node *xen_dt_get_node(struct device *dev) 297ef8ae384SOleksandr Tyshchenko { 298ef8ae384SOleksandr Tyshchenko if (dev_is_pci(dev)) { 299ef8ae384SOleksandr Tyshchenko struct pci_dev *pdev = to_pci_dev(dev); 300ef8ae384SOleksandr Tyshchenko struct pci_bus *bus = pdev->bus; 301ef8ae384SOleksandr Tyshchenko 302ef8ae384SOleksandr Tyshchenko /* Walk up to the root bus to look for PCI Host controller */ 303ef8ae384SOleksandr Tyshchenko while (!pci_is_root_bus(bus)) 304ef8ae384SOleksandr Tyshchenko bus = bus->parent; 305ef8ae384SOleksandr Tyshchenko 306*21a235bcSPetr Pavlu if (!bus->bridge->parent) 307*21a235bcSPetr Pavlu return NULL; 308ef8ae384SOleksandr Tyshchenko return of_node_get(bus->bridge->parent->of_node); 309ef8ae384SOleksandr Tyshchenko } 310ef8ae384SOleksandr Tyshchenko 311ef8ae384SOleksandr Tyshchenko return of_node_get(dev->of_node); 312ef8ae384SOleksandr Tyshchenko } 313ef8ae384SOleksandr Tyshchenko 314c9133112SJuergen Gross static int xen_dt_grant_init_backend_domid(struct device *dev, 315ef8ae384SOleksandr Tyshchenko struct device_node *np, 316035e3a43SOleksandr Tyshchenko domid_t *backend_domid) 317c9133112SJuergen Gross { 318ef8ae384SOleksandr Tyshchenko struct of_phandle_args iommu_spec = { .args_count = 1 }; 319c9133112SJuergen Gross 320ef8ae384SOleksandr Tyshchenko if (dev_is_pci(dev)) { 321ef8ae384SOleksandr Tyshchenko struct pci_dev *pdev = to_pci_dev(dev); 322ef8ae384SOleksandr Tyshchenko u32 rid = PCI_DEVID(pdev->bus->number, pdev->devfn); 323ef8ae384SOleksandr Tyshchenko 324ef8ae384SOleksandr Tyshchenko if (of_map_id(np, rid, "iommu-map", "iommu-map-mask", &iommu_spec.np, 325ef8ae384SOleksandr Tyshchenko iommu_spec.args)) { 326ef8ae384SOleksandr Tyshchenko dev_dbg(dev, "Cannot translate ID\n"); 327ef8ae384SOleksandr Tyshchenko return -ESRCH; 328ef8ae384SOleksandr Tyshchenko } 329ef8ae384SOleksandr Tyshchenko } else { 330ef8ae384SOleksandr Tyshchenko if (of_parse_phandle_with_args(np, "iommus", "#iommu-cells", 331c9133112SJuergen Gross 0, &iommu_spec)) { 332035e3a43SOleksandr Tyshchenko dev_dbg(dev, "Cannot parse iommus property\n"); 333c9133112SJuergen Gross return -ESRCH; 334c9133112SJuergen Gross } 335ef8ae384SOleksandr Tyshchenko } 336c9133112SJuergen Gross 337c9133112SJuergen Gross if (!of_device_is_compatible(iommu_spec.np, "xen,grant-dma") || 338c9133112SJuergen Gross iommu_spec.args_count != 1) { 339035e3a43SOleksandr Tyshchenko dev_dbg(dev, "Incompatible IOMMU node\n"); 340c9133112SJuergen Gross of_node_put(iommu_spec.np); 341c9133112SJuergen Gross return -ESRCH; 342c9133112SJuergen Gross } 343c9133112SJuergen Gross 344c9133112SJuergen Gross of_node_put(iommu_spec.np); 345c9133112SJuergen Gross 346c9133112SJuergen Gross /* 347c9133112SJuergen Gross * The endpoint ID here means the ID of the domain where the 348c9133112SJuergen Gross * corresponding backend is running 349c9133112SJuergen Gross */ 350035e3a43SOleksandr Tyshchenko *backend_domid = iommu_spec.args[0]; 351c9133112SJuergen Gross 352c9133112SJuergen Gross return 0; 353c9133112SJuergen Gross } 354c9133112SJuergen Gross 355035e3a43SOleksandr Tyshchenko static int xen_grant_init_backend_domid(struct device *dev, 356035e3a43SOleksandr Tyshchenko domid_t *backend_domid) 357035e3a43SOleksandr Tyshchenko { 358ef8ae384SOleksandr Tyshchenko struct device_node *np; 359035e3a43SOleksandr Tyshchenko int ret = -ENODEV; 360035e3a43SOleksandr Tyshchenko 361ef8ae384SOleksandr Tyshchenko np = xen_dt_get_node(dev); 362ef8ae384SOleksandr Tyshchenko if (np) { 363ef8ae384SOleksandr Tyshchenko ret = xen_dt_grant_init_backend_domid(dev, np, backend_domid); 364ef8ae384SOleksandr Tyshchenko of_node_put(np); 365035e3a43SOleksandr Tyshchenko } else if (IS_ENABLED(CONFIG_XEN_VIRTIO_FORCE_GRANT) || xen_pv_domain()) { 366035e3a43SOleksandr Tyshchenko dev_info(dev, "Using dom0 as backend\n"); 367035e3a43SOleksandr Tyshchenko *backend_domid = 0; 368035e3a43SOleksandr Tyshchenko ret = 0; 369035e3a43SOleksandr Tyshchenko } 370035e3a43SOleksandr Tyshchenko 371035e3a43SOleksandr Tyshchenko return ret; 372035e3a43SOleksandr Tyshchenko } 373035e3a43SOleksandr Tyshchenko 374035e3a43SOleksandr Tyshchenko static void xen_grant_setup_dma_ops(struct device *dev, domid_t backend_domid) 375d6aca350SJuergen Gross { 376d6aca350SJuergen Gross struct xen_grant_dma_data *data; 377d6aca350SJuergen Gross 378d6aca350SJuergen Gross data = find_xen_grant_dma_data(dev); 379d6aca350SJuergen Gross if (data) { 380d6aca350SJuergen Gross dev_err(dev, "Xen grant DMA data is already created\n"); 381d6aca350SJuergen Gross return; 382d6aca350SJuergen Gross } 383d6aca350SJuergen Gross 384d6aca350SJuergen Gross data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); 385d6aca350SJuergen Gross if (!data) 386d6aca350SJuergen Gross goto err; 387d6aca350SJuergen Gross 388035e3a43SOleksandr Tyshchenko data->backend_domid = backend_domid; 389d6aca350SJuergen Gross 39077be00f1SOleksandr Tyshchenko if (store_xen_grant_dma_data(dev, data)) { 391d6aca350SJuergen Gross dev_err(dev, "Cannot store Xen grant DMA data\n"); 392d6aca350SJuergen Gross goto err; 393d6aca350SJuergen Gross } 394d6aca350SJuergen Gross 395d6aca350SJuergen Gross dev->dma_ops = &xen_grant_dma_ops; 396d6aca350SJuergen Gross 397d6aca350SJuergen Gross return; 398d6aca350SJuergen Gross 399d6aca350SJuergen Gross err: 400c9133112SJuergen Gross devm_kfree(dev, data); 401d6aca350SJuergen Gross dev_err(dev, "Cannot set up Xen grant DMA ops, retain platform DMA ops\n"); 402d6aca350SJuergen Gross } 403d6aca350SJuergen Gross 40461367688SJuergen Gross bool xen_virtio_restricted_mem_acc(struct virtio_device *dev) 40561367688SJuergen Gross { 406035e3a43SOleksandr Tyshchenko domid_t backend_domid; 40761367688SJuergen Gross 408035e3a43SOleksandr Tyshchenko if (!xen_grant_init_backend_domid(dev->dev.parent, &backend_domid)) { 409035e3a43SOleksandr Tyshchenko xen_grant_setup_dma_ops(dev->dev.parent, backend_domid); 410035e3a43SOleksandr Tyshchenko return true; 411035e3a43SOleksandr Tyshchenko } 41261367688SJuergen Gross 413035e3a43SOleksandr Tyshchenko return false; 41461367688SJuergen Gross } 41561367688SJuergen Gross 416d6aca350SJuergen Gross MODULE_DESCRIPTION("Xen grant DMA-mapping layer"); 417d6aca350SJuergen Gross MODULE_AUTHOR("Juergen Gross <jgross@suse.com>"); 418d6aca350SJuergen Gross MODULE_LICENSE("GPL"); 419