aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Williamson <alex.williamson@redhat.com>2014-07-03 11:59:51 -0400
committerDave Airlie <airlied@redhat.com>2014-07-07 21:15:09 -0400
commit4e4e7dc55af5aa62497ac060e3cfd143bd4b4db3 (patch)
treec00f630b0142309cce11e2639a120fa3382ca15a
parentf71c5d9dd22f4d6b771cdb591050c84946a3e356 (diff)
vgaarb: We can own non-decoded resources
The VGA arbiter does not allow devices to "own" resources that it doesn't "decode". However, it does allow devices to "lock" resources that it doesn't decode. This gets us into trouble because locking the resource goes through the same bridge routing updates regardless of whether we decode the resource. This means that when a non-decoded resource is released, the bridge is left with VGA routing enabled and locking a different device won't clear it. This happens in the following scenario: VGA device 01:00.0 (VGA1) is owned by the radeon driver, which registers a set_vga_decode function which releases legacy VGA decodes. VGA device 02:00.0 (VGA2) is any VGA device. VGA1 user locks VGA resources triggering first_use callback of set_vga_decoded, clearing "decode" and "owns" of legacy resources on VGA1. VGA1 user unlocks VGA resources. VGA2 user locks VGA resources, which skips VGA1 as conflicting as it does not "own" legacy resources, although VGA routing is still enabled for the VGA1 bridge. VGA routing is enabled on VGA2 bridge. VGA2 may or may not receive VGA transactions depending on the bus priority of VGA1 vs VGA2 bridge. To resolve this, we need to allow devices to "own" resources that they do not "decode". This way we can track bus ownership of VGA. When a device decodes VGA, it only means that we must update the command bits in cases where the conflicting device is on the same bus. Signed-off-by: Alex Williamson <alex.williamson@redhat.com> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> Cc: Daniel Vetter <daniel.vetter@ffwll.ch> Cc: Dave Airlie <airlied@redhat.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
-rw-r--r--drivers/gpu/vga/vgaarb.c40
1 files changed, 22 insertions, 18 deletions
diff --git a/drivers/gpu/vga/vgaarb.c b/drivers/gpu/vga/vgaarb.c
index af0259708358..d2077f040f3e 100644
--- a/drivers/gpu/vga/vgaarb.c
+++ b/drivers/gpu/vga/vgaarb.c
@@ -237,12 +237,10 @@ static struct vga_device *__vga_tryget(struct vga_device *vgadev,
237 if (conflict->locks & lwants) 237 if (conflict->locks & lwants)
238 return conflict; 238 return conflict;
239 239
240 /* Ok, now check if he owns the resource we want. We don't need 240 /* Ok, now check if it owns the resource we want. We can
241 * to check "decodes" since it should be impossible to own 241 * lock resources that are not decoded, therefore a device
242 * own legacy resources you don't decode unless I have a bug 242 * can own resources it doesn't decode.
243 * in this code...
244 */ 243 */
245 WARN_ON(conflict->owns & ~conflict->decodes);
246 match = lwants & conflict->owns; 244 match = lwants & conflict->owns;
247 if (!match) 245 if (!match)
248 continue; 246 continue;
@@ -254,13 +252,19 @@ static struct vga_device *__vga_tryget(struct vga_device *vgadev,
254 flags = 0; 252 flags = 0;
255 pci_bits = 0; 253 pci_bits = 0;
256 254
255 /* If we can't control legacy resources via the bridge, we
256 * also need to disable normal decoding.
257 */
257 if (!conflict->bridge_has_one_vga) { 258 if (!conflict->bridge_has_one_vga) {
258 vga_irq_set_state(conflict, false); 259 if ((match & conflict->decodes) & VGA_RSRC_LEGACY_MEM)
259 flags |= PCI_VGA_STATE_CHANGE_DECODES;
260 if (match & (VGA_RSRC_LEGACY_MEM|VGA_RSRC_NORMAL_MEM))
261 pci_bits |= PCI_COMMAND_MEMORY; 260 pci_bits |= PCI_COMMAND_MEMORY;
262 if (match & (VGA_RSRC_LEGACY_IO|VGA_RSRC_NORMAL_IO)) 261 if ((match & conflict->decodes) & VGA_RSRC_LEGACY_IO)
263 pci_bits |= PCI_COMMAND_IO; 262 pci_bits |= PCI_COMMAND_IO;
263
264 if (pci_bits) {
265 vga_irq_set_state(conflict, false);
266 flags |= PCI_VGA_STATE_CHANGE_DECODES;
267 }
264 } 268 }
265 269
266 if (change_bridge) 270 if (change_bridge)
@@ -268,18 +272,19 @@ static struct vga_device *__vga_tryget(struct vga_device *vgadev,
268 272
269 pci_set_vga_state(conflict->pdev, false, pci_bits, flags); 273 pci_set_vga_state(conflict->pdev, false, pci_bits, flags);
270 conflict->owns &= ~match; 274 conflict->owns &= ~match;
271 /* If he also owned non-legacy, that is no longer the case */ 275
272 if (match & VGA_RSRC_LEGACY_MEM) 276 /* If we disabled normal decoding, reflect it in owns */
277 if (pci_bits & PCI_COMMAND_MEMORY)
273 conflict->owns &= ~VGA_RSRC_NORMAL_MEM; 278 conflict->owns &= ~VGA_RSRC_NORMAL_MEM;
274 if (match & VGA_RSRC_LEGACY_IO) 279 if (pci_bits & PCI_COMMAND_IO)
275 conflict->owns &= ~VGA_RSRC_NORMAL_IO; 280 conflict->owns &= ~VGA_RSRC_NORMAL_IO;
276 } 281 }
277 282
278enable_them: 283enable_them:
279 /* ok dude, we got it, everybody conflicting has been disabled, let's 284 /* ok dude, we got it, everybody conflicting has been disabled, let's
280 * enable us. Make sure we don't mark a bit in "owns" that we don't 285 * enable us. Mark any bits in "owns" regardless of whether we
281 * also have in "decodes". We can lock resources we don't decode but 286 * decoded them. We can lock resources we don't decode, therefore
282 * not own them. 287 * we must track them via "owns".
283 */ 288 */
284 flags = 0; 289 flags = 0;
285 pci_bits = 0; 290 pci_bits = 0;
@@ -291,7 +296,7 @@ enable_them:
291 if (wants & (VGA_RSRC_LEGACY_IO|VGA_RSRC_NORMAL_IO)) 296 if (wants & (VGA_RSRC_LEGACY_IO|VGA_RSRC_NORMAL_IO))
292 pci_bits |= PCI_COMMAND_IO; 297 pci_bits |= PCI_COMMAND_IO;
293 } 298 }
294 if (!!(wants & VGA_RSRC_LEGACY_MASK)) 299 if (wants & VGA_RSRC_LEGACY_MASK)
295 flags |= PCI_VGA_STATE_CHANGE_BRIDGE; 300 flags |= PCI_VGA_STATE_CHANGE_BRIDGE;
296 301
297 pci_set_vga_state(vgadev->pdev, true, pci_bits, flags); 302 pci_set_vga_state(vgadev->pdev, true, pci_bits, flags);
@@ -299,7 +304,7 @@ enable_them:
299 if (!vgadev->bridge_has_one_vga) { 304 if (!vgadev->bridge_has_one_vga) {
300 vga_irq_set_state(vgadev, true); 305 vga_irq_set_state(vgadev, true);
301 } 306 }
302 vgadev->owns |= (wants & vgadev->decodes); 307 vgadev->owns |= wants;
303lock_them: 308lock_them:
304 vgadev->locks |= (rsrc & VGA_RSRC_LEGACY_MASK); 309 vgadev->locks |= (rsrc & VGA_RSRC_LEGACY_MASK);
305 if (rsrc & VGA_RSRC_LEGACY_IO) 310 if (rsrc & VGA_RSRC_LEGACY_IO)
@@ -649,7 +654,6 @@ static inline void vga_update_device_decodes(struct vga_device *vgadev,
649 old_decodes = vgadev->decodes; 654 old_decodes = vgadev->decodes;
650 decodes_removed = ~new_decodes & old_decodes; 655 decodes_removed = ~new_decodes & old_decodes;
651 decodes_unlocked = vgadev->locks & decodes_removed; 656 decodes_unlocked = vgadev->locks & decodes_removed;
652 vgadev->owns &= ~decodes_removed;
653 vgadev->decodes = new_decodes; 657 vgadev->decodes = new_decodes;
654 658
655 pr_info("vgaarb: device changed decodes: PCI:%s,olddecodes=%s,decodes=%s:owns=%s\n", 659 pr_info("vgaarb: device changed decodes: PCI:%s,olddecodes=%s,decodes=%s:owns=%s\n",