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

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
Loading
Loading
Loading
Loading
+48 −6
Original line number Diff line number Diff line
@@ -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,
					bool freestanding,
					const struct drm_connector *connector,
					struct drm_cmdline_mode *mode)
{
@@ -1462,9 +1463,15 @@ static int drm_mode_parse_cmdline_extra(const char *str, int length,
	for (i = 0; i < length; i++) {
		switch (str[i]) {
		case 'i':
			if (freestanding)
				return -EINVAL;

			mode->interlace = true;
			break;
		case 'm':
			if (freestanding)
				return -EINVAL;

			mode->margins = true;
			break;
		case 'D':
@@ -1542,6 +1549,7 @@ static int drm_mode_parse_cmdline_res_mode(const char *str, unsigned int length,
			if (extras) {
				int ret = drm_mode_parse_cmdline_extra(end_ptr + i,
								       1,
								       false,
								       connector,
								       mode);
				if (ret)
@@ -1669,6 +1677,22 @@ static int drm_mode_parse_cmdline_options(char *str, size_t len,
	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
 * @mode_option: optional per connector mode option
@@ -1725,16 +1749,30 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
	 * bunch of things:
	 *   - We need to make sure that the first character (which
	 *     would be our resolution in X) is a digit.
	 *   - However, if the X resolution is missing, then we end up
	 *     with something like x<yres>, with our first character
	 *     being an alpha-numerical character, which would be
	 *     considered a named mode.
	 *   - If not, then it's either a named mode or a force on/off.
	 *     To distinguish between the two, we need to run the
	 *     extra parsing function, and if not, then we consider it
	 *     a named mode.
	 *
	 * If this isn't enough, we should add more heuristics here,
	 * 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;
	}

	/* Try to locate the bpp and refresh specifiers, if any */
	bpp_ptr = strchr(name, '-');
@@ -1772,6 +1810,10 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
	if (named_mode) {
		if (mode_end + 1 > DRM_DISPLAY_MODE_LEN)
			return false;

		if (!drm_named_mode_is_in_whitelist(name, mode_end))
			return false;

		strscpy(mode->name, name, mode_end + 1);
	} else {
		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,
	    extra_ptr != options_ptr) {
		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);
		if (ret)
			return false;
+2 −3
Original line number Diff line number Diff line
@@ -656,10 +656,9 @@ static int ingenic_drm_probe(struct platform_device *pdev)
		return ret;
	}

	if (panel) {
	if (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_phys,
+12 −0
Original line number Diff line number Diff line
@@ -190,6 +190,9 @@ MODULE_FIRMWARE("nvidia/gp102/nvdec/scrubber.bin");
MODULE_FIRMWARE("nvidia/gp102/sec2/desc.bin");
MODULE_FIRMWARE("nvidia/gp102/sec2/image.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/unload_bl.bin");
MODULE_FIRMWARE("nvidia/gp104/acr/ucode_load.bin");
@@ -210,6 +213,9 @@ MODULE_FIRMWARE("nvidia/gp104/nvdec/scrubber.bin");
MODULE_FIRMWARE("nvidia/gp104/sec2/desc.bin");
MODULE_FIRMWARE("nvidia/gp104/sec2/image.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/unload_bl.bin");
MODULE_FIRMWARE("nvidia/gp106/acr/ucode_load.bin");
@@ -230,6 +236,9 @@ MODULE_FIRMWARE("nvidia/gp106/nvdec/scrubber.bin");
MODULE_FIRMWARE("nvidia/gp106/sec2/desc.bin");
MODULE_FIRMWARE("nvidia/gp106/sec2/image.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/unload_bl.bin");
MODULE_FIRMWARE("nvidia/gp107/acr/ucode_load.bin");
@@ -250,3 +259,6 @@ MODULE_FIRMWARE("nvidia/gp107/nvdec/scrubber.bin");
MODULE_FIRMWARE("nvidia/gp107/sec2/desc.bin");
MODULE_FIRMWARE("nvidia/gp107/sec2/image.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");
+7 −0
Original line number Diff line number Diff line
@@ -9,6 +9,13 @@

#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_missing_x)
cmdline_test(drm_cmdline_test_res_missing_y)
+130 −0
Original line number Diff line number Diff line
@@ -17,6 +17,136 @@

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)
{
	struct drm_cmdline_mode mode = { };
Loading