From patchwork Tue Nov 18 18:19:04 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yinghai Lu X-Patchwork-Id: 412121 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 26D6F1400DE for ; Wed, 19 Nov 2014 05:19:06 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753952AbaKRSTE (ORCPT ); Tue, 18 Nov 2014 13:19:04 -0500 Received: from aserp1040.oracle.com ([141.146.126.69]:25997 "EHLO aserp1040.oracle.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753683AbaKRSTE (ORCPT ); Tue, 18 Nov 2014 13:19:04 -0500 Received: from acsinet21.oracle.com (acsinet21.oracle.com [141.146.126.237]) by aserp1040.oracle.com (Sentrion-MTA-4.3.2/Sentrion-MTA-4.3.2) with ESMTP id sAIIIvho010952 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Tue, 18 Nov 2014 18:18:57 GMT Received: from aserz7022.oracle.com (aserz7022.oracle.com [141.146.126.231]) by acsinet21.oracle.com (8.14.4+Sun/8.14.4) with ESMTP id sAIIIuuX014168 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=FAIL); Tue, 18 Nov 2014 18:18:56 GMT Received: from abhmp0011.oracle.com (abhmp0011.oracle.com [141.146.116.17]) by aserz7022.oracle.com (8.14.4+Sun/8.14.4) with ESMTP id sAIIIt15006228; Tue, 18 Nov 2014 18:18:56 GMT Received: from linux-siqj.site (/107.215.0.145) by default (Oracle Beehive Gateway v4.0) with ESMTP ; Tue, 18 Nov 2014 10:18:55 -0800 From: Yinghai Lu To: Bjorn Helgaas , Andrew Morton , "H. Peter Anvin" , Ingo Molnar Cc: linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org, Yinghai Lu Subject: [PATCH v2] PCI: Don't reject 64bit mmio on 32bit/PAE mode Date: Tue, 18 Nov 2014 10:19:04 -0800 Message-Id: <1416334744-16817-1-git-send-email-yinghai@kernel.org> X-Mailer: git-send-email 1.8.4.5 X-Source-IP: acsinet21.oracle.com [141.146.126.237] Sender: linux-pci-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pci@vger.kernel.org Aaron reported 32bit/PAE mode, has problem with 64bit resource. [ 6.610012] pci 0000:03:00.0: reg 0x10: [mem 0x383fffc00000-0x383fffdfffff 64bit pref] [ 6.622195] pci 0000:03:00.0: reg 0x20: [mem 0x383fffe04000-0x383fffe07fff 64bit pref] [ 6.656112] pci 0000:03:00.1: reg 0x10: [mem 0x383fffa00000-0x383fffbfffff 64bit pref] [ 6.668293] pci 0000:03:00.1: reg 0x20: [mem 0x383fffe00000-0x383fffe03fff 64bit pref] [ 6.702055] pci 0000:00:02.2: PCI bridge to [bus 03-04] [ 6.706434] pci 0000:00:02.2: bridge window [io 0x1000-0x1fff] [ 6.711783] pci 0000:00:02.2: bridge window [mem 0x91900000-0x91cfffff] [ 6.717906] pci 0000:00:02.2: can't handle 64-bit address space for bridge So the kernel reject 64bit mmio on pci pref bridge that is assigned by firmware. When 32bit PAE is enabled, we could support 64bit mmio. but BITS_PER_LONG==64 checking could reject firmware assigned mmio that is above 4G. On x86 32bit always has BITS_PER_LONG equal to 32. We could use CONFIG_ARCH_DMA_ADDR_T_64BIT or dma_addr_t size checking instead. Use dma_addr_t size checking to avoid using MARCO. Also need to change to use dma_addr_t instead of unsigned long for base/limit to avoid overflow. -v2: add u64 cast to avoid compiler warning. Link: https://bugzilla.kernel.org/show_bug.cgi?id=88131 Reported-by: Aaron Ma Tested-by: Aaron Ma Signed-off-by: Yinghai Lu --- drivers/pci/probe.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) -- To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Index: linux-2.6/drivers/pci/probe.c =================================================================== --- linux-2.6.orig/drivers/pci/probe.c +++ linux-2.6/drivers/pci/probe.c @@ -406,15 +406,15 @@ static void pci_read_bridge_mmio_pref(st { struct pci_dev *dev = child->self; u16 mem_base_lo, mem_limit_lo; - unsigned long base, limit; + dma_addr_t base, limit; struct pci_bus_region region; struct resource *res; res = child->resource[2]; pci_read_config_word(dev, PCI_PREF_MEMORY_BASE, &mem_base_lo); pci_read_config_word(dev, PCI_PREF_MEMORY_LIMIT, &mem_limit_lo); - base = ((unsigned long) mem_base_lo & PCI_PREF_RANGE_MASK) << 16; - limit = ((unsigned long) mem_limit_lo & PCI_PREF_RANGE_MASK) << 16; + base = ((dma_addr_t) mem_base_lo & PCI_PREF_RANGE_MASK) << 16; + limit = ((dma_addr_t) mem_limit_lo & PCI_PREF_RANGE_MASK) << 16; if ((mem_base_lo & PCI_PREF_RANGE_TYPE_MASK) == PCI_PREF_RANGE_TYPE_64) { u32 mem_base_hi, mem_limit_hi; @@ -428,15 +428,15 @@ static void pci_read_bridge_mmio_pref(st * this, just assume they are not being used. */ if (mem_base_hi <= mem_limit_hi) { -#if BITS_PER_LONG == 64 - base |= ((unsigned long) mem_base_hi) << 32; - limit |= ((unsigned long) mem_limit_hi) << 32; -#else - if (mem_base_hi || mem_limit_hi) { - dev_err(&dev->dev, "can't handle 64-bit address space for bridge\n"); - return; + if (sizeof(dma_addr_t) < 8) { + if (mem_base_hi || mem_limit_hi) { + dev_err(&dev->dev, "can't handle 64-bit address space for bridge\n"); + return; + } + } else { + base |= (dma_addr_t)(((u64)mem_base_hi)<<32); + limit |= (dma_addr_t)(((u64)mem_limit_hi)<<32); } -#endif } } if (base <= limit) {