Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 753e7c8c authored by Dave Airlie's avatar Dave Airlie
Browse files

Merge branch 'linux-4.8' of git://github.com/skeggsb/linux into drm-next

Runtime PM fixes, fbcon and nv30 fix.
* 'linux-4.8' of git://github.com/skeggsb/linux:
  drm/nouveau/gr/nv3x: fix instobj write offsets in gr setup
  drm/nouveau/acpi: fix lockup with PCIe runtime PM
  drm/nouveau/acpi: check for function 0x1B before using it
  drm/nouveau/acpi: return supported DSM functions
  drm/nouveau/acpi: ensure matching ACPI handle and supported functions
  drm/nouveau/fbcon: fix font width not divisible by 8
parents 1cf915d3 d0e62ef6
Loading
Loading
Loading
Loading
+68 −37
Original line number Diff line number Diff line
@@ -45,6 +45,8 @@
static struct nouveau_dsm_priv {
	bool dsm_detected;
	bool optimus_detected;
	bool optimus_flags_detected;
	bool optimus_skip_dsm;
	acpi_handle dhandle;
	acpi_handle rom_handle;
} nouveau_dsm_priv;
@@ -57,9 +59,6 @@ bool nouveau_is_v1_dsm(void) {
	return nouveau_dsm_priv.dsm_detected;
}

#define NOUVEAU_DSM_HAS_MUX 0x1
#define NOUVEAU_DSM_HAS_OPT 0x2

