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-m10-bmc.c (5990B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Intel MAX 10 Board Management Controller chip
      4 *
      5 * Copyright (C) 2018-2020 Intel Corporation. All rights reserved.
      6 */
      7#include <linux/bitfield.h>
      8#include <linux/init.h>
      9#include <linux/mfd/core.h>
     10#include <linux/mfd/intel-m10-bmc.h>
     11#include <linux/module.h>
     12#include <linux/mutex.h>
     13#include <linux/regmap.h>
     14#include <linux/spi/spi.h>
     15
     16enum m10bmc_type {
     17	M10_N3000,
     18	M10_D5005,
     19	M10_N5010,
     20};
     21
     22static struct mfd_cell m10bmc_d5005_subdevs[] = {
     23	{ .name = "d5005bmc-hwmon" },
     24};
     25
     26static struct mfd_cell m10bmc_pacn3000_subdevs[] = {
     27	{ .name = "n3000bmc-hwmon" },
     28	{ .name = "n3000bmc-retimer" },
     29	{ .name = "n3000bmc-secure" },
     30};
     31
     32static struct mfd_cell m10bmc_n5010_subdevs[] = {
     33	{ .name = "n5010bmc-hwmon" },
     34};
     35
     36static const struct regmap_range m10bmc_regmap_range[] = {
     37	regmap_reg_range(M10BMC_LEGACY_BUILD_VER, M10BMC_LEGACY_BUILD_VER),
     38	regmap_reg_range(M10BMC_SYS_BASE, M10BMC_SYS_END),
     39	regmap_reg_range(M10BMC_FLASH_BASE, M10BMC_FLASH_END),
     40};
     41
     42static const struct regmap_access_table m10bmc_access_table = {
     43	.yes_ranges	= m10bmc_regmap_range,
     44	.n_yes_ranges	= ARRAY_SIZE(m10bmc_regmap_range),
     45};
     46
     47static struct regmap_config intel_m10bmc_regmap_config = {
     48	.reg_bits = 32,
     49	.val_bits = 32,
     50	.reg_stride = 4,
     51	.wr_table = &m10bmc_access_table,
     52	.rd_table = &m10bmc_access_table,
     53	.max_register = M10BMC_MEM_END,
     54};
     55
     56static ssize_t bmc_version_show(struct device *dev,
     57				struct device_attribute *attr, char *buf)
     58{
     59	struct intel_m10bmc *ddata = dev_get_drvdata(dev);
     60	unsigned int val;
     61	int ret;
     62
     63	ret = m10bmc_sys_read(ddata, M10BMC_BUILD_VER, &val);
     64	if (ret)
     65		return ret;
     66
     67	return sprintf(buf, "0x%x\n", val);
     68}
     69static DEVICE_ATTR_RO(bmc_version);
     70
     71static ssize_t bmcfw_version_show(struct device *dev,
     72				  struct device_attribute *attr, char *buf)
     73{
     74	struct intel_m10bmc *ddata = dev_get_drvdata(dev);
     75	unsigned int val;
     76	int ret;
     77
     78	ret = m10bmc_sys_read(ddata, NIOS2_FW_VERSION, &val);
     79	if (ret)
     80		return ret;
     81
     82	return sprintf(buf, "0x%x\n", val);
     83}
     84static DEVICE_ATTR_RO(bmcfw_version);
     85
     86static ssize_t mac_address_show(struct device *dev,
     87				struct device_attribute *attr, char *buf)
     88{
     89	struct intel_m10bmc *max10 = dev_get_drvdata(dev);
     90	unsigned int macaddr_low, macaddr_high;
     91	int ret;
     92
     93	ret = m10bmc_sys_read(max10, M10BMC_MAC_LOW, &macaddr_low);
     94	if (ret)
     95		return ret;
     96
     97	ret = m10bmc_sys_read(max10, M10BMC_MAC_HIGH, &macaddr_high);
     98	if (ret)
     99		return ret;
    100
    101	return sysfs_emit(buf, "%02x:%02x:%02x:%02x:%02x:%02x\n",
    102			  (u8)FIELD_GET(M10BMC_MAC_BYTE1, macaddr_low),
    103			  (u8)FIELD_GET(M10BMC_MAC_BYTE2, macaddr_low),
    104			  (u8)FIELD_GET(M10BMC_MAC_BYTE3, macaddr_low),
    105			  (u8)FIELD_GET(M10BMC_MAC_BYTE4, macaddr_low),
    106			  (u8)FIELD_GET(M10BMC_MAC_BYTE5, macaddr_high),
    107			  (u8)FIELD_GET(M10BMC_MAC_BYTE6, macaddr_high));
    108}
    109static DEVICE_ATTR_RO(mac_address);
    110
    111static ssize_t mac_count_show(struct device *dev,
    112			      struct device_attribute *attr, char *buf)
    113{
    114	struct intel_m10bmc *max10 = dev_get_drvdata(dev);
    115	unsigned int macaddr_high;
    116	int ret;
    117
    118	ret = m10bmc_sys_read(max10, M10BMC_MAC_HIGH, &macaddr_high);
    119	if (ret)
    120		return ret;
    121
    122	return sysfs_emit(buf, "%u\n",
    123			  (u8)FIELD_GET(M10BMC_MAC_COUNT, macaddr_high));
    124}
    125static DEVICE_ATTR_RO(mac_count);
    126
    127static struct attribute *m10bmc_attrs[] = {
    128	&dev_attr_bmc_version.attr,
    129	&dev_attr_bmcfw_version.attr,
    130	&dev_attr_mac_address.attr,
    131	&dev_attr_mac_count.attr,
    132	NULL,
    133};
    134ATTRIBUTE_GROUPS(m10bmc);
    135
    136static int check_m10bmc_version(struct intel_m10bmc *ddata)
    137{
    138	unsigned int v;
    139	int ret;
    140
    141	/*
    142	 * This check is to filter out the very old legacy BMC versions. In the
    143	 * old BMC chips, the BMC version info is stored in the old version
    144	 * register (M10BMC_LEGACY_BUILD_VER), so its read out value would have
    145	 * not been M10BMC_VER_LEGACY_INVALID (0xffffffff). But in new BMC
    146	 * chips that the driver supports, the value of this register should be
    147	 * M10BMC_VER_LEGACY_INVALID.
    148	 */
    149	ret = m10bmc_raw_read(ddata, M10BMC_LEGACY_BUILD_VER, &v);
    150	if (ret)
    151		return -ENODEV;
    152
    153	if (v != M10BMC_VER_LEGACY_INVALID) {
    154		dev_err(ddata->dev, "bad version M10BMC detected\n");
    155		return -ENODEV;
    156	}
    157
    158	return 0;
    159}
    160
    161static int intel_m10_bmc_spi_probe(struct spi_device *spi)
    162{
    163	const struct spi_device_id *id = spi_get_device_id(spi);
    164	struct device *dev = &spi->dev;
    165	struct mfd_cell *cells;
    166	struct intel_m10bmc *ddata;
    167	int ret, n_cell;
    168
    169	ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
    170	if (!ddata)
    171		return -ENOMEM;
    172
    173	ddata->dev = dev;
    174
    175	ddata->regmap =
    176		devm_regmap_init_spi_avmm(spi, &intel_m10bmc_regmap_config);
    177	if (IS_ERR(ddata->regmap)) {
    178		ret = PTR_ERR(ddata->regmap);
    179		dev_err(dev, "Failed to allocate regmap: %d\n", ret);
    180		return ret;
    181	}
    182
    183	spi_set_drvdata(spi, ddata);
    184
    185	ret = check_m10bmc_version(ddata);
    186	if (ret) {
    187		dev_err(dev, "Failed to identify m10bmc hardware\n");
    188		return ret;
    189	}
    190
    191	switch (id->driver_data) {
    192	case M10_N3000:
    193		cells = m10bmc_pacn3000_subdevs;
    194		n_cell = ARRAY_SIZE(m10bmc_pacn3000_subdevs);
    195		break;
    196	case M10_D5005:
    197		cells = m10bmc_d5005_subdevs;
    198		n_cell = ARRAY_SIZE(m10bmc_d5005_subdevs);
    199		break;
    200	case M10_N5010:
    201		cells = m10bmc_n5010_subdevs;
    202		n_cell = ARRAY_SIZE(m10bmc_n5010_subdevs);
    203		break;
    204	default:
    205		return -ENODEV;
    206	}
    207
    208	ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, cells, n_cell,
    209				   NULL, 0, NULL);
    210	if (ret)
    211		dev_err(dev, "Failed to register sub-devices: %d\n", ret);
    212
    213	return ret;
    214}
    215
    216static const struct spi_device_id m10bmc_spi_id[] = {
    217	{ "m10-n3000", M10_N3000 },
    218	{ "m10-d5005", M10_D5005 },
    219	{ "m10-n5010", M10_N5010 },
    220	{ }
    221};
    222MODULE_DEVICE_TABLE(spi, m10bmc_spi_id);
    223
    224static struct spi_driver intel_m10bmc_spi_driver = {
    225	.driver = {
    226		.name = "intel-m10-bmc",
    227		.dev_groups = m10bmc_groups,
    228	},
    229	.probe = intel_m10_bmc_spi_probe,
    230	.id_table = m10bmc_spi_id,
    231};
    232module_spi_driver(intel_m10bmc_spi_driver);
    233
    234MODULE_DESCRIPTION("Intel MAX 10 BMC Device Driver");
    235MODULE_AUTHOR("Intel Corporation");
    236MODULE_LICENSE("GPL v2");
    237MODULE_ALIAS("spi:intel-m10-bmc");