cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

intel-sdw-acpi.c (4778B)


      1// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
      2// Copyright(c) 2015-2021 Intel Corporation.
      3
      4/*
      5 * SDW Intel ACPI scan helpers
      6 */
      7
      8#include <linux/acpi.h>
      9#include <linux/bits.h>
     10#include <linux/bitfield.h>
     11#include <linux/device.h>
     12#include <linux/errno.h>
     13#include <linux/export.h>
     14#include <linux/fwnode.h>
     15#include <linux/module.h>
     16#include <linux/soundwire/sdw_intel.h>
     17#include <linux/string.h>
     18
     19#define SDW_LINK_TYPE		4 /* from Intel ACPI documentation */
     20#define SDW_MAX_LINKS		4
     21
     22static int ctrl_link_mask;
     23module_param_named(sdw_link_mask, ctrl_link_mask, int, 0444);
     24MODULE_PARM_DESC(sdw_link_mask, "Intel link mask (one bit per link)");
     25
     26static bool is_link_enabled(struct fwnode_handle *fw_node, int i)
     27{
     28	struct fwnode_handle *link;
     29	char name[32];
     30	u32 quirk_mask = 0;
     31
     32	/* Find master handle */
     33	snprintf(name, sizeof(name),
     34		 "mipi-sdw-link-%d-subproperties", i);
     35
     36	link = fwnode_get_named_child_node(fw_node, name);
     37	if (!link)
     38		return false;
     39
     40	fwnode_property_read_u32(link,
     41				 "intel-quirk-mask",
     42				 &quirk_mask);
     43
     44	if (quirk_mask & SDW_INTEL_QUIRK_MASK_BUS_DISABLE)
     45		return false;
     46
     47	return true;
     48}
     49
     50static int
     51sdw_intel_scan_controller(struct sdw_intel_acpi_info *info)
     52{
     53	struct acpi_device *adev = acpi_fetch_acpi_dev(info->handle);
     54	int ret, i;
     55	u8 count;
     56
     57	if (!adev)
     58		return -EINVAL;
     59
     60	/* Found controller, find links supported */
     61	count = 0;
     62	ret = fwnode_property_read_u8_array(acpi_fwnode_handle(adev),
     63					    "mipi-sdw-master-count", &count, 1);
     64
     65	/*
     66	 * In theory we could check the number of links supported in
     67	 * hardware, but in that step we cannot assume SoundWire IP is
     68	 * powered.
     69	 *
     70	 * In addition, if the BIOS doesn't even provide this
     71	 * 'master-count' property then all the inits based on link
     72	 * masks will fail as well.
     73	 *
     74	 * We will check the hardware capabilities in the startup() step
     75	 */
     76
     77	if (ret) {
     78		dev_err(&adev->dev,
     79			"Failed to read mipi-sdw-master-count: %d\n", ret);
     80		return -EINVAL;
     81	}
     82
     83	/* Check count is within bounds */
     84	if (count > SDW_MAX_LINKS) {
     85		dev_err(&adev->dev, "Link count %d exceeds max %d\n",
     86			count, SDW_MAX_LINKS);
     87		return -EINVAL;
     88	}
     89
     90	if (!count) {
     91		dev_warn(&adev->dev, "No SoundWire links detected\n");
     92		return -EINVAL;
     93	}
     94	dev_dbg(&adev->dev, "ACPI reports %d SDW Link devices\n", count);
     95
     96	info->count = count;
     97	info->link_mask = 0;
     98
     99	for (i = 0; i < count; i++) {
    100		if (ctrl_link_mask && !(ctrl_link_mask & BIT(i))) {
    101			dev_dbg(&adev->dev,
    102				"Link %d masked, will not be enabled\n", i);
    103			continue;
    104		}
    105
    106		if (!is_link_enabled(acpi_fwnode_handle(adev), i)) {
    107			dev_dbg(&adev->dev,
    108				"Link %d not selected in firmware\n", i);
    109			continue;
    110		}
    111
    112		info->link_mask |= BIT(i);
    113	}
    114
    115	return 0;
    116}
    117
    118static acpi_status sdw_intel_acpi_cb(acpi_handle handle, u32 level,
    119				     void *cdata, void **return_value)
    120{
    121	struct sdw_intel_acpi_info *info = cdata;
    122	acpi_status status;
    123	u64 adr;
    124
    125	status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr);
    126	if (ACPI_FAILURE(status))
    127		return AE_OK; /* keep going */
    128
    129	if (!acpi_fetch_acpi_dev(handle)) {
    130		pr_err("%s: Couldn't find ACPI handle\n", __func__);
    131		return AE_NOT_FOUND;
    132	}
    133
    134	/*
    135	 * On some Intel platforms, multiple children of the HDAS
    136	 * device can be found, but only one of them is the SoundWire
    137	 * controller. The SNDW device is always exposed with
    138	 * Name(_ADR, 0x40000000), with bits 31..28 representing the
    139	 * SoundWire link so filter accordingly
    140	 */
    141	if (FIELD_GET(GENMASK(31, 28), adr) != SDW_LINK_TYPE)
    142		return AE_OK; /* keep going */
    143
    144	/* found the correct SoundWire controller */
    145	info->handle = handle;
    146
    147	/* device found, stop namespace walk */
    148	return AE_CTRL_TERMINATE;
    149}
    150
    151/**
    152 * sdw_intel_acpi_scan() - SoundWire Intel init routine
    153 * @parent_handle: ACPI parent handle
    154 * @info: description of what firmware/DSDT tables expose
    155 *
    156 * This scans the namespace and queries firmware to figure out which
    157 * links to enable. A follow-up use of sdw_intel_probe() and
    158 * sdw_intel_startup() is required for creation of devices and bus
    159 * startup
    160 */
    161int sdw_intel_acpi_scan(acpi_handle *parent_handle,
    162			struct sdw_intel_acpi_info *info)
    163{
    164	acpi_status status;
    165
    166	info->handle = NULL;
    167	/*
    168	 * In the HDAS ACPI scope, 'SNDW' may be either the child of
    169	 * 'HDAS' or the grandchild of 'HDAS'. So let's go through
    170	 * the ACPI from 'HDAS' at max depth of 2 to find the 'SNDW'
    171	 * device.
    172	 */
    173	status = acpi_walk_namespace(ACPI_TYPE_DEVICE,
    174				     parent_handle, 2,
    175				     sdw_intel_acpi_cb,
    176				     NULL, info, NULL);
    177	if (ACPI_FAILURE(status) || info->handle == NULL)
    178		return -ENODEV;
    179
    180	return sdw_intel_scan_controller(info);
    181}
    182EXPORT_SYMBOL_NS(sdw_intel_acpi_scan, SND_INTEL_SOUNDWIRE_ACPI);
    183
    184MODULE_LICENSE("Dual BSD/GPL");
    185MODULE_DESCRIPTION("Intel Soundwire ACPI helpers");