Commit 08d433d8 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'drm-fixes-2019-09-06' of git://anongit.freedesktop.org/drm/drm

Pull drm fixes from Dave Airlie:
 "Live from my friend's couch in Barcelona, latest round of drm fixes.

  The command line parser regression fixes look a bit larger because
  they come with selftests included for the bugs they fix. Otherwise a
  single nouveau, single ingenic and single vmwgfx fix:

  nouveau:
   - add missing MODULE_FIRMWARE definitions

  igenic:
   - hardcode panel type DPI

  vmwgfx:
   - double free fix

  core:
   - command line mode parser fixes"

* tag 'drm-fixes-2019-09-06' of git://anongit.freedesktop.org/drm/drm:
  drm/vmwgfx: Fix double free in vmw_recv_msg()
  drm/nouveau/sec2/gp102: add missing MODULE_FIRMWAREs
  drm/selftests: modes: Add more unit tests for the cmdline parser
  drm/modes: Introduce a whitelist for the named modes
  drm/modes: Fix the command line parser to take force options into account
  drm/modes: Add a switch to differentiate free standing options
  drm/ingenic: Hardcode panel type to DPI
parents 9d098a62 1e19ec6c
...@@ -1454,6 +1454,7 @@ static int drm_mode_parse_cmdline_refresh(const char *str, char **end_ptr, ...@@ -1454,6 +1454,7 @@ static int drm_mode_parse_cmdline_refresh(const char *str, char **end_ptr,
} }
static int drm_mode_parse_cmdline_extra(const char *str, int length, static int drm_mode_parse_cmdline_extra(const char *str, int length,
bool freestanding,
const struct drm_connector *connector, const struct drm_connector *connector,
struct drm_cmdline_mode *mode) struct drm_cmdline_mode *mode)
{ {
...@@ -1462,9 +1463,15 @@ static int drm_mode_parse_cmdline_extra(const char *str, int length, ...@@ -1462,9 +1463,15 @@ static int drm_mode_parse_cmdline_extra(const char *str, int length,
for (i = 0; i < length; i++) { for (i = 0; i < length; i++) {
switch (str[i]) { switch (str[i]) {
case 'i': case 'i':
if (freestanding)
return -EINVAL;
mode->interlace = true; mode->interlace = true;
break; break;
case 'm': case 'm':
if (freestanding)
return -EINVAL;
mode->margins = true; mode->margins = true;
break; break;
case 'D': case 'D':
...@@ -1542,6 +1549,7 @@ static int drm_mode_parse_cmdline_res_mode(const char *str, unsigned int length, ...@@ -1542,6 +1549,7 @@ static int drm_mode_parse_cmdline_res_mode(const char *str, unsigned int length,
if (extras) { if (extras) {
int ret = drm_mode_parse_cmdline_extra(end_ptr + i, int ret = drm_mode_parse_cmdline_extra(end_ptr + i,
1, 1,
false,
connector, connector,
mode); mode);
if (ret) if (ret)
...@@ -1669,6 +1677,22 @@ static int drm_mode_parse_cmdline_options(char *str, size_t len, ...@@ -1669,6 +1677,22 @@ static int drm_mode_parse_cmdline_options(char *str, size_t len,
return 0; return 0;
} }
static const char *drm_named_modes_whitelist[] = {
"NTSC",
"PAL",
};
static bool drm_named_mode_is_in_whitelist(const char *mode, unsigned int size)
{
int i;
for (i = 0; i < ARRAY_SIZE(drm_named_modes_whitelist); i++)
if (!strncmp(mode, drm_named_modes_whitelist[i], size))
return true;
return false;
}
/** /**
* drm_mode_parse_command_line_for_connector - parse command line modeline for connector * drm_mode_parse_command_line_for_connector - parse command line modeline for connector
* @mode_option: optional per connector mode option * @mode_option: optional per connector mode option
...@@ -1725,16 +1749,30 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option, ...@@ -1725,16 +1749,30 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
* bunch of things: * bunch of things:
* - We need to make sure that the first character (which * - We need to make sure that the first character (which
* would be our resolution in X) is a digit. * would be our resolution in X) is a digit.
* - However, if the X resolution is missing, then we end up * - If not, then it's either a named mode or a force on/off.
* with something like x<yres>, with our first character * To distinguish between the two, we need to run the
* being an alpha-numerical character, which would be * extra parsing function, and if not, then we consider it
* considered a named mode. * a named mode.
* *
* If this isn't enough, we should add more heuristics here, * If this isn't enough, we should add more heuristics here,
* and matching unit-tests. * and matching unit-tests.
*/ */
if (!isdigit(name[0]) && name[0] != 'x') if (!isdigit(name[0]) && name[0] != 'x') {
unsigned int namelen = strlen(name);
/*
* Only the force on/off options can be in that case,
* and they all take a single character.
*/
if (namelen == 1) {
ret = drm_mode_parse_cmdline_extra(name, namelen, true,
connector, mode);
if (!ret)
return true;
}
named_mode = true; named_mode = true;
}
/* Try to locate the bpp and refresh specifiers, if any */ /* Try to locate the bpp and refresh specifiers, if any */
bpp_ptr = strchr(name, '-'); bpp_ptr = strchr(name, '-');
...@@ -1772,6 +1810,10 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option, ...@@ -1772,6 +1810,10 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
if (named_mode) { if (named_mode) {
if (mode_end + 1 > DRM_DISPLAY_MODE_LEN) if (mode_end + 1 > DRM_DISPLAY_MODE_LEN)
return false; return false;
if (!drm_named_mode_is_in_whitelist(name, mode_end))
return false;
strscpy(mode->name, name, mode_end + 1); strscpy(mode->name, name, mode_end + 1);
} else { } else {
ret = drm_mode_parse_cmdline_res_mode(name, mode_end, ret = drm_mode_parse_cmdline_res_mode(name, mode_end,
...@@ -1811,7 +1853,7 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option, ...@@ -1811,7 +1853,7 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
extra_ptr != options_ptr) { extra_ptr != options_ptr) {
int len = strlen(name) - (extra_ptr - name); int len = strlen(name) - (extra_ptr - name);
ret = drm_mode_parse_cmdline_extra(extra_ptr, len, ret = drm_mode_parse_cmdline_extra(extra_ptr, len, false,
connector, mode); connector, mode);
if (ret) if (ret)
return false; return false;
......
...@@ -656,10 +656,9 @@ static int ingenic_drm_probe(struct platform_device *pdev) ...@@ -656,10 +656,9 @@ static int ingenic_drm_probe(struct platform_device *pdev)
return ret; return ret;
} }
if (panel) { if (panel)
bridge = devm_drm_panel_bridge_add(dev, panel, bridge = devm_drm_panel_bridge_add(dev, panel,
DRM_MODE_CONNECTOR_Unknown); DRM_MODE_CONNECTOR_DPI);
}
priv->dma_hwdesc = dma_alloc_coherent(dev, sizeof(*priv->dma_hwdesc), priv->dma_hwdesc = dma_alloc_coherent(dev, sizeof(*priv->dma_hwdesc),
&priv->dma_hwdesc_phys, &priv->dma_hwdesc_phys,
......
...@@ -190,6 +190,9 @@ MODULE_FIRMWARE("nvidia/gp102/nvdec/scrubber.bin"); ...@@ -190,6 +190,9 @@ MODULE_FIRMWARE("nvidia/gp102/nvdec/scrubber.bin");
MODULE_FIRMWARE("nvidia/gp102/sec2/desc.bin"); MODULE_FIRMWARE("nvidia/gp102/sec2/desc.bin");
MODULE_FIRMWARE("nvidia/gp102/sec2/image.bin"); MODULE_FIRMWARE("nvidia/gp102/sec2/image.bin");
MODULE_FIRMWARE("nvidia/gp102/sec2/sig.bin"); MODULE_FIRMWARE("nvidia/gp102/sec2/sig.bin");
MODULE_FIRMWARE("nvidia/gp102/sec2/desc-1.bin");
MODULE_FIRMWARE("nvidia/gp102/sec2/image-1.bin");
MODULE_FIRMWARE("nvidia/gp102/sec2/sig-1.bin");
MODULE_FIRMWARE("nvidia/gp104/acr/bl.bin"); MODULE_FIRMWARE("nvidia/gp104/acr/bl.bin");
MODULE_FIRMWARE("nvidia/gp104/acr/unload_bl.bin"); MODULE_FIRMWARE("nvidia/gp104/acr/unload_bl.bin");
MODULE_FIRMWARE("nvidia/gp104/acr/ucode_load.bin"); MODULE_FIRMWARE("nvidia/gp104/acr/ucode_load.bin");
...@@ -210,6 +213,9 @@ MODULE_FIRMWARE("nvidia/gp104/nvdec/scrubber.bin"); ...@@ -210,6 +213,9 @@ MODULE_FIRMWARE("nvidia/gp104/nvdec/scrubber.bin");
MODULE_FIRMWARE("nvidia/gp104/sec2/desc.bin"); MODULE_FIRMWARE("nvidia/gp104/sec2/desc.bin");
MODULE_FIRMWARE("nvidia/gp104/sec2/image.bin"); MODULE_FIRMWARE("nvidia/gp104/sec2/image.bin");
MODULE_FIRMWARE("nvidia/gp104/sec2/sig.bin"); MODULE_FIRMWARE("nvidia/gp104/sec2/sig.bin");
MODULE_FIRMWARE("nvidia/gp104/sec2/desc-1.bin");
MODULE_FIRMWARE("nvidia/gp104/sec2/image-1.bin");
MODULE_FIRMWARE("nvidia/gp104/sec2/sig-1.bin");
MODULE_FIRMWARE("nvidia/gp106/acr/bl.bin"); MODULE_FIRMWARE("nvidia/gp106/acr/bl.bin");
MODULE_FIRMWARE("nvidia/gp106/acr/unload_bl.bin"); MODULE_FIRMWARE("nvidia/gp106/acr/unload_bl.bin");
MODULE_FIRMWARE("nvidia/gp106/acr/ucode_load.bin"); MODULE_FIRMWARE("nvidia/gp106/acr/ucode_load.bin");
...@@ -230,6 +236,9 @@ MODULE_FIRMWARE("nvidia/gp106/nvdec/scrubber.bin"); ...@@ -230,6 +236,9 @@ MODULE_FIRMWARE("nvidia/gp106/nvdec/scrubber.bin");
MODULE_FIRMWARE("nvidia/gp106/sec2/desc.bin"); MODULE_FIRMWARE("nvidia/gp106/sec2/desc.bin");
MODULE_FIRMWARE("nvidia/gp106/sec2/image.bin"); MODULE_FIRMWARE("nvidia/gp106/sec2/image.bin");
MODULE_FIRMWARE("nvidia/gp106/sec2/sig.bin"); MODULE_FIRMWARE("nvidia/gp106/sec2/sig.bin");
MODULE_FIRMWARE("nvidia/gp106/sec2/desc-1.bin");
MODULE_FIRMWARE("nvidia/gp106/sec2/image-1.bin");
MODULE_FIRMWARE("nvidia/gp106/sec2/sig-1.bin");
MODULE_FIRMWARE("nvidia/gp107/acr/bl.bin"); MODULE_FIRMWARE("nvidia/gp107/acr/bl.bin");
MODULE_FIRMWARE("nvidia/gp107/acr/unload_bl.bin"); MODULE_FIRMWARE("nvidia/gp107/acr/unload_bl.bin");
MODULE_FIRMWARE("nvidia/gp107/acr/ucode_load.bin"); MODULE_FIRMWARE("nvidia/gp107/acr/ucode_load.bin");
...@@ -250,3 +259,6 @@ MODULE_FIRMWARE("nvidia/gp107/nvdec/scrubber.bin"); ...@@ -250,3 +259,6 @@ MODULE_FIRMWARE("nvidia/gp107/nvdec/scrubber.bin");
MODULE_FIRMWARE("nvidia/gp107/sec2/desc.bin"); MODULE_FIRMWARE("nvidia/gp107/sec2/desc.bin");
MODULE_FIRMWARE("nvidia/gp107/sec2/image.bin"); MODULE_FIRMWARE("nvidia/gp107/sec2/image.bin");
MODULE_FIRMWARE("nvidia/gp107/sec2/sig.bin"); MODULE_FIRMWARE("nvidia/gp107/sec2/sig.bin");
MODULE_FIRMWARE("nvidia/gp107/sec2/desc-1.bin");
MODULE_FIRMWARE("nvidia/gp107/sec2/image-1.bin");
MODULE_FIRMWARE("nvidia/gp107/sec2/sig-1.bin");
...@@ -9,6 +9,13 @@ ...@@ -9,6 +9,13 @@
#define cmdline_test(test) selftest(test, test) #define cmdline_test(test) selftest(test, test)
cmdline_test(drm_cmdline_test_force_d_only)
cmdline_test(drm_cmdline_test_force_D_only_dvi)
cmdline_test(drm_cmdline_test_force_D_only_hdmi)
cmdline_test(drm_cmdline_test_force_D_only_not_digital)
cmdline_test(drm_cmdline_test_force_e_only)
cmdline_test(drm_cmdline_test_margin_only)
cmdline_test(drm_cmdline_test_interlace_only)
cmdline_test(drm_cmdline_test_res) cmdline_test(drm_cmdline_test_res)
cmdline_test(drm_cmdline_test_res_missing_x) cmdline_test(drm_cmdline_test_res_missing_x)
cmdline_test(drm_cmdline_test_res_missing_y) cmdline_test(drm_cmdline_test_res_missing_y)
......
...@@ -17,6 +17,136 @@ ...@@ -17,6 +17,136 @@
static const struct drm_connector no_connector = {}; static const struct drm_connector no_connector = {};
static int drm_cmdline_test_force_e_only(void *ignored)
{
struct drm_cmdline_mode mode = { };
FAIL_ON(!drm_mode_parse_command_line_for_connector("e",
&no_connector,
&mode));
FAIL_ON(mode.specified);
FAIL_ON(mode.refresh_specified);
FAIL_ON(mode.bpp_specified);
FAIL_ON(mode.rb);
FAIL_ON(mode.cvt);
FAIL_ON(mode.interlace);
FAIL_ON(mode.margins);
FAIL_ON(mode.force != DRM_FORCE_ON);
return 0;
}
static int drm_cmdline_test_force_D_only_not_digital(void *ignored)
{
struct drm_cmdline_mode mode = { };
FAIL_ON(!drm_mode_parse_command_line_for_connector("D",
&no_connector,
&mode));
FAIL_ON(mode.specified);
FAIL_ON(mode.refresh_specified);
FAIL_ON(mode.bpp_specified);
FAIL_ON(mode.rb);
FAIL_ON(mode.cvt);
FAIL_ON(mode.interlace);
FAIL_ON(mode.margins);
FAIL_ON(mode.force != DRM_FORCE_ON);
return 0;
}
static const struct drm_connector connector_hdmi = {
.connector_type = DRM_MODE_CONNECTOR_HDMIB,
};
static int drm_cmdline_test_force_D_only_hdmi(void *ignored)
{
struct drm_cmdline_mode mode = { };
FAIL_ON(!drm_mode_parse_command_line_for_connector("D",
&connector_hdmi,
&mode));
FAIL_ON(mode.specified);
FAIL_ON(mode.refresh_specified);
FAIL_ON(mode.bpp_specified);
FAIL_ON(mode.rb);
FAIL_ON(mode.cvt);
FAIL_ON(mode.interlace);
FAIL_ON(mode.margins);
FAIL_ON(mode.force != DRM_FORCE_ON_DIGITAL);
return 0;
}
static const struct drm_connector connector_dvi = {
.connector_type = DRM_MODE_CONNECTOR_DVII,
};
static int drm_cmdline_test_force_D_only_dvi(void *ignored)
{
struct drm_cmdline_mode mode = { };
FAIL_ON(!drm_mode_parse_command_line_for_connector("D",
&connector_dvi,
&mode));
FAIL_ON(mode.specified);
FAIL_ON(mode.refresh_specified);
FAIL_ON(mode.bpp_specified);
FAIL_ON(mode.rb);
FAIL_ON(mode.cvt);
FAIL_ON(mode.interlace);
FAIL_ON(mode.margins);
FAIL_ON(mode.force != DRM_FORCE_ON_DIGITAL);
return 0;
}
static int drm_cmdline_test_force_d_only(void *ignored)
{
struct drm_cmdline_mode mode = { };
FAIL_ON(!drm_mode_parse_command_line_for_connector("d",
&no_connector,
&mode));
FAIL_ON(mode.specified);
FAIL_ON(mode.refresh_specified);
FAIL_ON(mode.bpp_specified);
FAIL_ON(mode.rb);
FAIL_ON(mode.cvt);
FAIL_ON(mode.interlace);
FAIL_ON(mode.margins);
FAIL_ON(mode.force != DRM_FORCE_OFF);
return 0;
}
static int drm_cmdline_test_margin_only(void *ignored)
{
struct drm_cmdline_mode mode = { };
FAIL_ON(drm_mode_parse_command_line_for_connector("m",
&no_connector,
&mode));
return 0;
}
static int drm_cmdline_test_interlace_only(void *ignored)
{
struct drm_cmdline_mode mode = { };
FAIL_ON(drm_mode_parse_command_line_for_connector("i",
&no_connector,
&mode));
return 0;
}
static int drm_cmdline_test_res(void *ignored) static int drm_cmdline_test_res(void *ignored)
{ {
struct drm_cmdline_mode mode = { }; struct drm_cmdline_mode mode = { };
......
...@@ -353,7 +353,7 @@ static int vmw_recv_msg(struct rpc_channel *channel, void **msg, ...@@ -353,7 +353,7 @@ static int vmw_recv_msg(struct rpc_channel *channel, void **msg,
!!(HIGH_WORD(ecx) & MESSAGE_STATUS_HB)); !!(HIGH_WORD(ecx) & MESSAGE_STATUS_HB));
if ((HIGH_WORD(ebx) & MESSAGE_STATUS_SUCCESS) == 0) { if ((HIGH_WORD(ebx) & MESSAGE_STATUS_SUCCESS) == 0) {
kfree(reply); kfree(reply);
reply = NULL;
if ((HIGH_WORD(ebx) & MESSAGE_STATUS_CPT) != 0) { if ((HIGH_WORD(ebx) & MESSAGE_STATUS_CPT) != 0) {
/* A checkpoint occurred. Retry. */ /* A checkpoint occurred. Retry. */
continue; continue;
...@@ -377,7 +377,7 @@ static int vmw_recv_msg(struct rpc_channel *channel, void **msg, ...@@ -377,7 +377,7 @@ static int vmw_recv_msg(struct rpc_channel *channel, void **msg,
if ((HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS) == 0) { if ((HIGH_WORD(ecx) & MESSAGE_STATUS_SUCCESS) == 0) {
kfree(reply); kfree(reply);
reply = NULL;
if ((HIGH_WORD(ecx) & MESSAGE_STATUS_CPT) != 0) { if ((HIGH_WORD(ecx) & MESSAGE_STATUS_CPT) != 0) {
/* A checkpoint occurred. Retry. */ /* A checkpoint occurred. Retry. */
continue; continue;
...@@ -389,10 +389,8 @@ static int vmw_recv_msg(struct rpc_channel *channel, void **msg, ...@@ -389,10 +389,8 @@ static int vmw_recv_msg(struct rpc_channel *channel, void **msg,
break; break;
} }
if (retries == RETRIES) { if (!reply)
kfree(reply);
return -EINVAL; return -EINVAL;
}
*msg_len = reply_len; *msg_len = reply_len;
*msg = reply; *msg = reply;
......
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