From patchwork Mon Apr 11 02:50:43 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tan Jui Nee X-Patchwork-Id: 608635 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3qjvjj36dVz9t3p for ; Mon, 11 Apr 2016 12:52:09 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751744AbcDKCv3 (ORCPT ); Sun, 10 Apr 2016 22:51:29 -0400 Received: from mga14.intel.com ([192.55.52.115]:53952 "EHLO mga14.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751713AbcDKCv2 (ORCPT ); Sun, 10 Apr 2016 22:51:28 -0400 Received: from orsmga001.jf.intel.com ([10.7.209.18]) by fmsmga103.fm.intel.com with ESMTP; 10 Apr 2016 19:51:27 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.24,462,1455004800"; d="scan'208";a="929619124" Received: from juineeta-ilbpg0.png.intel.com ([10.88.227.42]) by orsmga001.jf.intel.com with ESMTP; 10 Apr 2016 19:51:23 -0700 From: Tan Jui Nee To: mika.westerberg@linux.intel.com, heikki.krogerus@linux.intel.com, andriy.shevchenko@linux.intel.com, tglx@linutronix.de, mingo@redhat.com, hpa@zytor.com, x86@kernel.org, ptyser@xes-inc.com, lee.jones@linaro.org Cc: linux-gpio@vger.kernel.org, linux-kernel@vger.kernel.org, jui.nee.tan@intel.com, jonathan.yong@intel.com, ong.hock.yu@intel.com, weifeng.voon@intel.com, wan.ahmad.zainie.wan.mohamad@intel.com Subject: [PATCH 2/3] x86/platform/p2sb: New Primary to Sideband bridge support driver for Intel SOC's Date: Mon, 11 Apr 2016 10:50:43 +0800 Message-Id: <1460343044-1474-3-git-send-email-jui.nee.tan@intel.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1460343044-1474-1-git-send-email-jui.nee.tan@intel.com> References: <1460343044-1474-1-git-send-email-jui.nee.tan@intel.com> Sender: linux-gpio-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-gpio@vger.kernel.org From: Andy Shevchenko There is already one and at least one more user coming which require an access to Primary to Sideband bridge (P2SB) in order to get IO or MMIO bar hidden by BIOS. Create a driver to access P2SB for x86 devices. Signed-off-by: Yong, Jonathan Signed-off-by: Andy Shevchenko --- arch/x86/Kconfig | 4 ++ arch/x86/include/asm/p2sb.h | 27 +++++++++++ arch/x86/platform/intel/Makefile | 1 + arch/x86/platform/intel/p2sb.c | 99 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 131 insertions(+) create mode 100644 arch/x86/include/asm/p2sb.h create mode 100644 arch/x86/platform/intel/p2sb.c diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 2dc18605..b678380 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -606,6 +606,10 @@ config IOSF_MBI_DEBUG If you don't require the option or are in doubt, say N. +config P2SB + tristate + depends on PCI + config X86_RDC321X bool "RDC R-321x SoC" depends on X86_32 diff --git a/arch/x86/include/asm/p2sb.h b/arch/x86/include/asm/p2sb.h new file mode 100644 index 0000000..686e07b --- /dev/null +++ b/arch/x86/include/asm/p2sb.h @@ -0,0 +1,27 @@ +/* + * Primary to Sideband bridge (P2SB) access support + */ + +#ifndef P2SB_SYMS_H +#define P2SB_SYMS_H + +#include +#include + +#if IS_ENABLED(CONFIG_P2SB) + +int p2sb_bar(struct pci_dev *pdev, unsigned int devfn, + struct resource *res); + +#else /* CONFIG_P2SB is not set */ + +static inline +int p2sb_bar(struct pci_dev *pdev, unsigned int devfn, + struct resource *res) +{ + return -ENODEV; +} + +#endif /* CONFIG_P2SB */ + +#endif /* P2SB_SYMS_H */ diff --git a/arch/x86/platform/intel/Makefile b/arch/x86/platform/intel/Makefile index b878032..dbf9f10 100644 --- a/arch/x86/platform/intel/Makefile +++ b/arch/x86/platform/intel/Makefile @@ -1 +1,2 @@ obj-$(CONFIG_IOSF_MBI) += iosf_mbi.o +obj-$(CONFIG_P2SB) += p2sb.o diff --git a/arch/x86/platform/intel/p2sb.c b/arch/x86/platform/intel/p2sb.c new file mode 100644 index 0000000..8be47a4 --- /dev/null +++ b/arch/x86/platform/intel/p2sb.c @@ -0,0 +1,99 @@ +/* + * Primary to Sideband bridge (P2SB) driver + * + * Copyright (c) 2016, Intel Corporation. + * + * Authors: Andy Shevchenko + * Jonathan Yong + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ + +#include +#include +#include +#include + +#include + +#define SBREG_BAR 0x10 +#define SBREG_HIDE 0xe1 + +static DEFINE_SPINLOCK(p2sb_spinlock); + +/* + * p2sb_bar - Get Primary to Sideband bridge (P2SB) BAR + * @pdev: PCI device to get PCI bus to communicate with + * @devfn: PCI device and function to communicate with + * @res: resources to be filled in + * + * The BIOS prevents the P2SB device from being enumerated by the PCI + * subsystem, so we need to unhide and hide it back to lookup the P2SB BAR. + * + * Locking is handled by spinlock - cannot sleep. + * + * Return: + * 0 on success or appropriate errno value on error. + */ +int p2sb_bar(struct pci_dev *pdev, unsigned int devfn, + struct resource *res) +{ + u32 base_addr; + u64 base64_addr; + unsigned long flags; + + if (!res) + return -EINVAL; + + spin_lock(&p2sb_spinlock); + + /* Unhide the P2SB device */ + pci_bus_write_config_byte(pdev->bus, devfn, SBREG_HIDE, 0x00); + + /* Check if device present */ + pci_bus_read_config_dword(pdev->bus, devfn, 0, &base_addr); + if (base_addr == 0xffffffff || base_addr == 0x00000000) { + spin_unlock(&p2sb_spinlock); + dev_warn(&pdev->dev, "P2SB device access disabled by BIOS?\n"); + return -ENODEV; + } + + /* Get IO or MMIO BAR */ + pci_bus_read_config_dword(pdev->bus, devfn, SBREG_BAR, &base_addr); + if ((base_addr & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) { + flags = IORESOURCE_IO; + base64_addr = base_addr & PCI_BASE_ADDRESS_IO_MASK; + } else { + flags = IORESOURCE_MEM; + base64_addr = base_addr & PCI_BASE_ADDRESS_MEM_MASK; + if (base_addr & PCI_BASE_ADDRESS_MEM_TYPE_64) { + flags |= IORESOURCE_MEM_64; + pci_bus_read_config_dword(pdev->bus, devfn, + SBREG_BAR + 4, &base_addr); + base64_addr |= (u64)base_addr << 32; + } + } + + /* Hide the P2SB device */ + pci_bus_write_config_byte(pdev->bus, devfn, SBREG_HIDE, 0x01); + + spin_unlock(&p2sb_spinlock); + + /* User provides prefilled resources */ + res->start += (resource_size_t)base64_addr; + res->end += (resource_size_t)base64_addr; + res->flags = flags; + + return 0; +} +EXPORT_SYMBOL(p2sb_bar); + +MODULE_LICENSE("GPL");