Received: by 2002:a25:1506:0:0:0:0:0 with SMTP id 6csp1593728ybv; Thu, 20 Feb 2020 23:56:47 -0800 (PST) X-Google-Smtp-Source: APXvYqzc1lGO88IrDLrCiY1vfuINbtNylBqrN5t3wtKDocW7Jc5LYPUEEepFRZLI1YwnEzoGh8kx X-Received: by 2002:a9d:842:: with SMTP id 60mr15490439oty.318.1582271806810; Thu, 20 Feb 2020 23:56:46 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1582271806; cv=none; d=google.com; s=arc-20160816; b=hmE0cjvPwG38NacDyPWWVuIFSo0Y/SG3eNxWR5JV7XUFiDptSf+caPf9FaaIy1aySd k4cD7n7gfg3nEogVZRnlvk0rARG/hzmdY3q14KM5CR4e1RhYqZtBQ8A5y9eDrQIV6LBe ugoSRaP932eGy4wuugkxTXC6HNwFeKF2cBjw9WvdZ6wCJFoVO7P9rbkzC9bLO6lejHgQ pbqec4MoKNMsh2WXNEvKMNLa6bDJGiMrqAU2LBb4MJMmmtrGtA27F4ATIEskMexCljft /ft+iTa6w7aSg21XxkMZruAEyIdqU8xAPz001D4E7EpusIBpMdoaSQfE4f/ocnOO+21y B3Uw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=i37gkC9C+Yy2zmvLK9OyjseyDXHQoTjy8Q5/oNkAtDs=; b=zOeRUOmzzfKAbdjGufFMMpq8h2HGWAMJuYSH5Or2PT4OWtrHxsH/4Zq8xC92mzicvg S1M2XSw7XFNdbXOgjeULhPtuGHtQN5A8ii2QsELieXN2YmIQ0sUrGVQWG1r++R/IYGxh CfLhYDBbjfcHnAFf7WDAERxDyzSGvORu+qNMXLVQNCtdqfzCWGniuyhnkSLYIXjzAEB1 Tkhedur3mRl8Vw1wBUkTwKQfS5KjHXveWTB3ymCeX/KAhPM18SgKdcPptcgD/r3Qjlu8 VP1Rvr+X1b4p8YL66cTYhYgm0vDLlPB6YG+oSdjO03ijaVsHsK+SKRI9wlpwDW9tFTv5 qfgQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=KqCogJoH; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id 8si941446ota.266.2020.02.20.23.56.34; Thu, 20 Feb 2020 23:56:46 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=KqCogJoH; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730237AbgBUH4S (ORCPT + 99 others); Fri, 21 Feb 2020 02:56:18 -0500 Received: from mail.kernel.org ([198.145.29.99]:55478 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730447AbgBUH4O (ORCPT ); Fri, 21 Feb 2020 02:56:14 -0500 Received: from localhost (83-86-89-107.cable.dynamic.v4.ziggo.nl [83.86.89.107]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id 5EA8020578; Fri, 21 Feb 2020 07:56:13 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1582271773; bh=wEovUnVAJ3olaZoXD7wRRiPJz8vfxqM6vpopy8X8Pq8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=KqCogJoH492OFNhjxksuwYk+6MqJg5vD0U3vTN6Zn1lyA1/9jN+K7zSI5yy+Vr8G5 JrzmP21/662grOo+IVBov593LLnDf9JHQk9x3a50hkQdF3nD0wvpwZsd5+R90Pa8Dr ho4qEQCdKOsl3zCWBGQrCfosPL90LCoMhgNWgNPw= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Pankaj Bansal , Hanjun Guo , Lorenzo Pieralisi , Will Deacon , Sudeep Holla , Catalin Marinas , Robin Murphy , Sasha Levin Subject: [PATCH 5.5 293/399] ACPI/IORT: Fix Number of IDs handling in iort_id_map() Date: Fri, 21 Feb 2020 08:40:18 +0100 Message-Id: <20200221072430.253096930@linuxfoundation.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200221072402.315346745@linuxfoundation.org> References: <20200221072402.315346745@linuxfoundation.org> User-Agent: quilt/0.66 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Hanjun Guo [ Upstream commit 3c23b83a88d00383e1d498cfa515249aa2fe0238 ] The IORT specification [0] (Section 3, table 4, page 9) defines the 'Number of IDs' as 'The number of IDs in the range minus one'. However, the IORT ID mapping function iort_id_map() treats the 'Number of IDs' field as if it were the full IDs mapping count, with the following check in place to detect out of boundary input IDs: InputID >= Input base + Number of IDs This check is flawed in that it considers the 'Number of IDs' field as the full number of IDs mapping and disregards the 'minus one' from the IDs count. The correct check in iort_id_map() should be implemented as: InputID > Input base + Number of IDs this implements the specification correctly but unfortunately it breaks existing firmwares that erroneously set the 'Number of IDs' as the full IDs mapping count rather than IDs mapping count minus one. e.g. PCI hostbridge mapping entry 1: Input base: 0x1000 ID Count: 0x100 Output base: 0x1000 Output reference: 0xC4 //ITS reference PCI hostbridge mapping entry 2: Input base: 0x1100 ID Count: 0x100 Output base: 0x2000 Output reference: 0xD4 //ITS reference Two mapping entries which the second entry's Input base = the first entry's Input base + ID count, so for InputID 0x1100 and with the correct InputID check in place in iort_id_map() the kernel would map the InputID to ITS 0xC4 not 0xD4 as it would be expected. Therefore, to keep supporting existing flawed firmwares, introduce a workaround that instructs the kernel to use the old InputID range check logic in iort_id_map(), so that we can support both firmwares written with the flawed 'Number of IDs' logic and the correct one as defined in the specifications. [0]: http://infocenter.arm.com/help/topic/com.arm.doc.den0049d/DEN0049D_IO_Remapping_Table.pdf Reported-by: Pankaj Bansal Link: https://lore.kernel.org/linux-acpi/20191215203303.29811-1-pankaj.bansal@nxp.com/ Signed-off-by: Hanjun Guo Signed-off-by: Lorenzo Pieralisi Cc: Pankaj Bansal Cc: Will Deacon Cc: Sudeep Holla Cc: Catalin Marinas Cc: Robin Murphy Signed-off-by: Will Deacon Signed-off-by: Sasha Levin --- drivers/acpi/arm64/iort.c | 57 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 55 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c index 33f71983e0017..6078064684c6c 100644 --- a/drivers/acpi/arm64/iort.c +++ b/drivers/acpi/arm64/iort.c @@ -298,6 +298,59 @@ out: return status; } +struct iort_workaround_oem_info { + char oem_id[ACPI_OEM_ID_SIZE + 1]; + char oem_table_id[ACPI_OEM_TABLE_ID_SIZE + 1]; + u32 oem_revision; +}; + +static bool apply_id_count_workaround; + +static struct iort_workaround_oem_info wa_info[] __initdata = { + { + .oem_id = "HISI ", + .oem_table_id = "HIP07 ", + .oem_revision = 0, + }, { + .oem_id = "HISI ", + .oem_table_id = "HIP08 ", + .oem_revision = 0, + } +}; + +static void __init +iort_check_id_count_workaround(struct acpi_table_header *tbl) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(wa_info); i++) { + if (!memcmp(wa_info[i].oem_id, tbl->oem_id, ACPI_OEM_ID_SIZE) && + !memcmp(wa_info[i].oem_table_id, tbl->oem_table_id, ACPI_OEM_TABLE_ID_SIZE) && + wa_info[i].oem_revision == tbl->oem_revision) { + apply_id_count_workaround = true; + pr_warn(FW_BUG "ID count for ID mapping entry is wrong, applying workaround\n"); + break; + } + } +} + +static inline u32 iort_get_map_max(struct acpi_iort_id_mapping *map) +{ + u32 map_max = map->input_base + map->id_count; + + /* + * The IORT specification revision D (Section 3, table 4, page 9) says + * Number of IDs = The number of IDs in the range minus one, but the + * IORT code ignored the "minus one", and some firmware did that too, + * so apply a workaround here to keep compatible with both the spec + * compliant and non-spec compliant firmwares. + */ + if (apply_id_count_workaround) + map_max--; + + return map_max; +} + static int iort_id_map(struct acpi_iort_id_mapping *map, u8 type, u32 rid_in, u32 *rid_out) { @@ -314,8 +367,7 @@ static int iort_id_map(struct acpi_iort_id_mapping *map, u8 type, u32 rid_in, return -ENXIO; } - if (rid_in < map->input_base || - (rid_in >= map->input_base + map->id_count)) + if (rid_in < map->input_base || rid_in > iort_get_map_max(map)) return -ENXIO; *rid_out = map->output_base + (rid_in - map->input_base); @@ -1631,5 +1683,6 @@ void __init acpi_iort_init(void) return; } + iort_check_id_count_workaround(iort_table); iort_init_platform_devices(); } -- 2.20.1