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

ibmpowernv.c (17209B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * IBM PowerNV platform sensors for temperature/fan/voltage/power
      4 * Copyright (C) 2014 IBM
      5 */
      6
      7#define DRVNAME		"ibmpowernv"
      8#define pr_fmt(fmt)	DRVNAME ": " fmt
      9
     10#include <linux/init.h>
     11#include <linux/module.h>
     12#include <linux/kernel.h>
     13#include <linux/hwmon.h>
     14#include <linux/hwmon-sysfs.h>
     15#include <linux/of.h>
     16#include <linux/slab.h>
     17
     18#include <linux/platform_device.h>
     19#include <asm/opal.h>
     20#include <linux/err.h>
     21#include <asm/cputhreads.h>
     22#include <asm/smp.h>
     23
     24#define MAX_ATTR_LEN	32
     25#define MAX_LABEL_LEN	64
     26
     27/* Sensor suffix name from DT */
     28#define DT_FAULT_ATTR_SUFFIX		"faulted"
     29#define DT_DATA_ATTR_SUFFIX		"data"
     30#define DT_THRESHOLD_ATTR_SUFFIX	"thrs"
     31
     32/*
     33 * Enumerates all the types of sensors in the POWERNV platform and does index
     34 * into 'struct sensor_group'
     35 */
     36enum sensors {
     37	FAN,
     38	TEMP,
     39	POWER_SUPPLY,
     40	POWER_INPUT,
     41	CURRENT,
     42	ENERGY,
     43	MAX_SENSOR_TYPE,
     44};
     45
     46#define INVALID_INDEX (-1U)
     47
     48/*
     49 * 'compatible' string properties for sensor types as defined in old
     50 * PowerNV firmware (skiboot). These are ordered as 'enum sensors'.
     51 */
     52static const char * const legacy_compatibles[] = {
     53	"ibm,opal-sensor-cooling-fan",
     54	"ibm,opal-sensor-amb-temp",
     55	"ibm,opal-sensor-power-supply",
     56	"ibm,opal-sensor-power"
     57};
     58
     59static struct sensor_group {
     60	const char *name; /* matches property 'sensor-type' */
     61	struct attribute_group group;
     62	u32 attr_count;
     63	u32 hwmon_index;
     64} sensor_groups[] = {
     65	{ "fan"   },
     66	{ "temp"  },
     67	{ "in"    },
     68	{ "power" },
     69	{ "curr"  },
     70	{ "energy" },
     71};
     72
     73struct sensor_data {
     74	u32 id; /* An opaque id of the firmware for each sensor */
     75	u32 hwmon_index;
     76	u32 opal_index;
     77	enum sensors type;
     78	char label[MAX_LABEL_LEN];
     79	char name[MAX_ATTR_LEN];
     80	struct device_attribute dev_attr;
     81	struct sensor_group_data *sgrp_data;
     82};
     83
     84struct sensor_group_data {
     85	struct mutex mutex;
     86	u32 gid;
     87	bool enable;
     88};
     89
     90struct platform_data {
     91	const struct attribute_group *attr_groups[MAX_SENSOR_TYPE + 1];
     92	struct sensor_group_data *sgrp_data;
     93	u32 sensors_count; /* Total count of sensors from each group */
     94	u32 nr_sensor_groups; /* Total number of sensor groups */
     95};
     96
     97static ssize_t show_sensor(struct device *dev, struct device_attribute *devattr,
     98			   char *buf)
     99{
    100	struct sensor_data *sdata = container_of(devattr, struct sensor_data,
    101						 dev_attr);
    102	ssize_t ret;
    103	u64 x;
    104
    105	if (sdata->sgrp_data && !sdata->sgrp_data->enable)
    106		return -ENODATA;
    107
    108	ret =  opal_get_sensor_data_u64(sdata->id, &x);
    109
    110	if (ret)
    111		return ret;
    112
    113	/* Convert temperature to milli-degrees */
    114	if (sdata->type == TEMP)
    115		x *= 1000;
    116	/* Convert power to micro-watts */
    117	else if (sdata->type == POWER_INPUT)
    118		x *= 1000000;
    119
    120	return sprintf(buf, "%llu\n", x);
    121}
    122
    123static ssize_t show_enable(struct device *dev,
    124			   struct device_attribute *devattr, char *buf)
    125{
    126	struct sensor_data *sdata = container_of(devattr, struct sensor_data,
    127						 dev_attr);
    128
    129	return sprintf(buf, "%u\n", sdata->sgrp_data->enable);
    130}
    131
    132static ssize_t store_enable(struct device *dev,
    133			    struct device_attribute *devattr,
    134			    const char *buf, size_t count)
    135{
    136	struct sensor_data *sdata = container_of(devattr, struct sensor_data,
    137						 dev_attr);
    138	struct sensor_group_data *sgrp_data = sdata->sgrp_data;
    139	int ret;
    140	bool data;
    141
    142	ret = kstrtobool(buf, &data);
    143	if (ret)
    144		return ret;
    145
    146	ret = mutex_lock_interruptible(&sgrp_data->mutex);
    147	if (ret)
    148		return ret;
    149
    150	if (data != sgrp_data->enable) {
    151		ret =  sensor_group_enable(sgrp_data->gid, data);
    152		if (!ret)
    153			sgrp_data->enable = data;
    154	}
    155
    156	if (!ret)
    157		ret = count;
    158
    159	mutex_unlock(&sgrp_data->mutex);
    160	return ret;
    161}
    162
    163static ssize_t show_label(struct device *dev, struct device_attribute *devattr,
    164			  char *buf)
    165{
    166	struct sensor_data *sdata = container_of(devattr, struct sensor_data,
    167						 dev_attr);
    168
    169	return sprintf(buf, "%s\n", sdata->label);
    170}
    171
    172static int get_logical_cpu(int hwcpu)
    173{
    174	int cpu;
    175
    176	for_each_possible_cpu(cpu)
    177		if (get_hard_smp_processor_id(cpu) == hwcpu)
    178			return cpu;
    179
    180	return -ENOENT;
    181}
    182
    183static void make_sensor_label(struct device_node *np,
    184			      struct sensor_data *sdata, const char *label)
    185{
    186	u32 id;
    187	size_t n;
    188
    189	n = scnprintf(sdata->label, sizeof(sdata->label), "%s", label);
    190
    191	/*
    192	 * Core temp pretty print
    193	 */
    194	if (!of_property_read_u32(np, "ibm,pir", &id)) {
    195		int cpuid = get_logical_cpu(id);
    196
    197		if (cpuid >= 0)
    198			/*
    199			 * The digital thermal sensors are associated
    200			 * with a core.
    201			 */
    202			n += scnprintf(sdata->label + n,
    203				      sizeof(sdata->label) - n, " %d",
    204				      cpuid);
    205		else
    206			n += scnprintf(sdata->label + n,
    207				      sizeof(sdata->label) - n, " phy%d", id);
    208	}
    209
    210	/*
    211	 * Membuffer pretty print
    212	 */
    213	if (!of_property_read_u32(np, "ibm,chip-id", &id))
    214		n += scnprintf(sdata->label + n, sizeof(sdata->label) - n,
    215			      " %d", id & 0xffff);
    216}
    217
    218static int get_sensor_index_attr(const char *name, u32 *index, char *attr)
    219{
    220	char *hash_pos = strchr(name, '#');
    221	char buf[8] = { 0 };
    222	char *dash_pos;
    223	u32 copy_len;
    224	int err;
    225
    226	if (!hash_pos)
    227		return -EINVAL;
    228
    229	dash_pos = strchr(hash_pos, '-');
    230	if (!dash_pos)
    231		return -EINVAL;
    232
    233	copy_len = dash_pos - hash_pos - 1;
    234	if (copy_len >= sizeof(buf))
    235		return -EINVAL;
    236
    237	strncpy(buf, hash_pos + 1, copy_len);
    238
    239	err = kstrtou32(buf, 10, index);
    240	if (err)
    241		return err;
    242
    243	strscpy(attr, dash_pos + 1, MAX_ATTR_LEN);
    244
    245	return 0;
    246}
    247
    248static const char *convert_opal_attr_name(enum sensors type,
    249					  const char *opal_attr)
    250{
    251	const char *attr_name = NULL;
    252
    253	if (!strcmp(opal_attr, DT_FAULT_ATTR_SUFFIX)) {
    254		attr_name = "fault";
    255	} else if (!strcmp(opal_attr, DT_DATA_ATTR_SUFFIX)) {
    256		attr_name = "input";
    257	} else if (!strcmp(opal_attr, DT_THRESHOLD_ATTR_SUFFIX)) {
    258		if (type == TEMP)
    259			attr_name = "max";
    260		else if (type == FAN)
    261			attr_name = "min";
    262	}
    263
    264	return attr_name;
    265}
    266
    267/*
    268 * This function translates the DT node name into the 'hwmon' attribute name.
    269 * IBMPOWERNV device node appear like cooling-fan#2-data, amb-temp#1-thrs etc.
    270 * which need to be mapped as fan2_input, temp1_max respectively before
    271 * populating them inside hwmon device class.
    272 */
    273static const char *parse_opal_node_name(const char *node_name,
    274					enum sensors type, u32 *index)
    275{
    276	char attr_suffix[MAX_ATTR_LEN];
    277	const char *attr_name;
    278	int err;
    279
    280	err = get_sensor_index_attr(node_name, index, attr_suffix);
    281	if (err)
    282		return ERR_PTR(err);
    283
    284	attr_name = convert_opal_attr_name(type, attr_suffix);
    285	if (!attr_name)
    286		return ERR_PTR(-ENOENT);
    287
    288	return attr_name;
    289}
    290
    291static int get_sensor_type(struct device_node *np)
    292{
    293	enum sensors type;
    294	const char *str;
    295
    296	for (type = 0; type < ARRAY_SIZE(legacy_compatibles); type++) {
    297		if (of_device_is_compatible(np, legacy_compatibles[type]))
    298			return type;
    299	}
    300
    301	/*
    302	 * Let's check if we have a newer device tree
    303	 */
    304	if (!of_device_is_compatible(np, "ibm,opal-sensor"))
    305		return MAX_SENSOR_TYPE;
    306
    307	if (of_property_read_string(np, "sensor-type", &str))
    308		return MAX_SENSOR_TYPE;
    309
    310	for (type = 0; type < MAX_SENSOR_TYPE; type++)
    311		if (!strcmp(str, sensor_groups[type].name))
    312			return type;
    313
    314	return MAX_SENSOR_TYPE;
    315}
    316
    317static u32 get_sensor_hwmon_index(struct sensor_data *sdata,
    318				  struct sensor_data *sdata_table, int count)
    319{
    320	int i;
    321
    322	/*
    323	 * We don't use the OPAL index on newer device trees
    324	 */
    325	if (sdata->opal_index != INVALID_INDEX) {
    326		for (i = 0; i < count; i++)
    327			if (sdata_table[i].opal_index == sdata->opal_index &&
    328			    sdata_table[i].type == sdata->type)
    329				return sdata_table[i].hwmon_index;
    330	}
    331	return ++sensor_groups[sdata->type].hwmon_index;
    332}
    333
    334static int init_sensor_group_data(struct platform_device *pdev,
    335				  struct platform_data *pdata)
    336{
    337	struct sensor_group_data *sgrp_data;
    338	struct device_node *groups, *sgrp;
    339	int count = 0, ret = 0;
    340	enum sensors type;
    341
    342	groups = of_find_compatible_node(NULL, NULL, "ibm,opal-sensor-group");
    343	if (!groups)
    344		return ret;
    345
    346	for_each_child_of_node(groups, sgrp) {
    347		type = get_sensor_type(sgrp);
    348		if (type != MAX_SENSOR_TYPE)
    349			pdata->nr_sensor_groups++;
    350	}
    351
    352	if (!pdata->nr_sensor_groups)
    353		goto out;
    354
    355	sgrp_data = devm_kcalloc(&pdev->dev, pdata->nr_sensor_groups,
    356				 sizeof(*sgrp_data), GFP_KERNEL);
    357	if (!sgrp_data) {
    358		ret = -ENOMEM;
    359		goto out;
    360	}
    361
    362	for_each_child_of_node(groups, sgrp) {
    363		u32 gid;
    364
    365		type = get_sensor_type(sgrp);
    366		if (type == MAX_SENSOR_TYPE)
    367			continue;
    368
    369		if (of_property_read_u32(sgrp, "sensor-group-id", &gid))
    370			continue;
    371
    372		if (of_count_phandle_with_args(sgrp, "sensors", NULL) <= 0)
    373			continue;
    374
    375		sensor_groups[type].attr_count++;
    376		sgrp_data[count].gid = gid;
    377		mutex_init(&sgrp_data[count].mutex);
    378		sgrp_data[count++].enable = false;
    379	}
    380
    381	pdata->sgrp_data = sgrp_data;
    382out:
    383	of_node_put(groups);
    384	return ret;
    385}
    386
    387static struct sensor_group_data *get_sensor_group(struct platform_data *pdata,
    388						  struct device_node *node,
    389						  enum sensors gtype)
    390{
    391	struct sensor_group_data *sgrp_data = pdata->sgrp_data;
    392	struct device_node *groups, *sgrp;
    393
    394	groups = of_find_compatible_node(NULL, NULL, "ibm,opal-sensor-group");
    395	if (!groups)
    396		return NULL;
    397
    398	for_each_child_of_node(groups, sgrp) {
    399		struct of_phandle_iterator it;
    400		u32 gid;
    401		int rc, i;
    402		enum sensors type;
    403
    404		type = get_sensor_type(sgrp);
    405		if (type != gtype)
    406			continue;
    407
    408		if (of_property_read_u32(sgrp, "sensor-group-id", &gid))
    409			continue;
    410
    411		of_for_each_phandle(&it, rc, sgrp, "sensors", NULL, 0)
    412			if (it.phandle == node->phandle) {
    413				of_node_put(it.node);
    414				break;
    415			}
    416
    417		if (rc)
    418			continue;
    419
    420		for (i = 0; i < pdata->nr_sensor_groups; i++)
    421			if (gid == sgrp_data[i].gid) {
    422				of_node_put(sgrp);
    423				of_node_put(groups);
    424				return &sgrp_data[i];
    425			}
    426	}
    427
    428	of_node_put(groups);
    429	return NULL;
    430}
    431
    432static int populate_attr_groups(struct platform_device *pdev)
    433{
    434	struct platform_data *pdata = platform_get_drvdata(pdev);
    435	const struct attribute_group **pgroups = pdata->attr_groups;
    436	struct device_node *opal, *np;
    437	enum sensors type;
    438	int ret;
    439
    440	ret = init_sensor_group_data(pdev, pdata);
    441	if (ret)
    442		return ret;
    443
    444	opal = of_find_node_by_path("/ibm,opal/sensors");
    445	for_each_child_of_node(opal, np) {
    446		const char *label;
    447
    448		type = get_sensor_type(np);
    449		if (type == MAX_SENSOR_TYPE)
    450			continue;
    451
    452		sensor_groups[type].attr_count++;
    453
    454		/*
    455		 * add attributes for labels, min and max
    456		 */
    457		if (!of_property_read_string(np, "label", &label))
    458			sensor_groups[type].attr_count++;
    459		if (of_find_property(np, "sensor-data-min", NULL))
    460			sensor_groups[type].attr_count++;
    461		if (of_find_property(np, "sensor-data-max", NULL))
    462			sensor_groups[type].attr_count++;
    463	}
    464
    465	of_node_put(opal);
    466
    467	for (type = 0; type < MAX_SENSOR_TYPE; type++) {
    468		sensor_groups[type].group.attrs = devm_kcalloc(&pdev->dev,
    469					sensor_groups[type].attr_count + 1,
    470					sizeof(struct attribute *),
    471					GFP_KERNEL);
    472		if (!sensor_groups[type].group.attrs)
    473			return -ENOMEM;
    474
    475		pgroups[type] = &sensor_groups[type].group;
    476		pdata->sensors_count += sensor_groups[type].attr_count;
    477		sensor_groups[type].attr_count = 0;
    478	}
    479
    480	return 0;
    481}
    482
    483static void create_hwmon_attr(struct sensor_data *sdata, const char *attr_name,
    484			      ssize_t (*show)(struct device *dev,
    485					      struct device_attribute *attr,
    486					      char *buf),
    487			    ssize_t (*store)(struct device *dev,
    488					     struct device_attribute *attr,
    489					     const char *buf, size_t count))
    490{
    491	snprintf(sdata->name, MAX_ATTR_LEN, "%s%d_%s",
    492		 sensor_groups[sdata->type].name, sdata->hwmon_index,
    493		 attr_name);
    494
    495	sysfs_attr_init(&sdata->dev_attr.attr);
    496	sdata->dev_attr.attr.name = sdata->name;
    497	sdata->dev_attr.show = show;
    498	if (store) {
    499		sdata->dev_attr.store = store;
    500		sdata->dev_attr.attr.mode = 0664;
    501	} else {
    502		sdata->dev_attr.attr.mode = 0444;
    503	}
    504}
    505
    506static void populate_sensor(struct sensor_data *sdata, int od, int hd, int sid,
    507			    const char *attr_name, enum sensors type,
    508			    const struct attribute_group *pgroup,
    509			    struct sensor_group_data *sgrp_data,
    510			    ssize_t (*show)(struct device *dev,
    511					    struct device_attribute *attr,
    512					    char *buf),
    513			    ssize_t (*store)(struct device *dev,
    514					     struct device_attribute *attr,
    515					     const char *buf, size_t count))
    516{
    517	sdata->id = sid;
    518	sdata->type = type;
    519	sdata->opal_index = od;
    520	sdata->hwmon_index = hd;
    521	create_hwmon_attr(sdata, attr_name, show, store);
    522	pgroup->attrs[sensor_groups[type].attr_count++] = &sdata->dev_attr.attr;
    523	sdata->sgrp_data = sgrp_data;
    524}
    525
    526static char *get_max_attr(enum sensors type)
    527{
    528	switch (type) {
    529	case POWER_INPUT:
    530		return "input_highest";
    531	default:
    532		return "highest";
    533	}
    534}
    535
    536static char *get_min_attr(enum sensors type)
    537{
    538	switch (type) {
    539	case POWER_INPUT:
    540		return "input_lowest";
    541	default:
    542		return "lowest";
    543	}
    544}
    545
    546/*
    547 * Iterate through the device tree for each child of 'sensors' node, create
    548 * a sysfs attribute file, the file is named by translating the DT node name
    549 * to the name required by the higher 'hwmon' driver like fan1_input, temp1_max
    550 * etc..
    551 */
    552static int create_device_attrs(struct platform_device *pdev)
    553{
    554	struct platform_data *pdata = platform_get_drvdata(pdev);
    555	const struct attribute_group **pgroups = pdata->attr_groups;
    556	struct device_node *opal, *np;
    557	struct sensor_data *sdata;
    558	u32 count = 0;
    559	u32 group_attr_id[MAX_SENSOR_TYPE] = {0};
    560
    561	sdata = devm_kcalloc(&pdev->dev,
    562			     pdata->sensors_count, sizeof(*sdata),
    563			     GFP_KERNEL);
    564	if (!sdata)
    565		return -ENOMEM;
    566
    567	opal = of_find_node_by_path("/ibm,opal/sensors");
    568	for_each_child_of_node(opal, np) {
    569		struct sensor_group_data *sgrp_data;
    570		const char *attr_name;
    571		u32 opal_index, hw_id;
    572		u32 sensor_id;
    573		const char *label;
    574		enum sensors type;
    575
    576		type = get_sensor_type(np);
    577		if (type == MAX_SENSOR_TYPE)
    578			continue;
    579
    580		/*
    581		 * Newer device trees use a "sensor-data" property
    582		 * name for input.
    583		 */
    584		if (of_property_read_u32(np, "sensor-id", &sensor_id) &&
    585		    of_property_read_u32(np, "sensor-data", &sensor_id)) {
    586			dev_info(&pdev->dev,
    587				 "'sensor-id' missing in the node '%pOFn'\n",
    588				 np);
    589			continue;
    590		}
    591
    592		sdata[count].id = sensor_id;
    593		sdata[count].type = type;
    594
    595		/*
    596		 * If we can not parse the node name, it means we are
    597		 * running on a newer device tree. We can just forget
    598		 * about the OPAL index and use a defaut value for the
    599		 * hwmon attribute name
    600		 */
    601		attr_name = parse_opal_node_name(np->name, type, &opal_index);
    602		if (IS_ERR(attr_name)) {
    603			attr_name = "input";
    604			opal_index = INVALID_INDEX;
    605		}
    606
    607		hw_id = get_sensor_hwmon_index(&sdata[count], sdata, count);
    608		sgrp_data = get_sensor_group(pdata, np, type);
    609		populate_sensor(&sdata[count], opal_index, hw_id, sensor_id,
    610				attr_name, type, pgroups[type], sgrp_data,
    611				show_sensor, NULL);
    612		count++;
    613
    614		if (!of_property_read_string(np, "label", &label)) {
    615			/*
    616			 * For the label attribute, we can reuse the
    617			 * "properties" of the previous "input"
    618			 * attribute. They are related to the same
    619			 * sensor.
    620			 */
    621
    622			make_sensor_label(np, &sdata[count], label);
    623			populate_sensor(&sdata[count], opal_index, hw_id,
    624					sensor_id, "label", type, pgroups[type],
    625					NULL, show_label, NULL);
    626			count++;
    627		}
    628
    629		if (!of_property_read_u32(np, "sensor-data-max", &sensor_id)) {
    630			attr_name = get_max_attr(type);
    631			populate_sensor(&sdata[count], opal_index, hw_id,
    632					sensor_id, attr_name, type,
    633					pgroups[type], sgrp_data, show_sensor,
    634					NULL);
    635			count++;
    636		}
    637
    638		if (!of_property_read_u32(np, "sensor-data-min", &sensor_id)) {
    639			attr_name = get_min_attr(type);
    640			populate_sensor(&sdata[count], opal_index, hw_id,
    641					sensor_id, attr_name, type,
    642					pgroups[type], sgrp_data, show_sensor,
    643					NULL);
    644			count++;
    645		}
    646
    647		if (sgrp_data && !sgrp_data->enable) {
    648			sgrp_data->enable = true;
    649			hw_id = ++group_attr_id[type];
    650			populate_sensor(&sdata[count], opal_index, hw_id,
    651					sgrp_data->gid, "enable", type,
    652					pgroups[type], sgrp_data, show_enable,
    653					store_enable);
    654			count++;
    655		}
    656	}
    657
    658	of_node_put(opal);
    659	return 0;
    660}
    661
    662static int ibmpowernv_probe(struct platform_device *pdev)
    663{
    664	struct platform_data *pdata;
    665	struct device *hwmon_dev;
    666	int err;
    667
    668	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
    669	if (!pdata)
    670		return -ENOMEM;
    671
    672	platform_set_drvdata(pdev, pdata);
    673	pdata->sensors_count = 0;
    674	pdata->nr_sensor_groups = 0;
    675	err = populate_attr_groups(pdev);
    676	if (err)
    677		return err;
    678
    679	/* Create sysfs attribute data for each sensor found in the DT */
    680	err = create_device_attrs(pdev);
    681	if (err)
    682		return err;
    683
    684	/* Finally, register with hwmon */
    685	hwmon_dev = devm_hwmon_device_register_with_groups(&pdev->dev, DRVNAME,
    686							   pdata,
    687							   pdata->attr_groups);
    688
    689	return PTR_ERR_OR_ZERO(hwmon_dev);
    690}
    691
    692static const struct platform_device_id opal_sensor_driver_ids[] = {
    693	{
    694		.name = "opal-sensor",
    695	},
    696	{ }
    697};
    698MODULE_DEVICE_TABLE(platform, opal_sensor_driver_ids);
    699
    700static const struct of_device_id opal_sensor_match[] = {
    701	{ .compatible	= "ibm,opal-sensor" },
    702	{ },
    703};
    704MODULE_DEVICE_TABLE(of, opal_sensor_match);
    705
    706static struct platform_driver ibmpowernv_driver = {
    707	.probe		= ibmpowernv_probe,
    708	.id_table	= opal_sensor_driver_ids,
    709	.driver		= {
    710		.name	= DRVNAME,
    711		.of_match_table	= opal_sensor_match,
    712	},
    713};
    714
    715module_platform_driver(ibmpowernv_driver);
    716
    717MODULE_AUTHOR("Neelesh Gupta <neelegup@linux.vnet.ibm.com>");
    718MODULE_DESCRIPTION("IBM POWERNV platform sensors");
    719MODULE_LICENSE("GPL");