Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

drm/i915/vga: Stop trying to use GMCH_CTRL for VGA decode control

intel_gmch_vga_set_state() is a complete lie on ILK+ because
the GMCH_CTRL register is locked and can't actually be written.
But we still need to remove the iGPU from the VGA arbitration
on iGPU+dGPU systems, or else Xorg performance will tank due
to the constant VGA arbiter accesses.

For VGA memory decode we can't turn off the PCI_COMMAND
memory deocde as that would disable even normal MMIO.
Instead we can disable just the VGA memory decode via
the VGA MSR register. And we can do that just once
when disabling the VGA plane. That way we don't have
to touch VGA registers anywhere else.

We can also inform the arbiter that we're no longer decoding
VGA memory. This will stop the arbiter from disabling all
memory decode for the iGPU via PCI_COMMAND (and thus breaking
everything) whenever some other GPU wants to own the VGA memory
accesses.

For IO we can disable all IO decode via the PCI_COMMAND
register, except around the few VGA register accesses that
we need to do in intel_vga_disable(). Unfortunately we can't
disable IO decode permanently as it makes some laptops (eg.
Dell Latitude E5400) hang during reboot/shutdown. One option
would be to re-enable IO decode from the poweroff hooks, but
that won't help the sysrq emergency reboot/shutdown since it
won't call said hooks. So let's try to keep IO decode in its
original setting unless we really need to disable it to
exclude the GPU from VGA arbitration.

I suppose we could keep frobbing GMCH_CTRL on pre-ILK, but
it seems better to not do it since it has other side effects
such as changing the class code of the PCI device.

For discrete GPUs we'll rely on the bridge control instead.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Link: https://patch.msgid.link/20251208182637.334-9-ville.syrjala@linux.intel.com
Acked-by: Jani Nikula <jani.nikula@intel.com>

