Skip to content

Commit

Permalink
Merge tag 'drm-fixes-2019-06-21' of git://anongit.freedesktop.org/drm…
Browse files Browse the repository at this point in the history
…/drm

Pull drm fixes from Dave Airlie:
 "Just catching up on the week since back from holidays, everything
  seems quite sane.

  core:
   - copy_to_user fix for really legacy codepaths.

  vmwgfx:
   - two dma fixes
   - one virt hw interaction fix

  i915:
   - modesetting fix
   - gvt fix

  panfrost:
   - BO unmapping fix

  imx:
   - image converter fixes"

* tag 'drm-fixes-2019-06-21' of git://anongit.freedesktop.org/drm/drm:
  drm/i915: Don't clobber M/N values during fastset check
  drm: return -EFAULT if copy_to_user() fails
  drm/panfrost: Make sure a BO is only unmapped when appropriate
  drm/i915/gvt: ignore unexpected pvinfo write
  gpu: ipu-v3: image-convert: Fix image downsize coefficients
  gpu: ipu-v3: image-convert: Fix input bytesperline for packed formats
  gpu: ipu-v3: image-convert: Fix input bytesperline width/height align
  drm/vmwgfx: fix a warning due to missing dma_parms
  drm/vmwgfx: Honor the sg list segment size limitation
  drm/vmwgfx: Use the backdoor port if the HB port is not available
  • Loading branch information
torvalds committed Jun 21, 2019
2 parents db54615 + 5eab9cf commit 0728f6c
Show file tree
Hide file tree
Showing 11 changed files with 209 additions and 65 deletions.
5 changes: 4 additions & 1 deletion drivers/gpu/drm/drm_bufs.c
Expand Up @@ -1340,7 +1340,10 @@ static int copy_one_buf(void *data, int count, struct drm_buf_entry *from)
.size = from->buf_size,
.low_mark = from->low_mark,
.high_mark = from->high_mark};
return copy_to_user(to, &v, offsetof(struct drm_buf_desc, flags));

if (copy_to_user(to, &v, offsetof(struct drm_buf_desc, flags)))
return -EFAULT;
return 0;
}

int drm_legacy_infobufs(struct drm_device *dev, void *data,
Expand Down
5 changes: 4 additions & 1 deletion drivers/gpu/drm/drm_ioc32.c
Expand Up @@ -375,7 +375,10 @@ static int copy_one_buf32(void *data, int count, struct drm_buf_entry *from)
.size = from->buf_size,
.low_mark = from->low_mark,
.high_mark = from->high_mark};
return copy_to_user(to + count, &v, offsetof(drm_buf_desc32_t, flags));

if (copy_to_user(to + count, &v, offsetof(drm_buf_desc32_t, flags)))
return -EFAULT;
return 0;
}

static int drm_legacy_infobufs32(struct drm_device *dev, void *data,
Expand Down
15 changes: 9 additions & 6 deletions drivers/gpu/drm/i915/gvt/handlers.c
Expand Up @@ -1254,18 +1254,15 @@ static int send_display_ready_uevent(struct intel_vgpu *vgpu, int ready)
static int pvinfo_mmio_write(struct intel_vgpu *vgpu, unsigned int offset,
void *p_data, unsigned int bytes)
{
u32 data;
int ret;

write_vreg(vgpu, offset, p_data, bytes);
data = vgpu_vreg(vgpu, offset);
u32 data = *(u32 *)p_data;
bool invalid_write = false;

switch (offset) {
case _vgtif_reg(display_ready):
send_display_ready_uevent(vgpu, data ? 1 : 0);
break;
case _vgtif_reg(g2v_notify):
ret = handle_g2v_notification(vgpu, data);
handle_g2v_notification(vgpu, data);
break;
/* add xhot and yhot to handled list to avoid error log */
case _vgtif_reg(cursor_x_hot):
Expand All @@ -1282,13 +1279,19 @@ static int pvinfo_mmio_write(struct intel_vgpu *vgpu, unsigned int offset,
case _vgtif_reg(execlist_context_descriptor_hi):
break;
case _vgtif_reg(rsv5[0])..._vgtif_reg(rsv5[3]):
invalid_write = true;
enter_failsafe_mode(vgpu, GVT_FAILSAFE_INSUFFICIENT_RESOURCE);
break;
default:
invalid_write = true;
gvt_vgpu_err("invalid pvinfo write offset %x bytes %x data %x\n",
offset, bytes, data);
break;
}

if (!invalid_write)
write_vreg(vgpu, offset, p_data, bytes);

return 0;
}

Expand Down
38 changes: 29 additions & 9 deletions drivers/gpu/drm/i915/intel_display.c
Expand Up @@ -12005,9 +12005,6 @@ intel_compare_link_m_n(const struct intel_link_m_n *m_n,
m2_n2->gmch_m, m2_n2->gmch_n, !adjust) &&
intel_compare_m_n(m_n->link_m, m_n->link_n,
m2_n2->link_m, m2_n2->link_n, !adjust)) {
if (adjust)
*m2_n2 = *m_n;

return true;
}

Expand Down Expand Up @@ -13149,6 +13146,33 @@ static int calc_watermark_data(struct intel_atomic_state *state)
return 0;
}

