From patchwork Thu May 30 11:16:34 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ard Biesheuvel X-Patchwork-Id: 165439 Delivered-To: patch@linaro.org Received: by 2002:a92:9e1a:0:0:0:0:0 with SMTP id q26csp825356ili; Thu, 30 May 2019 04:16:59 -0700 (PDT) X-Google-Smtp-Source: APXvYqycD0sHIL1MzNY9XT+263ZLj/mVtMUbpuKzbFuD9pDp6B5vfGbD6p6ZsnAK6WMlMxRomsV1 X-Received: by 2002:a63:d145:: with SMTP id c5mr3255808pgj.254.1559215019158; Thu, 30 May 2019 04:16:59 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1559215019; cv=none; d=google.com; s=arc-20160816; b=fjglcLb0gHmAgyi3nY/OIlLBs+mNH9x1lgiZZthrtSGS3Y18Uvy+uDtXCk1DdT0ZD2 F8CrHLriyPRJVf1cIaZUC7Jr3Nep8roKkBiHz8/wMqu6cKuS5MCTjp+NWWPd2vbiyFb7 9QpzCl8Pq0LzQiMpgkj0TUX6cNJsGbD9Zm+oZ6DHd2+aqBEy2RjX6Y2OgvRfF+ArxbBi FfU1Y6BoPaIpVZu6RWGzuYl7CUH/e3Oea+uIr0yhcuemrMzMHhRqcTHlw62uylF+Q5Fi oN9WB6jI636IzSjWXSL26HgIoTDExwcB337gG5H/wwYDEr0WBSkCjrkb0kcLne2etKfX bO1A== 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 :message-id:date:subject:cc:to:from:dkim-signature; bh=xPPg1SCyHb64Fhr55IHPd5M7ZeQxhQTiEBH6THyaghI=; b=BFH9aXRdz772Q6jU2EOrwHGiQTVApmGCyZzsJWA1XZUkZ/NGejOV1Ne73srAT47nSG xH/W1IoRjb03Vz5rKbfgQPQSq7fZFAsNL2VQa6ZGBJmkOdVfeSYZ4PbduNvwJLpEkk7A EXqlG8A0WI/2koiN58k3bzRMfQCMp61b+RaP3NW5ll7bJIiSlrQiRue9Qd9H0+u9SaMF s6LonFnixZc3MSMLY66LHYgmBzzD4pI+wTi27oiTBrazpveb/k0WPsSOBFU5vNYRUKGs FUnGqbKQshZS+ckmMX/XFbTZs/aBQ+DgHau/TrR2IgkXiPfTLIruylSDRsmLEp3MxaTO ZUNg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=rt3jAT9E; spf=pass (google.com: best guess record for domain of linux-spi-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-spi-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id o5si2564223pjp.77.2019.05.30.04.16.59; Thu, 30 May 2019 04:16:59 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-spi-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=@linaro.org header.s=google header.b=rt3jAT9E; spf=pass (google.com: best guess record for domain of linux-spi-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-spi-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1725440AbfE3LQ5 (ORCPT + 1 other); Thu, 30 May 2019 07:16:57 -0400 Received: from mail-wr1-f65.google.com ([209.85.221.65]:37080 "EHLO mail-wr1-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726563AbfE3LQ5 (ORCPT ); Thu, 30 May 2019 07:16:57 -0400 Received: by mail-wr1-f65.google.com with SMTP id h1so3956173wro.4 for ; Thu, 30 May 2019 04:16:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=xPPg1SCyHb64Fhr55IHPd5M7ZeQxhQTiEBH6THyaghI=; b=rt3jAT9E+aS/pLbJBR6jccB06bJReZktWxsJpQQSpOAhpSMjOij7f9cPtX7U5PdSS4 Fs01nRwRVtHURRERGSIGy03+G0bE0HfKZ8mxG1BexzByLA1yAvm1voDXMS6c8+H5aZaT jsgtrPfQ/dn3YLVyX3rGrnyuYo/t2gYuiGN7Jm+4g/HAoQUV2z7BE3d/siRYIXFmfWOS d0itsFkNI97ncjX+Se94RSszYsUoAW5ouB7dde9MM+K6NY896VOMoOdR1ZsOVv5v5p0q NmpT2Ot+x4Ows/7KhjP9N382udG4R5CWWkDbZXJIKfAfrjm8JZonkubSRdsEDzYMWpsv 1Bmg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=xPPg1SCyHb64Fhr55IHPd5M7ZeQxhQTiEBH6THyaghI=; b=Dd5NEi9krCtxLzXPjipfOtx6jGH/LPHrF72SwoV+MYLkWouUI9ck8gXHI24iO588FX 1armRf6EFVj1juKFo44J3vGWQWafOM+veYLga6xMH1AOah6D3etMai4/2Zc+9kTdY71S /Kps5lnNaEAtTsFYjOhcttYC7yJGs6aJdhzYOrtuMdScKTtV0teVHmlij5PfTb0zOmTg 5aafWQy2bQiJefN8eWadEebM/qu00pWz0E8J2ztnowS/6Jyvh+b/Zr+jCtDmn3gnVxpV DUOde0jh4cmP+CAXupeLJXaZzb7YIDRQI4NgP60hVTGVQT1Byzd9X5Dvr6GXtkbi2MT8 xbpw== X-Gm-Message-State: APjAAAUWQ3SII7o+KPPZ0Z+mYsx2u8+PgCnACMFGu1FMKfb9Lhbq5S+g ZcIy/j9/EGbwZ7+yd2CPbjx+2w== X-Received: by 2002:adf:c606:: with SMTP id n6mr2215648wrg.62.1559215014685; Thu, 30 May 2019 04:16:54 -0700 (PDT) Received: from sudo.home ([2a01:cb1d:112:6f00:c225:e9ff:fe2e:ea8]) by smtp.gmail.com with ESMTPSA id z20sm2686421wmf.14.2019.05.30.04.16.53 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 30 May 2019 04:16:53 -0700 (PDT) From: Ard Biesheuvel To: linux-arm-kernel@lists.infradead.org Cc: Ard Biesheuvel , Mika Westerberg , linux-spi@vger.kernel.org, broonie@kernel.org, andy.shevchenko@gmail.com, masahisa.kojima@linaro.org, "Rafael J. Wysocki" , Jarkko Nikula , linux-acpi@vger.kernel.org, Lukas Wunner Subject: [PATCH v2] spi/acpi: enumerate all SPI slaves in the namespace Date: Thu, 30 May 2019 13:16:34 +0200 Message-Id: <20190530111634.32209-1-ard.biesheuvel@linaro.org> X-Mailer: git-send-email 2.20.1 MIME-Version: 1.0 Sender: linux-spi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-spi@vger.kernel.org Currently, the ACPI enumeration that takes place when registering a SPI master only considers immediate child devices in the ACPI namespace, rather than checking the ResourceSource field in the SpiSerialBus() resource descriptor. This is incorrect: SPI slaves could reside anywhere in the ACPI namespace, and so we should enumerate the entire namespace and look for any device that refers to the newly registered SPI master in its resource descriptor. So refactor the existing code and use a lookup structure so that allocating the SPI device structure is deferred until we have identified the device as an actual child of the controller. This approach is loosely based on the way the I2C subsystem handles ACPI enumeration. Note that Apple x86 hardware does not rely on SpiSerialBus() resources in _CRS but uses nested devices below the controller's device node in the ACPI namespace, with a special set of device properties. This means we have to take care to only parse those properties for device nodes that are direct children of the controller node. Cc: Mika Westerberg Cc: linux-spi@vger.kernel.org Cc: broonie@kernel.org Cc: andy.shevchenko@gmail.com Cc: masahisa.kojima@linaro.org Cc: "Rafael J. Wysocki" Cc: Jarkko Nikula Cc: linux-acpi@vger.kernel.org Cc: Lukas Wunner Signed-off-by: Ard Biesheuvel --- drivers/spi/spi.c | 103 ++++++++++++++------ 1 file changed, 72 insertions(+), 31 deletions(-) -- 2.20.1 diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 5e75944ad5d1..4661b219a7e7 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -1799,9 +1799,18 @@ static void of_register_spi_devices(struct spi_controller *ctlr) { } #endif #ifdef CONFIG_ACPI -static void acpi_spi_parse_apple_properties(struct spi_device *spi) +struct acpi_spi_lookup { + struct spi_controller *ctlr; + u32 max_speed_hz; + u32 mode; + int irq; + u8 bits_per_word; + u8 chip_select; +}; + +static void acpi_spi_parse_apple_properties(struct acpi_device *dev, + struct acpi_spi_lookup *lookup) { - struct acpi_device *dev = ACPI_COMPANION(&spi->dev); const union acpi_object *obj; if (!x86_apple_machine) @@ -1809,35 +1818,46 @@ static void acpi_spi_parse_apple_properties(struct spi_device *spi) if (!acpi_dev_get_property(dev, "spiSclkPeriod", ACPI_TYPE_BUFFER, &obj) && obj->buffer.length >= 4) - spi->max_speed_hz = NSEC_PER_SEC / *(u32 *)obj->buffer.pointer; + lookup->max_speed_hz = NSEC_PER_SEC / *(u32 *)obj->buffer.pointer; if (!acpi_dev_get_property(dev, "spiWordSize", ACPI_TYPE_BUFFER, &obj) && obj->buffer.length == 8) - spi->bits_per_word = *(u64 *)obj->buffer.pointer; + lookup->bits_per_word = *(u64 *)obj->buffer.pointer; if (!acpi_dev_get_property(dev, "spiBitOrder", ACPI_TYPE_BUFFER, &obj) && obj->buffer.length == 8 && !*(u64 *)obj->buffer.pointer) - spi->mode |= SPI_LSB_FIRST; + lookup->mode |= SPI_LSB_FIRST; if (!acpi_dev_get_property(dev, "spiSPO", ACPI_TYPE_BUFFER, &obj) && obj->buffer.length == 8 && *(u64 *)obj->buffer.pointer) - spi->mode |= SPI_CPOL; + lookup->mode |= SPI_CPOL; if (!acpi_dev_get_property(dev, "spiSPH", ACPI_TYPE_BUFFER, &obj) && obj->buffer.length == 8 && *(u64 *)obj->buffer.pointer) - spi->mode |= SPI_CPHA; + lookup->mode |= SPI_CPHA; } static int acpi_spi_add_resource(struct acpi_resource *ares, void *data) { - struct spi_device *spi = data; - struct spi_controller *ctlr = spi->controller; + struct acpi_spi_lookup *lookup = data; + struct spi_controller *ctlr = lookup->ctlr; if (ares->type == ACPI_RESOURCE_TYPE_SERIAL_BUS) { struct acpi_resource_spi_serialbus *sb; + acpi_handle parent_handle; + acpi_status status; sb = &ares->data.spi_serial_bus; if (sb->type == ACPI_RESOURCE_SERIAL_TYPE_SPI) { + + status = acpi_get_handle(NULL, + sb->resource_source.string_ptr, + &parent_handle); + + if (!status || + ACPI_HANDLE(ctlr->dev.parent) != parent_handle) + return -ENODEV; + /* * ACPI DeviceSelection numbering is handled by the * host controller driver in Windows and can vary @@ -1850,25 +1870,25 @@ static int acpi_spi_add_resource(struct acpi_resource *ares, void *data) sb->device_selection); if (cs < 0) return cs; - spi->chip_select = cs; + lookup->chip_select = cs; } else { - spi->chip_select = sb->device_selection; + lookup->chip_select = sb->device_selection; } - spi->max_speed_hz = sb->connection_speed; + lookup->max_speed_hz = sb->connection_speed; if (sb->clock_phase == ACPI_SPI_SECOND_PHASE) - spi->mode |= SPI_CPHA; + lookup->mode |= SPI_CPHA; if (sb->clock_polarity == ACPI_SPI_START_HIGH) - spi->mode |= SPI_CPOL; + lookup->mode |= SPI_CPOL; if (sb->device_polarity == ACPI_SPI_ACTIVE_HIGH) - spi->mode |= SPI_CS_HIGH; + lookup->mode |= SPI_CS_HIGH; } - } else if (spi->irq < 0) { + } else if (lookup->irq < 0) { struct resource r; if (acpi_dev_resource_interrupt(ares, 0, &r)) - spi->irq = r.start; + lookup->irq = r.start; } /* Always tell the ACPI core to skip this resource */ @@ -1878,7 +1898,9 @@ static int acpi_spi_add_resource(struct acpi_resource *ares, void *data) static acpi_status acpi_register_spi_device(struct spi_controller *ctlr, struct acpi_device *adev) { + acpi_handle parent_handle = NULL; struct list_head resource_list; + struct acpi_spi_lookup lookup; struct spi_device *spi; int ret; @@ -1886,28 +1908,44 @@ static acpi_status acpi_register_spi_device(struct spi_controller *ctlr, acpi_device_enumerated(adev)) return AE_OK; - spi = spi_alloc_device(ctlr); - if (!spi) { - dev_err(&ctlr->dev, "failed to allocate SPI device for %s\n", - dev_name(&adev->dev)); - return AE_NO_MEMORY; - } - - ACPI_COMPANION_SET(&spi->dev, adev); - spi->irq = -1; + lookup.ctlr = ctlr; + lookup.mode = 0; + lookup.bits_per_word = 0; + lookup.irq = -1; INIT_LIST_HEAD(&resource_list); ret = acpi_dev_get_resources(adev, &resource_list, - acpi_spi_add_resource, spi); + acpi_spi_add_resource, &lookup); acpi_dev_free_resource_list(&resource_list); - acpi_spi_parse_apple_properties(spi); + if (ret < 0) + /* found SPI in _CRS but it points to another controller */ + return AE_OK; - if (ret < 0 || !spi->max_speed_hz) { - spi_dev_put(spi); + if (!lookup.max_speed_hz && + !ACPI_FAILURE(acpi_get_parent(adev->handle, &parent_handle)) && + ACPI_HANDLE(ctlr->dev.parent) == parent_handle) { + /* Apple does not use _CRS but nested devices for SPI slaves */ + acpi_spi_parse_apple_properties(adev, &lookup); + } + + if (!lookup.max_speed_hz) return AE_OK; + + spi = spi_alloc_device(ctlr); + if (!spi) { + dev_err(&ctlr->dev, "failed to allocate SPI device for %s\n", + dev_name(&adev->dev)); + return AE_NO_MEMORY; } + ACPI_COMPANION_SET(&spi->dev, adev); + spi->max_speed_hz = lookup.max_speed_hz; + spi->mode = lookup.mode; + spi->irq = lookup.irq; + spi->bits_per_word = lookup.bits_per_word; + spi->chip_select = lookup.chip_select; + acpi_set_modalias(adev, acpi_device_hid(adev), spi->modalias, sizeof(spi->modalias)); @@ -1939,6 +1977,8 @@ static acpi_status acpi_spi_add_device(acpi_handle handle, u32 level, return acpi_register_spi_device(ctlr, adev); } +#define SPI_ACPI_ENUMERATE_MAX_DEPTH 32 + static void acpi_register_spi_devices(struct spi_controller *ctlr) { acpi_status status; @@ -1948,7 +1988,8 @@ static void acpi_register_spi_devices(struct spi_controller *ctlr) if (!handle) return; - status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1, + status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, + SPI_ACPI_ENUMERATE_MAX_DEPTH, acpi_spi_add_device, NULL, ctlr, NULL); if (ACPI_FAILURE(status)) dev_warn(&ctlr->dev, "failed to enumerate SPI slaves\n");