diff options
Diffstat (limited to 'linux-core/drm_crtc.c')
-rw-r--r-- | linux-core/drm_crtc.c | 338 |
1 files changed, 195 insertions, 143 deletions
diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 1586eb1a..245fe5be 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -39,8 +39,7 @@ * @ptr: object pointer, used to generate unique ID * * LOCKING: - * Process context (either init or calling process). Must take DRM mode_config - * lock around IDR allocation. + * Caller must hold DRM mode_config lock. * * Create a unique identifier based on @ptr in @dev's identifier space. Used * for tracking modes, CRTCs and outputs. @@ -59,15 +58,12 @@ again: return 0; } - spin_lock(&dev->mode_config.config_lock); - ret = idr_get_new_above(&dev->mode_config.crtc_idr, ptr, 1, &new_id); if (ret == -EAGAIN) { spin_unlock(&dev->mode_config.config_lock); goto again; } - spin_unlock(&dev->mode_config.config_lock); return new_id; } @@ -116,8 +112,7 @@ struct drm_crtc *drm_crtc_from_fb(struct drm_device *dev, * @dev: DRM device * * LOCKING: - * Process context (either init or calling process). Must take DRM mode_config - * lock around mode_config manipulation. + * Caller must hold mode config lock. * * Creates a new framebuffer objects and adds it to @dev's DRM mode_config. * @@ -128,27 +123,21 @@ struct drm_framebuffer *drm_framebuffer_create(drm_device_t *dev) { struct drm_framebuffer *fb; - spin_lock(&dev->mode_config.config_lock); /* Limit to single framebuffer for now */ if (dev->mode_config.num_fb > 1) { spin_unlock(&dev->mode_config.config_lock); DRM_ERROR("Attempt to add multiple framebuffers failed\n"); return NULL; } - spin_unlock(&dev->mode_config.config_lock); fb = kzalloc(sizeof(struct drm_framebuffer), GFP_KERNEL); - if (!fb) { - + if (!fb) return NULL; - } fb->id = drm_idr_get(dev, fb); fb->dev = dev; - spin_lock(&dev->mode_config.config_lock); dev->mode_config.num_fb++; list_add(&fb->head, &dev->mode_config.fb_list); - spin_unlock(&dev->mode_config.config_lock); return fb; } @@ -159,8 +148,7 @@ EXPORT_SYMBOL(drm_framebuffer_create); * @fb: framebuffer to remove * * LOCKING: - * Process context (either init or calling process). Must take DRM mode_config - * lock around mode_config manipulation. + * Caller must hold mode config lock. * * Scans all the CRTCs in @dev's mode_config. If they're using @fb, removes * it, setting it to NULL. @@ -171,7 +159,6 @@ void drm_framebuffer_destroy(struct drm_framebuffer *fb) struct drm_crtc *crtc; /* remove from any CRTC */ - spin_lock(&dev->mode_config.config_lock); list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { if (crtc->fb == fb) crtc->fb = NULL; @@ -180,7 +167,6 @@ void drm_framebuffer_destroy(struct drm_framebuffer *fb) drm_idr_put(dev, fb->id); list_del(&fb->head); dev->mode_config.num_fb--; - spin_unlock(&dev->mode_config.config_lock); kfree(fb); } @@ -192,8 +178,7 @@ EXPORT_SYMBOL(drm_framebuffer_destroy); * @funcs: callbacks for the new CRTC * * LOCKING: - * Process context (either init or calling process). Must take DRM mode_config - * lock around mode_config manipulation. + * Caller must hold mode config lock. * * Creates a new CRTC object and adds it to @dev's mode_config structure. * @@ -214,10 +199,8 @@ struct drm_crtc *drm_crtc_create(drm_device_t *dev, crtc->id = drm_idr_get(dev, crtc); - spin_lock(&dev->mode_config.config_lock); list_add_tail(&crtc->head, &dev->mode_config.crtc_list); dev->mode_config.num_crtc++; - spin_unlock(&dev->mode_config.config_lock); return crtc; } @@ -228,8 +211,7 @@ EXPORT_SYMBOL(drm_crtc_create); * @crtc: CRTC to remove * * LOCKING: - * Process context (either init or calling process). Must take DRM mode_config - * lock around mode_config traversal. + * Caller must hold mode config lock. * * Cleanup @crtc. Calls @crtc's cleanup function, then removes @crtc from * its associated DRM device's mode_config. Frees it afterwards. @@ -241,11 +223,9 @@ void drm_crtc_destroy(struct drm_crtc *crtc) if (crtc->funcs->cleanup) (*crtc->funcs->cleanup)(crtc); - spin_lock(&dev->mode_config.config_lock); drm_idr_put(dev, crtc->id); list_del(&crtc->head); dev->mode_config.num_crtc--; - spin_unlock(&dev->mode_config.config_lock); kfree(crtc); } EXPORT_SYMBOL(drm_crtc_destroy); @@ -255,7 +235,7 @@ EXPORT_SYMBOL(drm_crtc_destroy); * @crtc: CRTC to check * * LOCKING: - * Caller? (FIXME) + * Caller must hold mode config lock. * * Walk @crtc's DRM device's mode_config and see if it's in use. * @@ -290,7 +270,7 @@ static struct drm_display_mode std_mode[] = { * @maxY: max height for modes * * LOCKING: - * Caller? (FIXME) + * Caller must hold mode config lock. * * Based on @dev's mode_config layout, scan all the outputs and try to detect * modes on them. Modes will first be added to the output's probed_modes @@ -380,7 +360,7 @@ void drm_crtc_probe_output_modes(struct drm_device *dev, int maxX, int maxY) * @y: height of mode * * LOCKING: - * Caller? (FIXME) + * Caller must hold mode config lock. * * Try to set @mode on @crtc. Give @crtc and its associated outputs a chance * to fixup or reject the mode prior to trying to set it. @@ -498,7 +478,7 @@ EXPORT_SYMBOL(drm_crtc_set_mode); * @dev: DRM device * * LOCKING: - * Caller? (FIXME) + * Caller must hold mode config lock. * * If an output or CRTC isn't part of @dev's mode_config, it can be disabled * by calling its dpms function, which should power it off. @@ -525,17 +505,14 @@ void drm_disable_unused_functions(struct drm_device *dev) * @mode: mode data * * LOCKING: - * Process context (either init or calling process). Must take @output's - * mode_lock around mode list manipulation. + * Caller must hold mode config lock. * * Add @mode to @output's mode list for later use. */ void drm_mode_probed_add(struct drm_output *output, struct drm_display_mode *mode) { - spin_lock(&output->modes_lock); list_add(&mode->head, &output->probed_modes); - spin_unlock(&output->modes_lock); } EXPORT_SYMBOL(drm_mode_probed_add); @@ -545,16 +522,13 @@ EXPORT_SYMBOL(drm_mode_probed_add); * @mode: mode to remove * * LOCKING: - * Process context (either init or calling process). Must take @output's - * mode_lock around mode list manipulation. + * Caller must hold mode config lock. * * Remove @mode from @output's mode list, then free it. */ void drm_mode_remove(struct drm_output *output, struct drm_display_mode *mode) { - spin_lock(&output->modes_lock); list_del(&mode->head); - spin_unlock(&output->modes_lock); kfree(mode); } EXPORT_SYMBOL(drm_mode_remove); @@ -566,8 +540,7 @@ EXPORT_SYMBOL(drm_mode_remove); * @name: user visible name of the output * * LOCKING: - * Process context (either init or calling process). Must take @dev's - * mode_config lock around mode list manipulation. + * Caller must hold @dev's mode_config lock. * * Creates a new drm_output structure and adds it to @dev's mode_config * structure. @@ -594,7 +567,6 @@ struct drm_output *drm_output_create(drm_device_t *dev, output->subpixel_order = SubPixelUnknown; INIT_LIST_HEAD(&output->probed_modes); INIT_LIST_HEAD(&output->modes); - spin_lock_init(&output->modes_lock); /* randr_output? */ /* output_set_monitor(output)? */ /* check for output_ignored(output)? */ @@ -615,9 +587,7 @@ EXPORT_SYMBOL(drm_output_create); * @output: output to remove * * LOCKING: - * Process context (either init or calling process). Must take @dev's - * mode_config lock around mode list manipulation. Caller must hold - * modes lock? (FIXME) + * Caller must hold @dev's mode_config lock. * * Call @output's cleanup function, then remove the output from the DRM * mode_config after freeing @output's modes. @@ -705,7 +675,7 @@ EXPORT_SYMBOL(drm_mode_create); * @mode: mode to remove * * LOCKING: - * None. + * Caller must hold mode config lock. * * Free @mode's unique identifier, then free it. */ @@ -787,7 +757,7 @@ out_err: * @dev: DRM device * * LOCKING: - * None. + * Caller must hold mode config lock. */ static void drm_pick_crtcs (drm_device_t *dev) { @@ -875,7 +845,7 @@ clone: * @can_grow: this configuration is growable * * LOCKING: - * Must take various locks. (FIXME) + * Called at init time, must take mode config lock. * * Scan the CRTCs and outputs and try to put together an initial setup. * At the moment, this is a cloned configuration across all heads with @@ -887,6 +857,9 @@ clone: bool drm_initial_config(drm_device_t *dev, bool can_grow) { struct drm_output *output; + int ret = false; + + spin_lock(&dev->mode_config.config_lock); drm_crtc_probe_output_modes(dev, 2048, 2048); @@ -902,7 +875,8 @@ bool drm_initial_config(drm_device_t *dev, bool can_grow) } drm_disable_unused_functions(dev); - return false; + spin_unlock(&dev->mode_config.config_lock); + return ret; } EXPORT_SYMBOL(drm_initial_config); @@ -911,7 +885,7 @@ EXPORT_SYMBOL(drm_initial_config); * @dev: DRM device * * LOCKING: - * Caller? (FIXME) + * Caller must hold mode config lock. * * Free up all the outputs and CRTCs associated with this DRM device, then * free up the framebuffers and associated buffer objects. @@ -959,7 +933,7 @@ EXPORT_SYMBOL(drm_mode_config_cleanup); * @fb: new framebuffer * * LOCKING: - * Caller? (FIXME) + * Caller must hold mode config lock. * * Setup a new configuration, provided by the user in @crtc_info, and enable * it. @@ -1102,7 +1076,7 @@ void drm_crtc_convert_umode(struct drm_display_mode *out, struct drm_mode_modein * @arg: arg from ioctl * * LOCKING: - * Caller? (FIXME) + * Takes mode config lock. * * Construct a set of configuration description structures and return * them to the user, including CRTC, output and framebuffer configuration. @@ -1125,7 +1099,7 @@ int drm_mode_getresources(struct inode *inode, struct file *filp, struct drm_crtc *crtc; struct drm_mode_modeinfo u_mode; struct drm_display_mode *mode; - int retcode = 0; + int ret = 0; int mode_count= 0; int output_count = 0; int crtc_count = 0; @@ -1134,6 +1108,8 @@ int drm_mode_getresources(struct inode *inode, struct file *filp, memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo)); + spin_lock(&dev->mode_config.config_lock); + list_for_each(lh, &dev->mode_config.fb_list) fb_count++; @@ -1149,8 +1125,10 @@ int drm_mode_getresources(struct inode *inode, struct file *filp, list_for_each(lh, &dev->mode_config.usermode_list) mode_count++; - if (copy_from_user(&card_res, argp, sizeof(card_res))) - return -EFAULT; + if (copy_from_user(&card_res, argp, sizeof(card_res))) { + ret = -EFAULT; + goto out_unlock; + } if (card_res.count_modes == 0) { DRM_DEBUG("probing modes %dx%d\n", dev->mode_config.max_width, dev->mode_config.max_height); @@ -1170,7 +1148,7 @@ int drm_mode_getresources(struct inode *inode, struct file *filp, copied = 0; list_for_each_entry(fb, &dev->mode_config.fb_list, head) { if (put_user(fb->id, &card_res.fb_id[copied++])) { - retcode = -EFAULT; + ret = -EFAULT; goto done; } } @@ -1183,7 +1161,7 @@ int drm_mode_getresources(struct inode *inode, struct file *filp, list_for_each_entry(crtc, &dev->mode_config.crtc_list, head){ DRM_DEBUG("CRTC ID is %d\n", crtc->id); if (put_user(crtc->id, &card_res.crtc_id[copied++])) { - retcode = -EFAULT; + ret = -EFAULT; goto done; } } @@ -1198,7 +1176,7 @@ int drm_mode_getresources(struct inode *inode, struct file *filp, head) { DRM_DEBUG("OUTPUT ID is %d\n", output->id); if (put_user(output->id, &card_res.output_id[copied++])) { - retcode = -EFAULT; + ret = -EFAULT; goto done; } } @@ -1213,7 +1191,7 @@ int drm_mode_getresources(struct inode *inode, struct file *filp, list_for_each_entry(mode, &output->modes, head) { drm_crtc_convert_to_umode(&u_mode, mode); if (copy_to_user(&card_res.modes[copied++], &u_mode, sizeof(struct drm_mode_modeinfo))) { - retcode = -EFAULT; + ret = -EFAULT; goto done; } } @@ -1222,7 +1200,7 @@ int drm_mode_getresources(struct inode *inode, struct file *filp, list_for_each_entry(mode, &dev->mode_config.usermode_list, head) { drm_crtc_convert_to_umode(&u_mode, mode); if (copy_to_user(&card_res.modes[copied++], &u_mode, sizeof(struct drm_mode_modeinfo))) { - retcode = -EFAULT; + ret = -EFAULT; goto done; } } @@ -1235,9 +1213,11 @@ done: card_res.count_modes); if (copy_to_user(argp, &card_res, sizeof(card_res))) - return -EFAULT; + ret = -EFAULT; - return retcode; +out_unlock: + spin_unlock(&dev->mode_config.config_lock); + return ret; } /** @@ -1267,14 +1247,18 @@ int drm_mode_getcrtc(struct inode *inode, struct file *filp, struct drm_crtc *crtc; struct drm_output *output; int ocount; - int retcode = 0; + int ret = 0; if (copy_from_user(&crtc_resp, argp, sizeof(crtc_resp))) return -EFAULT; + spin_lock(&dev->mode_config.config_lock); crtc = idr_find(&dev->mode_config.crtc_idr, crtc_resp.crtc_id); - if (!crtc || (crtc->id != crtc_resp.crtc_id)) - return -EINVAL; + if (!crtc || (crtc->id != crtc_resp.crtc_id)) { + ret = -EINVAL; + goto out; + } + crtc_resp.x = crtc->x; crtc_resp.y = crtc->y; crtc_resp.fb_id = 1; @@ -1293,9 +1277,11 @@ int drm_mode_getcrtc(struct inode *inode, struct file *filp, } if (copy_to_user(argp, &crtc_resp, sizeof(crtc_resp))) - return -EFAULT; + ret = -EFAULT; - return retcode; +out: + spin_unlock(&dev->mode_config.config_lock); + return ret; } /** @@ -1325,7 +1311,7 @@ int drm_mode_getoutput(struct inode *inode, struct file *filp, struct drm_output *output; struct drm_display_mode *mode; int mode_count = 0; - int retcode = 0; + int ret = 0; int copied = 0; int i; @@ -1333,9 +1319,13 @@ int drm_mode_getoutput(struct inode *inode, struct file *filp, return -EFAULT; DRM_DEBUG("output id %d:\n", out_resp.output); + + spin_lock(&dev->mode_config.config_lock); output= idr_find(&dev->mode_config.crtc_idr, out_resp.output); - if (!output || (output->id != out_resp.output)) - return -EINVAL; + if (!output || (output->id != out_resp.output)) { + ret = -EINVAL; + goto out_unlock; + } list_for_each_entry(mode, &output->modes, head) mode_count++; @@ -1360,14 +1350,14 @@ int drm_mode_getoutput(struct inode *inode, struct file *filp, copied = 0; list_for_each_entry(mode, &output->modes, head) { if (put_user(mode->mode_id, &out_resp.modes[copied++])) { - retcode = -EFAULT; + ret = -EFAULT; goto done; } } for (i = 0; i < DRM_OUTPUT_MAX_UMODES; i++) { if (output->user_mode_ids[i] != 0) if (put_user(output->user_mode_ids[i], &out_resp.modes[copied++])) { - retcode = -EFAULT; + ret = -EFAULT; goto done; } } @@ -1377,9 +1367,11 @@ int drm_mode_getoutput(struct inode *inode, struct file *filp, done: if (copy_to_user(argp, &out_resp, sizeof(out_resp))) - return -EFAULT; + ret = -EFAULT; - return retcode; +out_unlock: + spin_unlock(&dev->mode_config.config_lock); + return ret; } /** @@ -1410,26 +1402,28 @@ int drm_mode_setcrtc(struct inode *inode, struct file *filp, struct drm_output **output_set = NULL, *output; struct drm_display_mode *mode; struct drm_framebuffer *fb = NULL; - int retcode = 0; + int ret = 0; int i; if (copy_from_user(&crtc_req, argp, sizeof(crtc_req))) return -EFAULT; + spin_lock(&dev->mode_config.config_lock); crtc = idr_find(&dev->mode_config.crtc_idr, crtc_req.crtc_id); if (!crtc || (crtc->id != crtc_req.crtc_id)) { DRM_DEBUG("Unknown CRTC ID %d\n", crtc_req.crtc_id); - return -EINVAL; + ret = -EINVAL; + goto out; } if (crtc_req.mode) { - /* if we have a mode we need a framebuffer */ if (crtc_req.fb_id) { fb = idr_find(&dev->mode_config.crtc_idr, crtc_req.fb_id); if (!fb || (fb->id != crtc_req.fb_id)) { DRM_DEBUG("Unknown FB ID%d\n", crtc_req.fb_id); - return -EINVAL; + ret = -EINVAL; + goto out; } } mode = idr_find(&dev->mode_config.crtc_idr, crtc_req.mode); @@ -1447,43 +1441,55 @@ int drm_mode_setcrtc(struct inode *inode, struct file *filp, } DRM_DEBUG("Unknown mode id %d, %p\n", crtc_req.mode, mode); - return -EINVAL; + ret = -EINVAL; + goto out; } } else mode = NULL; if (crtc_req.count_outputs == 0 && mode) { DRM_DEBUG("Count outputs is 0 but mode set\n"); - return -EINVAL; + ret = -EINVAL; + goto out; } if (crtc_req.count_outputs > 0 && !mode && !fb) { DRM_DEBUG("Count outputs is %d but no mode or fb set\n", crtc_req.count_outputs); - return -EINVAL; + ret = -EINVAL; + goto out; } if (crtc_req.count_outputs > 0) { u32 out_id; - output_set = kmalloc(crtc_req.count_outputs * sizeof(struct drm_output *), GFP_KERNEL); - if (!output_set) - return -ENOMEM; + output_set = kmalloc(crtc_req.count_outputs * + sizeof(struct drm_output *), GFP_KERNEL); + if (!output_set) { + ret = -ENOMEM; + goto out; + } for (i = 0; i < crtc_req.count_outputs; i++) { - if (get_user(out_id, &crtc_req.set_outputs[i])) - return -EFAULT; + if (get_user(out_id, &crtc_req.set_outputs[i])) { + ret = -EFAULT; + goto out; + } output = idr_find(&dev->mode_config.crtc_idr, out_id); if (!output || (out_id != output->id)) { DRM_DEBUG("Output id %d unknown\n", out_id); - return -EINVAL; + ret = -EINVAL; + goto out; } output_set[i] = output; } } - retcode = drm_crtc_set_config(crtc, &crtc_req, mode, output_set, fb); - return retcode; + ret = drm_crtc_set_config(crtc, &crtc_req, mode, output_set, fb); + +out: + spin_unlock(&dev->mode_config.config_lock); + return ret; } /** @@ -1494,7 +1500,7 @@ int drm_mode_setcrtc(struct inode *inode, struct file *filp, * @arg: arg from ioctl * * LOCKING: - * Caller? (FIXME) + * Takes mode config lock. * * Add a new FB to the specified CRTC, given a user request. * @@ -1513,7 +1519,8 @@ int drm_mode_addfb(struct inode *inode, struct file *filp, struct drm_mode_config *config = &dev->mode_config; struct drm_framebuffer *fb; struct drm_buffer_object *bo; - int ret; + struct drm_crtc *crtc; + int ret = 0; if (copy_from_user(&r, argp, sizeof(r))) return -EFAULT; @@ -1527,17 +1534,22 @@ int drm_mode_addfb(struct inode *inode, struct file *filp, return -EINVAL; } + spin_lock(&dev->mode_config.config_lock); /* TODO check limits are okay */ ret = drm_get_buffer_object(dev, &bo, r.handle); - if (ret || !bo) - return -EINVAL; + if (ret || !bo) { + ret = -EINVAL; + goto out; + } /* TODO check buffer is sufficently large */ /* TODO setup destructor callback */ fb = drm_framebuffer_create(dev); - if(!fb) - return -EINVAL;; + if (!fb) { + ret = -EINVAL; + goto out; + } fb->width = r.width; fb->height = r.height; @@ -1551,20 +1563,20 @@ int drm_mode_addfb(struct inode *inode, struct file *filp, list_add(&fb->filp_head, &priv->fbs); - if (copy_to_user(argp, &r, sizeof(r))) - return -EFAULT; + if (copy_to_user(argp, &r, sizeof(r))) { + ret = -EFAULT; + goto out; + } - /* bind the fb to the crtc for now */ - { - struct drm_crtc *crtc; - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - crtc->fb = fb; - - dev->driver->fb_probe(dev, crtc); - } + /* FIXME: bind the fb to the right crtc */ + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + crtc->fb = fb; + dev->driver->fb_probe(dev, crtc); } - return 0; +out: + spin_unlock(&dev->mode_config.config_lock); + return ret; } /** @@ -1575,7 +1587,7 @@ int drm_mode_addfb(struct inode *inode, struct file *filp, * @arg: arg from ioctl * * LOCKING: - * Caller? (FIXME) + * Takes mode config lock. * * Remove the FB specified by the user. * @@ -1591,12 +1603,15 @@ int drm_mode_rmfb(struct inode *inode, struct file *filp, drm_device_t *dev = priv->head->dev; struct drm_framebuffer *fb = 0; uint32_t id = arg; + int ret = 0; + spin_lock(&dev->mode_config.config_lock); fb = idr_find(&dev->mode_config.crtc_idr, id); /* TODO check that we realy get a framebuffer back. */ if (!fb || (id != fb->id)) { DRM_ERROR("mode invalid framebuffer id\n"); - return -EINVAL; + ret = -EINVAL; + goto out; } dev->driver->fb_remove(dev, drm_crtc_from_fb(dev, fb)); @@ -1608,7 +1623,9 @@ int drm_mode_rmfb(struct inode *inode, struct file *filp, drm_framebuffer_destroy(fb); - return 0; +out: + spin_unlock(&dev->mode_config.config_lock); + return ret; } /** @@ -1636,14 +1653,17 @@ int drm_mode_getfb(struct inode *inode, struct file *filp, struct drm_mode_fb_cmd __user *argp = (void __user *)arg; struct drm_mode_fb_cmd r; struct drm_framebuffer *fb; + int ret = 0; if (copy_from_user(&r, argp, sizeof(r))) return -EFAULT; + spin_lock(&dev->mode_config.config_lock); fb = idr_find(&dev->mode_config.crtc_idr, r.buffer_id); if (!fb || (r.buffer_id != fb->id)) { DRM_ERROR("invalid framebuffer id\n"); - return -EINVAL; + ret = -EINVAL; + goto out; } r.height = fb->height; @@ -1654,9 +1674,11 @@ int drm_mode_getfb(struct inode *inode, struct file *filp, r.pitch = fb->pitch; if (copy_to_user(argp, &r, sizeof(r))) - return -EFAULT; + ret = -EFAULT; - return 0; +out: + spin_unlock(&dev->mode_config.config_lock); + return ret; } /** @@ -1664,7 +1686,7 @@ int drm_mode_getfb(struct inode *inode, struct file *filp, * @filp: file * from the ioctl * * LOCKING: - * Caller? (FIXME) + * Takes mode config lock. * * Destroy all the FBs associated with @filp. * @@ -1679,11 +1701,13 @@ void drm_fb_release(struct file *filp) drm_device_t *dev = priv->head->dev; struct drm_framebuffer *fb, *tfb; + spin_lock(&dev->mode_config.config_lock); list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) { list_del(&fb->filp_head); dev->driver->fb_remove(dev, drm_crtc_from_fb(dev, fb)); drm_framebuffer_destroy(fb); } + spin_unlock(&dev->mode_config.config_lock); } /** @@ -1709,28 +1733,32 @@ int drm_mode_addmode(struct inode *inode, struct file *filp, struct drm_mode_modeinfo __user *argp = (void __user *)arg; struct drm_mode_modeinfo new_mode; struct drm_display_mode *user_mode; + int ret = 0; if (copy_from_user(&new_mode, argp, sizeof(new_mode))) return -EFAULT; + spin_lock(&dev->mode_config.config_lock); user_mode = drm_mode_create(dev); - if (!user_mode) - return -ENOMEM; + if (!user_mode) { + ret = -ENOMEM; + goto out; + } drm_crtc_convert_umode(user_mode, &new_mode); user_mode->type |= DRM_MODE_TYPE_USERDEF; user_mode->output_count = 0; - spin_lock(&dev->mode_config.config_lock); list_add(&user_mode->head, &dev->mode_config.usermode_list); - spin_unlock(&dev->mode_config.config_lock); new_mode.id = user_mode->mode_id; if (copy_to_user(argp, &new_mode, sizeof(new_mode))) - return -EFAULT; + ret = -EFAULT; - return 0; +out: + spin_unlock(&dev->mode_config.config_lock); + return ret; } /** @@ -1754,29 +1782,37 @@ int drm_mode_rmmode(struct inode *inode, struct file *filp, drm_device_t *dev = priv->head->dev; uint32_t id = arg; struct drm_display_mode *mode, *t; - int retcode = -EINVAL; + int ret = -EINVAL; + spin_lock(&dev->mode_config.config_lock); mode = idr_find(&dev->mode_config.crtc_idr, id); - if (!mode || (id != mode->mode_id)) - return -EINVAL; + if (!mode || (id != mode->mode_id)) { + ret = -EINVAL; + goto out; + } - if (!(mode->type & DRM_MODE_TYPE_USERDEF)) - return -EINVAL; + if (!(mode->type & DRM_MODE_TYPE_USERDEF)) { + ret = -EINVAL; + goto out; + } - if (mode->output_count) - return -EINVAL; + if (mode->output_count) { + ret = -EINVAL; + goto out; + } - spin_lock(&dev->mode_config.config_lock); list_for_each_entry(t, &dev->mode_config.usermode_list, head) { if (t == mode) { list_del(&mode->head); drm_mode_destroy(dev, mode); - retcode = 0; + ret = 0; break; } } + +out: spin_unlock(&dev->mode_config.config_lock); - return retcode; + return ret; } /** @@ -1801,18 +1837,24 @@ int drm_mode_attachmode(struct inode *inode, struct file *filp, struct drm_mode_mode_cmd mode_cmd; struct drm_output *output; struct drm_display_mode *mode; - int i; + int i, ret = 0; if (copy_from_user(&mode_cmd, argp, sizeof(mode_cmd))) return -EFAULT; + spin_lock(&dev->mode_config.config_lock); + mode = idr_find(&dev->mode_config.crtc_idr, mode_cmd.mode_id); - if (!mode || (mode->mode_id != mode_cmd.mode_id)) - return -EINVAL; + if (!mode || (mode->mode_id != mode_cmd.mode_id)) { + ret = -EINVAL; + goto out; + } output = idr_find(&dev->mode_config.crtc_idr, mode_cmd.output_id); - if (!output || (output->id != mode_cmd.output_id)) - return -EINVAL; + if (!output || (output->id != mode_cmd.output_id)) { + ret = -EINVAL; + goto out; + } for (i = 0; i < DRM_OUTPUT_MAX_UMODES; i++) { if (output->user_mode_ids[i] == 0) { @@ -1823,9 +1865,11 @@ int drm_mode_attachmode(struct inode *inode, struct file *filp, } if (i == DRM_OUTPUT_MAX_UMODES) - return -ENOSPC; + ret = -ENOSPC; - return 0; +out: + spin_unlock(&dev->mode_config.config_lock); + return ret; } @@ -1850,18 +1894,24 @@ int drm_mode_detachmode(struct inode *inode, struct file *filp, struct drm_mode_mode_cmd mode_cmd; struct drm_output *output; struct drm_display_mode *mode; - int i, found = 0; + int i, found = 0, ret = 0; if (copy_from_user(&mode_cmd, argp, sizeof(mode_cmd))) return -EFAULT; + spin_lock(&dev->mode_config.config_lock); + mode = idr_find(&dev->mode_config.crtc_idr, mode_cmd.mode_id); - if (!mode || (mode->mode_id != mode_cmd.mode_id)) - return -EINVAL; + if (!mode || (mode->mode_id != mode_cmd.mode_id)) { + ret = -EINVAL; + goto out; + } output = idr_find(&dev->mode_config.crtc_idr, mode_cmd.output_id); - if (!output || (output->id != mode_cmd.output_id)) - return -EINVAL; + if (!output || (output->id != mode_cmd.output_id)) { + ret = -EINVAL; + goto out; + } for (i = 0; i < DRM_OUTPUT_MAX_UMODES; i++) { @@ -1873,7 +1923,9 @@ int drm_mode_detachmode(struct inode *inode, struct file *filp, } if (!found) - return -EINVAL; - - return 0; + ret = -EINVAL; + +out: + spin_unlock(&dev->mode_config.config_lock); + return ret; } |