Commit f4f19c03 authored by Dave Airlie's avatar Dave Airlie

Merge tag 'drm-misc-fixes-2023-07-20' of git://anongit.freedesktop.org/drm/drm-misc into drm-fixes

Memory leak fixes in drm/client, memory access/leak fixes for
accel/qaic, another leak fix in dma-buf and three nouveau fixes around
hotplugging.
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>

From: Maxime Ripard <mripard@redhat.com>
Link: https://patchwork.freedesktop.org/patch/msgid/fmj5nok7zggux2lcpdtls2iknweba54wfc6o4zxq6i6s3dgi2r@7z3eawwhyhen
parents 78e9b217 ea293f82
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/overflow.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/scatterlist.h> #include <linux/scatterlist.h>
#include <linux/types.h> #include <linux/types.h>
...@@ -366,7 +367,7 @@ static int encode_passthrough(struct qaic_device *qdev, void *trans, struct wrap ...@@ -366,7 +367,7 @@ static int encode_passthrough(struct qaic_device *qdev, void *trans, struct wrap
if (in_trans->hdr.len % 8 != 0) if (in_trans->hdr.len % 8 != 0)
return -EINVAL; return -EINVAL;
if (msg_hdr_len + in_trans->hdr.len > QAIC_MANAGE_EXT_MSG_LENGTH) if (size_add(msg_hdr_len, in_trans->hdr.len) > QAIC_MANAGE_EXT_MSG_LENGTH)
return -ENOSPC; return -ENOSPC;
trans_wrapper = add_wrapper(wrappers, trans_wrapper = add_wrapper(wrappers,
...@@ -418,9 +419,12 @@ static int find_and_map_user_pages(struct qaic_device *qdev, ...@@ -418,9 +419,12 @@ static int find_and_map_user_pages(struct qaic_device *qdev,
} }
ret = get_user_pages_fast(xfer_start_addr, nr_pages, 0, page_list); ret = get_user_pages_fast(xfer_start_addr, nr_pages, 0, page_list);
if (ret < 0 || ret != nr_pages) { if (ret < 0)
ret = -EFAULT;
goto free_page_list; goto free_page_list;
if (ret != nr_pages) {
nr_pages = ret;
ret = -EFAULT;
goto put_pages;
} }
sgt = kmalloc(sizeof(*sgt), GFP_KERNEL); sgt = kmalloc(sizeof(*sgt), GFP_KERNEL);
...@@ -557,11 +561,8 @@ static int encode_dma(struct qaic_device *qdev, void *trans, struct wrapper_list ...@@ -557,11 +561,8 @@ static int encode_dma(struct qaic_device *qdev, void *trans, struct wrapper_list
msg = &wrapper->msg; msg = &wrapper->msg;
msg_hdr_len = le32_to_cpu(msg->hdr.len); msg_hdr_len = le32_to_cpu(msg->hdr.len);
if (msg_hdr_len > (UINT_MAX - QAIC_MANAGE_EXT_MSG_LENGTH))
return -EINVAL;
/* There should be enough space to hold at least one ASP entry. */ /* There should be enough space to hold at least one ASP entry. */
if (msg_hdr_len + sizeof(*out_trans) + sizeof(struct wire_addr_size_pair) > if (size_add(msg_hdr_len, sizeof(*out_trans) + sizeof(struct wire_addr_size_pair)) >
QAIC_MANAGE_EXT_MSG_LENGTH) QAIC_MANAGE_EXT_MSG_LENGTH)
return -ENOMEM; return -ENOMEM;
...@@ -634,7 +635,7 @@ static int encode_activate(struct qaic_device *qdev, void *trans, struct wrapper ...@@ -634,7 +635,7 @@ static int encode_activate(struct qaic_device *qdev, void *trans, struct wrapper
msg = &wrapper->msg; msg = &wrapper->msg;
msg_hdr_len = le32_to_cpu(msg->hdr.len); msg_hdr_len = le32_to_cpu(msg->hdr.len);
if (msg_hdr_len + sizeof(*out_trans) > QAIC_MANAGE_MAX_MSG_LENGTH) if (size_add(msg_hdr_len, sizeof(*out_trans)) > QAIC_MANAGE_MAX_MSG_LENGTH)
return -ENOSPC; return -ENOSPC;
if (!in_trans->queue_size) if (!in_trans->queue_size)
...@@ -718,7 +719,7 @@ static int encode_status(struct qaic_device *qdev, void *trans, struct wrapper_l ...@@ -718,7 +719,7 @@ static int encode_status(struct qaic_device *qdev, void *trans, struct wrapper_l
msg = &wrapper->msg; msg = &wrapper->msg;
msg_hdr_len = le32_to_cpu(msg->hdr.len); msg_hdr_len = le32_to_cpu(msg->hdr.len);
if (msg_hdr_len + in_trans->hdr.len > QAIC_MANAGE_MAX_MSG_LENGTH) if (size_add(msg_hdr_len, in_trans->hdr.len) > QAIC_MANAGE_MAX_MSG_LENGTH)
return -ENOSPC; return -ENOSPC;
trans_wrapper = add_wrapper(wrappers, sizeof(*trans_wrapper)); trans_wrapper = add_wrapper(wrappers, sizeof(*trans_wrapper));
...@@ -748,7 +749,8 @@ static int encode_message(struct qaic_device *qdev, struct manage_msg *user_msg, ...@@ -748,7 +749,8 @@ static int encode_message(struct qaic_device *qdev, struct manage_msg *user_msg,
int ret; int ret;
int i; int i;
if (!user_msg->count) { if (!user_msg->count ||
user_msg->len < sizeof(*trans_hdr)) {
ret = -EINVAL; ret = -EINVAL;
goto out; goto out;
} }
...@@ -765,12 +767,13 @@ static int encode_message(struct qaic_device *qdev, struct manage_msg *user_msg, ...@@ -765,12 +767,13 @@ static int encode_message(struct qaic_device *qdev, struct manage_msg *user_msg,
} }
for (i = 0; i < user_msg->count; ++i) { for (i = 0; i < user_msg->count; ++i) {
if (user_len >= user_msg->len) { if (user_len > user_msg->len - sizeof(*trans_hdr)) {
ret = -EINVAL; ret = -EINVAL;
break; break;
} }
trans_hdr = (struct qaic_manage_trans_hdr *)(user_msg->data + user_len); trans_hdr = (struct qaic_manage_trans_hdr *)(user_msg->data + user_len);
if (user_len + trans_hdr->len > user_msg->len) { if (trans_hdr->len < sizeof(trans_hdr) ||
size_add(user_len, trans_hdr->len) > user_msg->len) {
ret = -EINVAL; ret = -EINVAL;
break; break;
} }
...@@ -953,15 +956,23 @@ static int decode_message(struct qaic_device *qdev, struct manage_msg *user_msg, ...@@ -953,15 +956,23 @@ static int decode_message(struct qaic_device *qdev, struct manage_msg *user_msg,
int ret; int ret;
int i; int i;
if (msg_hdr_len > QAIC_MANAGE_MAX_MSG_LENGTH) if (msg_hdr_len < sizeof(*trans_hdr) ||
msg_hdr_len > QAIC_MANAGE_MAX_MSG_LENGTH)
return -EINVAL; return -EINVAL;
user_msg->len = 0; user_msg->len = 0;
user_msg->count = le32_to_cpu(msg->hdr.count); user_msg->count = le32_to_cpu(msg->hdr.count);
for (i = 0; i < user_msg->count; ++i) { for (i = 0; i < user_msg->count; ++i) {
u32 hdr_len;
if (msg_len > msg_hdr_len - sizeof(*trans_hdr))
return -EINVAL;
trans_hdr = (struct wire_trans_hdr *)(msg->data + msg_len); trans_hdr = (struct wire_trans_hdr *)(msg->data + msg_len);
if (msg_len + le32_to_cpu(trans_hdr->len) > msg_hdr_len) hdr_len = le32_to_cpu(trans_hdr->len);
if (hdr_len < sizeof(*trans_hdr) ||
size_add(msg_len, hdr_len) > msg_hdr_len)
return -EINVAL; return -EINVAL;
switch (le32_to_cpu(trans_hdr->type)) { switch (le32_to_cpu(trans_hdr->type)) {
......
...@@ -571,6 +571,7 @@ int dma_resv_get_fences(struct dma_resv *obj, enum dma_resv_usage usage, ...@@ -571,6 +571,7 @@ int dma_resv_get_fences(struct dma_resv *obj, enum dma_resv_usage usage,
dma_resv_for_each_fence_unlocked(&cursor, fence) { dma_resv_for_each_fence_unlocked(&cursor, fence) {
if (dma_resv_iter_is_restarted(&cursor)) { if (dma_resv_iter_is_restarted(&cursor)) {
struct dma_fence **new_fences;
unsigned int count; unsigned int count;
while (*num_fences) while (*num_fences)
...@@ -579,13 +580,17 @@ int dma_resv_get_fences(struct dma_resv *obj, enum dma_resv_usage usage, ...@@ -579,13 +580,17 @@ int dma_resv_get_fences(struct dma_resv *obj, enum dma_resv_usage usage,
count = cursor.num_fences + 1; count = cursor.num_fences + 1;
/* Eventually re-allocate the array */ /* Eventually re-allocate the array */
*fences = krealloc_array(*fences, count, new_fences = krealloc_array(*fences, count,
sizeof(void *), sizeof(void *),
GFP_KERNEL); GFP_KERNEL);
if (count && !*fences) { if (count && !new_fences) {
kfree(*fences);
*fences = NULL;
*num_fences = 0;
dma_resv_iter_end(&cursor); dma_resv_iter_end(&cursor);
return -ENOMEM; return -ENOMEM;
} }
*fences = new_fences;
} }
(*fences)[(*num_fences)++] = dma_fence_get(fence); (*fences)[(*num_fences)++] = dma_fence_get(fence);
......
...@@ -311,6 +311,9 @@ static bool drm_client_target_cloned(struct drm_device *dev, ...@@ -311,6 +311,9 @@ static bool drm_client_target_cloned(struct drm_device *dev,
can_clone = true; can_clone = true;
dmt_mode = drm_mode_find_dmt(dev, 1024, 768, 60, false); dmt_mode = drm_mode_find_dmt(dev, 1024, 768, 60, false);
if (!dmt_mode)
goto fail;
for (i = 0; i < connector_count; i++) { for (i = 0; i < connector_count; i++) {
if (!enabled[i]) if (!enabled[i])
continue; continue;
...@@ -326,11 +329,13 @@ static bool drm_client_target_cloned(struct drm_device *dev, ...@@ -326,11 +329,13 @@ static bool drm_client_target_cloned(struct drm_device *dev,
if (!modes[i]) if (!modes[i])
can_clone = false; can_clone = false;
} }
kfree(dmt_mode);
if (can_clone) { if (can_clone) {
DRM_DEBUG_KMS("can clone using 1024x768\n"); DRM_DEBUG_KMS("can clone using 1024x768\n");
return true; return true;
} }
fail:
DRM_INFO("kms: can't enable cloning when we probably wanted to.\n"); DRM_INFO("kms: can't enable cloning when we probably wanted to.\n");
return false; return false;
} }
...@@ -862,6 +867,7 @@ int drm_client_modeset_probe(struct drm_client_dev *client, unsigned int width, ...@@ -862,6 +867,7 @@ int drm_client_modeset_probe(struct drm_client_dev *client, unsigned int width,
break; break;
} }
kfree(modeset->mode);
modeset->mode = drm_mode_duplicate(dev, mode); modeset->mode = drm_mode_duplicate(dev, mode);
drm_connector_get(connector); drm_connector_get(connector);
modeset->connectors[modeset->num_connectors++] = connector; modeset->connectors[modeset->num_connectors++] = connector;
......
...@@ -1877,6 +1877,8 @@ nv50_pior_destroy(struct drm_encoder *encoder) ...@@ -1877,6 +1877,8 @@ nv50_pior_destroy(struct drm_encoder *encoder)
nvif_outp_dtor(&nv_encoder->outp); nvif_outp_dtor(&nv_encoder->outp);
drm_encoder_cleanup(encoder); drm_encoder_cleanup(encoder);
mutex_destroy(&nv_encoder->dp.hpd_irq_lock);
kfree(encoder); kfree(encoder);
} }
...@@ -1921,6 +1923,8 @@ nv50_pior_create(struct drm_connector *connector, struct dcb_output *dcbe) ...@@ -1921,6 +1923,8 @@ nv50_pior_create(struct drm_connector *connector, struct dcb_output *dcbe)
nv_encoder->i2c = ddc; nv_encoder->i2c = ddc;
nv_encoder->aux = aux; nv_encoder->aux = aux;
mutex_init(&nv_encoder->dp.hpd_irq_lock);
encoder = to_drm_encoder(nv_encoder); encoder = to_drm_encoder(nv_encoder);
encoder->possible_crtcs = dcbe->heads; encoder->possible_crtcs = dcbe->heads;
encoder->possible_clones = 0; encoder->possible_clones = 0;
......
...@@ -16,7 +16,7 @@ struct nvkm_i2c_bus { ...@@ -16,7 +16,7 @@ struct nvkm_i2c_bus {
const struct nvkm_i2c_bus_func *func; const struct nvkm_i2c_bus_func *func;
struct nvkm_i2c_pad *pad; struct nvkm_i2c_pad *pad;
#define NVKM_I2C_BUS_CCB(n) /* 'n' is ccb index */ (n) #define NVKM_I2C_BUS_CCB(n) /* 'n' is ccb index */ (n)
#define NVKM_I2C_BUS_EXT(n) /* 'n' is dcb external encoder type */ ((n) + 0x100) #define NVKM_I2C_BUS_EXT(n) /* 'n' is dcb external encoder type */ ((n) + 0x10)
#define NVKM_I2C_BUS_PRI /* ccb primary comm. port */ -1 #define NVKM_I2C_BUS_PRI /* ccb primary comm. port */ -1
#define NVKM_I2C_BUS_SEC /* ccb secondary comm. port */ -2 #define NVKM_I2C_BUS_SEC /* ccb secondary comm. port */ -2
int id; int id;
...@@ -38,7 +38,7 @@ struct nvkm_i2c_aux { ...@@ -38,7 +38,7 @@ struct nvkm_i2c_aux {
const struct nvkm_i2c_aux_func *func; const struct nvkm_i2c_aux_func *func;
struct nvkm_i2c_pad *pad; struct nvkm_i2c_pad *pad;
#define NVKM_I2C_AUX_CCB(n) /* 'n' is ccb index */ (n) #define NVKM_I2C_AUX_CCB(n) /* 'n' is ccb index */ (n)
#define NVKM_I2C_AUX_EXT(n) /* 'n' is dcb external encoder type */ ((n) + 0x100) #define NVKM_I2C_AUX_EXT(n) /* 'n' is dcb external encoder type */ ((n) + 0x10)
int id; int id;
struct mutex mutex; struct mutex mutex;
......
...@@ -81,20 +81,29 @@ nvkm_uconn_uevent(struct nvkm_object *object, void *argv, u32 argc, struct nvkm_ ...@@ -81,20 +81,29 @@ nvkm_uconn_uevent(struct nvkm_object *object, void *argv, u32 argc, struct nvkm_
return -ENOSYS; return -ENOSYS;
list_for_each_entry(outp, &conn->disp->outps, head) { list_for_each_entry(outp, &conn->disp->outps, head) {
if (outp->info.connector == conn->index && outp->dp.aux) { if (outp->info.connector == conn->index)
if (args->v0.types & NVIF_CONN_EVENT_V0_PLUG ) bits |= NVKM_I2C_PLUG; break;
if (args->v0.types & NVIF_CONN_EVENT_V0_UNPLUG) bits |= NVKM_I2C_UNPLUG; }
if (args->v0.types & NVIF_CONN_EVENT_V0_IRQ ) bits |= NVKM_I2C_IRQ;
return nvkm_uevent_add(uevent, &device->i2c->event, outp->dp.aux->id, bits, if (&outp->head == &conn->disp->outps)
nvkm_uconn_uevent_aux); return -EINVAL;
}
if (outp->dp.aux && !outp->info.location) {
if (args->v0.types & NVIF_CONN_EVENT_V0_PLUG ) bits |= NVKM_I2C_PLUG;
if (args->v0.types & NVIF_CONN_EVENT_V0_UNPLUG) bits |= NVKM_I2C_UNPLUG;
if (args->v0.types & NVIF_CONN_EVENT_V0_IRQ ) bits |= NVKM_I2C_IRQ;
return nvkm_uevent_add(uevent, &device->i2c->event, outp->dp.aux->id, bits,
nvkm_uconn_uevent_aux);
} }
if (args->v0.types & NVIF_CONN_EVENT_V0_PLUG ) bits |= NVKM_GPIO_HI; if (args->v0.types & NVIF_CONN_EVENT_V0_PLUG ) bits |= NVKM_GPIO_HI;
if (args->v0.types & NVIF_CONN_EVENT_V0_UNPLUG) bits |= NVKM_GPIO_LO; if (args->v0.types & NVIF_CONN_EVENT_V0_UNPLUG) bits |= NVKM_GPIO_LO;
if (args->v0.types & NVIF_CONN_EVENT_V0_IRQ) if (args->v0.types & NVIF_CONN_EVENT_V0_IRQ) {
return -EINVAL; /* TODO: support DP IRQ on ANX9805 and remove this hack. */
if (!outp->info.location)
return -EINVAL;
}
return nvkm_uevent_add(uevent, &device->gpio->event, conn->info.hpd, bits, return nvkm_uevent_add(uevent, &device->gpio->event, conn->info.hpd, bits,
nvkm_uconn_uevent_gpio); nvkm_uconn_uevent_gpio);
......
...@@ -260,10 +260,11 @@ nvkm_i2c_new_(const struct nvkm_i2c_func *func, struct nvkm_device *device, ...@@ -260,10 +260,11 @@ nvkm_i2c_new_(const struct nvkm_i2c_func *func, struct nvkm_device *device,
{ {
struct nvkm_bios *bios = device->bios; struct nvkm_bios *bios = device->bios;
struct nvkm_i2c *i2c; struct nvkm_i2c *i2c;
struct nvkm_i2c_aux *aux;
struct dcb_i2c_entry ccbE; struct dcb_i2c_entry ccbE;
struct dcb_output dcbE; struct dcb_output dcbE;
u8 ver, hdr; u8 ver, hdr;
int ret, i; int ret, i, ids;
if (!(i2c = *pi2c = kzalloc(sizeof(*i2c), GFP_KERNEL))) if (!(i2c = *pi2c = kzalloc(sizeof(*i2c), GFP_KERNEL)))
return -ENOMEM; return -ENOMEM;
...@@ -406,5 +407,11 @@ nvkm_i2c_new_(const struct nvkm_i2c_func *func, struct nvkm_device *device, ...@@ -406,5 +407,11 @@ nvkm_i2c_new_(const struct nvkm_i2c_func *func, struct nvkm_device *device,
} }
} }
return nvkm_event_init(&nvkm_i2c_intr_func, &i2c->subdev, 4, i, &i2c->event); ids = 0;
list_for_each_entry(aux, &i2c->aux, head)
ids = max(ids, aux->id + 1);
if (!ids)
return 0;
return nvkm_event_init(&nvkm_i2c_intr_func, &i2c->subdev, 4, ids, &i2c->event);
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment