On 12/14/2016 5:56 AM, Stephen Boyd wrote: > On 12/12, Imran Khan wrote: >> The SoC info driver provides information such as Chip ID, >> Chip family, serial number and other such details about >> Qualcomm SoCs. > > Yes but why do we care? > We intend to expose some standard SoC attributes (like soc-id) of QCOM SoCs to user space, so that if needed the user space utilities (like antutu) can query such information using sysfs interface. A further example can be a user space script (say Android's init.rc) which reads soc-id and does some gpio settings based on the soc-id. >> >> Signed-off-by: Imran Khan <kimran@xxxxxxxxxxxxxx> >> >> >> drivers/soc/qcom/Kconfig | 1 + >> drivers/soc/qcom/Makefile | 3 +- >> drivers/soc/qcom/smem.c | 5 + >> drivers/soc/qcom/socinfo.c | 671 +++++++++++++++++++++++++++++++++++++++++++++ > > There should be a Documentation/ABI/ file here as well to > document all the sysfs files added in this patch. > Sure. I will add this file in the subsequent patch set. >> diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c >> index 18ec52f..c598cac 100644 >> --- a/drivers/soc/qcom/smem.c >> +++ b/drivers/soc/qcom/smem.c >> @@ -85,6 +85,9 @@ >> /* Max number of processors/hosts in a system */ >> #define SMEM_HOST_COUNT 9 >> >> + >> +extern void qcom_socinfo_init(struct platform_device *pdev); > > We can't put this into a header file? > We can. In fact earlier I had put it in smem.h but since smem.h is public API for smem I removed it from there. As it was only a single function I used this extern declaration. Please let me know if it is acceptable. If it is not acceptable I will create a socinfo.h and will put this declaration there. >> diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c >> new file mode 100644 >> index 0000000..57e23dfc >> --- /dev/null >> +++ b/drivers/soc/qcom/socinfo.c >> @@ -0,0 +1,671 @@ >> +/* >> + * Copyright (c) 2009-2016, The Linux Foundation. All rights reserved. >> + * >> + * This program is free software; you can redistribute it and/or modify >> + * it under the terms of the GNU General Public License version 2 and >> + * only version 2 as published by the Free Software Foundation. >> + * >> + * This program is distributed in the hope that it will be useful, >> + * but WITHOUT ANY WARRANTY; without even the implied warranty of >> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >> + * GNU General Public License for more details. >> + * >> + */ >> + >> +#include <linux/export.h> >> +#include <linux/module.h> > > This include isn't necessary. > True. Will remove this in the next patch set. >> +#include <linux/err.h> >> +#include <linux/of.h> >> +#include <linux/platform_device.h> >> +#include <linux/sys_soc.h> >> +#include <linux/slab.h> >> +#include <linux/stat.h> > > Is this include used? > Will check and remove accordingly. >> +#include <linux/string.h> >> +#include <linux/types.h> >> +#include <linux/random.h> >> +#include <linux/soc/qcom/smem.h> >> + >> +#define PMIC_MODEL_UNKNOWN 0 > > Used? > Not used. Will remove this. >> +#define HW_PLATFORM_QRD 11 >> +#define PLATFORM_SUBTYPE_QRD_INVALID 6 >> +#define PLATFORM_SUBTYPE_INVALID 4 >> +/* >> + * SOC version type with major number in the upper 16 bits and minor >> + * number in the lower 16 bits. For example: >> + * 1.0 -> 0x00010000 >> + * 2.3 -> 0x00020003 >> + */ >> +#define SOC_VERSION_MAJOR(ver) (((ver) & 0xffff0000) >> 16) >> +#define SOC_VERSION_MINOR(ver) ((ver) & 0x0000ffff) >> +#define SOCINFO_VERSION_MAJOR SOC_VERSION_MAJOR >> +#define SOCINFO_VERSION_MINOR SOC_VERSION_MINOR >> + >> +#define SMEM_SOCINFO_BUILD_ID_LENGTH 32 >> +#define SMEM_IMAGE_VERSION_BLOCKS_COUNT 32 >> +#define SMEM_IMAGE_VERSION_SIZE 4096 >> +#define SMEM_IMAGE_VERSION_NAME_SIZE 75 >> +#define SMEM_IMAGE_VERSION_VARIANT_SIZE 20 >> +#define SMEM_IMAGE_VERSION_OEM_SIZE 32 >> +#define SMEM_IMAGE_VERSION_PARTITION_APPS 10 > > Used? > Again redundant. Will remove this. >> + >> +/* >> + * SMEM item ids, used to acquire handles to respective >> + * SMEM region. >> + */ >> +#define SMEM_IMAGE_VERSION_TABLE 469 >> +#define SMEM_HW_SW_BUILD_ID 137 >> + >> +#define MAX_ATTR_COUNT 15 >> + >> +/* >> + * SMEM Image table indices >> + */ >> +enum smem_image_table_index { >> + SMEM_IMAGE_TABLE_BOOT_INDEX = 0, >> + SMEM_IMAGE_TABLE_TZ_INDEX, >> + SMEM_IMAGE_TABLE_RPM_INDEX = 3, >> + SMEM_IMAGE_TABLE_APPS_INDEX = 10, >> + SMEM_IMAGE_TABLE_MPSS_INDEX, >> + SMEM_IMAGE_TABLE_ADSP_INDEX, >> + SMEM_IMAGE_TABLE_CNSS_INDEX, >> + SMEM_IMAGE_TABLE_VIDEO_INDEX > > Please just use #defines. The enum isn't buying us anything > besides confusion about what the numbers are. > Okay. Will replace the enum with #define as it will be easier to understand. >> +}; >> + >> +struct qcom_socinfo_attr { >> + struct device_attribute attr; >> + int min_version; >> +}; >> + >> +#define QCOM_SOCINFO_ATTR(_name, _show, _min_version) \ >> + { __ATTR(_name, 0444, _show, NULL), _min_version } >> + >> +#define SMEM_IMG_ATTR_ENTRY(_name, _mode, _show, _store, _index) \ >> + struct dev_ext_attribute dev_attr_##_name = \ > > add static. and const? > Yes. will do this. >> + { __ATTR(_name, _mode, _show, _store), (void *)_index } >> + >> +#define QCOM_SMEM_IMG_ITEM(_name, _mode, _index) \ >> + SMEM_IMG_ATTR_ENTRY(_name##_image_version, _mode, \ >> + qcom_show_image_version, qcom_store_image_version, \ >> + (unsigned long)_index); \ >> + SMEM_IMG_ATTR_ENTRY(_name##_image_variant, _mode, \ >> + qcom_show_image_variant, qcom_store_image_variant, \ >> + (unsigned long)_index); \ >> + SMEM_IMG_ATTR_ENTRY(_name##_image_crm, _mode, \ >> + qcom_show_image_crm, qcom_store_image_crm, \ >> + (unsigned long)_index); \ >> +static struct attribute *_name##_image_attrs[] = { \ >> + &dev_attr_##_name##_image_version.attr.attr, \ >> + &dev_attr_##_name##_image_variant.attr.attr, \ >> + &dev_attr_##_name##_image_crm.attr.attr, \ >> + NULL, \ >> +}; \ >> +static struct attribute_group _name##_image_attr_group = { \ >> + .attrs = _name##_image_attrs, \ >> +} >> + >> +/* Hardware platform types */ >> +static const char *const hw_platform[] = { >> + [0] = "Unknown", >> + [1] = "Surf", >> + [2] = "FFA", >> + [3] = "Fluid", >> + [4] = "SVLTE_FFA", >> + [5] = "SLVTE_SURF", >> + [7] = "MDM_MTP_NO_DISPLAY", >> + [8] = "MTP", >> + [9] = "Liquid", >> + [10] = "Dragon", >> + [11] = "QRD", >> + [13] = "HRD", >> + [14] = "DTV", >> + [21] = "RCM", >> + [23] = "STP", >> + [24] = "SBC", >> +}; > > These only make sense on qcom platforms. Other boards can reuse > the numbers here and have their own names for the platform field, > so it doesn't seem like a good idea to do this in the kernel. > Sorry could not understand this. Do you mean that we should only expose the information that we can via generic soc_device_attribute. This object is being used for hw_platform attribute which we are explicitly creating in sysfs, so it should not conflict with other's implementation. Or do you mean to just show the numbers and avoid the strings. I am using strings as I think in any case they will be more informative and also there are not many types/subtypes in any case. May be we can keep only those types/subtypes that are more frequent. I may be completely wrong in understanding the comment here so could you kindly elaborate this a bit. >> + >> +static const char *const qrd_hw_platform_subtype[] = { >> + [0] = "QRD", >> + [1] = "SKUAA", >> + [2] = "SKUF", >> + [3] = "SKUAB", >> + [5] = "SKUG", >> + [6] = "INVALID", >> +}; >> + >> +static const char *const hw_platform_subtype[] = { >> + "Unknown", "charm", "strange", "strange_2a", "Invalid", >> +}; > > Same point here. Seems impossible to maintain this so please get > rid of it and just output raw numbers if anything. > >> + >> +static const char *const pmic_model[] = { >> + [0] = "Unknown PMIC model", >> + [13] = "PMIC model: PM8058", >> + [14] = "PMIC model: PM8028", >> + [15] = "PMIC model: PM8901", >> + [16] = "PMIC model: PM8027", >> + [17] = "PMIC model: ISL9519", >> + [18] = "PMIC model: PM8921", >> + [19] = "PMIC model: PM8018", >> + [20] = "PMIC model: PM8015", >> + [21] = "PMIC model: PM8014", >> + [22] = "PMIC model: PM8821", >> + [23] = "PMIC model: PM8038", >> + [24] = "PMIC model: PM8922", >> + [25] = "PMIC model: PM8917", > > Why do we have "PMIC model:" in sysfs? Shouldn't that be evident > from the file name and shouldn't we strive for something more > machine readable? And do we expose all the different models in > sysfs or just the first one? > We are exposing just the first PMIC model and yes "PMIC model:" is redundant here. Will remove this in the next patch set. The SMEM content just gives the numeric PMIC id so here we can either dump that id or a string. As of now I am intending to dump string. Please let me know if that looks okay. >> +}; >> + >> +struct smem_image_version { >> + char name[SMEM_IMAGE_VERSION_NAME_SIZE]; >> + char variant[SMEM_IMAGE_VERSION_VARIANT_SIZE]; >> + char pad; >> + char oem[SMEM_IMAGE_VERSION_OEM_SIZE]; >> +}; <snip> >> + >> +struct socinfo_v0_12 { >> + struct socinfo_v0_11 v0_11; >> + u32 chip_family; >> + u32 raw_device_family; >> + u32 raw_device_number; > > __le32 for all these u32 fields? And the appropriate endian > accessors for them all as well? > Sure. Will do this. >> +}; >> + >> +static union { >> + struct socinfo_v0_1 v0_1; >> + struct socinfo_v0_2 v0_2; >> + struct socinfo_v0_3 v0_3; >> + struct socinfo_v0_4 v0_4; >> + struct socinfo_v0_5 v0_5; >> + struct socinfo_v0_6 v0_6; >> + struct socinfo_v0_7 v0_7; >> + struct socinfo_v0_8 v0_8; >> + struct socinfo_v0_9 v0_9; >> + struct socinfo_v0_10 v0_10; >> + struct socinfo_v0_11 v0_11; >> + struct socinfo_v0_12 v0_12; >> +} *socinfo; >> + >> +static struct smem_image_version *smem_image_version; >> +static u32 socinfo_format; > > Why are any of these things static and in the global namespace? > These are being used across multiple sysfs handlers. >> + >> +/* max socinfo format version supported */ >> +#define MAX_SOCINFO_FORMAT 12 >> + >> +static const char *const cpu_of_id[] = { >> + >> + [0] = "Unknown CPU", > > An SoC is not a CPU? Probably should rename this array soc_of_id > or machine_of_id instead. > Sure. soc_of_id would be more appropriate than cpu_of_id. Will make this change. >> + >> + /* 8x60 IDs */ >> + [87] = "MSM8960", >> + >> + /* 8x64 IDs */ <snip> >> + /* 8x74AB IDs */ >> + [209] = "APQ8074-AB", >> + [212] = "MSM8274-AB", >> + [215] = "MSM8674-AB", >> + /* >> + * Uninitialized IDs are not known to run Linux. >> + * MSM_CPU_UNKNOWN is set to 0 to ensure these IDs are > > What is this define? Please don't confuse CPUs with SoCs. > Sure. Will correct the comment and the macro. >> + * considered as unknown CPU. >> + */ >> +}; > [...] >> + >> +static const struct qcom_socinfo_attr qcom_socinfo_attrs[] = { >> + QCOM_SOCINFO_ATTR(chip_family, qcom_show_chip_family, 12), >> + QCOM_SOCINFO_ATTR(raw_device_family, qcom_show_raw_device_family, 12), >> + QCOM_SOCINFO_ATTR(raw_device_number, qcom_show_raw_device_number, 12), >> + QCOM_SOCINFO_ATTR(serial_number, qcom_show_serial_number, 10), >> + QCOM_SOCINFO_ATTR(foundry_id, qcom_show_foundry_id, 9), >> + QCOM_SOCINFO_ATTR(pmic_model, qcom_show_pmic_model, 7), >> + QCOM_SOCINFO_ATTR(pmic_die_revision, qcom_show_pmic_die_revision, 7), >> + QCOM_SOCINFO_ATTR(platform_subtype, qcom_show_platform_subtype, 6), >> + QCOM_SOCINFO_ATTR(platform_subtype_id, >> + qcom_show_platform_subtype_id, 6), >> + QCOM_SOCINFO_ATTR(accessory_chip, qcom_show_accessory_chip, 5), >> + QCOM_SOCINFO_ATTR(platform_version, qcom_show_platform_version, 4), >> + QCOM_SOCINFO_ATTR(hw_platform, qcom_show_hw_platform, 3), >> + QCOM_SOCINFO_ATTR(raw_version, qcom_show_raw_version, 2), >> + QCOM_SOCINFO_ATTR(build_id, qcom_show_build_id, 1), >> + QCOM_SOCINFO_ATTR(vendor, qcom_show_vendor, 0), >> +}; >> + >> +QCOM_SMEM_IMG_ITEM(boot, 0444, SMEM_IMAGE_TABLE_BOOT_INDEX); >> +QCOM_SMEM_IMG_ITEM(tz, 0444, SMEM_IMAGE_TABLE_TZ_INDEX); >> +QCOM_SMEM_IMG_ITEM(rpm, 0444, SMEM_IMAGE_TABLE_RPM_INDEX); >> +QCOM_SMEM_IMG_ITEM(apps, 0644, SMEM_IMAGE_TABLE_APPS_INDEX); >> +QCOM_SMEM_IMG_ITEM(mpss, 0444, SMEM_IMAGE_TABLE_MPSS_INDEX); >> +QCOM_SMEM_IMG_ITEM(adsp, 0444, SMEM_IMAGE_TABLE_ADSP_INDEX); >> +QCOM_SMEM_IMG_ITEM(cnss, 0444, SMEM_IMAGE_TABLE_CNSS_INDEX); >> +QCOM_SMEM_IMG_ITEM(video, 0444, SMEM_IMAGE_TABLE_VIDEO_INDEX); >> + >> +static struct attribute_group > > const? > Yes. Will do this. >> + *smem_image_table[SMEM_IMAGE_VERSION_BLOCKS_COUNT] = { >> + [SMEM_IMAGE_TABLE_BOOT_INDEX] = &boot_image_attr_group, >> + [SMEM_IMAGE_TABLE_TZ_INDEX] = &tz_image_attr_group, >> + [SMEM_IMAGE_TABLE_RPM_INDEX] = &rpm_image_attr_group, >> + [SMEM_IMAGE_TABLE_APPS_INDEX] = &apps_image_attr_group, >> + [SMEM_IMAGE_TABLE_MPSS_INDEX] = &mpss_image_attr_group, >> + [SMEM_IMAGE_TABLE_ADSP_INDEX] = &adsp_image_attr_group, >> + [SMEM_IMAGE_TABLE_CNSS_INDEX] = &cnss_image_attr_group, >> + [SMEM_IMAGE_TABLE_VIDEO_INDEX] = &video_image_attr_group, >> +}; >> + >> +static void socinfo_populate_sysfs_files(struct device *dev) >> +{ >> + int idx; >> + int err; >> + >> + /* >> + * Expose SMEM_IMAGE_TABLE to sysfs only when we have IMAGE_TABLE >> + * available in SMEM. As IMAGE_TABLE and SOCINFO are two separate >> + * items within SMEM, we expose the remaining soc information(i.e >> + * only the SOCINFO item available in SMEM) to sysfs even in the >> + * absence of an IMAGE_TABLE. >> + */ >> + if (smem_image_version) >> + for (idx = 0; idx < SMEM_IMAGE_VERSION_BLOCKS_COUNT; idx++) >> + if (smem_image_table[idx]) >> + err = sysfs_create_group(&dev->kobj, >> + smem_image_table[idx]); >> + >> + for (idx = 0; idx < MAX_ATTR_COUNT; idx++) > > Use ARRAY_SIZE instead? > Sure. That would avoid this redundant macro. >> + if (qcom_socinfo_attrs[idx].min_version <= socinfo_format) >> + device_create_file(dev, &qcom_socinfo_attrs[idx].attr); >> +} >> + >> +void qcom_socinfo_init(struct platform_device *pdev) > > Maybe this should just take a device argument as we don't use the > platform part at all. > Indeed, device would be better argument here. Will make this change. >> +{ >> + struct soc_device_attribute *attr; >> + struct device *qcom_soc_device; >> + struct soc_device *soc_dev; >> + size_t img_tbl_size; >> + u32 soc_version; >> + size_t size; >> + >> + socinfo = qcom_smem_get(QCOM_SMEM_HOST_ANY, SMEM_HW_SW_BUILD_ID, >> + &size); >> + if (IS_ERR(socinfo)) { >> + dev_err(&pdev->dev, "Coudn't find socinfo.\n"); >> + return; >> + } >> + >> + if ((SOCINFO_VERSION_MAJOR(socinfo->v0_1.format) != 0) || >> + (SOCINFO_VERSION_MINOR(socinfo->v0_1.format) < 0) || >> + (socinfo->v0_1.format > MAX_SOCINFO_FORMAT)) { > > Please drop all extraneous parenthesis here. > Sure I will. >> + dev_err(&pdev->dev, "Wrong socinfo format\n"); >> + return; >> + } >> + socinfo_format = socinfo->v0_1.format; >> + >> + if (!socinfo->v0_1.id) >> + dev_err(&pdev->dev, "socinfo: Unknown SoC ID!\n"); >> + >> + WARN(socinfo->v0_1.id >= ARRAY_SIZE(cpu_of_id), >> + "New IDs added! ID => CPU mapping needs an update.\n"); >> + >> + smem_image_version = qcom_smem_get(QCOM_SMEM_HOST_ANY, >> + SMEM_IMAGE_VERSION_TABLE, >> + &img_tbl_size); >> + if (IS_ERR(smem_image_version) || >> + (img_tbl_size != SMEM_IMAGE_VERSION_SIZE)) { > > More extraneous parenthesis. > >> + dev_warn(&pdev->dev, "Image version table absent.\n"); > > Will this warn on "older" platforms? Perhaps make this a > dev_dbg() instead. > Okay. I am fine with dev_dbg too. >> + smem_image_version = NULL; >> + } >> + >> + attr = kzalloc(sizeof(*attr), GFP_KERNEL); >> + if (!attr) { >> + dev_err(&pdev->dev, "Unable to allocate attributes.\n"); > > Please drop the full stop on all error messages. > Okay. >> + return; >> + } >> + soc_version = socinfo->v0_1.version; >> + >> + attr->soc_id = kasprintf(GFP_KERNEL, "%d", socinfo->v0_1.id); >> + attr->family = "Snapdragon"; >> + attr->machine = cpu_of_id[socinfo->v0_1.id]; > > The id is used twice. According to the ABI documentation soc_id > is a serial number. The part number is not the same as a serial > number so assigning soc_id doesn't seem correct. Probably we > should only assign soc_id to be v10 serial_number. > This part has been a point of confusion for me since long. Ealier I had discussed this point in threads pertaining to other patch sets but did not get any confirmation. I see that quite a few similar drivers have avoided the "attr->machine" field altogether: http://lxr.free-electrons.com/source/arch/arm/mach-tegra/tegra.c http://lxr.free-electrons.com/source/arch/arm/mach-zynq/common.c So not sure if we should do the same or have a string in machine and a numeric id in soc_id. I am afraid that since v10 is relatively newer version of socinfo format, some older socs may not be able to provide serial_number although they might be having a valid soc-id. Could you please provide your feedback in this regard? >> + attr->revision = kasprintf(GFP_KERNEL, "%u.%u", >> + SOC_VERSION_MAJOR(soc_version), >> + SOC_VERSION_MINOR(soc_version)); >> + >> + soc_dev = soc_device_register(attr); >> + if (IS_ERR(soc_dev)) { >> + kfree(attr); >> + return; >> + } >> + >> + qcom_soc_device = soc_device_to_device(soc_dev); >> + socinfo_populate_sysfs_files(qcom_soc_device); >> + >> + /* Feed the soc specific unique data into entropy pool */ >> + add_device_randomness(socinfo, size); > > And thus adding mostly the same random bits for every SoC that's > the same as a million other ones doesn't seem like a good choice > for device randomness. Probably only the v10 serial_number should > be added to the random pool. > Yes a lot of fields in socinfo object tend to have same value. How about putting soc-id and v10 serial number (if we can conclude that these 2 should be different) along with build-id. Thanks and Regards, Imran -- QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a\nmember of the Code Aurora Forum, hosted by The Linux Foundation -- To unsubscribe from this list: send the line "unsubscribe linux-soc" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html