static int pseries_devicetree_update(void)
{
	char *rtas_buf;
	u32 *data;
	int update_nodes_token;
	int rc;

	update_nodes_token = rtas_token("ibm,update-nodes");
	if (update_nodes_token == RTAS_UNKNOWN_SERVICE)
		return -EINVAL;

	rtas_buf = kzalloc(RTAS_DATA_BUF_SIZE, GFP_KERNEL);
	if (!rtas_buf)
		return -ENOMEM;

	do {
		rc = mobility_rtas_call(update_nodes_token, rtas_buf);
		if (rc && rc != 1)
			break;

		data = (u32 *)rtas_buf + 4;
		while (*data & NODE_ACTION_MASK) {
			int i;
			u32 action = *data & NODE_ACTION_MASK;
			int node_count = *data & NODE_COUNT_MASK;

			data++;

			for (i = 0; i < node_count; i++) {
				u32 phandle = *data++;
				u32 drc_index;

				switch (action) {
				case DELETE_DT_NODE:
					delete_dt_node(phandle);
					break;
				case UPDATE_DT_NODE:
					update_dt_node(phandle);
					break;
				case ADD_DT_NODE:
					drc_index = *data++;
					add_dt_node(phandle, drc_index);
					break;
				}
			}
		}
	} while (rc == 1);

	kfree(rtas_buf);
	return rc;
}
static int update_dt_node(u32 phandle)
{
	struct update_props_workarea *upwa;
	struct device_node *dn;
	struct property *prop = NULL;
	int i, rc;
	char *prop_data;
	char *rtas_buf;
	int update_properties_token;

	update_properties_token = rtas_token("ibm,update-properties");
	if (update_properties_token == RTAS_UNKNOWN_SERVICE)
		return -EINVAL;

	rtas_buf = kzalloc(RTAS_DATA_BUF_SIZE, GFP_KERNEL);
	if (!rtas_buf)
		return -ENOMEM;

	dn = of_find_node_by_phandle(phandle);
	if (!dn) {
		kfree(rtas_buf);
		return -ENOENT;
	}

	upwa = (struct update_props_workarea *)&rtas_buf[0];
	upwa->phandle = phandle;

	do {
		rc = mobility_rtas_call(update_properties_token, rtas_buf);
		if (rc < 0)
			break;

		prop_data = rtas_buf + sizeof(*upwa);

		for (i = 0; i < upwa->nprops; i++) {
			char *prop_name;
			u32 vd;

			prop_name = prop_data + 1;
			prop_data += strlen(prop_name) + 1;
			vd = *prop_data++;

			switch (vd) {
			case 0x00000000:
				/*                                   */
				break;

			case 0x80000000:
				prop = of_find_property(dn, prop_name, NULL);
				prom_remove_property(dn, prop);
				prop = NULL;
				break;

			default:
				rc = update_dt_property(dn, &prop, prop_name,
							vd, prop_data);
				if (rc) {
					printk(KERN_ERR "Could not update %s"
					       " property\n", prop_name);
				}

				prop_data += vd;
			}
		}
	} while (rc == 1);

	of_node_put(dn);
	kfree(rtas_buf);
	return 0;
}
Exemple #3
0
static int update_dt_node(u32 phandle, s32 scope)
{
	struct update_props_workarea *upwa;
	struct device_node *dn;
	struct property *prop = NULL;
	int i, rc, rtas_rc;
	char *prop_data;
	char *rtas_buf;
	int update_properties_token;
	u32 vd;

	update_properties_token = rtas_token("ibm,update-properties");
	if (update_properties_token == RTAS_UNKNOWN_SERVICE)
		return -EINVAL;

	rtas_buf = kzalloc(RTAS_DATA_BUF_SIZE, GFP_KERNEL);
	if (!rtas_buf)
		return -ENOMEM;

	dn = of_find_node_by_phandle(phandle);
	if (!dn) {
		kfree(rtas_buf);
		return -ENOENT;
	}

	upwa = (struct update_props_workarea *)&rtas_buf[0];
	upwa->phandle = phandle;

	do {
		rtas_rc = mobility_rtas_call(update_properties_token, rtas_buf,
					scope);
		if (rtas_rc < 0)
			break;

		prop_data = rtas_buf + sizeof(*upwa);

		/* On the first call to ibm,update-properties for a node the
		 * the first property value descriptor contains an empty
		 * property name, the property value length encoded as u32,
		 * and the property value is the node path being updated.
		 */
		if (*prop_data == 0) {
			prop_data++;
			vd = *(u32 *)prop_data;
			prop_data += vd + sizeof(vd);
			upwa->nprops--;
		}

		for (i = 0; i < upwa->nprops; i++) {
			char *prop_name;

			prop_name = prop_data;
			prop_data += strlen(prop_name) + 1;
			vd = *(u32 *)prop_data;
			prop_data += sizeof(vd);

			switch (vd) {
			case 0x00000000:
				/* name only property, nothing to do */
				break;

			case 0x80000000:
				prop = of_find_property(dn, prop_name, NULL);
				of_remove_property(dn, prop);
				prop = NULL;
				break;

			default:
				rc = update_dt_property(dn, &prop, prop_name,
							vd, prop_data);
				if (rc) {
					printk(KERN_ERR "Could not update %s"
					       " property\n", prop_name);
				}

				prop_data += vd;
			}
		}
	} while (rtas_rc == 1);

	of_node_put(dn);
	kfree(rtas_buf);
	return 0;
}