xref: /OK3568_Linux_fs/kernel/arch/powerpc/platforms/pseries/reconfig.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * pSeries_reconfig.c - support for dynamic reconfiguration (including PCI
4*4882a593Smuzhiyun  * Hotplug and Dynamic Logical Partitioning on RPA platforms).
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * Copyright (C) 2005 Nathan Lynch
7*4882a593Smuzhiyun  * Copyright (C) 2005 IBM Corporation
8*4882a593Smuzhiyun  */
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun #include <linux/kernel.h>
11*4882a593Smuzhiyun #include <linux/notifier.h>
12*4882a593Smuzhiyun #include <linux/proc_fs.h>
13*4882a593Smuzhiyun #include <linux/slab.h>
14*4882a593Smuzhiyun #include <linux/of.h>
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun #include <asm/prom.h>
17*4882a593Smuzhiyun #include <asm/machdep.h>
18*4882a593Smuzhiyun #include <linux/uaccess.h>
19*4882a593Smuzhiyun #include <asm/mmu.h>
20*4882a593Smuzhiyun 
21*4882a593Smuzhiyun #include "of_helpers.h"
22*4882a593Smuzhiyun 
pSeries_reconfig_add_node(const char * path,struct property * proplist)23*4882a593Smuzhiyun static int pSeries_reconfig_add_node(const char *path, struct property *proplist)
24*4882a593Smuzhiyun {
25*4882a593Smuzhiyun 	struct device_node *np;
26*4882a593Smuzhiyun 	int err = -ENOMEM;
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun 	np = kzalloc(sizeof(*np), GFP_KERNEL);
29*4882a593Smuzhiyun 	if (!np)
30*4882a593Smuzhiyun 		goto out_err;
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun 	np->full_name = kstrdup(kbasename(path), GFP_KERNEL);
33*4882a593Smuzhiyun 	if (!np->full_name)
34*4882a593Smuzhiyun 		goto out_err;
35*4882a593Smuzhiyun 
36*4882a593Smuzhiyun 	np->properties = proplist;
37*4882a593Smuzhiyun 	of_node_set_flag(np, OF_DYNAMIC);
38*4882a593Smuzhiyun 	of_node_init(np);
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun 	np->parent = pseries_of_derive_parent(path);
41*4882a593Smuzhiyun 	if (IS_ERR(np->parent)) {
42*4882a593Smuzhiyun 		err = PTR_ERR(np->parent);
43*4882a593Smuzhiyun 		goto out_err;
44*4882a593Smuzhiyun 	}
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun 	err = of_attach_node(np);
47*4882a593Smuzhiyun 	if (err) {
48*4882a593Smuzhiyun 		printk(KERN_ERR "Failed to add device node %s\n", path);
49*4882a593Smuzhiyun 		goto out_err;
50*4882a593Smuzhiyun 	}
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun 	of_node_put(np->parent);
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun 	return 0;
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun out_err:
57*4882a593Smuzhiyun 	if (np) {
58*4882a593Smuzhiyun 		of_node_put(np->parent);
59*4882a593Smuzhiyun 		kfree(np->full_name);
60*4882a593Smuzhiyun 		kfree(np);
61*4882a593Smuzhiyun 	}
62*4882a593Smuzhiyun 	return err;
63*4882a593Smuzhiyun }
64*4882a593Smuzhiyun 
pSeries_reconfig_remove_node(struct device_node * np)65*4882a593Smuzhiyun static int pSeries_reconfig_remove_node(struct device_node *np)
66*4882a593Smuzhiyun {
67*4882a593Smuzhiyun 	struct device_node *parent, *child;
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun 	parent = of_get_parent(np);
70*4882a593Smuzhiyun 	if (!parent)
71*4882a593Smuzhiyun 		return -EINVAL;
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun 	if ((child = of_get_next_child(np, NULL))) {
74*4882a593Smuzhiyun 		of_node_put(child);
75*4882a593Smuzhiyun 		of_node_put(parent);
76*4882a593Smuzhiyun 		return -EBUSY;
77*4882a593Smuzhiyun 	}
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun 	of_detach_node(np);
80*4882a593Smuzhiyun 	of_node_put(parent);
81*4882a593Smuzhiyun 	return 0;
82*4882a593Smuzhiyun }
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun /*
85*4882a593Smuzhiyun  * /proc/powerpc/ofdt - yucky binary interface for adding and removing
86*4882a593Smuzhiyun  * OF device nodes.  Should be deprecated as soon as we get an
87*4882a593Smuzhiyun  * in-kernel wrapper for the RTAS ibm,configure-connector call.
88*4882a593Smuzhiyun  */
89*4882a593Smuzhiyun 
release_prop_list(const struct property * prop)90*4882a593Smuzhiyun static void release_prop_list(const struct property *prop)
91*4882a593Smuzhiyun {
92*4882a593Smuzhiyun 	struct property *next;
93*4882a593Smuzhiyun 	for (; prop; prop = next) {
94*4882a593Smuzhiyun 		next = prop->next;
95*4882a593Smuzhiyun 		kfree(prop->name);
96*4882a593Smuzhiyun 		kfree(prop->value);
97*4882a593Smuzhiyun 		kfree(prop);
98*4882a593Smuzhiyun 	}
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun }
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun /**
103*4882a593Smuzhiyun  * parse_next_property - process the next property from raw input buffer
104*4882a593Smuzhiyun  * @buf: input buffer, must be nul-terminated
105*4882a593Smuzhiyun  * @end: end of the input buffer + 1, for validation
106*4882a593Smuzhiyun  * @name: return value; set to property name in buf
107*4882a593Smuzhiyun  * @length: return value; set to length of value
108*4882a593Smuzhiyun  * @value: return value; set to the property value in buf
109*4882a593Smuzhiyun  *
110*4882a593Smuzhiyun  * Note that the caller must make copies of the name and value returned,
111*4882a593Smuzhiyun  * this function does no allocation or copying of the data.  Return value
112*4882a593Smuzhiyun  * is set to the next name in buf, or NULL on error.
113*4882a593Smuzhiyun  */
parse_next_property(char * buf,char * end,char ** name,int * length,unsigned char ** value)114*4882a593Smuzhiyun static char * parse_next_property(char *buf, char *end, char **name, int *length,
115*4882a593Smuzhiyun 				  unsigned char **value)
116*4882a593Smuzhiyun {
117*4882a593Smuzhiyun 	char *tmp;
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun 	*name = buf;
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun 	tmp = strchr(buf, ' ');
122*4882a593Smuzhiyun 	if (!tmp) {
123*4882a593Smuzhiyun 		printk(KERN_ERR "property parse failed in %s at line %d\n",
124*4882a593Smuzhiyun 		       __func__, __LINE__);
125*4882a593Smuzhiyun 		return NULL;
126*4882a593Smuzhiyun 	}
127*4882a593Smuzhiyun 	*tmp = '\0';
128*4882a593Smuzhiyun 
129*4882a593Smuzhiyun 	if (++tmp >= end) {
130*4882a593Smuzhiyun 		printk(KERN_ERR "property parse failed in %s at line %d\n",
131*4882a593Smuzhiyun 		       __func__, __LINE__);
132*4882a593Smuzhiyun 		return NULL;
133*4882a593Smuzhiyun 	}
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 	/* now we're on the length */
136*4882a593Smuzhiyun 	*length = -1;
137*4882a593Smuzhiyun 	*length = simple_strtoul(tmp, &tmp, 10);
138*4882a593Smuzhiyun 	if (*length == -1) {
139*4882a593Smuzhiyun 		printk(KERN_ERR "property parse failed in %s at line %d\n",
140*4882a593Smuzhiyun 		       __func__, __LINE__);
141*4882a593Smuzhiyun 		return NULL;
142*4882a593Smuzhiyun 	}
143*4882a593Smuzhiyun 	if (*tmp != ' ' || ++tmp >= end) {
144*4882a593Smuzhiyun 		printk(KERN_ERR "property parse failed in %s at line %d\n",
145*4882a593Smuzhiyun 		       __func__, __LINE__);
146*4882a593Smuzhiyun 		return NULL;
147*4882a593Smuzhiyun 	}
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun 	/* now we're on the value */
150*4882a593Smuzhiyun 	*value = tmp;
151*4882a593Smuzhiyun 	tmp += *length;
152*4882a593Smuzhiyun 	if (tmp > end) {
153*4882a593Smuzhiyun 		printk(KERN_ERR "property parse failed in %s at line %d\n",
154*4882a593Smuzhiyun 		       __func__, __LINE__);
155*4882a593Smuzhiyun 		return NULL;
156*4882a593Smuzhiyun 	}
157*4882a593Smuzhiyun 	else if (tmp < end && *tmp != ' ' && *tmp != '\0') {
158*4882a593Smuzhiyun 		printk(KERN_ERR "property parse failed in %s at line %d\n",
159*4882a593Smuzhiyun 		       __func__, __LINE__);
160*4882a593Smuzhiyun 		return NULL;
161*4882a593Smuzhiyun 	}
162*4882a593Smuzhiyun 	tmp++;
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun 	/* and now we should be on the next name, or the end */
165*4882a593Smuzhiyun 	return tmp;
166*4882a593Smuzhiyun }
167*4882a593Smuzhiyun 
new_property(const char * name,const int length,const unsigned char * value,struct property * last)168*4882a593Smuzhiyun static struct property *new_property(const char *name, const int length,
169*4882a593Smuzhiyun 				     const unsigned char *value, struct property *last)
170*4882a593Smuzhiyun {
171*4882a593Smuzhiyun 	struct property *new = kzalloc(sizeof(*new), GFP_KERNEL);
172*4882a593Smuzhiyun 
173*4882a593Smuzhiyun 	if (!new)
174*4882a593Smuzhiyun 		return NULL;
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun 	if (!(new->name = kstrdup(name, GFP_KERNEL)))
177*4882a593Smuzhiyun 		goto cleanup;
178*4882a593Smuzhiyun 	if (!(new->value = kmalloc(length + 1, GFP_KERNEL)))
179*4882a593Smuzhiyun 		goto cleanup;
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun 	memcpy(new->value, value, length);
182*4882a593Smuzhiyun 	*(((char *)new->value) + length) = 0;
183*4882a593Smuzhiyun 	new->length = length;
184*4882a593Smuzhiyun 	new->next = last;
185*4882a593Smuzhiyun 	return new;
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun cleanup:
188*4882a593Smuzhiyun 	kfree(new->name);
189*4882a593Smuzhiyun 	kfree(new->value);
190*4882a593Smuzhiyun 	kfree(new);
191*4882a593Smuzhiyun 	return NULL;
192*4882a593Smuzhiyun }
193*4882a593Smuzhiyun 
do_add_node(char * buf,size_t bufsize)194*4882a593Smuzhiyun static int do_add_node(char *buf, size_t bufsize)
195*4882a593Smuzhiyun {
196*4882a593Smuzhiyun 	char *path, *end, *name;
197*4882a593Smuzhiyun 	struct device_node *np;
198*4882a593Smuzhiyun 	struct property *prop = NULL;
199*4882a593Smuzhiyun 	unsigned char* value;
200*4882a593Smuzhiyun 	int length, rv = 0;
201*4882a593Smuzhiyun 
202*4882a593Smuzhiyun 	end = buf + bufsize;
203*4882a593Smuzhiyun 	path = buf;
204*4882a593Smuzhiyun 	buf = strchr(buf, ' ');
205*4882a593Smuzhiyun 	if (!buf)
206*4882a593Smuzhiyun 		return -EINVAL;
207*4882a593Smuzhiyun 	*buf = '\0';
208*4882a593Smuzhiyun 	buf++;
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun 	if ((np = of_find_node_by_path(path))) {
211*4882a593Smuzhiyun 		of_node_put(np);
212*4882a593Smuzhiyun 		return -EINVAL;
213*4882a593Smuzhiyun 	}
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun 	/* rv = build_prop_list(tmp, bufsize - (tmp - buf), &proplist); */
216*4882a593Smuzhiyun 	while (buf < end &&
217*4882a593Smuzhiyun 	       (buf = parse_next_property(buf, end, &name, &length, &value))) {
218*4882a593Smuzhiyun 		struct property *last = prop;
219*4882a593Smuzhiyun 
220*4882a593Smuzhiyun 		prop = new_property(name, length, value, last);
221*4882a593Smuzhiyun 		if (!prop) {
222*4882a593Smuzhiyun 			rv = -ENOMEM;
223*4882a593Smuzhiyun 			prop = last;
224*4882a593Smuzhiyun 			goto out;
225*4882a593Smuzhiyun 		}
226*4882a593Smuzhiyun 	}
227*4882a593Smuzhiyun 	if (!buf) {
228*4882a593Smuzhiyun 		rv = -EINVAL;
229*4882a593Smuzhiyun 		goto out;
230*4882a593Smuzhiyun 	}
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun 	rv = pSeries_reconfig_add_node(path, prop);
233*4882a593Smuzhiyun 
234*4882a593Smuzhiyun out:
235*4882a593Smuzhiyun 	if (rv)
236*4882a593Smuzhiyun 		release_prop_list(prop);
237*4882a593Smuzhiyun 	return rv;
238*4882a593Smuzhiyun }
239*4882a593Smuzhiyun 
do_remove_node(char * buf)240*4882a593Smuzhiyun static int do_remove_node(char *buf)
241*4882a593Smuzhiyun {
242*4882a593Smuzhiyun 	struct device_node *node;
243*4882a593Smuzhiyun 	int rv = -ENODEV;
244*4882a593Smuzhiyun 
245*4882a593Smuzhiyun 	if ((node = of_find_node_by_path(buf)))
246*4882a593Smuzhiyun 		rv = pSeries_reconfig_remove_node(node);
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun 	of_node_put(node);
249*4882a593Smuzhiyun 	return rv;
250*4882a593Smuzhiyun }
251*4882a593Smuzhiyun 
parse_node(char * buf,size_t bufsize,struct device_node ** npp)252*4882a593Smuzhiyun static char *parse_node(char *buf, size_t bufsize, struct device_node **npp)
253*4882a593Smuzhiyun {
254*4882a593Smuzhiyun 	char *handle_str;
255*4882a593Smuzhiyun 	phandle handle;
256*4882a593Smuzhiyun 	*npp = NULL;
257*4882a593Smuzhiyun 
258*4882a593Smuzhiyun 	handle_str = buf;
259*4882a593Smuzhiyun 
260*4882a593Smuzhiyun 	buf = strchr(buf, ' ');
261*4882a593Smuzhiyun 	if (!buf)
262*4882a593Smuzhiyun 		return NULL;
263*4882a593Smuzhiyun 	*buf = '\0';
264*4882a593Smuzhiyun 	buf++;
265*4882a593Smuzhiyun 
266*4882a593Smuzhiyun 	handle = simple_strtoul(handle_str, NULL, 0);
267*4882a593Smuzhiyun 
268*4882a593Smuzhiyun 	*npp = of_find_node_by_phandle(handle);
269*4882a593Smuzhiyun 	return buf;
270*4882a593Smuzhiyun }
271*4882a593Smuzhiyun 
do_add_property(char * buf,size_t bufsize)272*4882a593Smuzhiyun static int do_add_property(char *buf, size_t bufsize)
273*4882a593Smuzhiyun {
274*4882a593Smuzhiyun 	struct property *prop = NULL;
275*4882a593Smuzhiyun 	struct device_node *np;
276*4882a593Smuzhiyun 	unsigned char *value;
277*4882a593Smuzhiyun 	char *name, *end;
278*4882a593Smuzhiyun 	int length;
279*4882a593Smuzhiyun 	end = buf + bufsize;
280*4882a593Smuzhiyun 	buf = parse_node(buf, bufsize, &np);
281*4882a593Smuzhiyun 
282*4882a593Smuzhiyun 	if (!np)
283*4882a593Smuzhiyun 		return -ENODEV;
284*4882a593Smuzhiyun 
285*4882a593Smuzhiyun 	if (parse_next_property(buf, end, &name, &length, &value) == NULL)
286*4882a593Smuzhiyun 		return -EINVAL;
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun 	prop = new_property(name, length, value, NULL);
289*4882a593Smuzhiyun 	if (!prop)
290*4882a593Smuzhiyun 		return -ENOMEM;
291*4882a593Smuzhiyun 
292*4882a593Smuzhiyun 	of_add_property(np, prop);
293*4882a593Smuzhiyun 
294*4882a593Smuzhiyun 	return 0;
295*4882a593Smuzhiyun }
296*4882a593Smuzhiyun 
do_remove_property(char * buf,size_t bufsize)297*4882a593Smuzhiyun static int do_remove_property(char *buf, size_t bufsize)
298*4882a593Smuzhiyun {
299*4882a593Smuzhiyun 	struct device_node *np;
300*4882a593Smuzhiyun 	char *tmp;
301*4882a593Smuzhiyun 	buf = parse_node(buf, bufsize, &np);
302*4882a593Smuzhiyun 
303*4882a593Smuzhiyun 	if (!np)
304*4882a593Smuzhiyun 		return -ENODEV;
305*4882a593Smuzhiyun 
306*4882a593Smuzhiyun 	tmp = strchr(buf,' ');
307*4882a593Smuzhiyun 	if (tmp)
308*4882a593Smuzhiyun 		*tmp = '\0';
309*4882a593Smuzhiyun 
310*4882a593Smuzhiyun 	if (strlen(buf) == 0)
311*4882a593Smuzhiyun 		return -EINVAL;
312*4882a593Smuzhiyun 
313*4882a593Smuzhiyun 	return of_remove_property(np, of_find_property(np, buf, NULL));
314*4882a593Smuzhiyun }
315*4882a593Smuzhiyun 
do_update_property(char * buf,size_t bufsize)316*4882a593Smuzhiyun static int do_update_property(char *buf, size_t bufsize)
317*4882a593Smuzhiyun {
318*4882a593Smuzhiyun 	struct device_node *np;
319*4882a593Smuzhiyun 	unsigned char *value;
320*4882a593Smuzhiyun 	char *name, *end, *next_prop;
321*4882a593Smuzhiyun 	int length;
322*4882a593Smuzhiyun 	struct property *newprop;
323*4882a593Smuzhiyun 	buf = parse_node(buf, bufsize, &np);
324*4882a593Smuzhiyun 	end = buf + bufsize;
325*4882a593Smuzhiyun 
326*4882a593Smuzhiyun 	if (!np)
327*4882a593Smuzhiyun 		return -ENODEV;
328*4882a593Smuzhiyun 
329*4882a593Smuzhiyun 	next_prop = parse_next_property(buf, end, &name, &length, &value);
330*4882a593Smuzhiyun 	if (!next_prop)
331*4882a593Smuzhiyun 		return -EINVAL;
332*4882a593Smuzhiyun 
333*4882a593Smuzhiyun 	if (!strlen(name))
334*4882a593Smuzhiyun 		return -ENODEV;
335*4882a593Smuzhiyun 
336*4882a593Smuzhiyun 	newprop = new_property(name, length, value, NULL);
337*4882a593Smuzhiyun 	if (!newprop)
338*4882a593Smuzhiyun 		return -ENOMEM;
339*4882a593Smuzhiyun 
340*4882a593Smuzhiyun 	if (!strcmp(name, "slb-size") || !strcmp(name, "ibm,slb-size"))
341*4882a593Smuzhiyun 		slb_set_size(*(int *)value);
342*4882a593Smuzhiyun 
343*4882a593Smuzhiyun 	return of_update_property(np, newprop);
344*4882a593Smuzhiyun }
345*4882a593Smuzhiyun 
346*4882a593Smuzhiyun /**
347*4882a593Smuzhiyun  * ofdt_write - perform operations on the Open Firmware device tree
348*4882a593Smuzhiyun  *
349*4882a593Smuzhiyun  * @file: not used
350*4882a593Smuzhiyun  * @buf: command and arguments
351*4882a593Smuzhiyun  * @count: size of the command buffer
352*4882a593Smuzhiyun  * @off: not used
353*4882a593Smuzhiyun  *
354*4882a593Smuzhiyun  * Operations supported at this time are addition and removal of
355*4882a593Smuzhiyun  * whole nodes along with their properties.  Operations on individual
356*4882a593Smuzhiyun  * properties are not implemented (yet).
357*4882a593Smuzhiyun  */
ofdt_write(struct file * file,const char __user * buf,size_t count,loff_t * off)358*4882a593Smuzhiyun static ssize_t ofdt_write(struct file *file, const char __user *buf, size_t count,
359*4882a593Smuzhiyun 			  loff_t *off)
360*4882a593Smuzhiyun {
361*4882a593Smuzhiyun 	int rv;
362*4882a593Smuzhiyun 	char *kbuf;
363*4882a593Smuzhiyun 	char *tmp;
364*4882a593Smuzhiyun 
365*4882a593Smuzhiyun 	kbuf = memdup_user_nul(buf, count);
366*4882a593Smuzhiyun 	if (IS_ERR(kbuf))
367*4882a593Smuzhiyun 		return PTR_ERR(kbuf);
368*4882a593Smuzhiyun 
369*4882a593Smuzhiyun 	tmp = strchr(kbuf, ' ');
370*4882a593Smuzhiyun 	if (!tmp) {
371*4882a593Smuzhiyun 		rv = -EINVAL;
372*4882a593Smuzhiyun 		goto out;
373*4882a593Smuzhiyun 	}
374*4882a593Smuzhiyun 	*tmp = '\0';
375*4882a593Smuzhiyun 	tmp++;
376*4882a593Smuzhiyun 
377*4882a593Smuzhiyun 	if (!strcmp(kbuf, "add_node"))
378*4882a593Smuzhiyun 		rv = do_add_node(tmp, count - (tmp - kbuf));
379*4882a593Smuzhiyun 	else if (!strcmp(kbuf, "remove_node"))
380*4882a593Smuzhiyun 		rv = do_remove_node(tmp);
381*4882a593Smuzhiyun 	else if (!strcmp(kbuf, "add_property"))
382*4882a593Smuzhiyun 		rv = do_add_property(tmp, count - (tmp - kbuf));
383*4882a593Smuzhiyun 	else if (!strcmp(kbuf, "remove_property"))
384*4882a593Smuzhiyun 		rv = do_remove_property(tmp, count - (tmp - kbuf));
385*4882a593Smuzhiyun 	else if (!strcmp(kbuf, "update_property"))
386*4882a593Smuzhiyun 		rv = do_update_property(tmp, count - (tmp - kbuf));
387*4882a593Smuzhiyun 	else
388*4882a593Smuzhiyun 		rv = -EINVAL;
389*4882a593Smuzhiyun out:
390*4882a593Smuzhiyun 	kfree(kbuf);
391*4882a593Smuzhiyun 	return rv ? rv : count;
392*4882a593Smuzhiyun }
393*4882a593Smuzhiyun 
394*4882a593Smuzhiyun static const struct proc_ops ofdt_proc_ops = {
395*4882a593Smuzhiyun 	.proc_write	= ofdt_write,
396*4882a593Smuzhiyun 	.proc_lseek	= noop_llseek,
397*4882a593Smuzhiyun };
398*4882a593Smuzhiyun 
399*4882a593Smuzhiyun /* create /proc/powerpc/ofdt write-only by root */
proc_ppc64_create_ofdt(void)400*4882a593Smuzhiyun static int proc_ppc64_create_ofdt(void)
401*4882a593Smuzhiyun {
402*4882a593Smuzhiyun 	struct proc_dir_entry *ent;
403*4882a593Smuzhiyun 
404*4882a593Smuzhiyun 	ent = proc_create("powerpc/ofdt", 0200, NULL, &ofdt_proc_ops);
405*4882a593Smuzhiyun 	if (ent)
406*4882a593Smuzhiyun 		proc_set_size(ent, 0);
407*4882a593Smuzhiyun 
408*4882a593Smuzhiyun 	return 0;
409*4882a593Smuzhiyun }
410*4882a593Smuzhiyun machine_device_initcall(pseries, proc_ppc64_create_ofdt);
411