static void intel_crtc_check_fastset(struct intel_crtc_state *old_crtc_state,
struct intel_crtc_state *new_crtc_state)
{
struct drm_i915_private *dev_priv =
to_i915(new_crtc_state->base.crtc->dev);

if (!intel_pipe_config_compare(dev_priv, old_crtc_state,
new_crtc_state, true))
return;

new_crtc_state->base.mode_changed = false;
new_crtc_state->update_pipe = true;

/*
* If we're not doing the full modeset we want to
* keep the current M/N values as they may be
* sufficiently different to the computed values
* to cause problems.
*
* FIXME: should really copy more fuzzy state here
*/
new_crtc_state->fdi_m_n = old_crtc_state->fdi_m_n;
new_crtc_state->dp_m_n = old_crtc_state->dp_m_n;
new_crtc_state->dp_m2_n2 = old_crtc_state->dp_m2_n2;
new_crtc_state->has_drrs = old_crtc_state->has_drrs;
}

/**
* intel_atomic_check - validate state object
* @dev: drm device
Expand Down Expand Up @@ -13197,12 +13221,8 @@ static int intel_atomic_check(struct drm_device *dev,
return ret;
}

if (intel_pipe_config_compare(dev_priv,
to_intel_crtc_state(old_crtc_state),
pipe_config, true)) {
crtc_state->mode_changed = false;
pipe_config->update_pipe = true;
}
intel_crtc_check_fastset(to_intel_crtc_state(old_crtc_state),
pipe_config);

if (needs_modeset(crtc_state))
any_ms = true;
Expand Down
3 changes: 2 additions & 1 deletion drivers/gpu/drm/panfrost/panfrost_gem.c
Expand Up @@ -19,7 +19,8 @@ static void panfrost_gem_free_object(struct drm_gem_object *obj)
struct panfrost_gem_object *bo = to_panfrost_bo(obj);
struct panfrost_device *pfdev = obj->dev->dev_private;

panfrost_mmu_unmap(bo);
if (bo->is_mapped)
panfrost_mmu_unmap(bo);

spin_lock(&pfdev->mm_lock);
drm_mm_remove_node(&bo->node);
Expand Down
1 change: 1 addition & 0 deletions drivers/gpu/drm/panfrost/panfrost_gem.h
Expand Up @@ -11,6 +11,7 @@ struct panfrost_gem_object {
struct drm_gem_shmem_object base;

struct drm_mm_node node;
bool is_mapped;
};

static inline
Expand Down
8 changes: 8 additions & 0 deletions drivers/gpu/drm/panfrost/panfrost_mmu.c
Expand Up @@ -156,6 +156,9 @@ int panfrost_mmu_map(struct panfrost_gem_object *bo)
struct sg_table *sgt;
int ret;

if (WARN_ON(bo->is_mapped))
return 0;

sgt = drm_gem_shmem_get_pages_sgt(obj);
if (WARN_ON(IS_ERR(sgt)))
return PTR_ERR(sgt);
Expand Down Expand Up @@ -189,6 +192,7 @@ int panfrost_mmu_map(struct panfrost_gem_object *bo)

pm_runtime_mark_last_busy(pfdev->dev);
pm_runtime_put_autosuspend(pfdev->dev);
bo->is_mapped = true;

return 0;
}
Expand All @@ -203,6 +207,9 @@ void panfrost_mmu_unmap(struct panfrost_gem_object *bo)
size_t unmapped_len = 0;
int ret;

if (WARN_ON(!bo->is_mapped))
return;

dev_dbg(pfdev->dev, "unmap: iova=%llx, len=%zx", iova, len);

ret = pm_runtime_get_sync(pfdev->dev);
Expand Down Expand Up @@ -230,6 +237,7 @@ void panfrost_mmu_unmap(struct panfrost_gem_object *bo)

pm_runtime_mark_last_busy(pfdev->dev);
pm_runtime_put_autosuspend(pfdev->dev);
bo->is_mapped = false;
}

static void mmu_tlb_inv_context_s1(void *cookie)
Expand Down
3 changes: 3 additions & 0 deletions drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
Expand Up @@ -747,6 +747,9 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
if (unlikely(ret != 0))
goto out_err0;

dma_set_max_seg_size(dev->dev, min_t(unsigned int, U32_MAX & PAGE_MASK,
SCATTERLIST_MAX_SEGMENT));

if (dev_priv->capabilities & SVGA_CAP_GMR2) {
DRM_INFO("Max GMR ids is %u\n",
(unsigned)dev_priv->max_gmr_ids);
Expand Down
146 changes: 117 additions & 29 deletions drivers/gpu/drm/vmwgfx/vmwgfx_msg.c
Expand Up @@ -136,6 +136,114 @@ static int vmw_close_channel(struct rpc_channel *channel)
return 0;
}

/**
* vmw_port_hb_out - Send the message payload either through the
* high-bandwidth port if available, or through the backdoor otherwise.
* @channel: The rpc channel.
* @msg: NULL-terminated message.
* @hb: Whether the high-bandwidth port is available.
*
* Return: The port status.
*/
static unsigned long vmw_port_hb_out(struct rpc_channel *channel,
const char *msg, bool hb)
{
unsigned long si, di, eax, ebx, ecx, edx;
unsigned long msg_len = strlen(msg);

if (hb) {
unsigned long bp = channel->cookie_high;

si = (uintptr_t) msg;
di = channel->cookie_low;

VMW_PORT_HB_OUT(
(MESSAGE_STATUS_SUCCESS << 16) | VMW_PORT_CMD_HB_MSG,
msg_len, si, di,
VMW_HYPERVISOR_HB_PORT | (channel->channel_id << 16),
VMW_HYPERVISOR_MAGIC, bp,
eax, ebx, ecx, edx, si, di);

return ebx;
}

/* HB port not available. Send the message 4 bytes at a time. */
ecx = MESSAGE_STATUS_SUCCESS << 16;
while (msg_len && (HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS)) {
unsigned int bytes = min_t(size_t, msg_len, 4);
unsigned long word = 0;

memcpy(&word, msg, bytes);
msg_len -= bytes;
msg += bytes;
si = channel->cookie_high;
di = channel->cookie_low;

VMW_PORT(VMW_PORT_CMD_MSG | (MSG_TYPE_SENDPAYLOAD << 16),
word, si, di,
VMW_HYPERVISOR_PORT | (channel->channel_id << 16),
VMW_HYPERVISOR_MAGIC,
eax, ebx, ecx, edx, si, di);
}

return ecx;
}

