From patchwork Thu Jul 3 15:59:51 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Alex Williamson X-Patchwork-Id: 4475771 Return-Path: X-Original-To: patchwork-dri-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 646CB9F387 for ; Thu, 3 Jul 2014 16:00:02 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 769572039E for ; Thu, 3 Jul 2014 16:00:01 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by mail.kernel.org (Postfix) with ESMTP id 4945920398 for ; Thu, 3 Jul 2014 16:00:00 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 77CA36E4BF; Thu, 3 Jul 2014 08:59:59 -0700 (PDT) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by gabe.freedesktop.org (Postfix) with ESMTP id DFF6A6E4BF for ; Thu, 3 Jul 2014 08:59:57 -0700 (PDT) Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id s63FxqrQ009020 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Thu, 3 Jul 2014 11:59:53 -0400 Received: from gimli.home ([10.3.113.3]) by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id s63FxpNo024252; Thu, 3 Jul 2014 11:59:52 -0400 From: Alex Williamson Subject: [RE-RESEND PATCH] vgaarb: We can own non-decoded resources To: linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org Date: Thu, 03 Jul 2014 09:59:51 -0600 Message-ID: <20140703155914.8524.94699.stgit@gimli.home> User-Agent: StGIT/0.14.3 MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.68 on 10.5.11.22 Cc: Daniel Vetter , Alex Williamson , Dave Airlie X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" X-Spam-Status: No, score=-4.2 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP 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 Cc: Ville Syrjälä Cc: Daniel Vetter Cc: Dave Airlie --- Can someone please claim ownership of vgaarb? drivers/gpu/vga/vgaarb.c | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/vga/vgaarb.c b/drivers/gpu/vga/vgaarb.c index af02597..d2077f0 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, if (conflict->locks & lwants) return conflict; - /* Ok, now check if he owns the resource we want. We don't need - * to check "decodes" since it should be impossible to own - * own legacy resources you don't decode unless I have a bug - * in this code... + /* Ok, now check if it owns the resource we want. We can + * lock resources that are not decoded, therefore a device + * can own resources it doesn't decode. */ - WARN_ON(conflict->owns & ~conflict->decodes); match = lwants & conflict->owns; if (!match) continue; @@ -254,13 +252,19 @@ static struct vga_device *__vga_tryget(struct vga_device *vgadev, flags = 0; pci_bits = 0; + /* If we can't control legacy resources via the bridge, we + * also need to disable normal decoding. + */ if (!conflict->bridge_has_one_vga) { - vga_irq_set_state(conflict, false); - flags |= PCI_VGA_STATE_CHANGE_DECODES; - if (match & (VGA_RSRC_LEGACY_MEM|VGA_RSRC_NORMAL_MEM)) + if ((match & conflict->decodes) & VGA_RSRC_LEGACY_MEM) pci_bits |= PCI_COMMAND_MEMORY; - if (match & (VGA_RSRC_LEGACY_IO|VGA_RSRC_NORMAL_IO)) + if ((match & conflict->decodes) & VGA_RSRC_LEGACY_IO) pci_bits |= PCI_COMMAND_IO; + + if (pci_bits) { + vga_irq_set_state(conflict, false); + flags |= PCI_VGA_STATE_CHANGE_DECODES; + } } if (change_bridge) @@ -268,18 +272,19 @@ static struct vga_device *__vga_tryget(struct vga_device *vgadev, pci_set_vga_state(conflict->pdev, false, pci_bits, flags); conflict->owns &= ~match; - /* If he also owned non-legacy, that is no longer the case */ - if (match & VGA_RSRC_LEGACY_MEM) + + /* If we disabled normal decoding, reflect it in owns */ + if (pci_bits & PCI_COMMAND_MEMORY) conflict->owns &= ~VGA_RSRC_NORMAL_MEM; - if (match & VGA_RSRC_LEGACY_IO) + if (pci_bits & PCI_COMMAND_IO) conflict->owns &= ~VGA_RSRC_NORMAL_IO; } enable_them: /* ok dude, we got it, everybody conflicting has been disabled, let's - * enable us. Make sure we don't mark a bit in "owns" that we don't - * also have in "decodes". We can lock resources we don't decode but - * not own them. + * enable us. Mark any bits in "owns" regardless of whether we + * decoded them. We can lock resources we don't decode, therefore + * we must track them via "owns". */ flags = 0; pci_bits = 0; @@ -291,7 +296,7 @@ enable_them: if (wants & (VGA_RSRC_LEGACY_IO|VGA_RSRC_NORMAL_IO)) pci_bits |= PCI_COMMAND_IO; } - if (!!(wants & VGA_RSRC_LEGACY_MASK)) + if (wants & VGA_RSRC_LEGACY_MASK) flags |= PCI_VGA_STATE_CHANGE_BRIDGE; pci_set_vga_state(vgadev->pdev, true, pci_bits, flags); @@ -299,7 +304,7 @@ enable_them: if (!vgadev->bridge_has_one_vga) { vga_irq_set_state(vgadev, true); } - vgadev->owns |= (wants & vgadev->decodes); + vgadev->owns |= wants; lock_them: vgadev->locks |= (rsrc & VGA_RSRC_LEGACY_MASK); if (rsrc & VGA_RSRC_LEGACY_IO) @@ -649,7 +654,6 @@ static inline void vga_update_device_decodes(struct vga_device *vgadev, old_decodes = vgadev->decodes; decodes_removed = ~new_decodes & old_decodes; decodes_unlocked = vgadev->locks & decodes_removed; - vgadev->owns &= ~decodes_removed; vgadev->decodes = new_decodes; pr_info("vgaarb: device changed decodes: PCI:%s,olddecodes=%s,decodes=%s:owns=%s\n",