From patchwork Fri May 3 23:00:29 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andy Lutomirski X-Patchwork-Id: 2519991 Return-Path: X-Original-To: patchwork-linux-fbdev@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by patchwork1.kernel.org (Postfix) with ESMTP id C346D3FCA5 for ; Fri, 3 May 2013 23:03:10 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1763828Ab3ECXA5 (ORCPT ); Fri, 3 May 2013 19:00:57 -0400 Received: from mail-pb0-f42.google.com ([209.85.160.42]:50340 "EHLO mail-pb0-f42.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1763754Ab3ECXAy (ORCPT ); Fri, 3 May 2013 19:00:54 -0400 Received: by mail-pb0-f42.google.com with SMTP id up7so1118310pbc.1 for ; Fri, 03 May 2013 16:00:54 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=x-received:from:to:cc:subject:date:message-id:x-mailer:in-reply-to :references:in-reply-to:references:x-gm-message-state; bh=vKTdHwRhi9b+g5JB6f59ezwSbIDMAXRVx4Dx1tCJB1k=; b=YaqVO9gqO4PB4o6dS/wIkzRJ2UDkWoDvZk3/ePsrBknsKnslJlLafvSnyHsaPQ/oKs wP2z0yHkkjFHa31GpN3mfuVN4zAFzH5Kf+gNSKoEVxgRZF3YJPEjs1C5PN+q6XvPyy59 eOGcBMPpBc5l6deBJF0MseyJmc9PQiEEM9Bj5OOXzR2YrwFrur2Lr+lCQGWGeHXmJCqz syn6XmVfTyBMnDzVuoYAxAFmxlk+QkxL7QFI01pksSL2YGIubajNaqbBxXSRmk/IYZLM +ZFbeuHP2KF8bNkL7LBIb1fOIu7jkcY8FdFSocHQ5SUtoC6L2hiRDC58yvz6iry9bTF5 /MPg== X-Received: by 10.68.113.194 with SMTP id ja2mr15766008pbb.65.1367622054303; Fri, 03 May 2013 16:00:54 -0700 (PDT) Received: from localhost (50-76-60-73-ip-static.hfc.comcastbusiness.net. [50.76.60.73]) by mx.google.com with ESMTPSA id uf2sm13236795pbc.41.2013.05.03.16.00.52 for (version=TLSv1.2 cipher=RC4-SHA bits=128/128); Fri, 03 May 2013 16:00:53 -0700 (PDT) From: Andy Lutomirski To: linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-fbdev@vger.kernel.org Cc: Andy Lutomirski , x86@kernel.org Subject: [PATCH 1/7] x86: Add mtrr_{add,del}_wc_if_needed Date: Fri, 3 May 2013 16:00:29 -0700 Message-Id: X-Mailer: git-send-email 1.8.1.4 In-Reply-To: References: In-Reply-To: References: X-Gm-Message-State: ALoCoQnNaSXaiH9JKKR2kw2OuUr/qu7Z834Sf5urbn9/mOrvnIptF7sH5j2J5JHbCSKHX5EHXA+F Sender: linux-fbdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fbdev@vger.kernel.org These MTRR helpers add a WC MTRR if PAT is disabled. Modern drivers should be using ioremap_wc, etc. to get WC memory; the MTRR is just a fallback if the system doesn't have PAT. So, rather than allocating an unnecessary MTRR even on PAT systems and having error handling spread out and handled differently by different drivers, consolidate it all and don't waste the MTRR on PAT-supporting systems. (Follow-up changes will update drivers.) This should be a simple change, a bit of a clean-up, and it will flush out any drivers that actually depend on the MTRR for write combining. Signed-off-by: Andy Lutomirski --- arch/x86/include/asm/mtrr.h | 21 ++++++++++++++++ arch/x86/kernel/cpu/mtrr/main.c | 53 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) diff --git a/arch/x86/include/asm/mtrr.h b/arch/x86/include/asm/mtrr.h index e235582..cc96c72 100644 --- a/arch/x86/include/asm/mtrr.h +++ b/arch/x86/include/asm/mtrr.h @@ -45,6 +45,18 @@ extern void mtrr_aps_init(void); extern void mtrr_bp_restore(void); extern int mtrr_trim_uncached_memory(unsigned long end_pfn); extern int amd_special_default_mtrr(void); + +/* + * These are for drivers (mostly video) that want to add WC MTRRs as a + * fallback if PAT is unavailable. There is no need to check for errors. + * + * The handles used by the _if_needed functions are *not* MTRR indices. + * mtrr_del_wc_if_needed(0) and mtrr_del_wc_if_needed(-1) are + * guaranteed to have no effect. + */ +extern int __must_check mtrr_add_wc_if_needed(unsigned long base, + unsigned long size); +extern void mtrr_del_wc_if_needed(int handle); # else static inline u8 mtrr_type_lookup(u64 addr, u64 end) { @@ -86,6 +98,15 @@ static inline void mtrr_centaur_report_mcr(int mcr, u32 lo, u32 hi) #define set_mtrr_aps_delayed_init() do {} while (0) #define mtrr_aps_init() do {} while (0) #define mtrr_bp_restore() do {} while (0) + +static inline int __must_check mtrr_add_wc_if_needed(unsigned long base, + unsigned long size) +{ + return -ENODEV; +} +static inline void mtrr_del_wc_if_needed(int handle) +{ +} # endif #ifdef CONFIG_COMPAT diff --git a/arch/x86/kernel/cpu/mtrr/main.c b/arch/x86/kernel/cpu/mtrr/main.c index 726bf96..6370238 100644 --- a/arch/x86/kernel/cpu/mtrr/main.c +++ b/arch/x86/kernel/cpu/mtrr/main.c @@ -51,6 +51,7 @@ #include #include #include +#include #include "mtrr.h" @@ -524,6 +525,58 @@ int mtrr_del(int reg, unsigned long base, unsigned long size) } EXPORT_SYMBOL(mtrr_del); +/** + * mtrr_add_wc_if_needed - add a WC MTRR and handle errors if PAT is unavailable + * @base: Physical base address + * @size: Size of region + * + * If PAT is available, this does nothing. If PAT is unavailable, it + * attempts to add a WC MTRR covering size bytes starting at base and + * logs an error if this fails. + * + * Drivers must store the return value to pass to mtrr_del_wc_if_needed, + * but drivers should not try to interpret that return value. + */ +int mtrr_add_wc_if_needed(unsigned long base, unsigned long size) +{ + int ret; + + if (pat_enabled) { + /* + * Don't bother -- we don't need the MTRR. Return an error + * so that no one gets confused. + */ + return -EBUSY; /* The error doesn't matter. */ + } + + ret = mtrr_add(base, size, MTRR_TYPE_WRCOMB, true); + if (ret < 0) { + pr_warn("Failed to add WC MTRR for [%p-%p]; performance will suffer.", + (void *)base, (void *)(base + size - 1)); + return ret; + } + return ret + 1000; +} +EXPORT_SYMBOL(mtrr_add_wc_if_needed); + +/* + * mtrr_del_wc_if_needed - undoes mtrr_add_wc_if_needed + * @handle: Return value from mtrr_add_wc_if_needed + * + * This cleans up after mtrr_add_wc_if_needed. + * + * The API guarantees that mtrr_del_wc_if_needed(-1) and + * mtrr_del_wc_if_needed(0) do nothing. + */ +extern void mtrr_del_wc_if_needed(int handle) +{ + if (handle >= 1) { + WARN_ON(handle < 1000); + mtrr_del(handle - 1000, 0, 0); + } +} +EXPORT_SYMBOL(mtrr_del_wc_if_needed); + /* * HACK ALERT! * These should be called implicitly, but we can't yet until all the initcall