/**
* vmw_port_hb_in - Receive the message payload either through the
* high-bandwidth port if available, or through the backdoor otherwise.
* @channel: The rpc channel.
* @reply: Pointer to buffer holding reply.
* @reply_len: Length of the reply.
* @hb: Whether the high-bandwidth port is available.
*
* Return: The port status.
*/
static unsigned long vmw_port_hb_in(struct rpc_channel *channel, char *reply,
unsigned long reply_len, bool hb)
{
unsigned long si, di, eax, ebx, ecx, edx;

if (hb) {
unsigned long bp = channel->cookie_low;

si = channel->cookie_high;
di = (uintptr_t) reply;

VMW_PORT_HB_IN(
(MESSAGE_STATUS_SUCCESS << 16) | VMW_PORT_CMD_HB_MSG,
reply_len, si, di,
VMW_HYPERVISOR_HB_PORT | (channel->channel_id << 16),
VMW_HYPERVISOR_MAGIC, bp,
eax, ebx, ecx, edx, si, di);

return ebx;
}

/* HB port not available. Retrieve the message 4 bytes at a time. */
ecx = MESSAGE_STATUS_SUCCESS << 16;
while (reply_len) {
unsigned int bytes = min_t(unsigned long, reply_len, 4);

si = channel->cookie_high;
di = channel->cookie_low;

VMW_PORT(VMW_PORT_CMD_MSG | (MSG_TYPE_RECVPAYLOAD << 16),
MESSAGE_STATUS_SUCCESS, si, di,
VMW_HYPERVISOR_PORT | (channel->channel_id << 16),
VMW_HYPERVISOR_MAGIC,
eax, ebx, ecx, edx, si, di);

if ((HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS) == 0)
break;

memcpy(reply, &ebx, bytes);
reply_len -= bytes;
reply += bytes;
}

return ecx;
}


