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; }
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; }