+57 -36
+57 -36
drivers/gpu/drm/i915/display/intel_vga.c
··· 71 71 return old & PCI_COMMAND_IO; 72 72 } 73 73 74 + static bool intel_pci_bridge_set_vga(struct pci_dev *pdev, bool enable) 75 + { 76 + u16 old = 0, ctl; 77 + 78 + pci_read_config_word(pdev->bus->self, PCI_BRIDGE_CONTROL, &old); 79 + ctl = old & ~PCI_BRIDGE_CTL_VGA; 80 + if (enable) 81 + ctl |= PCI_BRIDGE_CTL_VGA; 82 + pci_write_config_word(pdev->bus->self, PCI_BRIDGE_CONTROL, ctl); 83 + 84 + return old & PCI_BRIDGE_CTL_VGA; 85 + } 86 + 74 87 static bool intel_vga_get(struct intel_display *display) 75 88 { 76 89 struct pci_dev *pdev = to_pci_dev(display->drm->dev); ··· 121 108 /* Disable the VGA plane that we never use */ 122 109 void intel_vga_disable(struct intel_display *display) 123 110 { 111 + struct pci_dev *pdev = to_pci_dev(display->drm->dev); 124 112 i915_reg_t vga_reg = intel_vga_cntrl_reg(display); 125 113 bool io_decode; 126 114 u8 msr, sr1; ··· 175 161 176 162 msr = inb(VGA_MIS_R); 177 163 /* 164 + * Always disable VGA memory decode for iGPU so that 165 + * intel_vga_set_decode() doesn't need to access VGA registers. 166 + * VGA_MIS_ENB_MEM_ACCESS=0 is also the reset value. 167 + */ 168 + msr &= ~VGA_MIS_ENB_MEM_ACCESS; 169 + /* 178 170 * VGA_MIS_COLOR controls both GPU level and display engine level 179 171 * MDA vs. CGA decode logic. But when the register gets reset 180 172 * (reset value has VGA_MIS_COLOR=0) by the power well, only the ··· 197 177 198 178 intel_vga_put(display, io_decode); 199 179 180 + /* 181 + * Inform the arbiter about VGA memory decode being disabled so 182 + * that it doesn't disable all memory decode for the iGPU when 183 + * targeting another GPU. 184 + */ 185 + if (!display->platform.dgfx) 186 + vga_set_legacy_decoding(pdev, VGA_RSRC_LEGACY_IO); 187 + 200 188 udelay(300); 201 189 202 190 reset_vgacntr: ··· 212 184 intel_de_posting_read(display, vga_reg); 213 185 } 214 186 215 - static int intel_gmch_vga_set_state(struct intel_display *display, bool enable_decode) 216 - { 217 - struct pci_dev *pdev = to_pci_dev(display->drm->dev); 218 - u16 gmch_ctrl; 219 - 220 - if (pci_bus_read_config_word(pdev->bus, PCI_DEVFN(0, 0), 221 - intel_gmch_ctrl_reg(display), &gmch_ctrl)) { 222 - drm_err(display->drm, "failed to read control word\n"); 223 - return -EIO; 224 - } 225 - 226 - if (!!(gmch_ctrl & INTEL_GMCH_VGA_DISABLE) == !enable_decode) 227 - return 0; 228 - 229 - if (enable_decode) 230 - gmch_ctrl &= ~INTEL_GMCH_VGA_DISABLE; 231 - else 232 - gmch_ctrl |= INTEL_GMCH_VGA_DISABLE; 233 - 234 - if (pci_bus_write_config_word(pdev->bus, PCI_DEVFN(0, 0), 235 - intel_gmch_ctrl_reg(display), gmch_ctrl)) { 236 - drm_err(display->drm, "failed to write control word\n"); 237 - return -EIO; 238 - } 239 - 240 - return 0; 241 - } 242 - 243 - static unsigned int intel_gmch_vga_set_decode(struct pci_dev *pdev, bool enable_decode) 187 + static unsigned int intel_vga_set_decode(struct pci_dev *pdev, bool enable_decode) 244 188 { 245 189 struct intel_display *display = to_intel_display(pdev); 190 + unsigned int decodes = VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM; 246 191 247 - intel_gmch_vga_set_state(display, enable_decode); 192 + drm_dbg_kms(display->drm, "%s VGA decode due to VGA arbitration\n", 193 + str_enable_disable(enable_decode)); 248 194 249 - if (enable_decode) 250 - return VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM | 251 - VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM; 252 - else 253 - return VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM; 195 + /* 196 + * Can't use GMCH_CTRL INTEL_GMCH_VGA_DISABLE to disable VGA 197 + * decode on ILK+ since the register is locked. Instead 198 + * intel_disable_vga() will disable VGA memory decode for the 199 + * iGPU, and here we just need to take care of the IO decode. 200 + * For discrete GPUs we rely on the bridge VGA control. 201 + * 202 + * We can't disable IO decode already in intel_vga_disable() 203 + * because at least some laptops (eg. CTG Dell Latitude E5400) 204 + * will hang during reboot/shutfown with IO decode disabled. 205 + */ 206 + if (display->platform.dgfx) { 207 + if (!enable_decode) 208 + intel_pci_bridge_set_vga(pdev, false); 209 + else 210 + decodes |= VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM; 211 + } else { 212 + if (!enable_decode) 213 + intel_pci_set_io_decode(pdev, false); 214 + else 215 + decodes |= VGA_RSRC_LEGACY_IO; 216 + } 217 + 218 + return decodes; 254 219 } 255 220 256 221 void intel_vga_register(struct intel_display *display) ··· 260 239 * then we do not take part in VGA arbitration and the 261 240 * vga_client_register() fails with -ENODEV. 262 241 */ 263 - ret = vga_client_register(pdev, intel_gmch_vga_set_decode); 242 + ret = vga_client_register(pdev, intel_vga_set_decode); 264 243 drm_WARN_ON(display->drm, ret && ret != -ENODEV); 265 244 } 266 245