/**
Expand All @@ -148,11 +256,10 @@ static int vmw_close_channel(struct rpc_channel *channel)
*/
static int vmw_send_msg(struct rpc_channel *channel, const char *msg)
{
unsigned long eax, ebx, ecx, edx, si, di, bp;
unsigned long eax, ebx, ecx, edx, si, di;
size_t msg_len = strlen(msg);
int retries = 0;


while (retries < RETRIES) {
retries++;

Expand All @@ -166,23 +273,14 @@ static int vmw_send_msg(struct rpc_channel *channel, const char *msg)
VMW_HYPERVISOR_MAGIC,
eax, ebx, ecx, edx, si, di);

if ((HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS) == 0 ||
(HIGH_WORD(ecx) & MESSAGE_STATUS_HB) == 0) {
/* Expected success + high-bandwidth. Give up. */
if ((HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS) == 0) {
/* Expected success. Give up. */
return -EINVAL;
}

/* Send msg */
si = (uintptr_t) msg;
di = channel->cookie_low;
bp = channel->cookie_high;

VMW_PORT_HB_OUT(
(MESSAGE_STATUS_SUCCESS << 16) | VMW_PORT_CMD_HB_MSG,
msg_len, si, di,
VMW_HYPERVISOR_HB_PORT | (channel->channel_id << 16),
VMW_HYPERVISOR_MAGIC, bp,
eax, ebx, ecx, edx, si, di);
ebx = vmw_port_hb_out(channel, msg,
!!(HIGH_WORD(ecx) & MESSAGE_STATUS_HB));

if ((HIGH_WORD(ebx) & MESSAGE_STATUS_SUCCESS) != 0) {
return 0;
Expand Down Expand Up @@ -211,7 +309,7 @@ STACK_FRAME_NON_STANDARD(vmw_send_msg);
static int vmw_recv_msg(struct rpc_channel *channel, void **msg,
size_t *msg_len)
{
unsigned long eax, ebx, ecx, edx, si, di, bp;
unsigned long eax, ebx, ecx, edx, si, di;
char *reply;
size_t reply_len;
int retries = 0;
Expand All @@ -233,8 +331,7 @@ static int vmw_recv_msg(struct rpc_channel *channel, void **msg,
VMW_HYPERVISOR_MAGIC,
eax, ebx, ecx, edx, si, di);

if ((HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS) == 0 ||
(HIGH_WORD(ecx) & MESSAGE_STATUS_HB) == 0) {
if ((HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS) == 0) {
DRM_ERROR("Failed to get reply size for host message.\n");
return -EINVAL;
}
Expand All @@ -252,17 +349,8 @@ static int vmw_recv_msg(struct rpc_channel *channel, void **msg,


/* Receive buffer */
si = channel->cookie_high;
di = (uintptr_t) reply;
bp = channel->cookie_low;

VMW_PORT_HB_IN(
(MESSAGE_STATUS_SUCCESS << 16) | VMW_PORT_CMD_HB_MSG,
reply_len, si, di,
VMW_HYPERVISOR_HB_PORT | (channel->channel_id << 16),
VMW_HYPERVISOR_MAGIC, bp,
eax, ebx, ecx, edx, si, di);

ebx = vmw_port_hb_in(channel, reply, reply_len,
!!(HIGH_WORD(ecx) & MESSAGE_STATUS_HB));
if ((HIGH_WORD(ebx) & MESSAGE_STATUS_SUCCESS) == 0) {
kfree(reply);

Expand Down

0 comments on commit 0728f6c

Please sign in to comment.