Pull VFIO updates from Alex Williamson: - Cleanup vfio iommu_group creation (Christoph Hellwig) - Add individual device reset for vfio/fsl-mc (Diana Craciun) - IGD OpRegion 2.0+ support (Colin Xu) - Use modern cdev lifecycle for vfio_group (Jason Gunthorpe) - Use new mdev API in vfio_ccw (Jason Gunthorpe) * tag 'vfio-v5.16-rc1' of git://github.com/awilliam/linux-vfio: (27 commits) vfio/ccw: Convert to use vfio_register_emulated_iommu_dev() vfio/ccw: Pass vfio_ccw_private not mdev_device to various functions vfio/ccw: Use functions for alloc/free of the vfio_ccw_private vfio/ccw: Remove unneeded GFP_DMA vfio: Use cdev_device_add() instead of device_create() vfio: Use a refcount_t instead of a kref in the vfio_group vfio: Don't leak a group reference if the group already exists vfio: Do not open code the group list search in vfio_create_group() vfio: Delete vfio_get/put_group from vfio_iommu_group_notifier() vfio/pci: Add OpRegion 2.0+ Extended VBT support. vfio/iommu_type1: remove IS_IOMMU_CAP_DOMAIN_IN_CONTAINER vfio/iommu_type1: remove the "external" domain vfio/iommu_type1: initialize pgsize_bitmap in ->open vfio/spapr_tce: reject mediated devices vfio: clean up the check for mediated device in vfio_iommu_type1 vfio: remove the unused mdev iommu hook vfio: move the vfio_iommu_driver_ops interface out of <linux/vfio.h> vfio: remove unused method from vfio_iommu_driver_ops vfio: simplify iommu group allocation for mediated devices vfio: remove the iommudata hack for noiommu groups ...
Unified · Split
| @@ -15,7 +15,8 @@ mc-bus-driver-objs := fsl-mc-bus.o \ · 14 unmodified lines | ||
| 15 | 15 | dprc-driver.o \ |
| 16 | 16 | fsl-mc-allocator.o \ |
| 17 | 17 | fsl-mc-msi.o \ |
| 18 | − dpmcp.o | |
| 18 | + dpmcp.o \ | |
| 19 | + obj-api.o | |
| 19 | 20 | |
| 20 | 21 | # MC userspace support |
| 21 | 22 | obj-$(CONFIG_FSL_MC_UAPI_SUPPORT) += fsl-mc-uapi.o |
| @@ -48,7 +48,6 @@ struct dpmng_rsp_get_version { · 47 unmodified lines | ||
| 48 | 48 | |
| 49 | 49 | /* DPMCP command IDs */ |
| 50 | 50 | #define DPMCP_CMDID_CLOSE DPMCP_CMD(0x800) |
| 51 | −#define DPMCP_CMDID_OPEN DPMCP_CMD(0x80b) | |
| 52 | 51 | #define DPMCP_CMDID_RESET DPMCP_CMD(0x005) |
| 53 | 52 | |
| 54 | 53 | struct dpmcp_cmd_open { |
| @@ -91,7 +90,6 @@ int dpmcp_reset(struct fsl_mc_io *mc_io, · 36 unmodified lines | ||
| 91 | 90 | |
| 92 | 91 | /* DPRC command IDs */ |
| 93 | 92 | #define DPRC_CMDID_CLOSE DPRC_CMD(0x800) |
| 94 | −#define DPRC_CMDID_OPEN DPRC_CMD(0x805) | |
| 95 | 93 | #define DPRC_CMDID_GET_API_VERSION DPRC_CMD(0xa05) |
| 96 | 94 | |
| 97 | 95 | #define DPRC_CMDID_GET_ATTR DPRC_CMD(0x004) |
| @@ -453,7 +451,6 @@ int dprc_get_connection(struct fsl_mc_io *mc_io, · 355 unmodified lines | ||
| 453 | 451 | |
| 454 | 452 | /* Command IDs */ |
| 455 | 453 | #define DPBP_CMDID_CLOSE DPBP_CMD(0x800) |
| 456 | −#define DPBP_CMDID_OPEN DPBP_CMD(0x804) | |
| 457 | 454 | |
| 458 | 455 | #define DPBP_CMDID_ENABLE DPBP_CMD(0x002) |
| 459 | 456 | #define DPBP_CMDID_DISABLE DPBP_CMD(0x003) |
| @@ -492,7 +489,6 @@ struct dpbp_rsp_get_attributes { · 32 unmodified lines | ||
| 492 | 489 | |
| 493 | 490 | /* Command IDs */ |
| 494 | 491 | #define DPCON_CMDID_CLOSE DPCON_CMD(0x800) |
| 495 | −#define DPCON_CMDID_OPEN DPCON_CMD(0x808) | |
| 496 | 492 | |
| 497 | 493 | #define DPCON_CMDID_ENABLE DPCON_CMD(0x002) |
| 498 | 494 | #define DPCON_CMDID_DISABLE DPCON_CMD(0x003) |
| @@ -524,6 +520,41 @@ struct dpcon_cmd_set_notification { · 25 unmodified lines | ||
| 524 | 520 | __le64 user_ctx; |
| 525 | 521 | }; |
| 526 | 522 | |
| 523 | +/* | |
| 524 | + * Generic FSL MC API | |
| 525 | + */ | |
| 526 | + | |
| 527 | +/* generic command versioning */ | |
| 528 | +#define OBJ_CMD_BASE_VERSION 1 | |
| 529 | +#define OBJ_CMD_ID_OFFSET 4 | |
| 530 | + | |
| 531 | +#define OBJ_CMD(id) (((id) << OBJ_CMD_ID_OFFSET) | OBJ_CMD_BASE_VERSION) | |
| 532 | + | |
| 533 | +/* open command codes */ | |
| 534 | +#define DPRTC_CMDID_OPEN OBJ_CMD(0x810) | |
| 535 | +#define DPNI_CMDID_OPEN OBJ_CMD(0x801) | |
| 536 | +#define DPSW_CMDID_OPEN OBJ_CMD(0x802) | |
| 537 | +#define DPIO_CMDID_OPEN OBJ_CMD(0x803) | |
| 538 | +#define DPBP_CMDID_OPEN OBJ_CMD(0x804) | |
| 539 | +#define DPRC_CMDID_OPEN OBJ_CMD(0x805) | |
| 540 | +#define DPDMUX_CMDID_OPEN OBJ_CMD(0x806) | |
| 541 | +#define DPCI_CMDID_OPEN OBJ_CMD(0x807) | |
| 542 | +#define DPCON_CMDID_OPEN OBJ_CMD(0x808) | |
| 543 | +#define DPSECI_CMDID_OPEN OBJ_CMD(0x809) | |
| 544 | +#define DPAIOP_CMDID_OPEN OBJ_CMD(0x80a) | |
| 545 | +#define DPMCP_CMDID_OPEN OBJ_CMD(0x80b) | |
| 546 | +#define DPMAC_CMDID_OPEN OBJ_CMD(0x80c) | |
| 547 | +#define DPDCEI_CMDID_OPEN OBJ_CMD(0x80d) | |
| 548 | +#define DPDMAI_CMDID_OPEN OBJ_CMD(0x80e) | |
| 549 | +#define DPDBG_CMDID_OPEN OBJ_CMD(0x80f) | |
| 550 | + | |
| 551 | +/* Generic object command IDs */ | |
| 552 | +#define OBJ_CMDID_CLOSE OBJ_CMD(0x800) | |
| 553 | +#define OBJ_CMDID_RESET OBJ_CMD(0x005) | |
| 554 | + | |
| 555 | +struct fsl_mc_obj_cmd_open { | |
| 556 | + __le32 obj_id; | |
| 557 | +}; | |
| 527 | 558 | |
| 528 | 559 | /** |
| 529 | 560 | * struct fsl_mc_resource_pool - Pool of MC resources of a given |
| @@ -0,0 +1,103 @@ | ||
| 1 | +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) | |
| 2 | +/* | |
| 3 | + * Copyright 2021 NXP | |
| 4 | + * | |
| 5 | + */ | |
| 6 | +#include <linux/kernel.h> | |
| 7 | +#include <linux/fsl/mc.h> | |
| 8 | + | |
| 9 | +#include "fsl-mc-private.h" | |
| 10 | + | |
| 11 | +static int fsl_mc_get_open_cmd_id(const char *type) | |
| 12 | +{ | |
| 13 | + static const struct { | |
| 14 | + int cmd_id; | |
| 15 | + const char *type; | |
| 16 | + } dev_ids[] = { | |
| 17 | + { DPRTC_CMDID_OPEN, "dprtc" }, | |
| 18 | + { DPRC_CMDID_OPEN, "dprc" }, | |
| 19 | + { DPNI_CMDID_OPEN, "dpni" }, | |
| 20 | + { DPIO_CMDID_OPEN, "dpio" }, | |
| 21 | + { DPSW_CMDID_OPEN, "dpsw" }, | |
| 22 | + { DPBP_CMDID_OPEN, "dpbp" }, | |
| 23 | + { DPCON_CMDID_OPEN, "dpcon" }, | |
| 24 | + { DPMCP_CMDID_OPEN, "dpmcp" }, | |
| 25 | + { DPMAC_CMDID_OPEN, "dpmac" }, | |
| 26 | + { DPSECI_CMDID_OPEN, "dpseci" }, | |
| 27 | + { DPDMUX_CMDID_OPEN, "dpdmux" }, | |
| 28 | + { DPDCEI_CMDID_OPEN, "dpdcei" }, | |
| 29 | + { DPAIOP_CMDID_OPEN, "dpaiop" }, | |
| 30 | + { DPCI_CMDID_OPEN, "dpci" }, | |
| 31 | + { DPDMAI_CMDID_OPEN, "dpdmai" }, | |
| 32 | + { DPDBG_CMDID_OPEN, "dpdbg" }, | |
| 33 | + { 0, NULL } | |
| 34 | + }; | |
| 35 | + int i; | |
| 36 | + | |
| 37 | + for (i = 0; dev_ids[i].type; i++) | |
| 38 | + if (!strcmp(dev_ids[i].type, type)) | |
| 39 | + return dev_ids[i].cmd_id; | |
| 40 | + | |
| 41 | + return -1; | |
| 42 | +} | |
| 43 | + | |
| 44 | +int fsl_mc_obj_open(struct fsl_mc_io *mc_io, | |
| 45 | + u32 cmd_flags, | |
| 46 | + int obj_id, | |
| 47 | + char *obj_type, | |
| 48 | + u16 *token) | |
| 49 | +{ | |
| 50 | + struct fsl_mc_command cmd = { 0 }; | |
| 51 | + struct fsl_mc_obj_cmd_open *cmd_params; | |
| 52 | + int err = 0; | |
| 53 | + int cmd_id = fsl_mc_get_open_cmd_id(obj_type); | |
| 54 | + | |
| 55 | + if (cmd_id == -1) | |
| 56 | + return -ENODEV; | |
| 57 | + | |
| 58 | + /* prepare command */ | |
| 59 | + cmd.header = mc_encode_cmd_header(cmd_id, cmd_flags, 0); | |
| 60 | + cmd_params = (struct fsl_mc_obj_cmd_open *)cmd.params; | |
| 61 | + cmd_params->obj_id = cpu_to_le32(obj_id); | |
| 62 | + | |
| 63 | + /* send command to mc*/ | |
| 64 | + err = mc_send_command(mc_io, &cmd); | |
| 65 | + if (err) | |
| 66 | + return err; | |
| 67 | + | |
| 68 | + /* retrieve response parameters */ | |
| 69 | + *token = mc_cmd_hdr_read_token(&cmd); | |
| 70 | + | |
| 71 | + return err; | |
| 72 | +} | |
| 73 | +EXPORT_SYMBOL_GPL(fsl_mc_obj_open); | |
| 74 | + | |
| 75 | +int fsl_mc_obj_close(struct fsl_mc_io *mc_io, | |
| 76 | + u32 cmd_flags, | |
| 77 | + u16 token) | |
| 78 | +{ | |
| 79 | + struct fsl_mc_command cmd = { 0 }; | |
| 80 | + | |
| 81 | + /* prepare command */ | |
| 82 | + cmd.header = mc_encode_cmd_header(OBJ_CMDID_CLOSE, cmd_flags, | |
| 83 | + token); | |
| 84 | + | |
| 85 | + /* send command to mc*/ | |
| 86 | + return mc_send_command(mc_io, &cmd); | |
| 87 | +} | |
| 88 | +EXPORT_SYMBOL_GPL(fsl_mc_obj_close); | |
| 89 | + | |
| 90 | +int fsl_mc_obj_reset(struct fsl_mc_io *mc_io, | |
| 91 | + u32 cmd_flags, | |
| 92 | + u16 token) | |
| 93 | +{ | |
| 94 | + struct fsl_mc_command cmd = { 0 }; | |
| 95 | + | |
| 96 | + /* prepare command */ | |
| 97 | + cmd.header = mc_encode_cmd_header(OBJ_CMDID_RESET, cmd_flags, | |
| 98 | + token); | |
| 99 | + | |
| 100 | + /* send command to mc*/ | |
| 101 | + return mc_send_command(mc_io, &cmd); | |
| 102 | +} | |
| 103 | +EXPORT_SYMBOL_GPL(fsl_mc_obj_reset); | |
| @@ -137,77 +137,107 @@ static void vfio_ccw_sch_irq(struct subchannel *sch) · 136 unmodified lines | ||
| 137 | 137 | vfio_ccw_fsm_event(private, VFIO_CCW_EVENT_INTERRUPT); |
| 138 | 138 | } |
| 139 | 139 | |
| 140 | −static void vfio_ccw_free_regions(struct vfio_ccw_private *private) | |
| 140 | +static struct vfio_ccw_private *vfio_ccw_alloc_private(struct subchannel *sch) | |
| 141 | 141 | { |
| 142 | − if (private->crw_region) | |
| 143 | − kmem_cache_free(vfio_ccw_crw_region, private->crw_region); | |
| 144 | − if (private->schib_region) | |
| 145 | − kmem_cache_free(vfio_ccw_schib_region, private->schib_region); | |
| 146 | − if (private->cmd_region) | |
| 147 | − kmem_cache_free(vfio_ccw_cmd_region, private->cmd_region); | |
| 148 | − if (private->io_region) | |
| 149 | − kmem_cache_free(vfio_ccw_io_region, private->io_region); | |
| 150 | −} | |
| 151 | − | |
| 152 | −static int vfio_ccw_sch_probe(struct subchannel *sch) | |
| 153 | −{ | |
| 154 | − struct pmcw *pmcw = &sch->schib.pmcw; | |
| 155 | 142 | struct vfio_ccw_private *private; |
| 156 | − int ret = -ENOMEM; | |
| 157 | 143 | |
| 158 | − if (pmcw->qf) { | |
| 159 | − dev_warn(&sch->dev, "vfio: ccw: does not support QDIO: %s\n", | |
| 160 | − dev_name(&sch->dev)); | |
| 161 | − return -ENODEV; | |
| 162 | − } | |
| 163 | − | |
| 164 | − private = kzalloc(sizeof(*private), GFP_KERNEL | GFP_DMA); | |
| 144 | + private = kzalloc(sizeof(*private), GFP_KERNEL); | |
| 165 | 145 | if (!private) |
| 166 | − return -ENOMEM; | |
| 146 | + return ERR_PTR(-ENOMEM); | |
| 147 | + | |
| 148 | + private->sch = sch; | |
| 149 | + mutex_init(&private->io_mutex); | |
| 150 | + private->state = VFIO_CCW_STATE_NOT_OPER; | |
| 151 | + INIT_LIST_HEAD(&private->crw); | |
| 152 | + INIT_WORK(&private->io_work, vfio_ccw_sch_io_todo); | |
| 153 | + INIT_WORK(&private->crw_work, vfio_ccw_crw_todo); | |
| 154 | + atomic_set(&private->avail, 1); | |
| 167 | 155 | |
| 168 | 156 | private->cp.guest_cp = kcalloc(CCWCHAIN_LEN_MAX, sizeof(struct ccw1), |
| 169 | 157 | GFP_KERNEL); |
| 170 | 158 | if (!private->cp.guest_cp) |
| 171 | − goto out_free; | |
| 159 | + goto out_free_private; | |
| 172 | 160 | |
| 173 | 161 | private->io_region = kmem_cache_zalloc(vfio_ccw_io_region, |
| 174 | 162 | GFP_KERNEL | GFP_DMA); |
| 175 | 163 | if (!private->io_region) |
| 176 | − goto out_free; | |
| 164 | + goto out_free_cp; | |
| 177 | 165 | |
| 178 | 166 | private->cmd_region = kmem_cache_zalloc(vfio_ccw_cmd_region, |
| 179 | 167 | GFP_KERNEL | GFP_DMA); |
| 180 | 168 | if (!private->cmd_region) |
| 181 | − goto out_free; | |
| 169 | + goto out_free_io; | |
| 182 | 170 | |
| 183 | 171 | private->schib_region = kmem_cache_zalloc(vfio_ccw_schib_region, |
| 184 | 172 | GFP_KERNEL | GFP_DMA); |
| 185 | 173 | |
| 186 | 174 | if (!private->schib_region) |
| 187 | − goto out_free; | |
| 175 | + goto out_free_cmd; | |
| 188 | 176 | |
| 189 | 177 | private->crw_region = kmem_cache_zalloc(vfio_ccw_crw_region, |
| 190 | 178 | GFP_KERNEL | GFP_DMA); |
| 191 | 179 | |
| 192 | 180 | if (!private->crw_region) |
| 193 | − goto out_free; | |
| 181 | + goto out_free_schib; | |
| 182 | + return private; | |
| 183 | + | |
| 184 | +out_free_schib: | |
| 185 | + kmem_cache_free(vfio_ccw_schib_region, private->schib_region); | |
| 186 | +out_free_cmd: | |
| 187 | + kmem_cache_free(vfio_ccw_cmd_region, private->cmd_region); | |
| 188 | +out_free_io: | |
| 189 | + kmem_cache_free(vfio_ccw_io_region, private->io_region); | |
| 190 | +out_free_cp: | |
| 191 | + kfree(private->cp.guest_cp); | |
| 192 | +out_free_private: | |
| 193 | + mutex_destroy(&private->io_mutex); | |
| 194 | + kfree(private); | |
| 195 | + return ERR_PTR(-ENOMEM); | |
| 196 | +} | |
| 197 | + | |
| 198 | +static void vfio_ccw_free_private(struct vfio_ccw_private *private) | |
| 199 | +{ | |
| 200 | + struct vfio_ccw_crw *crw, *temp; | |
| 201 | + | |
| 202 | + list_for_each_entry_safe(crw, temp, &private->crw, next) { | |
| 203 | + list_del(&crw->next); | |
| 204 | + kfree(crw); | |
| 205 | + } | |
| 206 | + | |
| 207 | + kmem_cache_free(vfio_ccw_crw_region, private->crw_region); | |
| 208 | + kmem_cache_free(vfio_ccw_schib_region, private->schib_region); | |
| 209 | + kmem_cache_free(vfio_ccw_cmd_region, private->cmd_region); | |
| 210 | + kmem_cache_free(vfio_ccw_io_region, private->io_region); | |
| 211 | + kfree(private->cp.guest_cp); | |
| 212 | + mutex_destroy(&private->io_mutex); | |
| 213 | + kfree(private); | |
| 214 | +} | |
| 215 | + | |
| 216 | +static int vfio_ccw_sch_probe(struct subchannel *sch) | |
| 217 | +{ | |
| 218 | + struct pmcw *pmcw = &sch->schib.pmcw; | |
| 219 | + struct vfio_ccw_private *private; | |
| 220 | + int ret = -ENOMEM; | |
| 221 | + | |
| 222 | + if (pmcw->qf) { | |
| 223 | + dev_warn(&sch->dev, "vfio: ccw: does not support QDIO: %s\n", | |
| 224 | + dev_name(&sch->dev)); | |
| 225 | + return -ENODEV; | |
| 226 | + } | |
| 227 | + | |
| 228 | + private = vfio_ccw_alloc_private(sch); | |
| 229 | + if (IS_ERR(private)) | |
| 230 | + return PTR_ERR(private); | |
| 194 | 231 | |
| 195 | − private->sch = sch; | |
| 196 | 232 | dev_set_drvdata(&sch->dev, private); |
| 197 | − mutex_init(&private->io_mutex); | |
| 198 | 233 | |
| 199 | 234 | spin_lock_irq(sch->lock); |
| 200 | − private->state = VFIO_CCW_STATE_NOT_OPER; | |
| 201 | 235 | sch->isc = VFIO_CCW_ISC; |
| 202 | 236 | ret = cio_enable_subchannel(sch, (u32)(unsigned long)sch); |
| 203 | 237 | spin_unlock_irq(sch->lock); |
| 204 | 238 | if (ret) |
| 205 | 239 | goto out_free; |
| 206 | 240 | |
| 207 | − INIT_LIST_HEAD(&private->crw); | |
| 208 | − INIT_WORK(&private->io_work, vfio_ccw_sch_io_todo); | |
| 209 | − INIT_WORK(&private->crw_work, vfio_ccw_crw_todo); | |
| 210 | − atomic_set(&private->avail, 1); | |
| 211 | 241 | private->state = VFIO_CCW_STATE_STANDBY; |
| 212 | 242 | |
| 213 | 243 | ret = vfio_ccw_mdev_reg(sch); |
| @@ -228,31 +258,20 @@ out_disable: · 14 unmodified lines | ||
| 228 | 258 | cio_disable_subchannel(sch); |
| 229 | 259 | out_free: |
| 230 | 260 | dev_set_drvdata(&sch->dev, NULL); |
| 231 | − vfio_ccw_free_regions(private); | |
| 232 | − kfree(private->cp.guest_cp); | |
| 233 | − kfree(private); | |
| 261 | + vfio_ccw_free_private(private); | |
| 234 | 262 | return ret; |
| 235 | 263 | } |
| 236 | 264 | |
| 237 | 265 | static void vfio_ccw_sch_remove(struct subchannel *sch) |
| 238 | 266 | { |
| 239 | 267 | struct vfio_ccw_private *private = dev_get_drvdata(&sch->dev); |
| 240 | − struct vfio_ccw_crw *crw, *temp; | |
| 241 | 268 | |
| 242 | 269 | vfio_ccw_sch_quiesce(sch); |
| 243 | − | |
| 244 | − list_for_each_entry_safe(crw, temp, &private->crw, next) { | |
| 245 | − list_del(&crw->next); | |
| 246 | − kfree(crw); | |
| 247 | − } | |
| 248 | − | |
| 249 | 270 | vfio_ccw_mdev_unreg(sch); |
| 250 | 271 | |
| 251 | 272 | dev_set_drvdata(&sch->dev, NULL); |
| 252 | 273 | |
| 253 | − vfio_ccw_free_regions(private); | |
| 254 | − kfree(private->cp.guest_cp); | |
| 255 | − kfree(private); | |
| 274 | + vfio_ccw_free_private(private); | |
| 256 | 275 | |
| 257 | 276 | VFIO_CCW_MSG_EVENT(4, "unbound from subchannel %x.%x.%04x\n", |
| 258 | 277 | sch->schid.cssid, sch->schid.ssid, |
| @@ -449,7 +468,7 @@ static int __init vfio_ccw_sch_init(void) · 190 unmodified lines | ||
| 449 | 468 | vfio_ccw_work_q = create_singlethread_workqueue("vfio-ccw"); |
| 450 | 469 | if (!vfio_ccw_work_q) { |
| 451 | 470 | ret = -ENOMEM; |
| 452 | − goto out_err; | |
| 471 | + goto out_regions; | |
| 453 | 472 | } |
| 454 | 473 | |
| 455 | 474 | vfio_ccw_io_region = kmem_cache_create_usercopy("vfio_ccw_io_region", |
| @@ -458,7 +477,7 @@ static int __init vfio_ccw_sch_init(void) · 2 unmodified lines | ||
| 458 | 477 | sizeof(struct ccw_io_region), NULL); |
| 459 | 478 | if (!vfio_ccw_io_region) { |
| 460 | 479 | ret = -ENOMEM; |
| 461 | − goto out_err; | |
| 480 | + goto out_regions; | |
| 462 | 481 | } |
| 463 | 482 | |
| 464 | 483 | vfio_ccw_cmd_region = kmem_cache_create_usercopy("vfio_ccw_cmd_region", |
| @@ -467,7 +486,7 @@ static int __init vfio_ccw_sch_init(void) · 2 unmodified lines | ||
| 467 | 486 | sizeof(struct ccw_cmd_region), NULL); |
| 468 | 487 | if (!vfio_ccw_cmd_region) { |
| 469 | 488 | ret = -ENOMEM; |
| 470 | − goto out_err; | |
| 489 | + goto out_regions; | |
| 471 | 490 | } |
| 472 | 491 | |
| 473 | 492 | vfio_ccw_schib_region = kmem_cache_create_usercopy("vfio_ccw_schib_region", |
| @@ -477,7 +496,7 @@ static int __init vfio_ccw_sch_init(void) · 3 unmodified lines | ||
| 477 | 496 | |
| 478 | 497 | if (!vfio_ccw_schib_region) { |
| 479 | 498 | ret = -ENOMEM; |
| 480 | − goto out_err; | |
| 499 | + goto out_regions; | |
| 481 | 500 | } |
| 482 | 501 | |
| 483 | 502 | vfio_ccw_crw_region = kmem_cache_create_usercopy("vfio_ccw_crw_region", |
| @@ -487,19 +506,25 @@ static int __init vfio_ccw_sch_init(void) · 3 unmodified lines | ||
| 487 | 506 | |
| 488 | 507 | if (!vfio_ccw_crw_region) { |
| 489 | 508 | ret = -ENOMEM; |
| 490 | − goto out_err; | |
| 509 | + goto out_regions; | |
| 491 | 510 | } |
| 492 | 511 | |
| 512 | + ret = mdev_register_driver(&vfio_ccw_mdev_driver); | |
| 513 | + if (ret) | |
| 514 | + goto out_regions; | |
| 515 | + | |
| 493 | 516 | isc_register(VFIO_CCW_ISC); |
| 494 | 517 | ret = css_driver_register(&vfio_ccw_sch_driver); |
| 495 | 518 | if (ret) { |
| 496 | 519 | isc_unregister(VFIO_CCW_ISC); |
| 497 | − goto out_err; | |
| 520 | + goto out_driver; | |
| 498 | 521 | } |
| 499 | 522 | |
| 500 | 523 | return ret; |
| 501 | 524 | |
| 502 | −out_err: | |
| 525 | +out_driver: | |
| 526 | + mdev_unregister_driver(&vfio_ccw_mdev_driver); | |
| 527 | +out_regions: | |
| 503 | 528 | vfio_ccw_destroy_regions(); |
| 504 | 529 | destroy_workqueue(vfio_ccw_work_q); |
| 505 | 530 | vfio_ccw_debug_exit(); |
| @@ -509,6 +534,7 @@ out_err: · 3 unmodified lines | ||
| 509 | 534 | static void __exit vfio_ccw_sch_exit(void) |
| 510 | 535 | { |
| 511 | 536 | css_driver_unregister(&vfio_ccw_sch_driver); |
| 537 | + mdev_unregister_driver(&vfio_ccw_mdev_driver); | |
| 512 | 538 | isc_unregister(VFIO_CCW_ISC); |
| 513 | 539 | vfio_ccw_destroy_regions(); |
| 514 | 540 | destroy_workqueue(vfio_ccw_work_q); |
| @@ -17,13 +17,13 @@ · 16 unmodified lines | ||
| 17 | 17 | |
| 18 | 18 | #include "vfio_ccw_private.h" |
| 19 | 19 | |
| 20 | −static int vfio_ccw_mdev_reset(struct mdev_device *mdev) | |
| 20 | +static const struct vfio_device_ops vfio_ccw_dev_ops; | |
| 21 | + | |
| 22 | +static int vfio_ccw_mdev_reset(struct vfio_ccw_private *private) | |
| 21 | 23 | { |
| 22 | − struct vfio_ccw_private *private; | |
| 23 | 24 | struct subchannel *sch; |
| 24 | 25 | int ret; |
| 25 | 26 | |
| 26 | − private = dev_get_drvdata(mdev_parent_dev(mdev)); | |
| 27 | 27 | sch = private->sch; |
| 28 | 28 | /* |
| 29 | 29 | * TODO: |
| @@ -61,7 +61,7 @@ static int vfio_ccw_mdev_notifier(struct notifier_block *nb, · 31 unmodified lines | ||
| 61 | 61 | if (!cp_iova_pinned(&private->cp, unmap->iova)) |
| 62 | 62 | return NOTIFY_OK; |
| 63 | 63 | |
| 64 | − if (vfio_ccw_mdev_reset(private->mdev)) | |
| 64 | + if (vfio_ccw_mdev_reset(private)) | |
| 65 | 65 | return NOTIFY_BAD; |
| 66 | 66 | |
| 67 | 67 | cp_free(&private->cp); |
| @@ -113,10 +113,10 @@ static struct attribute_group *mdev_type_groups[] = { · 45 unmodified lines | ||
| 113 | 113 | NULL, |
| 114 | 114 | }; |
| 115 | 115 | |
| 116 | −static int vfio_ccw_mdev_create(struct mdev_device *mdev) | |
| 116 | +static int vfio_ccw_mdev_probe(struct mdev_device *mdev) | |
| 117 | 117 | { |
| 118 | − struct vfio_ccw_private *private = | |
| 119 | − dev_get_drvdata(mdev_parent_dev(mdev)); | |
| 118 | + struct vfio_ccw_private *private = dev_get_drvdata(mdev->dev.parent); | |
| 119 | + int ret; | |
| 120 | 120 | |
| 121 | 121 | if (private->state == VFIO_CCW_STATE_NOT_OPER) |
| 122 | 122 | return -ENODEV; |
| @@ -124,6 +124,10 @@ static int vfio_ccw_mdev_create(struct mdev_device *mdev) · 1 unmodified line | ||
| 124 | 124 | if (atomic_dec_if_positive(&private->avail) < 0) |
| 125 | 125 | return -EPERM; |
| 126 | 126 | |
| 127 | + memset(&private->vdev, 0, sizeof(private->vdev)); | |
| 128 | + vfio_init_group_dev(&private->vdev, &mdev->dev, | |
| 129 | + &vfio_ccw_dev_ops); | |
| 130 | + | |
| 127 | 131 | private->mdev = mdev; |
| 128 | 132 | private->state = VFIO_CCW_STATE_IDLE; |
| 129 | 133 | |
| @@ -132,19 +136,31 @@ static int vfio_ccw_mdev_create(struct mdev_device *mdev) · 2 unmodified lines | ||
| 132 | 136 | private->sch->schid.ssid, |
| 133 | 137 | private->sch->schid.sch_no); |
| 134 | 138 | |
| 139 | + ret = vfio_register_emulated_iommu_dev(&private->vdev); | |
| 140 | + if (ret) | |
| 141 | + goto err_atomic; | |
| 142 | + dev_set_drvdata(&mdev->dev, private); | |
| 135 | 143 | return 0; |
| 144 | + | |
| 145 | +err_atomic: | |
| 146 | + vfio_uninit_group_dev(&private->vdev); | |
| 147 | + atomic_inc(&private->avail); | |
| 148 | + private->mdev = NULL; | |
| 149 | + private->state = VFIO_CCW_STATE_IDLE; | |
| 150 | + return ret; | |
| 136 | 151 | } |
| 137 | 152 | |
| 138 | −static int vfio_ccw_mdev_remove(struct mdev_device *mdev) | |
| 153 | +static void vfio_ccw_mdev_remove(struct mdev_device *mdev) | |
| 139 | 154 | { |
| 140 | − struct vfio_ccw_private *private = | |
| 141 | − dev_get_drvdata(mdev_parent_dev(mdev)); | |
| 155 | + struct vfio_ccw_private *private = dev_get_drvdata(mdev->dev.parent); | |
| 142 | 156 | |
| 143 | 157 | VFIO_CCW_MSG_EVENT(2, "mdev %pUl, sch %x.%x.%04x: remove\n", |
| 144 | 158 | mdev_uuid(mdev), private->sch->schid.cssid, |
| 145 | 159 | private->sch->schid.ssid, |
| 146 | 160 | private->sch->schid.sch_no); |
| 147 | 161 | |
| 162 | + vfio_unregister_group_dev(&private->vdev); | |
| 163 | + | |
| 148 | 164 | if ((private->state != VFIO_CCW_STATE_NOT_OPER) && |
| 149 | 165 | (private->state != VFIO_CCW_STATE_STANDBY)) { |
| 150 | 166 | if (!vfio_ccw_sch_quiesce(private->sch)) |
| @@ -152,23 +168,22 @@ static int vfio_ccw_mdev_remove(struct mdev_device *mdev) · 1 unmodified line | ||
| 152 | 168 | /* The state will be NOT_OPER on error. */ |
| 153 | 169 | } |
| 154 | 170 | |
| 171 | + vfio_uninit_group_dev(&private->vdev); | |
| 155 | 172 | cp_free(&private->cp); |
| 156 | 173 | private->mdev = NULL; |
| 157 | 174 | atomic_inc(&private->avail); |
| 158 | − | |
| 159 | − return 0; | |
| 160 | 175 | } |
| 161 | 176 | |
| 162 | −static int vfio_ccw_mdev_open_device(struct mdev_device *mdev) | |
| 177 | +static int vfio_ccw_mdev_open_device(struct vfio_device *vdev) | |
| 163 | 178 | { |
| 164 | 179 | struct vfio_ccw_private *private = |
| 165 | − dev_get_drvdata(mdev_parent_dev(mdev)); | |
| 180 | + container_of(vdev, struct vfio_ccw_private, vdev); | |
| 166 | 181 | unsigned long events = VFIO_IOMMU_NOTIFY_DMA_UNMAP; |
| 167 | 182 | int ret; |
| 168 | 183 | |
| 169 | 184 | private->nb.notifier_call = vfio_ccw_mdev_notifier; |
| 170 | 185 | |
| 171 | − ret = vfio_register_notifier(mdev_dev(mdev), VFIO_IOMMU_NOTIFY, | |
| 186 | + ret = vfio_register_notifier(vdev->dev, VFIO_IOMMU_NOTIFY, | |
| 172 | 187 | &events, &private->nb); |
| 173 | 188 | if (ret) |
| 174 | 189 | return ret; |
| @@ -189,27 +204,26 @@ static int vfio_ccw_mdev_open_device(struct mdev_device *mdev) · 14 unmodified lines | ||
| 189 | 204 | |
| 190 | 205 | out_unregister: |
| 191 | 206 | vfio_ccw_unregister_dev_regions(private); |
| 192 | − vfio_unregister_notifier(mdev_dev(mdev), VFIO_IOMMU_NOTIFY, | |
| 207 | + vfio_unregister_notifier(vdev->dev, VFIO_IOMMU_NOTIFY, | |
| 193 | 208 | &private->nb); |
| 194 | 209 | return ret; |
| 195 | 210 | } |
| 196 | 211 | |
| 197 | −static void vfio_ccw_mdev_close_device(struct mdev_device *mdev) | |
| 212 | +static void vfio_ccw_mdev_close_device(struct vfio_device *vdev) | |
| 198 | 213 | { |
| 199 | 214 | struct vfio_ccw_private *private = |
| 200 | − dev_get_drvdata(mdev_parent_dev(mdev)); | |
| 215 | + container_of(vdev, struct vfio_ccw_private, vdev); | |
| 201 | 216 | |
| 202 | 217 | if ((private->state != VFIO_CCW_STATE_NOT_OPER) && |
| 203 | 218 | (private->state != VFIO_CCW_STATE_STANDBY)) { |
| 204 | − if (!vfio_ccw_mdev_reset(mdev)) | |
| 219 | + if (!vfio_ccw_mdev_reset(private)) | |
| 205 | 220 | private->state = VFIO_CCW_STATE_STANDBY; |
| 206 | 221 | /* The state will be NOT_OPER on error. */ |
| 207 | 222 | } |
| 208 | 223 | |
| 209 | 224 | cp_free(&private->cp); |
| 210 | 225 | vfio_ccw_unregister_dev_regions(private); |
| 211 | − vfio_unregister_notifier(mdev_dev(mdev), VFIO_IOMMU_NOTIFY, | |
| 212 | − &private->nb); | |
| 226 | + vfio_unregister_notifier(vdev->dev, VFIO_IOMMU_NOTIFY, &private->nb); | |
| 213 | 227 | } |
| 214 | 228 | |
| 215 | 229 | static ssize_t vfio_ccw_mdev_read_io_region(struct vfio_ccw_private *private, |
| @@ -233,15 +247,14 @@ static ssize_t vfio_ccw_mdev_read_io_region(struct vfio_ccw_private *private, · 17 unmodified lines | ||
| 233 | 247 | return ret; |
| 234 | 248 | } |
| 235 | 249 | |
| 236 | −static ssize_t vfio_ccw_mdev_read(struct mdev_device *mdev, | |
| 250 | +static ssize_t vfio_ccw_mdev_read(struct vfio_device *vdev, | |
| 237 | 251 | char __user *buf, |
| 238 | 252 | size_t count, |
| 239 | 253 | loff_t *ppos) |
| 240 | 254 | { |
| 255 | + struct vfio_ccw_private *private = | |
| 256 | + container_of(vdev, struct vfio_ccw_private, vdev); | |
| 241 | 257 | unsigned int index = VFIO_CCW_OFFSET_TO_INDEX(*ppos); |
| 242 | − struct vfio_ccw_private *private; | |
| 243 | − | |
| 244 | − private = dev_get_drvdata(mdev_parent_dev(mdev)); | |
| 245 | 258 | |
| 246 | 259 | if (index >= VFIO_CCW_NUM_REGIONS + private->num_regions) |
| 247 | 260 | return -EINVAL; |
| @@ -286,15 +299,14 @@ out_unlock: · 38 unmodified lines | ||
| 286 | 299 | return ret; |
| 287 | 300 | } |
| 288 | 301 | |
| 289 | −static ssize_t vfio_ccw_mdev_write(struct mdev_device *mdev, | |
| 302 | +static ssize_t vfio_ccw_mdev_write(struct vfio_device *vdev, | |
| 290 | 303 | const char __user *buf, |
| 291 | 304 | size_t count, |
| 292 | 305 | loff_t *ppos) |
| 293 | 306 | { |
| 307 | + struct vfio_ccw_private *private = | |
| 308 | + container_of(vdev, struct vfio_ccw_private, vdev); | |
| 294 | 309 | unsigned int index = VFIO_CCW_OFFSET_TO_INDEX(*ppos); |
| 295 | − struct vfio_ccw_private *private; | |
| 296 | − | |
| 297 | − private = dev_get_drvdata(mdev_parent_dev(mdev)); | |
| 298 | 310 | |
| 299 | 311 | if (index >= VFIO_CCW_NUM_REGIONS + private->num_regions) |
| 300 | 312 | return -EINVAL; |
| @@ -311,12 +323,9 @@ static ssize_t vfio_ccw_mdev_write(struct mdev_device *mdev, · 10 unmodified lines | ||
| 311 | 323 | return -EINVAL; |
| 312 | 324 | } |
| 313 | 325 | |
| 314 | −static int vfio_ccw_mdev_get_device_info(struct vfio_device_info *info, | |
| 315 | − struct mdev_device *mdev) | |
| 326 | +static int vfio_ccw_mdev_get_device_info(struct vfio_ccw_private *private, | |
| 327 | + struct vfio_device_info *info) | |
| 316 | 328 | { |
| 317 | − struct vfio_ccw_private *private; | |
| 318 | − | |
| 319 | − private = dev_get_drvdata(mdev_parent_dev(mdev)); | |
| 320 | 329 | info->flags = VFIO_DEVICE_FLAGS_CCW | VFIO_DEVICE_FLAGS_RESET; |
| 321 | 330 | info->num_regions = VFIO_CCW_NUM_REGIONS + private->num_regions; |
| 322 | 331 | info->num_irqs = VFIO_CCW_NUM_IRQS; |
| @@ -324,14 +333,12 @@ static int vfio_ccw_mdev_get_device_info(struct vfio_device_info *info, · 1 unmodified line | ||
| 324 | 333 | return 0; |
| 325 | 334 | } |
| 326 | 335 | |
| 327 | −static int vfio_ccw_mdev_get_region_info(struct vfio_region_info *info, | |
| 328 | − struct mdev_device *mdev, | |
| 336 | +static int vfio_ccw_mdev_get_region_info(struct vfio_ccw_private *private, | |
| 337 | + struct vfio_region_info *info, | |
| 329 | 338 | unsigned long arg) |
| 330 | 339 | { |
| 331 | − struct vfio_ccw_private *private; | |
| 332 | 340 | int i; |
| 333 | 341 | |
| 334 | − private = dev_get_drvdata(mdev_parent_dev(mdev)); | |
| 335 | 342 | switch (info->index) { |
| 336 | 343 | case VFIO_CCW_CONFIG_REGION_INDEX: |
| 337 | 344 | info->offset = 0; |
| @@ -406,19 +413,16 @@ static int vfio_ccw_mdev_get_irq_info(struct vfio_irq_info *info) · 68 unmodified lines | ||
| 406 | 413 | return 0; |
| 407 | 414 | } |
| 408 | 415 | |
| 409 | −static int vfio_ccw_mdev_set_irqs(struct mdev_device *mdev, | |
| 416 | +static int vfio_ccw_mdev_set_irqs(struct vfio_ccw_private *private, | |
| 410 | 417 | uint32_t flags, |
| 411 | 418 | uint32_t index, |
| 412 | 419 | void __user *data) |
| 413 | 420 | { |
| 414 | − struct vfio_ccw_private *private; | |
| 415 | 421 | struct eventfd_ctx **ctx; |
| 416 | 422 | |
| 417 | 423 | if (!(flags & VFIO_IRQ_SET_ACTION_TRIGGER)) |
| 418 | 424 | return -EINVAL; |
| 419 | 425 | |
| 420 | − private = dev_get_drvdata(mdev_parent_dev(mdev)); | |
| 421 | − | |
| 422 | 426 | switch (index) { |
| 423 | 427 | case VFIO_CCW_IO_IRQ_INDEX: |
| 424 | 428 | ctx = &private->io_trigger; |
| @@ -520,10 +524,12 @@ void vfio_ccw_unregister_dev_regions(struct vfio_ccw_private *private) · 95 unmodified lines | ||
| 520 | 524 | private->region = NULL; |
| 521 | 525 | } |
| 522 | 526 | |
| 523 | −static ssize_t vfio_ccw_mdev_ioctl(struct mdev_device *mdev, | |
| 527 | +static ssize_t vfio_ccw_mdev_ioctl(struct vfio_device *vdev, | |
| 524 | 528 | unsigned int cmd, |
| 525 | 529 | unsigned long arg) |
| 526 | 530 | { |
| 531 | + struct vfio_ccw_private *private = | |
| 532 | + container_of(vdev, struct vfio_ccw_private, vdev); | |
| 527 | 533 | int ret = 0; |
| 528 | 534 | unsigned long minsz; |
| 529 | 535 | |
| @@ -540,7 +546,7 @@ static ssize_t vfio_ccw_mdev_ioctl(struct mdev_device *mdev, · 10 unmodified lines | ||
| 540 | 546 | if (info.argsz < minsz) |
| 541 | 547 | return -EINVAL; |
| 542 | 548 | |
| 543 | − ret = vfio_ccw_mdev_get_device_info(&info, mdev); | |
| 549 | + ret = vfio_ccw_mdev_get_device_info(private, &info); | |
| 544 | 550 | if (ret) |
| 545 | 551 | return ret; |
| 546 | 552 | |
| @@ -558,7 +564,7 @@ static ssize_t vfio_ccw_mdev_ioctl(struct mdev_device *mdev, · 11 unmodified lines | ||
| 558 | 564 | if (info.argsz < minsz) |
| 559 | 565 | return -EINVAL; |
| 560 | 566 | |
| 561 | − ret = vfio_ccw_mdev_get_region_info(&info, mdev, arg); | |
| 567 | + ret = vfio_ccw_mdev_get_region_info(private, &info, arg); | |
| 562 | 568 | if (ret) |
| 563 | 569 | return ret; |
| 564 | 570 | |
| @@ -603,47 +609,59 @@ static ssize_t vfio_ccw_mdev_ioctl(struct mdev_device *mdev, · 38 unmodified lines | ||
| 603 | 609 | return ret; |
| 604 | 610 | |
| 605 | 611 | data = (void __user *)(arg + minsz); |
| 606 | − return vfio_ccw_mdev_set_irqs(mdev, hdr.flags, hdr.index, data); | |
| 612 | + return vfio_ccw_mdev_set_irqs(private, hdr.flags, hdr.index, | |
| 613 | + data); | |
| 607 | 614 | } |
| 608 | 615 | case VFIO_DEVICE_RESET: |
| 609 | − return vfio_ccw_mdev_reset(mdev); | |
| 616 | + return vfio_ccw_mdev_reset(private); | |
| 610 | 617 | default: |
| 611 | 618 | return -ENOTTY; |
| 612 | 619 | } |
| 613 | 620 | } |
| 614 | 621 | |
| 615 | 622 | /* Request removal of the device*/ |
| 616 | −static void vfio_ccw_mdev_request(struct mdev_device *mdev, unsigned int count) | |
| 623 | +static void vfio_ccw_mdev_request(struct vfio_device *vdev, unsigned int count) | |
| 617 | 624 | { |
| 618 | − struct vfio_ccw_private *private = dev_get_drvdata(mdev_parent_dev(mdev)); | |
| 619 | − | |
| 620 | − if (!private) | |
| 621 | − return; | |
| 625 | + struct vfio_ccw_private *private = | |
| 626 | + container_of(vdev, struct vfio_ccw_private, vdev); | |
| 627 | + struct device *dev = vdev->dev; | |
| 622 | 628 | |
| 623 | 629 | if (private->req_trigger) { |
| 624 | 630 | if (!(count % 10)) |
| 625 | − dev_notice_ratelimited(mdev_dev(private->mdev), | |
| 631 | + dev_notice_ratelimited(dev, | |
| 626 | 632 | "Relaying device request to user (#%u)\n", |
| 627 | 633 | count); |
| 628 | 634 | |
| 629 | 635 | eventfd_signal(private->req_trigger, 1); |
| 630 | 636 | } else if (count == 0) { |
| 631 | − dev_notice(mdev_dev(private->mdev), | |
| 637 | + dev_notice(dev, | |
| 632 | 638 | "No device request channel registered, blocked until released by user\n"); |
| 633 | 639 | } |
| 634 | 640 | } |
| 635 | 641 | |
| 642 | +static const struct vfio_device_ops vfio_ccw_dev_ops = { | |
| 643 | + .open_device = vfio_ccw_mdev_open_device, | |
| 644 | + .close_device = vfio_ccw_mdev_close_device, | |
| 645 | + .read = vfio_ccw_mdev_read, | |
| 646 | + .write = vfio_ccw_mdev_write, | |
| 647 | + .ioctl = vfio_ccw_mdev_ioctl, | |
| 648 | + .request = vfio_ccw_mdev_request, | |
| 649 | +}; | |
| 650 | + | |
| 651 | +struct mdev_driver vfio_ccw_mdev_driver = { | |
| 652 | + .driver = { | |
| 653 | + .name = "vfio_ccw_mdev", | |
| 654 | + .owner = THIS_MODULE, | |
| 655 | + .mod_name = KBUILD_MODNAME, | |
| 656 | + }, | |
| 657 | + .probe = vfio_ccw_mdev_probe, | |
| 658 | + .remove = vfio_ccw_mdev_remove, | |
| 659 | +}; | |
| 660 | + | |
| 636 | 661 | static const struct mdev_parent_ops vfio_ccw_mdev_ops = { |
| 637 | 662 | .owner = THIS_MODULE, |
| 663 | + .device_driver = &vfio_ccw_mdev_driver, | |
| 638 | 664 | .supported_type_groups = mdev_type_groups, |
| 639 | − .create = vfio_ccw_mdev_create, | |
| 640 | − .remove = vfio_ccw_mdev_remove, | |
| 641 | − .open_device = vfio_ccw_mdev_open_device, | |
| 642 | − .close_device = vfio_ccw_mdev_close_device, | |
| 643 | − .read = vfio_ccw_mdev_read, | |
| 644 | − .write = vfio_ccw_mdev_write, | |
| 645 | − .ioctl = vfio_ccw_mdev_ioctl, | |
| 646 | − .request = vfio_ccw_mdev_request, | |
| 647 | 665 | }; |
| 648 | 666 | |
| 649 | 667 | int vfio_ccw_mdev_reg(struct subchannel *sch) |
| @@ -17,6 +17,7 @@ · 16 unmodified lines | ||
| 17 | 17 | #include <linux/eventfd.h> |
| 18 | 18 | #include <linux/workqueue.h> |
| 19 | 19 | #include <linux/vfio_ccw.h> |
| 20 | +#include <linux/vfio.h> | |
| 20 | 21 | #include <asm/crw.h> |
| 21 | 22 | #include <asm/debug.h> |
| 22 | 23 | |
| @@ -67,6 +68,7 @@ struct vfio_ccw_crw { · 44 unmodified lines | ||
| 67 | 68 | |
| 68 | 69 | /** |
| 69 | 70 | * struct vfio_ccw_private |
| 71 | + * @vdev: Embedded VFIO device | |
| 70 | 72 | * @sch: pointer to the subchannel |
| 71 | 73 | * @state: internal state of the device |
| 72 | 74 | * @completion: synchronization helper of the I/O completion |
| @@ -90,6 +92,7 @@ struct vfio_ccw_crw { · 17 unmodified lines | ||
| 90 | 92 | * @crw_work: work for deferral process of CRW handling |
| 91 | 93 | */ |
| 92 | 94 | struct vfio_ccw_private { |
| 95 | + struct vfio_device vdev; | |
| 93 | 96 | struct subchannel *sch; |
| 94 | 97 | int state; |
| 95 | 98 | struct completion *completion; |
| @@ -121,6 +124,8 @@ extern void vfio_ccw_mdev_unreg(struct subchannel *sch); · 25 unmodified lines | ||
| 121 | 124 | |
| 122 | 125 | extern int vfio_ccw_sch_quiesce(struct subchannel *sch); |
| 123 | 126 | |
| 127 | +extern struct mdev_driver vfio_ccw_mdev_driver; | |
| 128 | + | |
| 124 | 129 | /* |
| 125 | 130 | * States of the device statemachine. |
| 126 | 131 | */ |
| @@ -351,7 +351,7 @@ static int vfio_ap_mdev_probe(struct mdev_device *mdev) · 350 unmodified lines | ||
| 351 | 351 | list_add(&matrix_mdev->node, &matrix_dev->mdev_list); |
| 352 | 352 | mutex_unlock(&matrix_dev->lock); |
| 353 | 353 | |
| 354 | − ret = vfio_register_group_dev(&matrix_mdev->vdev); | |
| 354 | + ret = vfio_register_emulated_iommu_dev(&matrix_mdev->vdev); | |
| 355 | 355 | if (ret) |
| 356 | 356 | goto err_list; |
| 357 | 357 | dev_set_drvdata(&mdev->dev, matrix_mdev); |
| @@ -65,6 +65,34 @@ static void vfio_fsl_mc_regions_cleanup(struct vfio_fsl_mc_device *vdev) · 64 unmodified lines | ||
| 65 | 65 | kfree(vdev->regions); |
| 66 | 66 | } |
| 67 | 67 | |
| 68 | +static int vfio_fsl_mc_reset_device(struct vfio_fsl_mc_device *vdev) | |
| 69 | +{ | |
| 70 | + struct fsl_mc_device *mc_dev = vdev->mc_dev; | |
| 71 | + int ret = 0; | |
| 72 | + | |
| 73 | + if (is_fsl_mc_bus_dprc(vdev->mc_dev)) { | |
| 74 | + return dprc_reset_container(mc_dev->mc_io, 0, | |
| 75 | + mc_dev->mc_handle, | |
| 76 | + mc_dev->obj_desc.id, | |
| 77 | + DPRC_RESET_OPTION_NON_RECURSIVE); | |
| 78 | + } else { | |
| 79 | + u16 token; | |
| 80 | + | |
| 81 | + ret = fsl_mc_obj_open(mc_dev->mc_io, 0, mc_dev->obj_desc.id, | |
| 82 | + mc_dev->obj_desc.type, | |
| 83 | + &token); | |
| 84 | + if (ret) | |
| 85 | + goto out; | |
| 86 | + ret = fsl_mc_obj_reset(mc_dev->mc_io, 0, token); | |
| 87 | + if (ret) { | |
| 88 | + fsl_mc_obj_close(mc_dev->mc_io, 0, token); | |
| 89 | + goto out; | |
| 90 | + } | |
| 91 | + ret = fsl_mc_obj_close(mc_dev->mc_io, 0, token); | |
| 92 | + } | |
| 93 | +out: | |
| 94 | + return ret; | |
| 95 | +} | |
| 68 | 96 | |
| 69 | 97 | static void vfio_fsl_mc_close_device(struct vfio_device *core_vdev) |
| 70 | 98 | { |
| @@ -78,9 +106,7 @@ static void vfio_fsl_mc_close_device(struct vfio_device *core_vdev) · 7 unmodified lines | ||
| 78 | 106 | vfio_fsl_mc_regions_cleanup(vdev); |
| 79 | 107 | |
| 80 | 108 | /* reset the device before cleaning up the interrupts */ |
| 81 | − ret = dprc_reset_container(mc_cont->mc_io, 0, mc_cont->mc_handle, | |
| 82 | − mc_cont->obj_desc.id, | |
| 83 | − DPRC_RESET_OPTION_NON_RECURSIVE); | |
| 109 | + ret = vfio_fsl_mc_reset_device(vdev); | |
| 84 | 110 | |
| 85 | 111 | if (WARN_ON(ret)) |
| 86 | 112 | dev_warn(&mc_cont->dev, |
| @@ -203,18 +229,7 @@ static long vfio_fsl_mc_ioctl(struct vfio_device *core_vdev, · 116 unmodified lines | ||
| 203 | 229 | } |
| 204 | 230 | case VFIO_DEVICE_RESET: |
| 205 | 231 | { |
| 206 | − int ret; | |
| 207 | − struct fsl_mc_device *mc_dev = vdev->mc_dev; | |
| 208 | − | |
| 209 | − /* reset is supported only for the DPRC */ | |
| 210 | − if (!is_fsl_mc_bus_dprc(mc_dev)) | |
| 211 | − return -ENOTTY; | |
| 212 | − | |
| 213 | − ret = dprc_reset_container(mc_dev->mc_io, 0, | |
| 214 | − mc_dev->mc_handle, | |
| 215 | − mc_dev->obj_desc.id, | |
| 216 | − DPRC_RESET_OPTION_NON_RECURSIVE); | |
| 217 | − return ret; | |
| 232 | + return vfio_fsl_mc_reset_device(vdev); | |
| 218 | 233 | |
| 219 | 234 | } |
| 220 | 235 | default: |
| @@ -505,22 +520,13 @@ static void vfio_fsl_uninit_device(struct vfio_fsl_mc_device *vdev) · 284 unmodified lines | ||
| 505 | 520 | |
| 506 | 521 | static int vfio_fsl_mc_probe(struct fsl_mc_device *mc_dev) |
| 507 | 522 | { |
| 508 | − struct iommu_group *group; | |
| 509 | 523 | struct vfio_fsl_mc_device *vdev; |
| 510 | 524 | struct device *dev = &mc_dev->dev; |
| 511 | 525 | int ret; |
| 512 | 526 | |
| 513 | − group = vfio_iommu_group_get(dev); | |
| 514 | − if (!group) { | |
| 515 | − dev_err(dev, "VFIO_FSL_MC: No IOMMU group\n"); | |
| 516 | − return -EINVAL; | |
| 517 | − } | |
| 518 | − | |
| 519 | 527 | vdev = kzalloc(sizeof(*vdev), GFP_KERNEL); |
| 520 | − if (!vdev) { | |
| 521 | − ret = -ENOMEM; | |
| 522 | − goto out_group_put; | |
| 523 | − } | |
| 528 | + if (!vdev) | |
| 529 | + return -ENOMEM; | |
| 524 | 530 | |
| 525 | 531 | vfio_init_group_dev(&vdev->vdev, dev, &vfio_fsl_mc_ops); |
| 526 | 532 | vdev->mc_dev = mc_dev; |
| @@ -556,8 +562,6 @@ out_device: · 29 unmodified lines | ||
| 556 | 562 | out_uninit: |
| 557 | 563 | vfio_uninit_group_dev(&vdev->vdev); |
| 558 | 564 | kfree(vdev); |
| 559 | −out_group_put: | |
| 560 | − vfio_iommu_group_put(group, dev); | |
| 561 | 565 | return ret; |
| 562 | 566 | } |
| 563 | 567 | |
| @@ -574,8 +578,6 @@ static int vfio_fsl_mc_remove(struct fsl_mc_device *mc_dev) · 10 unmodified lines | ||
| 574 | 578 | |
| 575 | 579 | vfio_uninit_group_dev(&vdev->vdev); |
| 576 | 580 | kfree(vdev); |
| 577 | − vfio_iommu_group_put(mc_dev->dev.iommu_group, dev); | |
| 578 | − | |
| 579 | 581 | return 0; |
| 580 | 582 | } |
| 581 | 583 | |
| @@ -13,60 +13,23 @@ · 12 unmodified lines | ||
| 13 | 13 | |
| 14 | 14 | #include "mdev_private.h" |
| 15 | 15 | |
| 16 | −static int mdev_attach_iommu(struct mdev_device *mdev) | |
| 17 | −{ | |
| 18 | − int ret; | |
| 19 | − struct iommu_group *group; | |
| 20 | − | |
| 21 | − group = iommu_group_alloc(); | |
| 22 | − if (IS_ERR(group)) | |
| 23 | − return PTR_ERR(group); | |
| 24 | − | |
| 25 | − ret = iommu_group_add_device(group, &mdev->dev); | |
| 26 | − if (!ret) | |
| 27 | − dev_info(&mdev->dev, "MDEV: group_id = %d\n", | |
| 28 | − iommu_group_id(group)); | |
| 29 | − | |
| 30 | − iommu_group_put(group); | |
| 31 | − return ret; | |
| 32 | −} | |
| 33 | − | |
| 34 | −static void mdev_detach_iommu(struct mdev_device *mdev) | |
| 35 | −{ | |
| 36 | − iommu_group_remove_device(&mdev->dev); | |
| 37 | − dev_info(&mdev->dev, "MDEV: detaching iommu\n"); | |
| 38 | −} | |
| 39 | − | |
| 40 | 16 | static int mdev_probe(struct device *dev) |
| 41 | 17 | { |
| 42 | 18 | struct mdev_driver *drv = |
| 43 | 19 | container_of(dev->driver, struct mdev_driver, driver); |
| 44 | − struct mdev_device *mdev = to_mdev_device(dev); | |
| 45 | − int ret; | |
| 46 | 20 | |
| 47 | − ret = mdev_attach_iommu(mdev); | |
| 48 | − if (ret) | |
| 49 | − return ret; | |
| 50 | − | |
| 51 | − if (drv->probe) { | |
| 52 | − ret = drv->probe(mdev); | |
| 53 | − if (ret) | |
| 54 | − mdev_detach_iommu(mdev); | |
| 55 | − } | |
| 56 | − | |
| 57 | − return ret; | |
| 21 | + if (!drv->probe) | |
| 22 | + return 0; | |
| 23 | + return drv->probe(to_mdev_device(dev)); | |
| 58 | 24 | } |
| 59 | 25 | |
| 60 | 26 | static void mdev_remove(struct device *dev) |
| 61 | 27 | { |
| 62 | 28 | struct mdev_driver *drv = |
| 63 | 29 | container_of(dev->driver, struct mdev_driver, driver); |
| 64 | − struct mdev_device *mdev = to_mdev_device(dev); | |
| 65 | 30 | |
| 66 | 31 | if (drv->remove) |
| 67 | − drv->remove(mdev); | |
| 68 | − | |
| 69 | − mdev_detach_iommu(mdev); | |
| 32 | + drv->remove(to_mdev_device(dev)); | |
| 70 | 33 | } |
| 71 | 34 | |
| 72 | 35 | static int mdev_match(struct device *dev, struct device_driver *drv) |
| @@ -119,7 +119,7 @@ static int vfio_mdev_probe(struct mdev_device *mdev) · 118 unmodified lines | ||
| 119 | 119 | return -ENOMEM; |
| 120 | 120 | |
| 121 | 121 | vfio_init_group_dev(vdev, &mdev->dev, &vfio_mdev_dev_ops); |
| 122 | − ret = vfio_register_group_dev(vdev); | |
| 122 | + ret = vfio_register_emulated_iommu_dev(vdev); | |
| 123 | 123 | if (ret) |
| 124 | 124 | goto out_uninit; |
| 125 | 125 | |
| @@ -1806,7 +1806,6 @@ EXPORT_SYMBOL_GPL(vfio_pci_core_uninit_device); · 1805 unmodified lines | ||
| 1806 | 1806 | int vfio_pci_core_register_device(struct vfio_pci_core_device *vdev) |
| 1807 | 1807 | { |
| 1808 | 1808 | struct pci_dev *pdev = vdev->pdev; |
| 1809 | − struct iommu_group *group; | |
| 1810 | 1809 | int ret; |
| 1811 | 1810 | |
| 1812 | 1811 | if (pdev->hdr_type != PCI_HEADER_TYPE_NORMAL) |
| @@ -1825,10 +1824,6 @@ int vfio_pci_core_register_device(struct vfio_pci_core_device *vdev) · 12 unmodified lines | ||
| 1825 | 1824 | return -EBUSY; |
| 1826 | 1825 | } |
| 1827 | 1826 | |
| 1828 | − group = vfio_iommu_group_get(&pdev->dev); | |
| 1829 | − if (!group) | |
| 1830 | − return -EINVAL; | |
| 1831 | − | |
| 1832 | 1827 | if (pci_is_root_bus(pdev->bus)) { |
| 1833 | 1828 | ret = vfio_assign_device_set(&vdev->vdev, vdev); |
| 1834 | 1829 | } else if (!pci_probe_reset_slot(pdev->slot)) { |
| @@ -1842,10 +1837,10 @@ int vfio_pci_core_register_device(struct vfio_pci_core_device *vdev) · 7 unmodified lines | ||
| 1842 | 1837 | } |
| 1843 | 1838 | |
| 1844 | 1839 | if (ret) |
| 1845 | − goto out_group_put; | |
| 1840 | + return ret; | |
| 1846 | 1841 | ret = vfio_pci_vf_init(vdev); |
| 1847 | 1842 | if (ret) |
| 1848 | − goto out_group_put; | |
| 1843 | + return ret; | |
| 1849 | 1844 | ret = vfio_pci_vga_init(vdev); |
| 1850 | 1845 | if (ret) |
| 1851 | 1846 | goto out_vf; |
| @@ -1876,8 +1871,6 @@ out_power: · 24 unmodified lines | ||
| 1876 | 1871 | vfio_pci_set_power_state(vdev, PCI_D0); |
| 1877 | 1872 | out_vf: |
| 1878 | 1873 | vfio_pci_vf_uninit(vdev); |
| 1879 | −out_group_put: | |
| 1880 | − vfio_iommu_group_put(group, &pdev->dev); | |
| 1881 | 1874 | return ret; |
| 1882 | 1875 | } |
| 1883 | 1876 | EXPORT_SYMBOL_GPL(vfio_pci_core_register_device); |
| @@ -1893,8 +1886,6 @@ void vfio_pci_core_unregister_device(struct vfio_pci_core_device *vdev) · 9 unmodified lines | ||
| 1893 | 1886 | vfio_pci_vf_uninit(vdev); |
| 1894 | 1887 | vfio_pci_vga_uninit(vdev); |
| 1895 | 1888 | |
| 1896 | − vfio_iommu_group_put(pdev->dev.iommu_group, &pdev->dev); | |
| 1897 | − | |
| 1898 | 1889 | if (!disable_idle_d3) |
| 1899 | 1890 | vfio_pci_set_power_state(vdev, PCI_D0); |
| 1900 | 1891 | } |
| @@ -25,20 +25,121 @@ · 24 unmodified lines | ||
| 25 | 25 | #define OPREGION_RVDS 0x3c2 |
| 26 | 26 | #define OPREGION_VERSION 0x16 |
| 27 | 27 | |
| 28 | +struct igd_opregion_vbt { | |
| 29 | + void *opregion; | |
| 30 | + void *vbt_ex; | |
| 31 | +}; | |
| 32 | + | |
| 33 | +/** | |
| 34 | + * igd_opregion_shift_copy() - Copy OpRegion to user buffer and shift position. | |
| 35 | + * @dst: User buffer ptr to copy to. | |
| 36 | + * @off: Offset to user buffer ptr. Increased by bytes on return. | |
| 37 | + * @src: Source buffer to copy from. | |
| 38 | + * @pos: Increased by bytes on return. | |
| 39 | + * @remaining: Decreased by bytes on return. | |
| 40 | + * @bytes: Bytes to copy and adjust off, pos and remaining. | |
| 41 | + * | |
| 42 | + * Copy OpRegion to offset from specific source ptr and shift the offset. | |
| 43 | + * | |
| 44 | + * Return: 0 on success, -EFAULT otherwise. | |
| 45 | + * | |
| 46 | + */ | |
| 47 | +static inline unsigned long igd_opregion_shift_copy(char __user *dst, | |
| 48 | + loff_t *off, | |
| 49 | + void *src, | |
| 50 | + loff_t *pos, | |
| 51 | + size_t *remaining, | |
| 52 | + size_t bytes) | |
| 53 | +{ | |
| 54 | + if (copy_to_user(dst + (*off), src, bytes)) | |
| 55 | + return -EFAULT; | |
| 56 | + | |
| 57 | + *off += bytes; | |
| 58 | + *pos += bytes; | |
| 59 | + *remaining -= bytes; | |
| 60 | + | |
| 61 | + return 0; | |
| 62 | +} | |
| 63 | + | |
| 28 | 64 | static ssize_t vfio_pci_igd_rw(struct vfio_pci_core_device *vdev, |
| 29 | 65 | char __user *buf, size_t count, loff_t *ppos, |
| 30 | 66 | bool iswrite) |
| 31 | 67 | { |
| 32 | 68 | unsigned int i = VFIO_PCI_OFFSET_TO_INDEX(*ppos) - VFIO_PCI_NUM_REGIONS; |
| 33 | − void *base = vdev->region[i].data; | |
| 34 | − loff_t pos = *ppos & VFIO_PCI_OFFSET_MASK; | |
| 69 | + struct igd_opregion_vbt *opregionvbt = vdev->region[i].data; | |
| 70 | + loff_t pos = *ppos & VFIO_PCI_OFFSET_MASK, off = 0; | |
| 71 | + size_t remaining; | |
| 35 | 72 | |
| 36 | 73 | if (pos >= vdev->region[i].size || iswrite) |
| 37 | 74 | return -EINVAL; |
| 38 | 75 | |
| 39 | − count = min(count, (size_t)(vdev->region[i].size - pos)); | |
| 76 | + count = min_t(size_t, count, vdev->region[i].size - pos); | |
| 77 | + remaining = count; | |
| 78 | + | |
| 79 | + /* Copy until OpRegion version */ | |
| 80 | + if (remaining && pos < OPREGION_VERSION) { | |
| 81 | + size_t bytes = min_t(size_t, remaining, OPREGION_VERSION - pos); | |
| 82 | + | |
| 83 | + if (igd_opregion_shift_copy(buf, &off, | |
| 84 | + opregionvbt->opregion + pos, &pos, | |
| 85 | + &remaining, bytes)) | |
| 86 | + return -EFAULT; | |
| 87 | + } | |
| 88 | + | |
| 89 | + /* Copy patched (if necessary) OpRegion version */ | |
| 90 | + if (remaining && pos < OPREGION_VERSION + sizeof(__le16)) { | |
| 91 | + size_t bytes = min_t(size_t, remaining, | |
| 92 | + OPREGION_VERSION + sizeof(__le16) - pos); | |
| 93 | + __le16 version = *(__le16 *)(opregionvbt->opregion + | |
| 94 | + OPREGION_VERSION); | |
| 95 | + | |
| 96 | + /* Patch to 2.1 if OpRegion 2.0 has extended VBT */ | |
| 97 | + if (le16_to_cpu(version) == 0x0200 && opregionvbt->vbt_ex) | |
| 98 | + version = cpu_to_le16(0x0201); | |
| 99 | + | |
| 100 | + if (igd_opregion_shift_copy(buf, &off, | |
| 101 | + &version + (pos - OPREGION_VERSION), | |
| 102 | + &pos, &remaining, bytes)) | |
| 103 | + return -EFAULT; | |
| 104 | + } | |
| 105 | + | |
| 106 | + /* Copy until RVDA */ | |
| 107 | + if (remaining && pos < OPREGION_RVDA) { | |
| 108 | + size_t bytes = min_t(size_t, remaining, OPREGION_RVDA - pos); | |
| 40 | 109 | |
| 41 | − if (copy_to_user(buf, base + pos, count)) | |
| 110 | + if (igd_opregion_shift_copy(buf, &off, | |
| 111 | + opregionvbt->opregion + pos, &pos, | |
| 112 | + &remaining, bytes)) | |
| 113 | + return -EFAULT; | |
| 114 | + } | |
| 115 | + | |
| 116 | + /* Copy modified (if necessary) RVDA */ | |
| 117 | + if (remaining && pos < OPREGION_RVDA + sizeof(__le64)) { | |
| 118 | + size_t bytes = min_t(size_t, remaining, | |
| 119 | + OPREGION_RVDA + sizeof(__le64) - pos); | |
| 120 | + __le64 rvda = cpu_to_le64(opregionvbt->vbt_ex ? | |
| 121 | + OPREGION_SIZE : 0); | |
| 122 | + | |
| 123 | + if (igd_opregion_shift_copy(buf, &off, | |
| 124 | + &rvda + (pos - OPREGION_RVDA), | |
| 125 | + &pos, &remaining, bytes)) | |
| 126 | + return -EFAULT; | |
| 127 | + } | |
| 128 | + | |
| 129 | + /* Copy the rest of OpRegion */ | |
| 130 | + if (remaining && pos < OPREGION_SIZE) { | |
| 131 | + size_t bytes = min_t(size_t, remaining, OPREGION_SIZE - pos); | |
| 132 | + | |
| 133 | + if (igd_opregion_shift_copy(buf, &off, | |
| 134 | + opregionvbt->opregion + pos, &pos, | |
| 135 | + &remaining, bytes)) | |
| 136 | + return -EFAULT; | |
| 137 | + } | |
| 138 | + | |
| 139 | + /* Copy extended VBT if exists */ | |
| 140 | + if (remaining && | |
| 141 | + copy_to_user(buf + off, opregionvbt->vbt_ex + (pos - OPREGION_SIZE), | |
| 142 | + remaining)) | |
| 42 | 143 | return -EFAULT; |
| 43 | 144 | |
| 44 | 145 | *ppos += count; |
| @@ -49,7 +150,13 @@ static ssize_t vfio_pci_igd_rw(struct vfio_pci_core_device *vdev, · 4 unmodified lines | ||
| 49 | 150 | static void vfio_pci_igd_release(struct vfio_pci_core_device *vdev, |
| 50 | 151 | struct vfio_pci_region *region) |
| 51 | 152 | { |
| 52 | − memunmap(region->data); | |
| 153 | + struct igd_opregion_vbt *opregionvbt = region->data; | |
| 154 | + | |
| 155 | + if (opregionvbt->vbt_ex) | |
| 156 | + memunmap(opregionvbt->vbt_ex); | |
| 157 | + | |
| 158 | + memunmap(opregionvbt->opregion); | |
| 159 | + kfree(opregionvbt); | |
| 53 | 160 | } |
| 54 | 161 | |
| 55 | 162 | static const struct vfio_pci_regops vfio_pci_igd_regops = { |
| @@ -61,7 +168,7 @@ static int vfio_pci_igd_opregion_init(struct vfio_pci_core_device *vdev) · 5 unmodified lines | ||
| 61 | 168 | { |
| 62 | 169 | __le32 *dwordp = (__le32 *)(vdev->vconfig + OPREGION_PCI_ADDR); |
| 63 | 170 | u32 addr, size; |
| 64 | − void *base; | |
| 171 | + struct igd_opregion_vbt *opregionvbt; | |
| 65 | 172 | int ret; |
| 66 | 173 | u16 version; |
| 67 | 174 | |
| @@ -72,84 +179,93 @@ static int vfio_pci_igd_opregion_init(struct vfio_pci_core_device *vdev) · 4 unmodified lines | ||
| 72 | 179 | if (!addr || !(~addr)) |
| 73 | 180 | return -ENODEV; |
| 74 | 181 | |
| 75 | − base = memremap(addr, OPREGION_SIZE, MEMREMAP_WB); | |
| 76 | − if (!base) | |
| 182 | + opregionvbt = kzalloc(sizeof(*opregionvbt), GFP_KERNEL); | |
| 183 | + if (!opregionvbt) | |
| 184 | + return -ENOMEM; | |
| 185 | + | |
| 186 | + opregionvbt->opregion = memremap(addr, OPREGION_SIZE, MEMREMAP_WB); | |
| 187 | + if (!opregionvbt->opregion) { | |
| 188 | + kfree(opregionvbt); | |
| 77 | 189 | return -ENOMEM; |
| 190 | + } | |
| 78 | 191 | |
| 79 | − if (memcmp(base, OPREGION_SIGNATURE, 16)) { | |
| 80 | − memunmap(base); | |
| 192 | + if (memcmp(opregionvbt->opregion, OPREGION_SIGNATURE, 16)) { | |
| 193 | + memunmap(opregionvbt->opregion); | |
| 194 | + kfree(opregionvbt); | |
| 81 | 195 | return -EINVAL; |
| 82 | 196 | } |
| 83 | 197 | |
| 84 | − size = le32_to_cpu(*(__le32 *)(base + 16)); | |
| 198 | + size = le32_to_cpu(*(__le32 *)(opregionvbt->opregion + 16)); | |
| 85 | 199 | if (!size) { |
| 86 | − memunmap(base); | |
| 200 | + memunmap(opregionvbt->opregion); | |
| 201 | + kfree(opregionvbt); | |
| 87 | 202 | return -EINVAL; |
| 88 | 203 | } |
| 89 | 204 | |
| 90 | 205 | size *= 1024; /* In KB */ |
| 91 | 206 | |
| 92 | 207 | /* |
| 93 | − * Support opregion v2.1+ | |
| 94 | − * When VBT data exceeds 6KB size and cannot be within mailbox #4, then | |
| 95 | − * the Extended VBT region next to opregion is used to hold the VBT data. | |
| 96 | − * RVDA (Relative Address of VBT Data from Opregion Base) and RVDS | |
| 97 | − * (Raw VBT Data Size) from opregion structure member are used to hold the | |
| 98 | − * address from region base and size of VBT data. RVDA/RVDS are not | |
| 99 | − * defined before opregion 2.0. | |
| 100 | − * | |
| 101 | − * opregion 2.1+: RVDA is unsigned, relative offset from | |
| 102 | − * opregion base, and should point to the end of opregion. | |
| 103 | − * otherwise, exposing to userspace to allow read access to everything between | |
| 104 | − * the OpRegion and VBT is not safe. | |
| 105 | − * RVDS is defined as size in bytes. | |
| 208 | + * OpRegion and VBT: | |
| 209 | + * When VBT data doesn't exceed 6KB, it's stored in Mailbox #4. | |
| 210 | + * When VBT data exceeds 6KB size, Mailbox #4 is no longer large enough | |
| 211 | + * to hold the VBT data, the Extended VBT region is introduced since | |
| 212 | + * OpRegion 2.0 to hold the VBT data. Since OpRegion 2.0, RVDA/RVDS are | |
| 213 | + * introduced to define the extended VBT data location and size. | |
| 214 | + * OpRegion 2.0: RVDA defines the absolute physical address of the | |
| 215 | + * extended VBT data, RVDS defines the VBT data size. | |
| 216 | + * OpRegion 2.1 and above: RVDA defines the relative address of the | |
| 217 | + * extended VBT data to OpRegion base, RVDS defines the VBT data size. | |
| 106 | 218 | * |
| 107 | − * opregion 2.0: rvda is the physical VBT address. | |
| 108 | − * Since rvda is HPA it cannot be directly used in guest. | |
| 109 | − * And it should not be practically available for end user,so it is not supported. | |
| 219 | + * Due to the RVDA definition diff in OpRegion VBT (also the only diff | |
| 220 | + * between 2.0 and 2.1), exposing OpRegion and VBT as a contiguous range | |
| 221 | + * for OpRegion 2.0 and above makes it possible to support the | |
| 222 | + * non-contiguous VBT through a single vfio region. From r/w ops view, | |
| 223 | + * only contiguous VBT after OpRegion with version 2.1+ is exposed, | |
| 224 | + * regardless the host OpRegion is 2.0 or non-contiguous 2.1+. The r/w | |
| 225 | + * ops will on-the-fly shift the actural offset into VBT so that data at | |
| 226 | + * correct position can be returned to the requester. | |
| 110 | 227 | */ |
| 111 | − version = le16_to_cpu(*(__le16 *)(base + OPREGION_VERSION)); | |
| 228 | + version = le16_to_cpu(*(__le16 *)(opregionvbt->opregion + | |
| 229 | + OPREGION_VERSION)); | |
| 112 | 230 | if (version >= 0x0200) { |
| 113 | − u64 rvda; | |
| 114 | − u32 rvds; | |
| 231 | + u64 rvda = le64_to_cpu(*(__le64 *)(opregionvbt->opregion + | |
| 232 | + OPREGION_RVDA)); | |
| 233 | + u32 rvds = le32_to_cpu(*(__le32 *)(opregionvbt->opregion + | |
| 234 | + OPREGION_RVDS)); | |
| 115 | 235 | |
| 116 | − rvda = le64_to_cpu(*(__le64 *)(base + OPREGION_RVDA)); | |
| 117 | − rvds = le32_to_cpu(*(__le32 *)(base + OPREGION_RVDS)); | |
| 236 | + /* The extended VBT is valid only when RVDA/RVDS are non-zero */ | |
| 118 | 237 | if (rvda && rvds) { |
| 119 | − /* no support for opregion v2.0 with physical VBT address */ | |
| 120 | − if (version == 0x0200) { | |
| 121 | − memunmap(base); | |
| 122 | − pci_err(vdev->pdev, | |
| 123 | − "IGD assignment does not support opregion v2.0 with an extended VBT region\n"); | |
| 124 | − return -EINVAL; | |
| 125 | − } | |
| 238 | + size += rvds; | |
| 126 | 239 | |
| 127 | − if (rvda != size) { | |
| 128 | − memunmap(base); | |
| 129 | − pci_err(vdev->pdev, | |
| 130 | − "Extended VBT does not follow opregion on version 0x%04x\n", | |
| 131 | − version); | |
| 132 | − return -EINVAL; | |
| 240 | + /* | |
| 241 | + * Extended VBT location by RVDA: | |
| 242 | + * Absolute physical addr for 2.0. | |
| 243 | + * Relative addr to OpRegion header for 2.1+. | |
| 244 | + */ | |
| 245 | + if (version == 0x0200) | |
| 246 | + addr = rvda; | |
| 247 | + else | |
| 248 | + addr += rvda; | |
| 249 | + | |
| 250 | + opregionvbt->vbt_ex = memremap(addr, rvds, MEMREMAP_WB); | |
| 251 | + if (!opregionvbt->vbt_ex) { | |
| 252 | + memunmap(opregionvbt->opregion); | |
| 253 | + kfree(opregionvbt); | |
| 254 | + return -ENOMEM; | |
| 133 | 255 | } |
| 134 | − | |
| 135 | − /* region size for opregion v2.0+: opregion and VBT size. */ | |
| 136 | − size += rvds; | |
| 137 | 256 | } |
| 138 | 257 | } |
| 139 | 258 | |
| 140 | − if (size != OPREGION_SIZE) { | |
| 141 | − memunmap(base); | |
| 142 | − base = memremap(addr, size, MEMREMAP_WB); | |
| 143 | − if (!base) | |
| 144 | − return -ENOMEM; | |
| 145 | − } | |
| 146 | − | |
| 147 | 259 | ret = vfio_pci_register_dev_region(vdev, |
| 148 | 260 | PCI_VENDOR_ID_INTEL | VFIO_REGION_TYPE_PCI_VENDOR_TYPE, |
| 149 | − VFIO_REGION_SUBTYPE_INTEL_IGD_OPREGION, | |
| 150 | − &vfio_pci_igd_regops, size, VFIO_REGION_INFO_FLAG_READ, base); | |
| 261 | + VFIO_REGION_SUBTYPE_INTEL_IGD_OPREGION, &vfio_pci_igd_regops, | |
| 262 | + size, VFIO_REGION_INFO_FLAG_READ, opregionvbt); | |
| 151 | 263 | if (ret) { |
| 152 | − memunmap(base); | |
| 264 | + if (opregionvbt->vbt_ex) | |
| 265 | + memunmap(opregionvbt->vbt_ex); | |
| 266 | + | |
| 267 | + memunmap(opregionvbt->opregion); | |
| 268 | + kfree(opregionvbt); | |
| 153 | 269 | return ret; |
| 154 | 270 | } |
| 155 | 271 | |
| @@ -642,7 +642,6 @@ static int vfio_platform_of_probe(struct vfio_platform_device *vdev, · 641 unmodified lines | ||
| 642 | 642 | int vfio_platform_probe_common(struct vfio_platform_device *vdev, |
| 643 | 643 | struct device *dev) |
| 644 | 644 | { |
| 645 | − struct iommu_group *group; | |
| 646 | 645 | int ret; |
| 647 | 646 | |
| 648 | 647 | vfio_init_group_dev(&vdev->vdev, dev, &vfio_platform_ops); |
| @@ -663,24 +662,15 @@ int vfio_platform_probe_common(struct vfio_platform_device *vdev, · 14 unmodified lines | ||
| 663 | 662 | goto out_uninit; |
| 664 | 663 | } |
| 665 | 664 | |
| 666 | − group = vfio_iommu_group_get(dev); | |
| 667 | − if (!group) { | |
| 668 | − dev_err(dev, "No IOMMU group for device %s\n", vdev->name); | |
| 669 | − ret = -EINVAL; | |
| 670 | − goto put_reset; | |
| 671 | − } | |
| 672 | − | |
| 673 | 665 | ret = vfio_register_group_dev(&vdev->vdev); |
| 674 | 666 | if (ret) |
| 675 | − goto put_iommu; | |
| 667 | + goto put_reset; | |
| 676 | 668 | |
| 677 | 669 | mutex_init(&vdev->igate); |
| 678 | 670 | |
| 679 | 671 | pm_runtime_enable(dev); |
| 680 | 672 | return 0; |
| 681 | 673 | |
| 682 | −put_iommu: | |
| 683 | − vfio_iommu_group_put(group, dev); | |
| 684 | 674 | put_reset: |
| 685 | 675 | vfio_platform_put_reset(vdev); |
| 686 | 676 | out_uninit: |
| @@ -696,7 +686,6 @@ void vfio_platform_remove_common(struct vfio_platform_device *vdev) · 9 unmodified lines | ||
| 696 | 686 | pm_runtime_disable(vdev->device); |
| 697 | 687 | vfio_platform_put_reset(vdev); |
| 698 | 688 | vfio_uninit_group_dev(&vdev->vdev); |
| 699 | − vfio_iommu_group_put(vdev->vdev.dev->iommu_group, vdev->vdev.dev); | |
| 700 | 689 | } |
| 701 | 690 | EXPORT_SYMBOL_GPL(vfio_platform_remove_common); |
| 702 | 691 | |
| @@ -32,6 +32,7 @@ · 31 unmodified lines | ||
| 32 | 32 | #include <linux/vfio.h> |
| 33 | 33 | #include <linux/wait.h> |
| 34 | 34 | #include <linux/sched/signal.h> |
| 35 | +#include "vfio.h" | |
| 35 | 36 | |
| 36 | 37 | #define DRIVER_VERSION "0.3" |
| 37 | 38 | #define DRIVER_AUTHOR "Alex Williamson <alex.williamson@redhat.com>" |
| @@ -42,9 +43,8 @@ static struct vfio { · 4 unmodified lines | ||
| 42 | 43 | struct list_head iommu_drivers_list; |
| 43 | 44 | struct mutex iommu_drivers_lock; |
| 44 | 45 | struct list_head group_list; |
| 45 | − struct idr group_idr; | |
| 46 | − struct mutex group_lock; | |
| 47 | − struct cdev group_cdev; | |
| 46 | + struct mutex group_lock; /* locks group_list */ | |
| 47 | + struct ida group_ida; | |
| 48 | 48 | dev_t group_devt; |
| 49 | 49 | } vfio; |
| 50 | 50 | |
| @@ -68,14 +68,14 @@ struct vfio_unbound_dev { · 17 unmodified lines | ||
| 68 | 68 | }; |
| 69 | 69 | |
| 70 | 70 | struct vfio_group { |
| 71 | − struct kref kref; | |
| 72 | − int minor; | |
| 71 | + struct device dev; | |
| 72 | + struct cdev cdev; | |
| 73 | + refcount_t users; | |
| 73 | 74 | atomic_t container_users; |
| 74 | 75 | struct iommu_group *iommu_group; |
| 75 | 76 | struct vfio_container *container; |
| 76 | 77 | struct list_head device_list; |
| 77 | 78 | struct mutex device_lock; |
| 78 | − struct device *dev; | |
| 79 | 79 | struct notifier_block nb; |
| 80 | 80 | struct list_head vfio_next; |
| 81 | 81 | struct list_head container_next; |
| @@ -83,7 +83,7 @@ struct vfio_group { · 1 unmodified line | ||
| 83 | 83 | struct mutex unbound_lock; |
| 84 | 84 | atomic_t opened; |
| 85 | 85 | wait_queue_head_t container_q; |
| 86 | − bool noiommu; | |
| 86 | + enum vfio_group_type type; | |
| 87 | 87 | unsigned int dev_counter; |
| 88 | 88 | struct kvm *kvm; |
| 89 | 89 | struct blocking_notifier_head notifier; |
| @@ -97,6 +97,7 @@ MODULE_PARM_DESC(enable_unsafe_noiommu_mode, "Enable UNSAFE, no-IOMMU mode. Thi · 7 unmodified lines | ||
| 97 | 97 | #endif |
| 98 | 98 | |
| 99 | 99 | static DEFINE_XARRAY(vfio_device_set_xa); |
| 100 | +static const struct file_operations vfio_group_fops; | |
| 100 | 101 | |
| 101 | 102 | int vfio_assign_device_set(struct vfio_device *device, void *set_id) |
| 102 | 103 | { |
| @@ -169,70 +170,6 @@ static void vfio_release_device_set(struct vfio_device *device) · 66 unmodified lines | ||
| 169 | 170 | xa_unlock(&vfio_device_set_xa); |
| 170 | 171 | } |
| 171 | 172 | |
| 172 | −/* | |
| 173 | − * vfio_iommu_group_{get,put} are only intended for VFIO bus driver probe | |
| 174 | − * and remove functions, any use cases other than acquiring the first | |
| 175 | − * reference for the purpose of calling vfio_register_group_dev() or removing | |
| 176 | − * that symmetric reference after vfio_unregister_group_dev() should use the raw | |
| 177 | − * iommu_group_{get,put} functions. In particular, vfio_iommu_group_put() | |
| 178 | − * removes the device from the dummy group and cannot be nested. | |
| 179 | − */ | |
| 180 | −struct iommu_group *vfio_iommu_group_get(struct device *dev) | |
| 181 | −{ | |
| 182 | − struct iommu_group *group; | |
| 183 | − int __maybe_unused ret; | |
| 184 | − | |
| 185 | − group = iommu_group_get(dev); | |
| 186 | − | |
| 187 | −#ifdef CONFIG_VFIO_NOIOMMU | |
| 188 | − /* | |
| 189 | − * With noiommu enabled, an IOMMU group will be created for a device | |
| 190 | − * that doesn't already have one and doesn't have an iommu_ops on their | |
| 191 | − * bus. We set iommudata simply to be able to identify these groups | |
| 192 | − * as special use and for reclamation later. | |
| 193 | − */ | |
| 194 | − if (group || !noiommu || iommu_present(dev->bus)) | |
| 195 | − return group; | |
| 196 | − | |
| 197 | − group = iommu_group_alloc(); | |
| 198 | − if (IS_ERR(group)) | |
| 199 | − return NULL; | |
| 200 | − | |
| 201 | − iommu_group_set_name(group, "vfio-noiommu"); | |
| 202 | − iommu_group_set_iommudata(group, &noiommu, NULL); | |
| 203 | − ret = iommu_group_add_device(group, dev); | |
| 204 | − if (ret) { | |
| 205 | − iommu_group_put(group); | |
| 206 | − return NULL; | |
| 207 | − } | |
| 208 | − | |
| 209 | − /* | |
| 210 | − * Where to taint? At this point we've added an IOMMU group for a | |
| 211 | − * device that is not backed by iommu_ops, therefore any iommu_ | |
| 212 | − * callback using iommu_ops can legitimately Oops. So, while we may | |
| 213 | − * be about to give a DMA capable device to a user without IOMMU | |
| 214 | − * protection, which is clearly taint-worthy, let's go ahead and do | |
| 215 | − * it here. | |
| 216 | − */ | |
| 217 | − add_taint(TAINT_USER, LOCKDEP_STILL_OK); | |
| 218 | − dev_warn(dev, "Adding kernel taint for vfio-noiommu group on device\n"); | |
| 219 | −#endif | |
| 220 | − | |
| 221 | − return group; | |
| 222 | −} | |
| 223 | −EXPORT_SYMBOL_GPL(vfio_iommu_group_get); | |
| 224 | − | |
| 225 | −void vfio_iommu_group_put(struct iommu_group *group, struct device *dev) | |
| 226 | −{ | |
| 227 | −#ifdef CONFIG_VFIO_NOIOMMU | |
| 228 | − if (iommu_group_get_iommudata(group) == &noiommu) | |
| 229 | − iommu_group_remove_device(dev); | |
| 230 | −#endif | |
| 231 | − | |
| 232 | − iommu_group_put(group); | |
| 233 | −} | |
| 234 | −EXPORT_SYMBOL_GPL(vfio_iommu_group_put); | |
| 235 | − | |
| 236 | 173 | #ifdef CONFIG_VFIO_NOIOMMU |
| 237 | 174 | static void *vfio_noiommu_open(unsigned long arg) |
| 238 | 175 | { |
| @@ -258,9 +195,9 @@ static long vfio_noiommu_ioctl(void *iommu_data, · 19 unmodified lines | ||
| 258 | 195 | } |
| 259 | 196 | |
| 260 | 197 | static int vfio_noiommu_attach_group(void *iommu_data, |
| 261 | − struct iommu_group *iommu_group) | |
| 198 | + struct iommu_group *iommu_group, enum vfio_group_type type) | |
| 262 | 199 | { |
| 263 | − return iommu_group_get_iommudata(iommu_group) == &noiommu ? 0 : -EINVAL; | |
| 200 | + return 0; | |
| 264 | 201 | } |
| 265 | 202 | |
| 266 | 203 | static void vfio_noiommu_detach_group(void *iommu_data, |
| @@ -277,8 +214,23 @@ static const struct vfio_iommu_driver_ops vfio_noiommu_ops = { · 10 unmodified lines | ||
| 277 | 214 | .attach_group = vfio_noiommu_attach_group, |
| 278 | 215 | .detach_group = vfio_noiommu_detach_group, |
| 279 | 216 | }; |
| 280 | −#endif | |
| 281 | 217 | |
| 218 | +/* | |
| 219 | + * Only noiommu containers can use vfio-noiommu and noiommu containers can only | |
| 220 | + * use vfio-noiommu. | |
| 221 | + */ | |
| 222 | +static inline bool vfio_iommu_driver_allowed(struct vfio_container *container, | |
| 223 | + const struct vfio_iommu_driver *driver) | |
| 224 | +{ | |
| 225 | + return container->noiommu == (driver->ops == &vfio_noiommu_ops); | |
| 226 | +} | |
| 227 | +#else | |
| 228 | +static inline bool vfio_iommu_driver_allowed(struct vfio_container *container, | |
| 229 | + const struct vfio_iommu_driver *driver) | |
| 230 | +{ | |
| 231 | + return true; | |
| 232 | +} | |
| 233 | +#endif /* CONFIG_VFIO_NOIOMMU */ | |
| 282 | 234 | |
| 283 | 235 | /** |
| 284 | 236 | * IOMMU driver registration |
| @@ -329,19 +281,6 @@ void vfio_unregister_iommu_driver(const struct vfio_iommu_driver_ops *ops) · 44 unmodified lines | ||
| 329 | 281 | } |
| 330 | 282 | EXPORT_SYMBOL_GPL(vfio_unregister_iommu_driver); |
| 331 | 283 | |
| 332 | −/** | |
| 333 | − * Group minor allocation/free - both called with vfio.group_lock held | |
| 334 | − */ | |
| 335 | −static int vfio_alloc_group_minor(struct vfio_group *group) | |
| 336 | −{ | |
| 337 | − return idr_alloc(&vfio.group_idr, group, 0, MINORMASK + 1, GFP_KERNEL); | |
| 338 | −} | |
| 339 | − | |
| 340 | −static void vfio_free_group_minor(int minor) | |
| 341 | −{ | |
| 342 | − idr_remove(&vfio.group_idr, minor); | |
| 343 | −} | |
| 344 | − | |
| 345 | 284 | static int vfio_iommu_group_notifier(struct notifier_block *nb, |
| 346 | 285 | unsigned long action, void *data); |
| 347 | 286 | static void vfio_group_get(struct vfio_group *group); |
| @@ -370,105 +309,38 @@ static void vfio_container_put(struct vfio_container *container) · 22 unmodified lines | ||
| 370 | 309 | kref_put(&container->kref, vfio_container_release); |
| 371 | 310 | } |
| 372 | 311 | |
| 373 | −static void vfio_group_unlock_and_free(struct vfio_group *group) | |
| 374 | −{ | |
| 375 | − mutex_unlock(&vfio.group_lock); | |
| 376 | − /* | |
| 377 | − * Unregister outside of lock. A spurious callback is harmless now | |
| 378 | − * that the group is no longer in vfio.group_list. | |
| 379 | − */ | |
| 380 | − iommu_group_unregister_notifier(group->iommu_group, &group->nb); | |
| 381 | − kfree(group); | |
| 382 | −} | |
| 383 | − | |
| 384 | 312 | /** |
| 385 | 313 | * Group objects - create, release, get, put, search |
| 386 | 314 | */ |
| 387 | −static struct vfio_group *vfio_create_group(struct iommu_group *iommu_group) | |
| 315 | +static struct vfio_group * | |
| 316 | +__vfio_group_get_from_iommu(struct iommu_group *iommu_group) | |
| 388 | 317 | { |
| 389 | − struct vfio_group *group, *tmp; | |
| 390 | − struct device *dev; | |
| 391 | − int ret, minor; | |
| 392 | − | |
| 393 | − group = kzalloc(sizeof(*group), GFP_KERNEL); | |
| 394 | − if (!group) | |
| 395 | − return ERR_PTR(-ENOMEM); | |
| 396 | − | |
| 397 | − kref_init(&group->kref); | |
| 398 | − INIT_LIST_HEAD(&group->device_list); | |
| 399 | − mutex_init(&group->device_lock); | |
| 400 | − INIT_LIST_HEAD(&group->unbound_list); | |
| 401 | − mutex_init(&group->unbound_lock); | |
| 402 | − atomic_set(&group->container_users, 0); | |
| 403 | − atomic_set(&group->opened, 0); | |
| 404 | − init_waitqueue_head(&group->container_q); | |
| 405 | − group->iommu_group = iommu_group; | |
| 406 | −#ifdef CONFIG_VFIO_NOIOMMU | |
| 407 | − group->noiommu = (iommu_group_get_iommudata(iommu_group) == &noiommu); | |
| 408 | −#endif | |
| 409 | − BLOCKING_INIT_NOTIFIER_HEAD(&group->notifier); | |
| 410 | − | |
| 411 | − group->nb.notifier_call = vfio_iommu_group_notifier; | |
| 412 | − | |
| 413 | − /* | |
| 414 | − * blocking notifiers acquire a rwsem around registering and hold | |
| 415 | − * it around callback. Therefore, need to register outside of | |
| 416 | − * vfio.group_lock to avoid A-B/B-A contention. Our callback won't | |
| 417 | − * do anything unless it can find the group in vfio.group_list, so | |
| 418 | − * no harm in registering early. | |
| 419 | − */ | |
| 420 | − ret = iommu_group_register_notifier(iommu_group, &group->nb); | |
| 421 | − if (ret) { | |
| 422 | − kfree(group); | |
| 423 | − return ERR_PTR(ret); | |
| 424 | − } | |
| 425 | − | |
| 426 | − mutex_lock(&vfio.group_lock); | |
| 318 | + struct vfio_group *group; | |
| 427 | 319 | |
| 428 | − /* Did we race creating this group? */ | |
| 429 | − list_for_each_entry(tmp, &vfio.group_list, vfio_next) { | |
| 430 | − if (tmp->iommu_group == iommu_group) { | |
| 431 | − vfio_group_get(tmp); | |
| 432 | − vfio_group_unlock_and_free(group); | |
| 433 | − return tmp; | |
| 320 | + list_for_each_entry(group, &vfio.group_list, vfio_next) { | |
| 321 | + if (group->iommu_group == iommu_group) { | |
| 322 | + vfio_group_get(group); | |
| 323 | + return group; | |
| 434 | 324 | } |
| 435 | 325 | } |
| 326 | + return NULL; | |
| 327 | +} | |
| 436 | 328 | |
| 437 | − minor = vfio_alloc_group_minor(group); | |
| 438 | − if (minor < 0) { | |
| 439 | − vfio_group_unlock_and_free(group); | |
| 440 | − return ERR_PTR(minor); | |
| 441 | − } | |
| 442 | − | |
| 443 | − dev = device_create(vfio.class, NULL, | |
| 444 | − MKDEV(MAJOR(vfio.group_devt), minor), | |
| 445 | − group, "%s%d", group->noiommu ? "noiommu-" : "", | |
| 446 | − iommu_group_id(iommu_group)); | |
| 447 | − if (IS_ERR(dev)) { | |
| 448 | − vfio_free_group_minor(minor); | |
| 449 | − vfio_group_unlock_and_free(group); | |
| 450 | − return ERR_CAST(dev); | |
| 451 | − } | |
| 452 | − | |
| 453 | − group->minor = minor; | |
| 454 | − group->dev = dev; | |
| 455 | − | |
| 456 | − list_add(&group->vfio_next, &vfio.group_list); | |
| 329 | +static struct vfio_group * | |
| 330 | +vfio_group_get_from_iommu(struct iommu_group *iommu_group) | |
| 331 | +{ | |
| 332 | + struct vfio_group *group; | |
| 457 | 333 | |
| 334 | + mutex_lock(&vfio.group_lock); | |
| 335 | + group = __vfio_group_get_from_iommu(iommu_group); | |
| 458 | 336 | mutex_unlock(&vfio.group_lock); |
| 459 | − | |
| 460 | 337 | return group; |
| 461 | 338 | } |
| 462 | 339 | |
| 463 | −/* called with vfio.group_lock held */ | |
| 464 | −static void vfio_group_release(struct kref *kref) | |
| 340 | +static void vfio_group_release(struct device *dev) | |
| 465 | 341 | { |
| 466 | − struct vfio_group *group = container_of(kref, struct vfio_group, kref); | |
| 342 | + struct vfio_group *group = container_of(dev, struct vfio_group, dev); | |
| 467 | 343 | struct vfio_unbound_dev *unbound, *tmp; |
| 468 | − struct iommu_group *iommu_group = group->iommu_group; | |
| 469 | − | |
| 470 | − WARN_ON(!list_empty(&group->device_list)); | |
| 471 | − WARN_ON(group->notifier.head); | |
| 472 | 344 | |
| 473 | 345 | list_for_each_entry_safe(unbound, tmp, |
| 474 | 346 | &group->unbound_list, unbound_next) { |
| @@ -476,105 +348,129 @@ static void vfio_group_release(struct kref *kref) · 1 unmodified line | ||
| 476 | 348 | kfree(unbound); |
| 477 | 349 | } |
| 478 | 350 | |
| 479 | − device_destroy(vfio.class, MKDEV(MAJOR(vfio.group_devt), group->minor)); | |
| 480 | − list_del(&group->vfio_next); | |
| 481 | − vfio_free_group_minor(group->minor); | |
| 482 | − vfio_group_unlock_and_free(group); | |
| 483 | − iommu_group_put(iommu_group); | |
| 351 | + mutex_destroy(&group->device_lock); | |
| 352 | + mutex_destroy(&group->unbound_lock); | |
| 353 | + iommu_group_put(group->iommu_group); | |
| 354 | + ida_free(&vfio.group_ida, MINOR(group->dev.devt)); | |
| 355 | + kfree(group); | |
| 484 | 356 | } |
| 485 | 357 | |
| 486 | −static void vfio_group_put(struct vfio_group *group) | |
| 358 | +static struct vfio_group *vfio_group_alloc(struct iommu_group *iommu_group, | |
| 359 | + enum vfio_group_type type) | |
| 487 | 360 | { |
| 488 | − kref_put_mutex(&group->kref, vfio_group_release, &vfio.group_lock); | |
| 489 | −} | |
| 490 | − | |
| 491 | −struct vfio_group_put_work { | |
| 492 | − struct work_struct work; | |
| 493 | 361 | struct vfio_group *group; |
| 494 | −}; | |
| 362 | + int minor; | |
| 495 | 363 | |
| 496 | −static void vfio_group_put_bg(struct work_struct *work) | |
| 497 | −{ | |
| 498 | − struct vfio_group_put_work *do_work; | |
| 499 | − | |
| 500 | − do_work = container_of(work, struct vfio_group_put_work, work); | |
| 364 | + group = kzalloc(sizeof(*group), GFP_KERNEL); | |
| 365 | + if (!group) | |
| 366 | + return ERR_PTR(-ENOMEM); | |
| 501 | 367 | |
| 502 | − vfio_group_put(do_work->group); | |
| 503 | − kfree(do_work); | |
| 504 | −} | |
| 368 | + minor = ida_alloc_max(&vfio.group_ida, MINORMASK, GFP_KERNEL); | |
| 369 | + if (minor < 0) { | |
| 370 | + kfree(group); | |
| 371 | + return ERR_PTR(minor); | |
| 372 | + } | |
| 505 | 373 | |
| 506 | −static void vfio_group_schedule_put(struct vfio_group *group) | |
| 507 | −{ | |
| 508 | − struct vfio_group_put_work *do_work; | |
| 374 | + device_initialize(&group->dev); | |
| 375 | + group->dev.devt = MKDEV(MAJOR(vfio.group_devt), minor); | |
| 376 | + group->dev.class = vfio.class; | |
| 377 | + group->dev.release = vfio_group_release; | |
| 378 | + cdev_init(&group->cdev, &vfio_group_fops); | |
| 379 | + group->cdev.owner = THIS_MODULE; | |
| 509 | 380 | |
| 510 | − do_work = kmalloc(sizeof(*do_work), GFP_KERNEL); | |
| 511 | − if (WARN_ON(!do_work)) | |
| 512 | − return; | |
| 381 | + refcount_set(&group->users, 1); | |
| 382 | + INIT_LIST_HEAD(&group->device_list); | |
| 383 | + mutex_init(&group->device_lock); | |
| 384 | + INIT_LIST_HEAD(&group->unbound_list); | |
| 385 | + mutex_init(&group->unbound_lock); | |
| 386 | + init_waitqueue_head(&group->container_q); | |
| 387 | + group->iommu_group = iommu_group; | |
| 388 | + /* put in vfio_group_release() */ | |
| 389 | + iommu_group_ref_get(iommu_group); | |
| 390 | + group->type = type; | |
| 391 | + BLOCKING_INIT_NOTIFIER_HEAD(&group->notifier); | |
| 513 | 392 | |
| 514 | − INIT_WORK(&do_work->work, vfio_group_put_bg); | |
| 515 | − do_work->group = group; | |
| 516 | − schedule_work(&do_work->work); | |
| 393 | + return group; | |
| 517 | 394 | } |
| 518 | 395 | |
| 519 | −/* Assume group_lock or group reference is held */ | |
| 520 | −static void vfio_group_get(struct vfio_group *group) | |
| 396 | +static struct vfio_group *vfio_create_group(struct iommu_group *iommu_group, | |
| 397 | + enum vfio_group_type type) | |
| 521 | 398 | { |
| 522 | − kref_get(&group->kref); | |
| 523 | −} | |
| 399 | + struct vfio_group *group; | |
| 400 | + struct vfio_group *ret; | |
| 401 | + int err; | |
| 524 | 402 | |
| 525 | −/* | |
| 526 | − * Not really a try as we will sleep for mutex, but we need to make | |
| 527 | − * sure the group pointer is valid under lock and get a reference. | |
| 528 | − */ | |
| 529 | −static struct vfio_group *vfio_group_try_get(struct vfio_group *group) | |
| 530 | −{ | |
| 531 | − struct vfio_group *target = group; | |
| 403 | + group = vfio_group_alloc(iommu_group, type); | |
| 404 | + if (IS_ERR(group)) | |
| 405 | + return group; | |
| 532 | 406 | |
| 533 | − mutex_lock(&vfio.group_lock); | |
| 534 | − list_for_each_entry(group, &vfio.group_list, vfio_next) { | |
| 535 | − if (group == target) { | |
| 536 | − vfio_group_get(group); | |
| 537 | − mutex_unlock(&vfio.group_lock); | |
| 538 | − return group; | |
| 539 | − } | |
| 407 | + err = dev_set_name(&group->dev, "%s%d", | |
| 408 | + group->type == VFIO_NO_IOMMU ? "noiommu-" : "", | |
| 409 | + iommu_group_id(iommu_group)); | |
| 410 | + if (err) { | |
| 411 | + ret = ERR_PTR(err); | |
| 412 | + goto err_put; | |
| 540 | 413 | } |
| 541 | − mutex_unlock(&vfio.group_lock); | |
| 542 | 414 | |
| 543 | − return NULL; | |
| 544 | −} | |
| 545 | − | |
| 546 | −static | |
| 547 | −struct vfio_group *vfio_group_get_from_iommu(struct iommu_group *iommu_group) | |
| 548 | −{ | |
| 549 | − struct vfio_group *group; | |
| 415 | + group->nb.notifier_call = vfio_iommu_group_notifier; | |
| 416 | + err = iommu_group_register_notifier(iommu_group, &group->nb); | |
| 417 | + if (err) { | |
| 418 | + ret = ERR_PTR(err); | |
| 419 | + goto err_put; | |
| 420 | + } | |
| 550 | 421 | |
| 551 | 422 | mutex_lock(&vfio.group_lock); |
| 552 | − list_for_each_entry(group, &vfio.group_list, vfio_next) { | |
| 553 | − if (group->iommu_group == iommu_group) { | |
| 554 | − vfio_group_get(group); | |
| 555 | − mutex_unlock(&vfio.group_lock); | |
| 556 | − return group; | |
| 557 | − } | |
| 423 | + | |
| 424 | + /* Did we race creating this group? */ | |
| 425 | + ret = __vfio_group_get_from_iommu(iommu_group); | |
| 426 | + if (ret) | |
| 427 | + goto err_unlock; | |
| 428 | + | |
| 429 | + err = cdev_device_add(&group->cdev, &group->dev); | |
| 430 | + if (err) { | |
| 431 | + ret = ERR_PTR(err); | |
| 432 | + goto err_unlock; | |
| 558 | 433 | } |
| 434 | + | |
| 435 | + list_add(&group->vfio_next, &vfio.group_list); | |
| 436 | + | |
| 559 | 437 | mutex_unlock(&vfio.group_lock); |
| 438 | + return group; | |
| 560 | 439 | |
| 561 | − return NULL; | |
| 440 | +err_unlock: | |
| 441 | + mutex_unlock(&vfio.group_lock); | |
| 442 | + iommu_group_unregister_notifier(group->iommu_group, &group->nb); | |
| 443 | +err_put: | |
| 444 | + put_device(&group->dev); | |
| 445 | + return ret; | |
| 562 | 446 | } |
| 563 | 447 | |
| 564 | −static struct vfio_group *vfio_group_get_from_minor(int minor) | |
| 448 | +static void vfio_group_put(struct vfio_group *group) | |
| 565 | 449 | { |
| 566 | − struct vfio_group *group; | |
| 450 | + if (!refcount_dec_and_mutex_lock(&group->users, &vfio.group_lock)) | |
| 451 | + return; | |
| 567 | 452 | |
| 568 | − mutex_lock(&vfio.group_lock); | |
| 569 | − group = idr_find(&vfio.group_idr, minor); | |
| 570 | − if (!group) { | |
| 571 | − mutex_unlock(&vfio.group_lock); | |
| 572 | − return NULL; | |
| 573 | − } | |
| 574 | − vfio_group_get(group); | |
| 453 | + /* | |
| 454 | + * These data structures all have paired operations that can only be | |
| 455 | + * undone when the caller holds a live reference on the group. Since all | |
| 456 | + * pairs must be undone these WARN_ON's indicate some caller did not | |
| 457 | + * properly hold the group reference. | |
| 458 | + */ | |
| 459 | + WARN_ON(!list_empty(&group->device_list)); | |
| 460 | + WARN_ON(atomic_read(&group->container_users)); | |
| 461 | + WARN_ON(group->notifier.head); | |
| 462 | + | |
| 463 | + list_del(&group->vfio_next); | |
| 464 | + cdev_device_del(&group->cdev, &group->dev); | |
| 575 | 465 | mutex_unlock(&vfio.group_lock); |
| 576 | 466 | |
| 577 | − return group; | |
| 467 | + iommu_group_unregister_notifier(group->iommu_group, &group->nb); | |
| 468 | + put_device(&group->dev); | |
| 469 | +} | |
| 470 | + | |
| 471 | +static void vfio_group_get(struct vfio_group *group) | |
| 472 | +{ | |
| 473 | + refcount_inc(&group->users); | |
| 578 | 474 | } |
| 579 | 475 | |
| 580 | 476 | static struct vfio_group *vfio_group_get_from_dev(struct device *dev) |
| @@ -740,14 +636,6 @@ static int vfio_iommu_group_notifier(struct notifier_block *nb, · 159 unmodified lines | ||
| 740 | 636 | struct device *dev = data; |
| 741 | 637 | struct vfio_unbound_dev *unbound; |
| 742 | 638 | |
| 743 | − /* | |
| 744 | − * Need to go through a group_lock lookup to get a reference or we | |
| 745 | − * risk racing a group being removed. Ignore spurious notifies. | |
| 746 | − */ | |
| 747 | − group = vfio_group_try_get(group); | |
| 748 | − if (!group) | |
| 749 | − return NOTIFY_OK; | |
| 750 | − | |
| 751 | 639 | switch (action) { |
| 752 | 640 | case IOMMU_GROUP_NOTIFY_ADD_DEVICE: |
| 753 | 641 | vfio_group_nb_add_dev(group, dev); |
| @@ -798,15 +686,6 @@ static int vfio_iommu_group_notifier(struct notifier_block *nb, · 44 unmodified lines | ||
| 798 | 686 | mutex_unlock(&group->unbound_lock); |
| 799 | 687 | break; |
| 800 | 688 | } |
| 801 | − | |
| 802 | − /* | |
| 803 | − * If we're the last reference to the group, the group will be | |
| 804 | − * released, which includes unregistering the iommu group notifier. | |
| 805 | − * We hold a read-lock on that notifier list, unregistering needs | |
| 806 | − * a write-lock... deadlock. Release our reference asynchronously | |
| 807 | − * to avoid that situation. | |
| 808 | − */ | |
| 809 | − vfio_group_schedule_put(group); | |
| 810 | 689 | return NOTIFY_OK; |
| 811 | 690 | } |
| 812 | 691 | |
| @@ -828,11 +707,78 @@ void vfio_uninit_group_dev(struct vfio_device *device) · 15 unmodified lines | ||
| 828 | 707 | } |
| 829 | 708 | EXPORT_SYMBOL_GPL(vfio_uninit_group_dev); |
| 830 | 709 | |
| 831 | −int vfio_register_group_dev(struct vfio_device *device) | |
| 710 | +static struct vfio_group *vfio_noiommu_group_alloc(struct device *dev, | |
| 711 | + enum vfio_group_type type) | |
| 832 | 712 | { |
| 833 | − struct vfio_device *existing_device; | |
| 834 | 713 | struct iommu_group *iommu_group; |
| 835 | 714 | struct vfio_group *group; |
| 715 | + int ret; | |
| 716 | + | |
| 717 | + iommu_group = iommu_group_alloc(); | |
| 718 | + if (IS_ERR(iommu_group)) | |
| 719 | + return ERR_CAST(iommu_group); | |
| 720 | + | |
| 721 | + iommu_group_set_name(iommu_group, "vfio-noiommu"); | |
| 722 | + ret = iommu_group_add_device(iommu_group, dev); | |
| 723 | + if (ret) | |
| 724 | + goto out_put_group; | |
| 725 | + | |
| 726 | + group = vfio_create_group(iommu_group, type); | |
| 727 | + if (IS_ERR(group)) { | |
| 728 | + ret = PTR_ERR(group); | |
| 729 | + goto out_remove_device; | |
| 730 | + } | |
| 731 | + iommu_group_put(iommu_group); | |
| 732 | + return group; | |
| 733 | + | |
| 734 | +out_remove_device: | |
| 735 | + iommu_group_remove_device(dev); | |
| 736 | +out_put_group: | |
| 737 | + iommu_group_put(iommu_group); | |
| 738 | + return ERR_PTR(ret); | |
| 739 | +} | |
| 740 | + | |
| 741 | +static struct vfio_group *vfio_group_find_or_alloc(struct device *dev) | |
| 742 | +{ | |
| 743 | + struct iommu_group *iommu_group; | |
| 744 | + struct vfio_group *group; | |
| 745 | + | |
| 746 | + iommu_group = iommu_group_get(dev); | |
| 747 | +#ifdef CONFIG_VFIO_NOIOMMU | |
| 748 | + if (!iommu_group && noiommu && !iommu_present(dev->bus)) { | |
| 749 | + /* | |
| 750 | + * With noiommu enabled, create an IOMMU group for devices that | |
| 751 | + * don't already have one and don't have an iommu_ops on their | |
| 752 | + * bus. Taint the kernel because we're about to give a DMA | |
| 753 | + * capable device to a user without IOMMU protection. | |
| 754 | + */ | |
| 755 | + group = vfio_noiommu_group_alloc(dev, VFIO_NO_IOMMU); | |
| 756 | + if (!IS_ERR(group)) { | |
| 757 | + add_taint(TAINT_USER, LOCKDEP_STILL_OK); | |
| 758 | + dev_warn(dev, "Adding kernel taint for vfio-noiommu group on device\n"); | |
| 759 | + } | |
| 760 | + return group; | |
| 761 | + } | |
| 762 | +#endif | |
| 763 | + if (!iommu_group) | |
| 764 | + return ERR_PTR(-EINVAL); | |
| 765 | + | |
| 766 | + group = vfio_group_get_from_iommu(iommu_group); | |
| 767 | + if (!group) | |
| 768 | + group = vfio_create_group(iommu_group, VFIO_IOMMU); | |
| 769 | + | |
| 770 | + /* The vfio_group holds a reference to the iommu_group */ | |
| 771 | + iommu_group_put(iommu_group); | |
| 772 | + return group; | |
| 773 | +} | |
| 774 | + | |
| 775 | +static int __vfio_register_dev(struct vfio_device *device, | |
| 776 | + struct vfio_group *group) | |
| 777 | +{ | |
| 778 | + struct vfio_device *existing_device; | |
| 779 | + | |
| 780 | + if (IS_ERR(group)) | |
| 781 | + return PTR_ERR(group); | |
| 836 | 782 | |
| 837 | 783 | /* |
| 838 | 784 | * If the driver doesn't specify a set then the device is added to a |
| @@ -841,30 +787,14 @@ int vfio_register_group_dev(struct vfio_device *device) · 2 unmodified lines | ||
| 841 | 787 | if (!device->dev_set) |
| 842 | 788 | vfio_assign_device_set(device, device); |
| 843 | 789 | |
| 844 | − iommu_group = iommu_group_get(device->dev); | |
| 845 | − if (!iommu_group) | |
| 846 | − return -EINVAL; | |
| 847 | − | |
| 848 | − group = vfio_group_get_from_iommu(iommu_group); | |
| 849 | − if (!group) { | |
| 850 | − group = vfio_create_group(iommu_group); | |
| 851 | − if (IS_ERR(group)) { | |
| 852 | − iommu_group_put(iommu_group); | |
| 853 | − return PTR_ERR(group); | |
| 854 | − } | |
| 855 | − } else { | |
| 856 | − /* | |
| 857 | − * A found vfio_group already holds a reference to the | |
| 858 | − * iommu_group. A created vfio_group keeps the reference. | |
| 859 | − */ | |
| 860 | − iommu_group_put(iommu_group); | |
| 861 | − } | |
| 862 | − | |
| 863 | 790 | existing_device = vfio_group_get_device(group, device->dev); |
| 864 | 791 | if (existing_device) { |
| 865 | 792 | dev_WARN(device->dev, "Device already exists on group %d\n", |
| 866 | − iommu_group_id(iommu_group)); | |
| 793 | + iommu_group_id(group->iommu_group)); | |
| 867 | 794 | vfio_device_put(existing_device); |
| 795 | + if (group->type == VFIO_NO_IOMMU || | |
| 796 | + group->type == VFIO_EMULATED_IOMMU) | |
| 797 | + iommu_group_remove_device(device->dev); | |
| 868 | 798 | vfio_group_put(group); |
| 869 | 799 | return -EBUSY; |
| 870 | 800 | } |
| @@ -882,8 +812,25 @@ int vfio_register_group_dev(struct vfio_device *device) · 11 unmodified lines | ||
| 882 | 812 | |
| 883 | 813 | return 0; |
| 884 | 814 | } |
| 815 | + | |
| 816 | +int vfio_register_group_dev(struct vfio_device *device) | |
| 817 | +{ | |
| 818 | + return __vfio_register_dev(device, | |
| 819 | + vfio_group_find_or_alloc(device->dev)); | |
| 820 | +} | |
| 885 | 821 | EXPORT_SYMBOL_GPL(vfio_register_group_dev); |
| 886 | 822 | |
| 823 | +/* | |
| 824 | + * Register a virtual device without IOMMU backing. The user of this | |
| 825 | + * device must not be able to directly trigger unmediated DMA. | |
| 826 | + */ | |
| 827 | +int vfio_register_emulated_iommu_dev(struct vfio_device *device) | |
| 828 | +{ | |
| 829 | + return __vfio_register_dev(device, | |
| 830 | + vfio_noiommu_group_alloc(device->dev, VFIO_EMULATED_IOMMU)); | |
| 831 | +} | |
| 832 | +EXPORT_SYMBOL_GPL(vfio_register_emulated_iommu_dev); | |
| 833 | + | |
| 887 | 834 | /** |
| 888 | 835 | * Get a reference to the vfio_device for a device. Even if the |
| 889 | 836 | * caller thinks they own the device, they could be racing with a |
| @@ -1010,6 +957,9 @@ void vfio_unregister_group_dev(struct vfio_device *device) · 120 unmodified lines | ||
| 1010 | 957 | if (list_empty(&group->device_list)) |
| 1011 | 958 | wait_event(group->container_q, !group->container); |
| 1012 | 959 | |
| 960 | + if (group->type == VFIO_NO_IOMMU || group->type == VFIO_EMULATED_IOMMU) | |
| 961 | + iommu_group_remove_device(device->dev); | |
| 962 | + | |
| 1013 | 963 | /* Matches the get in vfio_register_group_dev() */ |
| 1014 | 964 | vfio_group_put(group); |
| 1015 | 965 | } |
| @@ -1042,13 +992,10 @@ static long vfio_ioctl_check_extension(struct vfio_container *container, · 26 unmodified lines | ||
| 1042 | 992 | list_for_each_entry(driver, &vfio.iommu_drivers_list, |
| 1043 | 993 | vfio_next) { |
| 1044 | 994 | |
| 1045 | −#ifdef CONFIG_VFIO_NOIOMMU | |
| 1046 | 995 | if (!list_empty(&container->group_list) && |
| 1047 | − (container->noiommu != | |
| 1048 | − (driver->ops == &vfio_noiommu_ops))) | |
| 996 | + !vfio_iommu_driver_allowed(container, | |
| 997 | + driver)) | |
| 1049 | 998 | continue; |
| 1050 | −#endif | |
| 1051 | − | |
| 1052 | 999 | if (!try_module_get(driver->ops->owner)) |
| 1053 | 1000 | continue; |
| 1054 | 1001 | |
| @@ -1079,7 +1026,8 @@ static int __vfio_container_attach_groups(struct vfio_container *container, · 24 unmodified lines | ||
| 1079 | 1026 | int ret = -ENODEV; |
| 1080 | 1027 | |
| 1081 | 1028 | list_for_each_entry(group, &container->group_list, container_next) { |
| 1082 | − ret = driver->ops->attach_group(data, group->iommu_group); | |
| 1029 | + ret = driver->ops->attach_group(data, group->iommu_group, | |
| 1030 | + group->type); | |
| 1083 | 1031 | if (ret) |
| 1084 | 1032 | goto unwind; |
| 1085 | 1033 | } |
| @@ -1120,15 +1068,8 @@ static long vfio_ioctl_set_iommu(struct vfio_container *container, · 34 unmodified lines | ||
| 1120 | 1068 | list_for_each_entry(driver, &vfio.iommu_drivers_list, vfio_next) { |
| 1121 | 1069 | void *data; |
| 1122 | 1070 | |
| 1123 | −#ifdef CONFIG_VFIO_NOIOMMU | |
| 1124 | − /* | |
| 1125 | − * Only noiommu containers can use vfio-noiommu and noiommu | |
| 1126 | − * containers can only use vfio-noiommu. | |
| 1127 | − */ | |
| 1128 | − if (container->noiommu != (driver->ops == &vfio_noiommu_ops)) | |
| 1071 | + if (!vfio_iommu_driver_allowed(container, driver)) | |
| 1129 | 1072 | continue; |
| 1130 | −#endif | |
| 1131 | − | |
| 1132 | 1073 | if (!try_module_get(driver->ops->owner)) |
| 1133 | 1074 | continue; |
| 1134 | 1075 | |
| @@ -1234,62 +1175,12 @@ static int vfio_fops_release(struct inode *inode, struct file *filep) · 99 unmodified lines | ||
| 1234 | 1175 | return 0; |
| 1235 | 1176 | } |
| 1236 | 1177 | |
| 1237 | −/* | |
| 1238 | − * Once an iommu driver is set, we optionally pass read/write/mmap | |
| 1239 | − * on to the driver, allowing management interfaces beyond ioctl. | |
| 1240 | − */ | |
| 1241 | −static ssize_t vfio_fops_read(struct file *filep, char __user *buf, | |
| 1242 | − size_t count, loff_t *ppos) | |
| 1243 | −{ | |
| 1244 | − struct vfio_container *container = filep->private_data; | |
| 1245 | − struct vfio_iommu_driver *driver; | |
| 1246 | − ssize_t ret = -EINVAL; | |
| 1247 | − | |
| 1248 | − driver = container->iommu_driver; | |
| 1249 | − if (likely(driver && driver->ops->read)) | |
| 1250 | − ret = driver->ops->read(container->iommu_data, | |
| 1251 | − buf, count, ppos); | |
| 1252 | − | |
| 1253 | − return ret; | |
| 1254 | −} | |
| 1255 | − | |
| 1256 | −static ssize_t vfio_fops_write(struct file *filep, const char __user *buf, | |
| 1257 | − size_t count, loff_t *ppos) | |
| 1258 | −{ | |
| 1259 | − struct vfio_container *container = filep->private_data; | |
| 1260 | − struct vfio_iommu_driver *driver; | |
| 1261 | − ssize_t ret = -EINVAL; | |
| 1262 | − | |
| 1263 | − driver = container->iommu_driver; | |
| 1264 | − if (likely(driver && driver->ops->write)) | |
| 1265 | − ret = driver->ops->write(container->iommu_data, | |
| 1266 | − buf, count, ppos); | |
| 1267 | − | |
| 1268 | − return ret; | |
| 1269 | −} | |
| 1270 | − | |
| 1271 | −static int vfio_fops_mmap(struct file *filep, struct vm_area_struct *vma) | |
| 1272 | −{ | |
| 1273 | − struct vfio_container *container = filep->private_data; | |
| 1274 | − struct vfio_iommu_driver *driver; | |
| 1275 | − int ret = -EINVAL; | |
| 1276 | − | |
| 1277 | − driver = container->iommu_driver; | |
| 1278 | − if (likely(driver && driver->ops->mmap)) | |
| 1279 | − ret = driver->ops->mmap(container->iommu_data, vma); | |
| 1280 | − | |
| 1281 | − return ret; | |
| 1282 | −} | |
| 1283 | − | |
| 1284 | 1178 | static const struct file_operations vfio_fops = { |
| 1285 | 1179 | .owner = THIS_MODULE, |
| 1286 | 1180 | .open = vfio_fops_open, |
| 1287 | 1181 | .release = vfio_fops_release, |
| 1288 | − .read = vfio_fops_read, | |
| 1289 | − .write = vfio_fops_write, | |
| 1290 | 1182 | .unlocked_ioctl = vfio_fops_unl_ioctl, |
| 1291 | 1183 | .compat_ioctl = compat_ptr_ioctl, |
| 1292 | − .mmap = vfio_fops_mmap, | |
| 1293 | 1184 | }; |
| 1294 | 1185 | |
| 1295 | 1186 | /** |
| @@ -1366,7 +1257,7 @@ static int vfio_group_set_container(struct vfio_group *group, int container_fd) · 70 unmodified lines | ||
| 1366 | 1257 | if (atomic_read(&group->container_users)) |
| 1367 | 1258 | return -EINVAL; |
| 1368 | 1259 | |
| 1369 | − if (group->noiommu && !capable(CAP_SYS_RAWIO)) | |
| 1260 | + if (group->type == VFIO_NO_IOMMU && !capable(CAP_SYS_RAWIO)) | |
| 1370 | 1261 | return -EPERM; |
| 1371 | 1262 | |
| 1372 | 1263 | f = fdget(container_fd); |
| @@ -1386,7 +1277,7 @@ static int vfio_group_set_container(struct vfio_group *group, int container_fd) · 13 unmodified lines | ||
| 1386 | 1277 | |
| 1387 | 1278 | /* Real groups and fake groups cannot mix */ |
| 1388 | 1279 | if (!list_empty(&container->group_list) && |
| 1389 | − container->noiommu != group->noiommu) { | |
| 1280 | + container->noiommu != (group->type == VFIO_NO_IOMMU)) { | |
| 1390 | 1281 | ret = -EPERM; |
| 1391 | 1282 | goto unlock_out; |
| 1392 | 1283 | } |
| @@ -1394,13 +1285,14 @@ static int vfio_group_set_container(struct vfio_group *group, int container_fd) · 1 unmodified line | ||
| 1394 | 1285 | driver = container->iommu_driver; |
| 1395 | 1286 | if (driver) { |
| 1396 | 1287 | ret = driver->ops->attach_group(container->iommu_data, |
| 1397 | − group->iommu_group); | |
| 1288 | + group->iommu_group, | |
| 1289 | + group->type); | |
| 1398 | 1290 | if (ret) |
| 1399 | 1291 | goto unlock_out; |
| 1400 | 1292 | } |
| 1401 | 1293 | |
| 1402 | 1294 | group->container = container; |
| 1403 | − container->noiommu = group->noiommu; | |
| 1295 | + container->noiommu = (group->type == VFIO_NO_IOMMU); | |
| 1404 | 1296 | list_add(&group->container_next, &container->group_list); |
| 1405 | 1297 | |
| 1406 | 1298 | /* Get a reference on the container and mark a user within the group */ |
| @@ -1424,7 +1316,7 @@ static int vfio_group_add_container_user(struct vfio_group *group) · 17 unmodified lines | ||
| 1424 | 1316 | if (!atomic_inc_not_zero(&group->container_users)) |
| 1425 | 1317 | return -EINVAL; |
| 1426 | 1318 | |
| 1427 | − if (group->noiommu) { | |
| 1319 | + if (group->type == VFIO_NO_IOMMU) { | |
| 1428 | 1320 | atomic_dec(&group->container_users); |
| 1429 | 1321 | return -EPERM; |
| 1430 | 1322 | } |
| @@ -1449,7 +1341,7 @@ static int vfio_group_get_device_fd(struct vfio_group *group, char *buf) · 18 unmodified lines | ||
| 1449 | 1341 | !group->container->iommu_driver || !vfio_group_viable(group)) |
| 1450 | 1342 | return -EINVAL; |
| 1451 | 1343 | |
| 1452 | − if (group->noiommu && !capable(CAP_SYS_RAWIO)) | |
| 1344 | + if (group->type == VFIO_NO_IOMMU && !capable(CAP_SYS_RAWIO)) | |
| 1453 | 1345 | return -EPERM; |
| 1454 | 1346 | |
| 1455 | 1347 | device = vfio_device_get_from_name(group, buf); |
| @@ -1496,7 +1388,7 @@ static int vfio_group_get_device_fd(struct vfio_group *group, char *buf) · 40 unmodified lines | ||
| 1496 | 1388 | |
| 1497 | 1389 | fd_install(fdno, filep); |
| 1498 | 1390 | |
| 1499 | − if (group->noiommu) | |
| 1391 | + if (group->type == VFIO_NO_IOMMU) | |
| 1500 | 1392 | dev_warn(device->dev, "vfio-noiommu device opened by user " |
| 1501 | 1393 | "(%s:%d)\n", current->comm, task_pid_nr(current)); |
| 1502 | 1394 | return fdno; |
| @@ -1585,14 +1477,15 @@ static long vfio_group_fops_unl_ioctl(struct file *filep, · 82 unmodified lines | ||
| 1585 | 1477 | |
| 1586 | 1478 | static int vfio_group_fops_open(struct inode *inode, struct file *filep) |
| 1587 | 1479 | { |
| 1588 | − struct vfio_group *group; | |
| 1480 | + struct vfio_group *group = | |
| 1481 | + container_of(inode->i_cdev, struct vfio_group, cdev); | |
| 1589 | 1482 | int opened; |
| 1590 | 1483 | |
| 1591 | − group = vfio_group_get_from_minor(iminor(inode)); | |
| 1592 | − if (!group) | |
| 1484 | + /* users can be zero if this races with vfio_group_put() */ | |
| 1485 | + if (!refcount_inc_not_zero(&group->users)) | |
| 1593 | 1486 | return -ENODEV; |
| 1594 | 1487 | |
| 1595 | − if (group->noiommu && !capable(CAP_SYS_RAWIO)) { | |
| 1488 | + if (group->type == VFIO_NO_IOMMU && !capable(CAP_SYS_RAWIO)) { | |
| 1596 | 1489 | vfio_group_put(group); |
| 1597 | 1490 | return -EPERM; |
| 1598 | 1491 | } |
| @@ -1757,6 +1650,9 @@ struct vfio_group *vfio_group_get_external_user(struct file *filep) · 158 unmodified lines | ||
| 1757 | 1650 | if (ret) |
| 1758 | 1651 | return ERR_PTR(ret); |
| 1759 | 1652 | |
| 1653 | + /* | |
| 1654 | + * Since the caller holds the fget on the file group->users must be >= 1 | |
| 1655 | + */ | |
| 1760 | 1656 | vfio_group_get(group); |
| 1761 | 1657 | |
| 1762 | 1658 | return group; |
| @@ -2396,7 +2292,7 @@ static int __init vfio_init(void) · 633 unmodified lines | ||
| 2396 | 2292 | { |
| 2397 | 2293 | int ret; |
| 2398 | 2294 | |
| 2399 | − idr_init(&vfio.group_idr); | |
| 2295 | + ida_init(&vfio.group_ida); | |
| 2400 | 2296 | mutex_init(&vfio.group_lock); |
| 2401 | 2297 | mutex_init(&vfio.iommu_drivers_lock); |
| 2402 | 2298 | INIT_LIST_HEAD(&vfio.group_list); |
| @@ -2421,11 +2317,6 @@ static int __init vfio_init(void) · 18 unmodified lines | ||
| 2421 | 2317 | if (ret) |
| 2422 | 2318 | goto err_alloc_chrdev; |
| 2423 | 2319 | |
| 2424 | − cdev_init(&vfio.group_cdev, &vfio_group_fops); | |
| 2425 | − ret = cdev_add(&vfio.group_cdev, vfio.group_devt, MINORMASK + 1); | |
| 2426 | − if (ret) | |
| 2427 | − goto err_cdev_add; | |
| 2428 | − | |
| 2429 | 2320 | pr_info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); |
| 2430 | 2321 | |
| 2431 | 2322 | #ifdef CONFIG_VFIO_NOIOMMU |
| @@ -2433,8 +2324,6 @@ static int __init vfio_init(void) · 1 unmodified line | ||
| 2433 | 2324 | #endif |
| 2434 | 2325 | return 0; |
| 2435 | 2326 | |
| 2436 | −err_cdev_add: | |
| 2437 | − unregister_chrdev_region(vfio.group_devt, MINORMASK + 1); | |
| 2438 | 2327 | err_alloc_chrdev: |
| 2439 | 2328 | class_destroy(vfio.class); |
| 2440 | 2329 | vfio.class = NULL; |
| @@ -2450,8 +2339,7 @@ static void __exit vfio_cleanup(void) · 9 unmodified lines | ||
| 2450 | 2339 | #ifdef CONFIG_VFIO_NOIOMMU |
| 2451 | 2340 | vfio_unregister_iommu_driver(&vfio_noiommu_ops); |
| 2452 | 2341 | #endif |
| 2453 | − idr_destroy(&vfio.group_idr); | |
| 2454 | − cdev_del(&vfio.group_cdev); | |
| 2342 | + ida_destroy(&vfio.group_ida); | |
| 2455 | 2343 | unregister_chrdev_region(vfio.group_devt, MINORMASK + 1); |
| 2456 | 2344 | class_destroy(vfio.class); |
| 2457 | 2345 | vfio.class = NULL; |
| @@ -0,0 +1,72 @@ | ||
| 1 | +/* SPDX-License-Identifier: GPL-2.0-only */ | |
| 2 | +/* | |
| 3 | + * Copyright (C) 2012 Red Hat, Inc. All rights reserved. | |
| 4 | + * Author: Alex Williamson <alex.williamson@redhat.com> | |
| 5 | + */ | |
| 6 | + | |
| 7 | +enum vfio_group_type { | |
| 8 | + /* | |
| 9 | + * Physical device with IOMMU backing. | |
| 10 | + */ | |
| 11 | + VFIO_IOMMU, | |
| 12 | + | |
| 13 | + /* | |
| 14 | + * Virtual device without IOMMU backing. The VFIO core fakes up an | |
| 15 | + * iommu_group as the iommu_group sysfs interface is part of the | |
| 16 | + * userspace ABI. The user of these devices must not be able to | |
| 17 | + * directly trigger unmediated DMA. | |
| 18 | + */ | |
| 19 | + VFIO_EMULATED_IOMMU, | |
| 20 | + | |
| 21 | + /* | |
| 22 | + * Physical device without IOMMU backing. The VFIO core fakes up an | |
| 23 | + * iommu_group as the iommu_group sysfs interface is part of the | |
| 24 | + * userspace ABI. Users can trigger unmediated DMA by the device, | |
| 25 | + * usage is highly dangerous, requires an explicit opt-in and will | |
| 26 | + * taint the kernel. | |
| 27 | + */ | |
| 28 | + VFIO_NO_IOMMU, | |
| 29 | +}; | |
| 30 | + | |
| 31 | +/* events for the backend driver notify callback */ | |
| 32 | +enum vfio_iommu_notify_type { | |
| 33 | + VFIO_IOMMU_CONTAINER_CLOSE = 0, | |
| 34 | +}; | |
| 35 | + | |
| 36 | +/** | |
| 37 | + * struct vfio_iommu_driver_ops - VFIO IOMMU driver callbacks | |
| 38 | + */ | |
| 39 | +struct vfio_iommu_driver_ops { | |
| 40 | + char *name; | |
| 41 | + struct module *owner; | |
| 42 | + void *(*open)(unsigned long arg); | |
| 43 | + void (*release)(void *iommu_data); | |
| 44 | + long (*ioctl)(void *iommu_data, unsigned int cmd, | |
| 45 | + unsigned long arg); | |
| 46 | + int (*attach_group)(void *iommu_data, | |
| 47 | + struct iommu_group *group, | |
| 48 | + enum vfio_group_type); | |
| 49 | + void (*detach_group)(void *iommu_data, | |
| 50 | + struct iommu_group *group); | |
| 51 | + int (*pin_pages)(void *iommu_data, | |
| 52 | + struct iommu_group *group, | |
| 53 | + unsigned long *user_pfn, | |
| 54 | + int npage, int prot, | |
| 55 | + unsigned long *phys_pfn); | |
| 56 | + int (*unpin_pages)(void *iommu_data, | |
| 57 | + unsigned long *user_pfn, int npage); | |
| 58 | + int (*register_notifier)(void *iommu_data, | |
| 59 | + unsigned long *events, | |
| 60 | + struct notifier_block *nb); | |
| 61 | + int (*unregister_notifier)(void *iommu_data, | |
| 62 | + struct notifier_block *nb); | |
| 63 | + int (*dma_rw)(void *iommu_data, dma_addr_t user_iova, | |
| 64 | + void *data, size_t count, bool write); | |
| 65 | + struct iommu_domain *(*group_iommu_domain)(void *iommu_data, | |
| 66 | + struct iommu_group *group); | |
| 67 | + void (*notify)(void *iommu_data, | |
| 68 | + enum vfio_iommu_notify_type event); | |
| 69 | +}; | |
| 70 | + | |
| 71 | +int vfio_register_iommu_driver(const struct vfio_iommu_driver_ops *ops); | |
| 72 | +void vfio_unregister_iommu_driver(const struct vfio_iommu_driver_ops *ops); | |
| @@ -20,6 +20,7 @@ · 19 unmodified lines | ||
| 20 | 20 | #include <linux/sched/mm.h> |
| 21 | 21 | #include <linux/sched/signal.h> |
| 22 | 22 | #include <linux/mm.h> |
| 23 | +#include "vfio.h" | |
| 23 | 24 | |
| 24 | 25 | #include <asm/iommu.h> |
| 25 | 26 | #include <asm/tce.h> |
| @@ -1238,13 +1239,16 @@ release_exit: · 1212 unmodified lines | ||
| 1238 | 1239 | } |
| 1239 | 1240 | |
| 1240 | 1241 | static int tce_iommu_attach_group(void *iommu_data, |
| 1241 | − struct iommu_group *iommu_group) | |
| 1242 | + struct iommu_group *iommu_group, enum vfio_group_type type) | |
| 1242 | 1243 | { |
| 1243 | 1244 | int ret = 0; |
| 1244 | 1245 | struct tce_container *container = iommu_data; |
| 1245 | 1246 | struct iommu_table_group *table_group; |
| 1246 | 1247 | struct tce_iommu_group *tcegrp = NULL; |
| 1247 | 1248 | |
| 1249 | + if (type == VFIO_EMULATED_IOMMU) | |
| 1250 | + return -EINVAL; | |
| 1251 | + | |
| 1248 | 1252 | mutex_lock(&container->lock); |
| 1249 | 1253 | |
| 1250 | 1254 | /* pr_debug("tce_vfio: Attaching group #%u to iommu %p\n", |
| @@ -36,10 +36,10 @@ · 35 unmodified lines | ||
| 36 | 36 | #include <linux/uaccess.h> |
| 37 | 37 | #include <linux/vfio.h> |
| 38 | 38 | #include <linux/workqueue.h> |
| 39 | −#include <linux/mdev.h> | |
| 40 | 39 | #include <linux/notifier.h> |
| 41 | 40 | #include <linux/dma-iommu.h> |
| 42 | 41 | #include <linux/irqdomain.h> |
| 42 | +#include "vfio.h" | |
| 43 | 43 | |
| 44 | 44 | #define DRIVER_VERSION "0.2" |
| 45 | 45 | #define DRIVER_AUTHOR "Alex Williamson <alex.williamson@redhat.com>" |
| @@ -65,7 +65,6 @@ MODULE_PARM_DESC(dma_entry_limit, · 19 unmodified lines | ||
| 65 | 65 | struct vfio_iommu { |
| 66 | 66 | struct list_head domain_list; |
| 67 | 67 | struct list_head iova_list; |
| 68 | − struct vfio_domain *external_domain; /* domain for external user */ | |
| 69 | 68 | struct mutex lock; |
| 70 | 69 | struct rb_root dma_list; |
| 71 | 70 | struct blocking_notifier_head notifier; |
| @@ -78,6 +77,7 @@ struct vfio_iommu { · 6 unmodified lines | ||
| 78 | 77 | bool nesting; |
| 79 | 78 | bool dirty_page_tracking; |
| 80 | 79 | bool container_open; |
| 80 | + struct list_head emulated_iommu_groups; | |
| 81 | 81 | }; |
| 82 | 82 | |
| 83 | 83 | struct vfio_domain { |
| @@ -113,7 +113,6 @@ struct vfio_batch { · 29 unmodified lines | ||
| 113 | 113 | struct vfio_iommu_group { |
| 114 | 114 | struct iommu_group *iommu_group; |
| 115 | 115 | struct list_head next; |
| 116 | − bool mdev_group; /* An mdev group */ | |
| 117 | 116 | bool pinned_page_dirty_scope; |
| 118 | 117 | }; |
| 119 | 118 | |
| @@ -140,9 +139,6 @@ struct vfio_regions { · 20 unmodified lines | ||
| 140 | 139 | size_t len; |
| 141 | 140 | }; |
| 142 | 141 | |
| 143 | −#define IS_IOMMU_CAP_DOMAIN_IN_CONTAINER(iommu) \ | |
| 144 | − (!list_empty(&iommu->domain_list)) | |
| 145 | − | |
| 146 | 142 | #define DIRTY_BITMAP_BYTES(n) (ALIGN(n, BITS_PER_TYPE(u64)) / BITS_PER_BYTE) |
| 147 | 143 | |
| 148 | 144 | /* |
| @@ -880,7 +876,7 @@ again: · 731 unmodified lines | ||
| 880 | 876 | * already pinned and accounted. Accounting should be done if there is no |
| 881 | 877 | * iommu capable domain in the container. |
| 882 | 878 | */ |
| 883 | − do_accounting = !IS_IOMMU_CAP_DOMAIN_IN_CONTAINER(iommu); | |
| 879 | + do_accounting = list_empty(&iommu->domain_list); | |
| 884 | 880 | |
| 885 | 881 | for (i = 0; i < npage; i++) { |
| 886 | 882 | struct vfio_pfn *vpfn; |
| @@ -969,7 +965,7 @@ static int vfio_iommu_type1_unpin_pages(void *iommu_data, · 82 unmodified lines | ||
| 969 | 965 | |
| 970 | 966 | mutex_lock(&iommu->lock); |
| 971 | 967 | |
| 972 | − do_accounting = !IS_IOMMU_CAP_DOMAIN_IN_CONTAINER(iommu); | |
| 968 | + do_accounting = list_empty(&iommu->domain_list); | |
| 973 | 969 | for (i = 0; i < npage; i++) { |
| 974 | 970 | struct vfio_dma *dma; |
| 975 | 971 | dma_addr_t iova; |
| @@ -1090,7 +1086,7 @@ static long vfio_unmap_unpin(struct vfio_iommu *iommu, struct vfio_dma *dma, · 114 unmodified lines | ||
| 1090 | 1086 | if (!dma->size) |
| 1091 | 1087 | return 0; |
| 1092 | 1088 | |
| 1093 | − if (!IS_IOMMU_CAP_DOMAIN_IN_CONTAINER(iommu)) | |
| 1089 | + if (list_empty(&iommu->domain_list)) | |
| 1094 | 1090 | return 0; |
| 1095 | 1091 | |
| 1096 | 1092 | /* |
| @@ -1667,7 +1663,7 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu, · 570 unmodified lines | ||
| 1667 | 1663 | vfio_link_dma(iommu, dma); |
| 1668 | 1664 | |
| 1669 | 1665 | /* Don't pin and map if container doesn't contain IOMMU capable domain*/ |
| 1670 | − if (!IS_IOMMU_CAP_DOMAIN_IN_CONTAINER(iommu)) | |
| 1666 | + if (list_empty(&iommu->domain_list)) | |
| 1671 | 1667 | dma->size = size; |
| 1672 | 1668 | else |
| 1673 | 1669 | ret = vfio_pin_map_dma(iommu, dma, size); |
| @@ -1893,8 +1889,8 @@ static struct vfio_iommu_group* · 219 unmodified lines | ||
| 1893 | 1889 | vfio_iommu_find_iommu_group(struct vfio_iommu *iommu, |
| 1894 | 1890 | struct iommu_group *iommu_group) |
| 1895 | 1891 | { |
| 1892 | + struct vfio_iommu_group *group; | |
| 1896 | 1893 | struct vfio_domain *domain; |
| 1897 | − struct vfio_iommu_group *group = NULL; | |
| 1898 | 1894 | |
| 1899 | 1895 | list_for_each_entry(domain, &iommu->domain_list, next) { |
| 1900 | 1896 | group = find_iommu_group(domain, iommu_group); |
| @@ -1902,10 +1898,10 @@ vfio_iommu_find_iommu_group(struct vfio_iommu *iommu, · 1 unmodified line | ||
| 1902 | 1898 | return group; |
| 1903 | 1899 | } |
| 1904 | 1900 | |
| 1905 | − if (iommu->external_domain) | |
| 1906 | − group = find_iommu_group(iommu->external_domain, iommu_group); | |
| 1907 | − | |
| 1908 | − return group; | |
| 1901 | + list_for_each_entry(group, &iommu->emulated_iommu_groups, next) | |
| 1902 | + if (group->iommu_group == iommu_group) | |
| 1903 | + return group; | |
| 1904 | + return NULL; | |
| 1909 | 1905 | } |
| 1910 | 1906 | |
| 1911 | 1907 | static bool vfio_iommu_has_sw_msi(struct list_head *group_resv_regions, |
| @@ -1934,89 +1930,6 @@ static bool vfio_iommu_has_sw_msi(struct list_head *group_resv_regions, · 22 unmodified lines | ||
| 1934 | 1930 | return ret; |
| 1935 | 1931 | } |
| 1936 | 1932 | |
| 1937 | −static int vfio_mdev_attach_domain(struct device *dev, void *data) | |
| 1938 | −{ | |
| 1939 | − struct mdev_device *mdev = to_mdev_device(dev); | |
| 1940 | − struct iommu_domain *domain = data; | |
| 1941 | − struct device *iommu_device; | |
| 1942 | − | |
| 1943 | − iommu_device = mdev_get_iommu_device(mdev); | |
| 1944 | − if (iommu_device) { | |
| 1945 | − if (iommu_dev_feature_enabled(iommu_device, IOMMU_DEV_FEAT_AUX)) | |
| 1946 | − return iommu_aux_attach_device(domain, iommu_device); | |
| 1947 | − else | |
| 1948 | − return iommu_attach_device(domain, iommu_device); | |
| 1949 | − } | |
| 1950 | − | |
| 1951 | − return -EINVAL; | |
| 1952 | −} | |
| 1953 | − | |
| 1954 | −static int vfio_mdev_detach_domain(struct device *dev, void *data) | |
| 1955 | −{ | |
| 1956 | − struct mdev_device *mdev = to_mdev_device(dev); | |
| 1957 | − struct iommu_domain *domain = data; | |
| 1958 | − struct device *iommu_device; | |
| 1959 | − | |
| 1960 | − iommu_device = mdev_get_iommu_device(mdev); | |
| 1961 | − if (iommu_device) { | |
| 1962 | − if (iommu_dev_feature_enabled(iommu_device, IOMMU_DEV_FEAT_AUX)) | |
| 1963 | − iommu_aux_detach_device(domain, iommu_device); | |
| 1964 | − else | |
| 1965 | − iommu_detach_device(domain, iommu_device); | |
| 1966 | − } | |
| 1967 | − | |
| 1968 | − return 0; | |
| 1969 | −} | |
| 1970 | − | |
| 1971 | −static int vfio_iommu_attach_group(struct vfio_domain *domain, | |
| 1972 | − struct vfio_iommu_group *group) | |
| 1973 | −{ | |
| 1974 | − if (group->mdev_group) | |
| 1975 | − return iommu_group_for_each_dev(group->iommu_group, | |
| 1976 | − domain->domain, | |
| 1977 | − vfio_mdev_attach_domain); | |
| 1978 | − else | |
| 1979 | − return iommu_attach_group(domain->domain, group->iommu_group); | |
| 1980 | −} | |
| 1981 | − | |
| 1982 | −static void vfio_iommu_detach_group(struct vfio_domain *domain, | |
| 1983 | − struct vfio_iommu_group *group) | |
| 1984 | −{ | |
| 1985 | − if (group->mdev_group) | |
| 1986 | − iommu_group_for_each_dev(group->iommu_group, domain->domain, | |
| 1987 | − vfio_mdev_detach_domain); | |
| 1988 | − else | |
| 1989 | − iommu_detach_group(domain->domain, group->iommu_group); | |
| 1990 | −} | |
| 1991 | − | |
| 1992 | −static bool vfio_bus_is_mdev(struct bus_type *bus) | |
| 1993 | −{ | |
| 1994 | − struct bus_type *mdev_bus; | |
| 1995 | − bool ret = false; | |
| 1996 | − | |
| 1997 | − mdev_bus = symbol_get(mdev_bus_type); | |
| 1998 | − if (mdev_bus) { | |
| 1999 | − ret = (bus == mdev_bus); | |
| 2000 | − symbol_put(mdev_bus_type); | |
| 2001 | − } | |
| 2002 | − | |
| 2003 | − return ret; | |
| 2004 | −} | |
| 2005 | − | |
| 2006 | −static int vfio_mdev_iommu_device(struct device *dev, void *data) | |
| 2007 | −{ | |
| 2008 | − struct mdev_device *mdev = to_mdev_device(dev); | |
| 2009 | − struct device **old = data, *new; | |
| 2010 | − | |
| 2011 | − new = mdev_get_iommu_device(mdev); | |
| 2012 | − if (!new || (*old && *old != new)) | |
| 2013 | − return -EINVAL; | |
| 2014 | − | |
| 2015 | − *old = new; | |
| 2016 | − | |
| 2017 | − return 0; | |
| 2018 | −} | |
| 2019 | − | |
| 2020 | 1933 | /* |
| 2021 | 1934 | * This is a helper function to insert an address range to iova list. |
| 2022 | 1935 | * The list is initially created with a single entry corresponding to |
| @@ -2241,81 +2154,58 @@ static void vfio_iommu_iova_insert_copy(struct vfio_iommu *iommu, · 218 unmodified lines | ||
| 2241 | 2154 | } |
| 2242 | 2155 | |
| 2243 | 2156 | static int vfio_iommu_type1_attach_group(void *iommu_data, |
| 2244 | − struct iommu_group *iommu_group) | |
| 2157 | + struct iommu_group *iommu_group, enum vfio_group_type type) | |
| 2245 | 2158 | { |
| 2246 | 2159 | struct vfio_iommu *iommu = iommu_data; |
| 2247 | 2160 | struct vfio_iommu_group *group; |
| 2248 | 2161 | struct vfio_domain *domain, *d; |
| 2249 | 2162 | struct bus_type *bus = NULL; |
| 2250 | − int ret; | |
| 2251 | 2163 | bool resv_msi, msi_remap; |
| 2252 | 2164 | phys_addr_t resv_msi_base = 0; |
| 2253 | 2165 | struct iommu_domain_geometry *geo; |
| 2254 | 2166 | LIST_HEAD(iova_copy); |
| 2255 | 2167 | LIST_HEAD(group_resv_regions); |
| 2168 | + int ret = -EINVAL; | |
| 2256 | 2169 | |
| 2257 | 2170 | mutex_lock(&iommu->lock); |
| 2258 | 2171 | |
| 2259 | 2172 | /* Check for duplicates */ |
| 2260 | − if (vfio_iommu_find_iommu_group(iommu, iommu_group)) { | |
| 2261 | − mutex_unlock(&iommu->lock); | |
| 2262 | − return -EINVAL; | |
| 2263 | − } | |
| 2173 | + if (vfio_iommu_find_iommu_group(iommu, iommu_group)) | |
| 2174 | + goto out_unlock; | |
| 2264 | 2175 | |
| 2176 | + ret = -ENOMEM; | |
| 2265 | 2177 | group = kzalloc(sizeof(*group), GFP_KERNEL); |
| 2266 | − domain = kzalloc(sizeof(*domain), GFP_KERNEL); | |
| 2267 | − if (!group || !domain) { | |
| 2268 | − ret = -ENOMEM; | |
| 2269 | − goto out_free; | |
| 2270 | − } | |
| 2271 | − | |
| 2178 | + if (!group) | |
| 2179 | + goto out_unlock; | |
| 2272 | 2180 | group->iommu_group = iommu_group; |
| 2273 | 2181 | |
| 2182 | + if (type == VFIO_EMULATED_IOMMU) { | |
| 2183 | + list_add(&group->next, &iommu->emulated_iommu_groups); | |
| 2184 | + /* | |
| 2185 | + * An emulated IOMMU group cannot dirty memory directly, it can | |
| 2186 | + * only use interfaces that provide dirty tracking. | |
| 2187 | + * The iommu scope can only be promoted with the addition of a | |
| 2188 | + * dirty tracking group. | |
| 2189 | + */ | |
| 2190 | + group->pinned_page_dirty_scope = true; | |
| 2191 | + ret = 0; | |
| 2192 | + goto out_unlock; | |
| 2193 | + } | |
| 2194 | + | |
| 2274 | 2195 | /* Determine bus_type in order to allocate a domain */ |
| 2275 | 2196 | ret = iommu_group_for_each_dev(iommu_group, &bus, vfio_bus_type); |
| 2276 | 2197 | if (ret) |
| 2277 | − goto out_free; | |
| 2278 | − | |
| 2279 | − if (vfio_bus_is_mdev(bus)) { | |
| 2280 | − struct device *iommu_device = NULL; | |
| 2281 | − | |
| 2282 | − group->mdev_group = true; | |
| 2283 | − | |
| 2284 | − /* Determine the isolation type */ | |
| 2285 | − ret = iommu_group_for_each_dev(iommu_group, &iommu_device, | |
| 2286 | − vfio_mdev_iommu_device); | |
| 2287 | − if (ret || !iommu_device) { | |
| 2288 | − if (!iommu->external_domain) { | |
| 2289 | − INIT_LIST_HEAD(&domain->group_list); | |
| 2290 | − iommu->external_domain = domain; | |
| 2291 | − vfio_update_pgsize_bitmap(iommu); | |
| 2292 | − } else { | |
| 2293 | − kfree(domain); | |
| 2294 | − } | |
| 2295 | − | |
| 2296 | − list_add(&group->next, | |
| 2297 | − &iommu->external_domain->group_list); | |
| 2298 | − /* | |
| 2299 | − * Non-iommu backed group cannot dirty memory directly, | |
| 2300 | − * it can only use interfaces that provide dirty | |
| 2301 | − * tracking. | |
| 2302 | − * The iommu scope can only be promoted with the | |
| 2303 | − * addition of a dirty tracking group. | |
| 2304 | − */ | |
| 2305 | − group->pinned_page_dirty_scope = true; | |
| 2306 | − mutex_unlock(&iommu->lock); | |
| 2198 | + goto out_free_group; | |
| 2307 | 2199 | |
| 2308 | − return 0; | |
| 2309 | − } | |
| 2310 | − | |
| 2311 | − bus = iommu_device->bus; | |
| 2312 | − } | |
| 2200 | + ret = -ENOMEM; | |
| 2201 | + domain = kzalloc(sizeof(*domain), GFP_KERNEL); | |
| 2202 | + if (!domain) | |
| 2203 | + goto out_free_group; | |
| 2313 | 2204 | |
| 2205 | + ret = -EIO; | |
| 2314 | 2206 | domain->domain = iommu_domain_alloc(bus); |
| 2315 | − if (!domain->domain) { | |
| 2316 | − ret = -EIO; | |
| 2317 | − goto out_free; | |
| 2318 | − } | |
| 2207 | + if (!domain->domain) | |
| 2208 | + goto out_free_domain; | |
| 2319 | 2209 | |
| 2320 | 2210 | if (iommu->nesting) { |
| 2321 | 2211 | ret = iommu_enable_nesting(domain->domain); |
| @@ -2323,7 +2213,7 @@ static int vfio_iommu_type1_attach_group(void *iommu_data, · 1 unmodified line | ||
| 2323 | 2213 | goto out_domain; |
| 2324 | 2214 | } |
| 2325 | 2215 | |
| 2326 | − ret = vfio_iommu_attach_group(domain, group); | |
| 2216 | + ret = iommu_attach_group(domain->domain, group->iommu_group); | |
| 2327 | 2217 | if (ret) |
| 2328 | 2218 | goto out_domain; |
| 2329 | 2219 | |
| @@ -2390,15 +2280,17 @@ static int vfio_iommu_type1_attach_group(void *iommu_data, · 60 unmodified lines | ||
| 2390 | 2280 | list_for_each_entry(d, &iommu->domain_list, next) { |
| 2391 | 2281 | if (d->domain->ops == domain->domain->ops && |
| 2392 | 2282 | d->prot == domain->prot) { |
| 2393 | − vfio_iommu_detach_group(domain, group); | |
| 2394 | − if (!vfio_iommu_attach_group(d, group)) { | |
| 2283 | + iommu_detach_group(domain->domain, group->iommu_group); | |
| 2284 | + if (!iommu_attach_group(d->domain, | |
| 2285 | + group->iommu_group)) { | |
| 2395 | 2286 | list_add(&group->next, &d->group_list); |
| 2396 | 2287 | iommu_domain_free(domain->domain); |
| 2397 | 2288 | kfree(domain); |
| 2398 | 2289 | goto done; |
| 2399 | 2290 | } |
| 2400 | 2291 | |
| 2401 | − ret = vfio_iommu_attach_group(domain, group); | |
| 2292 | + ret = iommu_attach_group(domain->domain, | |
| 2293 | + group->iommu_group); | |
| 2402 | 2294 | if (ret) |
| 2403 | 2295 | goto out_domain; |
| 2404 | 2296 | } |
| @@ -2435,14 +2327,16 @@ done: · 30 unmodified lines | ||
| 2435 | 2327 | return 0; |
| 2436 | 2328 | |
| 2437 | 2329 | out_detach: |
| 2438 | − vfio_iommu_detach_group(domain, group); | |
| 2330 | + iommu_detach_group(domain->domain, group->iommu_group); | |
| 2439 | 2331 | out_domain: |
| 2440 | 2332 | iommu_domain_free(domain->domain); |
| 2441 | 2333 | vfio_iommu_iova_free(&iova_copy); |
| 2442 | 2334 | vfio_iommu_resv_free(&group_resv_regions); |
| 2443 | −out_free: | |
| 2335 | +out_free_domain: | |
| 2444 | 2336 | kfree(domain); |
| 2337 | +out_free_group: | |
| 2445 | 2338 | kfree(group); |
| 2339 | +out_unlock: | |
| 2446 | 2340 | mutex_unlock(&iommu->lock); |
| 2447 | 2341 | return ret; |
| 2448 | 2342 | } |
| @@ -2567,25 +2461,19 @@ static void vfio_iommu_type1_detach_group(void *iommu_data, · 118 unmodified lines | ||
| 2567 | 2461 | LIST_HEAD(iova_copy); |
| 2568 | 2462 | |
| 2569 | 2463 | mutex_lock(&iommu->lock); |
| 2464 | + list_for_each_entry(group, &iommu->emulated_iommu_groups, next) { | |
| 2465 | + if (group->iommu_group != iommu_group) | |
| 2466 | + continue; | |
| 2467 | + update_dirty_scope = !group->pinned_page_dirty_scope; | |
| 2468 | + list_del(&group->next); | |
| 2469 | + kfree(group); | |
| 2570 | 2470 | |
| 2571 | − if (iommu->external_domain) { | |
| 2572 | − group = find_iommu_group(iommu->external_domain, iommu_group); | |
| 2573 | − if (group) { | |
| 2574 | − update_dirty_scope = !group->pinned_page_dirty_scope; | |
| 2575 | − list_del(&group->next); | |
| 2576 | − kfree(group); | |
| 2577 | − | |
| 2578 | − if (list_empty(&iommu->external_domain->group_list)) { | |
| 2579 | − if (!IS_IOMMU_CAP_DOMAIN_IN_CONTAINER(iommu)) { | |
| 2580 | − WARN_ON(iommu->notifier.head); | |
| 2581 | − vfio_iommu_unmap_unpin_all(iommu); | |
| 2582 | − } | |
| 2583 | − | |
| 2584 | − kfree(iommu->external_domain); | |
| 2585 | − iommu->external_domain = NULL; | |
| 2586 | − } | |
| 2587 | − goto detach_group_done; | |
| 2471 | + if (list_empty(&iommu->emulated_iommu_groups) && | |
| 2472 | + list_empty(&iommu->domain_list)) { | |
| 2473 | + WARN_ON(iommu->notifier.head); | |
| 2474 | + vfio_iommu_unmap_unpin_all(iommu); | |
| 2588 | 2475 | } |
| 2476 | + goto detach_group_done; | |
| 2589 | 2477 | } |
| 2590 | 2478 | |
| 2591 | 2479 | /* |
| @@ -2600,7 +2488,7 @@ static void vfio_iommu_type1_detach_group(void *iommu_data, · 8 unmodified lines | ||
| 2600 | 2488 | if (!group) |
| 2601 | 2489 | continue; |
| 2602 | 2490 | |
| 2603 | − vfio_iommu_detach_group(domain, group); | |
| 2491 | + iommu_detach_group(domain->domain, group->iommu_group); | |
| 2604 | 2492 | update_dirty_scope = !group->pinned_page_dirty_scope; |
| 2605 | 2493 | list_del(&group->next); |
| 2606 | 2494 | kfree(group); |
| @@ -2613,7 +2501,7 @@ static void vfio_iommu_type1_detach_group(void *iommu_data, · 6 unmodified lines | ||
| 2613 | 2501 | */ |
| 2614 | 2502 | if (list_empty(&domain->group_list)) { |
| 2615 | 2503 | if (list_is_singular(&iommu->domain_list)) { |
| 2616 | − if (!iommu->external_domain) { | |
| 2504 | + if (list_empty(&iommu->emulated_iommu_groups)) { | |
| 2617 | 2505 | WARN_ON(iommu->notifier.head); |
| 2618 | 2506 | vfio_iommu_unmap_unpin_all(iommu); |
| 2619 | 2507 | } else { |
| @@ -2677,41 +2565,43 @@ static void *vfio_iommu_type1_open(unsigned long arg) · 57 unmodified lines | ||
| 2677 | 2565 | mutex_init(&iommu->lock); |
| 2678 | 2566 | BLOCKING_INIT_NOTIFIER_HEAD(&iommu->notifier); |
| 2679 | 2567 | init_waitqueue_head(&iommu->vaddr_wait); |
| 2568 | + iommu->pgsize_bitmap = PAGE_MASK; | |
| 2569 | + INIT_LIST_HEAD(&iommu->emulated_iommu_groups); | |
| 2680 | 2570 | |
| 2681 | 2571 | return iommu; |
| 2682 | 2572 | } |
| 2683 | 2573 | |
| 2684 | −static void vfio_release_domain(struct vfio_domain *domain, bool external) | |
| 2574 | +static void vfio_release_domain(struct vfio_domain *domain) | |
| 2685 | 2575 | { |
| 2686 | 2576 | struct vfio_iommu_group *group, *group_tmp; |
| 2687 | 2577 | |
| 2688 | 2578 | list_for_each_entry_safe(group, group_tmp, |
| 2689 | 2579 | &domain->group_list, next) { |
| 2690 | − if (!external) | |
| 2691 | − vfio_iommu_detach_group(domain, group); | |
| 2580 | + iommu_detach_group(domain->domain, group->iommu_group); | |
| 2692 | 2581 | list_del(&group->next); |
| 2693 | 2582 | kfree(group); |
| 2694 | 2583 | } |
| 2695 | 2584 | |
| 2696 | − if (!external) | |
| 2697 | − iommu_domain_free(domain->domain); | |
| 2585 | + iommu_domain_free(domain->domain); | |
| 2698 | 2586 | } |
| 2699 | 2587 | |
| 2700 | 2588 | static void vfio_iommu_type1_release(void *iommu_data) |
| 2701 | 2589 | { |
| 2702 | 2590 | struct vfio_iommu *iommu = iommu_data; |
| 2703 | 2591 | struct vfio_domain *domain, *domain_tmp; |
| 2592 | + struct vfio_iommu_group *group, *next_group; | |
| 2704 | 2593 | |
| 2705 | − if (iommu->external_domain) { | |
| 2706 | − vfio_release_domain(iommu->external_domain, true); | |
| 2707 | − kfree(iommu->external_domain); | |
| 2594 | + list_for_each_entry_safe(group, next_group, | |
| 2595 | + &iommu->emulated_iommu_groups, next) { | |
| 2596 | + list_del(&group->next); | |
| 2597 | + kfree(group); | |
| 2708 | 2598 | } |
| 2709 | 2599 | |
| 2710 | 2600 | vfio_iommu_unmap_unpin_all(iommu); |
| 2711 | 2601 | |
| 2712 | 2602 | list_for_each_entry_safe(domain, domain_tmp, |
| 2713 | 2603 | &iommu->domain_list, next) { |
| 2714 | − vfio_release_domain(domain, false); | |
| 2604 | + vfio_release_domain(domain); | |
| 2715 | 2605 | list_del(&domain->next); |
| 2716 | 2606 | kfree(domain); |
| 2717 | 2607 | } |
| @@ -620,6 +620,20 @@ int dpcon_reset(struct fsl_mc_io *mc_io, · 619 unmodified lines | ||
| 620 | 620 | u32 cmd_flags, |
| 621 | 621 | u16 token); |
| 622 | 622 | |
| 623 | +int fsl_mc_obj_open(struct fsl_mc_io *mc_io, | |
| 624 | + u32 cmd_flags, | |
| 625 | + int obj_id, | |
| 626 | + char *obj_type, | |
| 627 | + u16 *token); | |
| 628 | + | |
| 629 | +int fsl_mc_obj_close(struct fsl_mc_io *mc_io, | |
| 630 | + u32 cmd_flags, | |
| 631 | + u16 token); | |
| 632 | + | |
| 633 | +int fsl_mc_obj_reset(struct fsl_mc_io *mc_io, | |
| 634 | + u32 cmd_flags, | |
| 635 | + u16 token); | |
| 636 | + | |
| 623 | 637 | /** |
| 624 | 638 | * struct dpcon_attr - Structure representing DPCON attributes |
| 625 | 639 | * @id: DPCON object ID |
| @@ -18,7 +18,6 @@ struct mdev_device { · 17 unmodified lines | ||
| 18 | 18 | void *driver_data; |
| 19 | 19 | struct list_head next; |
| 20 | 20 | struct mdev_type *type; |
| 21 | − struct device *iommu_device; | |
| 22 | 21 | bool active; |
| 23 | 22 | }; |
| 24 | 23 | |
| @@ -27,25 +26,6 @@ static inline struct mdev_device *to_mdev_device(struct device *dev) · 2 unmodified lines | ||
| 27 | 26 | return container_of(dev, struct mdev_device, dev); |
| 28 | 27 | } |
| 29 | 28 | |
| 30 | −/* | |
| 31 | − * Called by the parent device driver to set the device which represents | |
| 32 | − * this mdev in iommu protection scope. By default, the iommu device is | |
| 33 | − * NULL, that indicates using vendor defined isolation. | |
| 34 | − * | |
| 35 | − * @dev: the mediated device that iommu will isolate. | |
| 36 | − * @iommu_device: a pci device which represents the iommu for @dev. | |
| 37 | − */ | |
| 38 | −static inline void mdev_set_iommu_device(struct mdev_device *mdev, | |
| 39 | − struct device *iommu_device) | |
| 40 | −{ | |
| 41 | − mdev->iommu_device = iommu_device; | |
| 42 | −} | |
| 43 | − | |
| 44 | −static inline struct device *mdev_get_iommu_device(struct mdev_device *mdev) | |
| 45 | −{ | |
| 46 | − return mdev->iommu_device; | |
| 47 | −} | |
| 48 | − | |
| 49 | 29 | unsigned int mdev_get_type_group_id(struct mdev_device *mdev); |
| 50 | 30 | unsigned int mtype_get_type_group_id(struct mdev_type *mtype); |
| 51 | 31 | struct device *mtype_get_parent_dev(struct mdev_type *mtype); |
| @@ -71,68 +71,17 @@ struct vfio_device_ops { · 70 unmodified lines | ||
| 71 | 71 | int (*match)(struct vfio_device *vdev, char *buf); |
| 72 | 72 | }; |
| 73 | 73 | |
| 74 | −extern struct iommu_group *vfio_iommu_group_get(struct device *dev); | |
| 75 | −extern void vfio_iommu_group_put(struct iommu_group *group, struct device *dev); | |
| 76 | − | |
| 77 | 74 | void vfio_init_group_dev(struct vfio_device *device, struct device *dev, |
| 78 | 75 | const struct vfio_device_ops *ops); |
| 79 | 76 | void vfio_uninit_group_dev(struct vfio_device *device); |
| 80 | 77 | int vfio_register_group_dev(struct vfio_device *device); |
| 78 | +int vfio_register_emulated_iommu_dev(struct vfio_device *device); | |
| 81 | 79 | void vfio_unregister_group_dev(struct vfio_device *device); |
| 82 | 80 | extern struct vfio_device *vfio_device_get_from_dev(struct device *dev); |
| 83 | 81 | extern void vfio_device_put(struct vfio_device *device); |
| 84 | 82 | |
| 85 | 83 | int vfio_assign_device_set(struct vfio_device *device, void *set_id); |
| 86 | 84 | |
| 87 | −/* events for the backend driver notify callback */ | |
| 88 | −enum vfio_iommu_notify_type { | |
| 89 | − VFIO_IOMMU_CONTAINER_CLOSE = 0, | |
| 90 | −}; | |
| 91 | − | |
| 92 | −/** | |
| 93 | − * struct vfio_iommu_driver_ops - VFIO IOMMU driver callbacks | |
| 94 | − */ | |
| 95 | −struct vfio_iommu_driver_ops { | |
| 96 | − char *name; | |
| 97 | − struct module *owner; | |
| 98 | − void *(*open)(unsigned long arg); | |
| 99 | − void (*release)(void *iommu_data); | |
| 100 | − ssize_t (*read)(void *iommu_data, char __user *buf, | |
| 101 | − size_t count, loff_t *ppos); | |
| 102 | − ssize_t (*write)(void *iommu_data, const char __user *buf, | |
| 103 | − size_t count, loff_t *size); | |
| 104 | − long (*ioctl)(void *iommu_data, unsigned int cmd, | |
| 105 | − unsigned long arg); | |
| 106 | − int (*mmap)(void *iommu_data, struct vm_area_struct *vma); | |
| 107 | − int (*attach_group)(void *iommu_data, | |
| 108 | − struct iommu_group *group); | |
| 109 | − void (*detach_group)(void *iommu_data, | |
| 110 | − struct iommu_group *group); | |
| 111 | − int (*pin_pages)(void *iommu_data, | |
| 112 | − struct iommu_group *group, | |
| 113 | − unsigned long *user_pfn, | |
| 114 | − int npage, int prot, | |
| 115 | − unsigned long *phys_pfn); | |
| 116 | − int (*unpin_pages)(void *iommu_data, | |
| 117 | − unsigned long *user_pfn, int npage); | |
| 118 | − int (*register_notifier)(void *iommu_data, | |
| 119 | − unsigned long *events, | |
| 120 | − struct notifier_block *nb); | |
| 121 | − int (*unregister_notifier)(void *iommu_data, | |
| 122 | − struct notifier_block *nb); | |
| 123 | − int (*dma_rw)(void *iommu_data, dma_addr_t user_iova, | |
| 124 | − void *data, size_t count, bool write); | |
| 125 | − struct iommu_domain *(*group_iommu_domain)(void *iommu_data, | |
| 126 | − struct iommu_group *group); | |
| 127 | − void (*notify)(void *iommu_data, | |
| 128 | − enum vfio_iommu_notify_type event); | |
| 129 | −}; | |
| 130 | − | |
| 131 | −extern int vfio_register_iommu_driver(const struct vfio_iommu_driver_ops *ops); | |
| 132 | − | |
| 133 | −extern void vfio_unregister_iommu_driver( | |
| 134 | − const struct vfio_iommu_driver_ops *ops); | |
| 135 | − | |
| 136 | 85 | /* |
| 137 | 86 | * External user API |
| 138 | 87 | */ |
| @@ -553,7 +553,7 @@ static int mbochs_probe(struct mdev_device *mdev) · 552 unmodified lines | ||
| 553 | 553 | mbochs_create_config_space(mdev_state); |
| 554 | 554 | mbochs_reset(mdev_state); |
| 555 | 555 | |
| 556 | − ret = vfio_register_group_dev(&mdev_state->vdev); | |
| 556 | + ret = vfio_register_emulated_iommu_dev(&mdev_state->vdev); | |
| 557 | 557 | if (ret) |
| 558 | 558 | goto err_mem; |
| 559 | 559 | dev_set_drvdata(&mdev->dev, mdev_state); |
| @@ -258,7 +258,7 @@ static int mdpy_probe(struct mdev_device *mdev) · 257 unmodified lines | ||
| 258 | 258 | |
| 259 | 259 | mdpy_count++; |
| 260 | 260 | |
| 261 | − ret = vfio_register_group_dev(&mdev_state->vdev); | |
| 261 | + ret = vfio_register_emulated_iommu_dev(&mdev_state->vdev); | |
| 262 | 262 | if (ret) |
| 263 | 263 | goto err_mem; |
| 264 | 264 | dev_set_drvdata(&mdev->dev, mdev_state); |
| @@ -741,7 +741,7 @@ static int mtty_probe(struct mdev_device *mdev) · 740 unmodified lines | ||
| 741 | 741 | |
| 742 | 742 | mtty_create_config_space(mdev_state); |
| 743 | 743 | |
| 744 | − ret = vfio_register_group_dev(&mdev_state->vdev); | |
| 744 | + ret = vfio_register_emulated_iommu_dev(&mdev_state->vdev); | |
| 745 | 745 | if (ret) |
| 746 | 746 | goto err_vconfig; |
| 747 | 747 | dev_set_drvdata(&mdev->dev, mdev_state); |