#ifdef CONFIG_VGA_SWITCHEROO
static const char nouveau_dsm_muid[] = {
	0xA0, 0xA0, 0x95, 0x9D, 0x60, 0x00, 0x48, 0x4D,
@@ -110,7 +109,7 @@ static int nouveau_optimus_dsm(acpi_handle handle, int func, int arg, uint32_t *
 * requirements on the fourth parameter, so a private implementation
 * instead of using acpi_check_dsm().
 */
static int nouveau_check_optimus_dsm(acpi_handle handle)
static int nouveau_dsm_get_optimus_functions(acpi_handle handle)
{
	int result;

@@ -125,7 +124,9 @@ static int nouveau_check_optimus_dsm(acpi_handle handle)
	 * ACPI Spec v4 9.14.1: if bit 0 is zero, no function is supported.
	 * If the n-th bit is enabled, function n is supported
	 */
	return result & 1 && result & (1 << NOUVEAU_DSM_OPTIMUS_CAPS);
	if (result & 1 && result & (1 << NOUVEAU_DSM_OPTIMUS_CAPS))
		return result;
	return 0;
}

static int nouveau_dsm(acpi_handle handle, int func, int arg)
@@ -212,26 +213,55 @@ static const struct vga_switcheroo_handler nouveau_dsm_handler = {
	.get_client_id = nouveau_dsm_get_client_id,
};

static int nouveau_dsm_pci_probe(struct pci_dev *pdev)
/*
 * Firmware supporting Windows 8 or later do not use _DSM to put the device into
 * D3cold, they instead rely on disabling power resources on the parent.
 */
static bool nouveau_pr3_present(struct pci_dev *pdev)
{
	struct pci_dev *parent_pdev = pci_upstream_bridge(pdev);
	struct acpi_device *parent_adev;

	if (!parent_pdev)
		return false;

	parent_adev = ACPI_COMPANION(&parent_pdev->dev);
	if (!parent_adev)
		return false;

	return acpi_has_method(parent_adev->handle, "_PR3");
}

static void nouveau_dsm_pci_probe(struct pci_dev *pdev, acpi_handle *dhandle_out,
				  bool *has_mux, bool *has_opt,
				  bool *has_opt_flags, bool *has_pr3)
{
	acpi_handle dhandle;
	int retval = 0;
	bool supports_mux;
	int optimus_funcs;

	dhandle = ACPI_HANDLE(&pdev->dev);
	if (!dhandle)
		return false;
		return;

	if (!acpi_has_method(dhandle, "_DSM"))
		return false;
		return;

	supports_mux = acpi_check_dsm(dhandle, nouveau_dsm_muid, 0x00000102,
				      1 << NOUVEAU_DSM_POWER);
	optimus_funcs = nouveau_dsm_get_optimus_functions(dhandle);

	if (acpi_check_dsm(dhandle, nouveau_dsm_muid, 0x00000102,
			   1 << NOUVEAU_DSM_POWER))
		retval |= NOUVEAU_DSM_HAS_MUX;
	/* Does not look like a Nvidia device. */
	if (!supports_mux && !optimus_funcs)
		return;

	if (nouveau_check_optimus_dsm(dhandle))
		retval |= NOUVEAU_DSM_HAS_OPT;
	*dhandle_out = dhandle;
	*has_mux = supports_mux;
	*has_opt = !!optimus_funcs;
	*has_opt_flags = optimus_funcs & (1 << NOUVEAU_DSM_OPTIMUS_FLAGS);
	*has_pr3 = false;

	if (retval & NOUVEAU_DSM_HAS_OPT) {
	if (optimus_funcs) {
		uint32_t result;
		nouveau_optimus_dsm(dhandle, NOUVEAU_DSM_OPTIMUS_CAPS, 0,
				    &result);
@@ -239,11 +269,9 @@ static int nouveau_dsm_pci_probe(struct pci_dev *pdev)
			 (result & OPTIMUS_ENABLED) ? "enabled" : "disabled",
			 (result & OPTIMUS_DYNAMIC_PWR_CAP) ? "dynamic power, " : "",
			 (result & OPTIMUS_HDA_CODEC_MASK) ? "hda bios codec supported" : "");
	}
	if (retval)
		nouveau_dsm_priv.dhandle = dhandle;

	return retval;
		*has_pr3 = nouveau_pr3_present(pdev);
	}
}

static bool nouveau_dsm_detect(void)
@@ -251,11 +279,13 @@ static bool nouveau_dsm_detect(void)
	char acpi_method_name[255] = { 0 };
	struct acpi_buffer buffer = {sizeof(acpi_method_name), acpi_method_name};
	struct pci_dev *pdev = NULL;
	int has_dsm = 0;
	int has_optimus = 0;
	acpi_handle dhandle = NULL;
	bool has_mux = false;
	bool has_optimus = false;
	bool has_optimus_flags = false;
	bool has_power_resources = false;
	int vga_count = 0;
	bool guid_valid;
	int retval;
	bool ret = false;

	/* lookup the MXM GUID */
@@ -268,32 +298,32 @@ static bool nouveau_dsm_detect(void)
	while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {
		vga_count++;

		retval = nouveau_dsm_pci_probe(pdev);
		if (retval & NOUVEAU_DSM_HAS_MUX)
			has_dsm |= 1;
		if (retval & NOUVEAU_DSM_HAS_OPT)
			has_optimus = 1;
		nouveau_dsm_pci_probe(pdev, &dhandle, &has_mux, &has_optimus,
				      &has_optimus_flags, &has_power_resources);
	}

	while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_3D << 8, pdev)) != NULL) {
		vga_count++;

		retval = nouveau_dsm_pci_probe(pdev);
		if (retval & NOUVEAU_DSM_HAS_MUX)
			has_dsm |= 1;
		if (retval & NOUVEAU_DSM_HAS_OPT)
			has_optimus = 1;
		nouveau_dsm_pci_probe(pdev, &dhandle, &has_mux, &has_optimus,
				      &has_optimus_flags, &has_power_resources);
	}

	/* find the optimus DSM or the old v1 DSM */
	if (has_optimus == 1) {
	if (has_optimus) {
		nouveau_dsm_priv.dhandle = dhandle;
		acpi_get_name(nouveau_dsm_priv.dhandle, ACPI_FULL_PATHNAME,
			&buffer);
		printk(KERN_INFO "VGA switcheroo: detected Optimus DSM method %s handle\n",
			acpi_method_name);
		if (has_power_resources)
			pr_info("nouveau: detected PR support, will not use DSM\n");
		nouveau_dsm_priv.optimus_detected = true;
		nouveau_dsm_priv.optimus_flags_detected = has_optimus_flags;
		nouveau_dsm_priv.optimus_skip_dsm = has_power_resources;
		ret = true;
	} else if (vga_count == 2 && has_dsm && guid_valid) {
	} else if (vga_count == 2 && has_mux && guid_valid) {
		nouveau_dsm_priv.dhandle = dhandle;
		acpi_get_name(nouveau_dsm_priv.dhandle, ACPI_FULL_PATHNAME,
			&buffer);
		printk(KERN_INFO "VGA switcheroo: detected DSM switching method %s handle\n",
@@ -321,9 +351,10 @@ void nouveau_register_dsm_handler(void)
void nouveau_switcheroo_optimus_dsm(void)
{
	u32 result = 0;
	if (!nouveau_dsm_priv.optimus_detected)
	if (!nouveau_dsm_priv.optimus_detected || nouveau_dsm_priv.optimus_skip_dsm)
		return;

	if (nouveau_dsm_priv.optimus_flags_detected)
		nouveau_optimus_dsm(nouveau_dsm_priv.dhandle, NOUVEAU_DSM_OPTIMUS_FLAGS,
				    0x3, &result);

+2 −2
Original line number Diff line number Diff line
@@ -107,11 +107,11 @@ nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
			 ((image->dx + image->width) & 0xffff));
	OUT_RING(chan, bg);
	OUT_RING(chan, fg);
	OUT_RING(chan, (image->height << 16) | image->width);
	OUT_RING(chan, (image->height << 16) | ALIGN(image->width, 8));
	OUT_RING(chan, (image->height << 16) | image->width);
	OUT_RING(chan, (image->dy << 16) | (image->dx & 0xffff));

	dsize = ALIGN(image->width * image->height, 32) >> 5;
	dsize = ALIGN(ALIGN(image->width, 8) * image->height, 32) >> 5;
	while (dsize) {
		int iter_len = dsize > 128 ? 128 : dsize;

+1 −1
Original line number Diff line number Diff line
@@ -125,7 +125,7 @@ nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
	OUT_RING(chan, 0);
	OUT_RING(chan, image->dy);

	dwords = ALIGN(image->width * image->height, 32) >> 5;
	dwords = ALIGN(ALIGN(image->width, 8) * image->height, 32) >> 5;
	while (dwords) {
		int push = dwords > 2047 ? 2047 : dwords;

+1 −1
Original line number Diff line number Diff line
@@ -125,7 +125,7 @@ nvc0_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
	OUT_RING  (chan, 0);
	OUT_RING  (chan, image->dy);

	dwords = ALIGN(image->width * image->height, 32) >> 5;
	dwords = ALIGN(ALIGN(image->width, 8) * image->height, 32) >> 5;
	while (dwords) {
		int push = dwords > 2047 ? 2047 : dwords;

+2 −2
Original line number Diff line number Diff line
@@ -76,8 +76,8 @@ nv30_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch,
		nvkm_wo32(chan->inst, i, 0x00040004);
	for (i = 0x1f18; i <= 0x3088 ; i += 16) {
		nvkm_wo32(chan->inst, i + 0, 0x10700ff9);
		nvkm_wo32(chan->inst, i + 1, 0x0436086c);
		nvkm_wo32(chan->inst, i + 2, 0x000c001b);
		nvkm_wo32(chan->inst, i + 4, 0x0436086c);
		nvkm_wo32(chan->inst, i + 8, 0x000c001b);
	}
	for (i = 0x30b8; i < 0x30c8; i += 4)
		nvkm_wo32(chan->inst, i, 0x0000ffff);
Loading