xref: /openbmc/linux/drivers/misc/ibmasm/ibmasmfs.c (revision 64c70b1c)
1 /*
2  * IBM ASM Service Processor Device Driver
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17  *
18  * Copyright (C) IBM Corporation, 2004
19  *
20  * Author: Max Asb�ck <amax@us.ibm.com>
21  *
22  */
23 
24 /*
25  * Parts of this code are based on an article by Jonathan Corbet
26  * that appeared in Linux Weekly News.
27  */
28 
29 
30 /*
31  * The IBMASM file virtual filesystem. It creates the following hierarchy
32  * dymamically when mounted from user space:
33  *
34  *    /ibmasm
35  *    |-- 0
36  *    |   |-- command
37  *    |   |-- event
38  *    |   |-- reverse_heartbeat
39  *    |   `-- remote_video
40  *    |       |-- depth
41  *    |       |-- height
42  *    |       `-- width
43  *    .
44  *    .
45  *    .
46  *    `-- n
47  *        |-- command
48  *        |-- event
49  *        |-- reverse_heartbeat
50  *        `-- remote_video
51  *            |-- depth
52  *            |-- height
53  *            `-- width
54  *
55  * For each service processor the following files are created:
56  *
57  * command: execute dot commands
58  * 	write: execute a dot command on the service processor
59  * 	read: return the result of a previously executed dot command
60  *
61  * events: listen for service processor events
62  * 	read: sleep (interruptible) until an event occurs
63  *      write: wakeup sleeping event listener
64  *
65  * reverse_heartbeat: send a heartbeat to the service processor
66  * 	read: sleep (interruptible) until the reverse heartbeat fails
67  *      write: wakeup sleeping heartbeat listener
68  *
69  * remote_video/width
70  * remote_video/height
71  * remote_video/width: control remote display settings
72  * 	write: set value
73  * 	read: read value
74  */
75 
76 #include <linux/fs.h>
77 #include <linux/pagemap.h>
78 #include <asm/uaccess.h>
79 #include <asm/io.h>
80 #include "ibmasm.h"
81 #include "remote.h"
82 #include "dot_command.h"
83 
84 #define IBMASMFS_MAGIC 0x66726f67
85 
86 static LIST_HEAD(service_processors);
87 
88 static struct inode *ibmasmfs_make_inode(struct super_block *sb, int mode);
89 static void ibmasmfs_create_files (struct super_block *sb, struct dentry *root);
90 static int ibmasmfs_fill_super (struct super_block *sb, void *data, int silent);
91 
92 
93 static int ibmasmfs_get_super(struct file_system_type *fst,
94 			int flags, const char *name, void *data,
95 			struct vfsmount *mnt)
96 {
97 	return get_sb_single(fst, flags, data, ibmasmfs_fill_super, mnt);
98 }
99 
100 static struct super_operations ibmasmfs_s_ops = {
101 	.statfs		= simple_statfs,
102 	.drop_inode	= generic_delete_inode,
103 };
104 
105 static const struct file_operations *ibmasmfs_dir_ops = &simple_dir_operations;
106 
107 static struct file_system_type ibmasmfs_type = {
108 	.owner          = THIS_MODULE,
109 	.name           = "ibmasmfs",
110 	.get_sb         = ibmasmfs_get_super,
111 	.kill_sb        = kill_litter_super,
112 };
113 
114 static int ibmasmfs_fill_super (struct super_block *sb, void *data, int silent)
115 {
116 	struct inode *root;
117 	struct dentry *root_dentry;
118 
119 	sb->s_blocksize = PAGE_CACHE_SIZE;
120 	sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
121 	sb->s_magic = IBMASMFS_MAGIC;
122 	sb->s_op = &ibmasmfs_s_ops;
123 	sb->s_time_gran = 1;
124 
125 	root = ibmasmfs_make_inode (sb, S_IFDIR | 0500);
126 	if (!root)
127 		return -ENOMEM;
128 
129 	root->i_op = &simple_dir_inode_operations;
130 	root->i_fop = ibmasmfs_dir_ops;
131 
132 	root_dentry = d_alloc_root(root);
133 	if (!root_dentry) {
134 		iput(root);
135 		return -ENOMEM;
136 	}
137 	sb->s_root = root_dentry;
138 
139 	ibmasmfs_create_files(sb, root_dentry);
140 	return 0;
141 }
142 
143 static struct inode *ibmasmfs_make_inode(struct super_block *sb, int mode)
144 {
145 	struct inode *ret = new_inode(sb);
146 
147 	if (ret) {
148 		ret->i_mode = mode;
149 		ret->i_uid = ret->i_gid = 0;
150 		ret->i_blocks = 0;
151 		ret->i_atime = ret->i_mtime = ret->i_ctime = CURRENT_TIME;
152 	}
153 	return ret;
154 }
155 
156 static struct dentry *ibmasmfs_create_file (struct super_block *sb,
157 			struct dentry *parent,
158 		       	const char *name,
159 			const struct file_operations *fops,
160 			void *data,
161 			int mode)
162 {
163 	struct dentry *dentry;
164 	struct inode *inode;
165 
166 	dentry = d_alloc_name(parent, name);
167 	if (!dentry)
168 		return NULL;
169 
170 	inode = ibmasmfs_make_inode(sb, S_IFREG | mode);
171 	if (!inode) {
172 		dput(dentry);
173 		return NULL;
174 	}
175 
176 	inode->i_fop = fops;
177 	inode->i_private = data;
178 
179 	d_add(dentry, inode);
180 	return dentry;
181 }
182 
183 static struct dentry *ibmasmfs_create_dir (struct super_block *sb,
184 				struct dentry *parent,
185 				const char *name)
186 {
187 	struct dentry *dentry;
188 	struct inode *inode;
189 
190 	dentry = d_alloc_name(parent, name);
191 	if (!dentry)
192 		return NULL;
193 
194 	inode = ibmasmfs_make_inode(sb, S_IFDIR | 0500);
195 	if (!inode) {
196 		dput(dentry);
197 		return NULL;
198 	}
199 
200 	inode->i_op = &simple_dir_inode_operations;
201 	inode->i_fop = ibmasmfs_dir_ops;
202 
203 	d_add(dentry, inode);
204 	return dentry;
205 }
206 
207 int ibmasmfs_register(void)
208 {
209 	return register_filesystem(&ibmasmfs_type);
210 }
211 
212 void ibmasmfs_unregister(void)
213 {
214 	unregister_filesystem(&ibmasmfs_type);
215 }
216 
217 void ibmasmfs_add_sp(struct service_processor *sp)
218 {
219 	list_add(&sp->node, &service_processors);
220 }
221 
222 /* struct to save state between command file operations */
223 struct ibmasmfs_command_data {
224 	struct service_processor	*sp;
225 	struct command			*command;
226 };
227 
228 /* struct to save state between event file operations */
229 struct ibmasmfs_event_data {
230 	struct service_processor	*sp;
231 	struct event_reader		reader;
232 	int				active;
233 };
234 
235 /* struct to save state between reverse heartbeat file operations */
236 struct ibmasmfs_heartbeat_data {
237 	struct service_processor	*sp;
238 	struct reverse_heartbeat	heartbeat;
239 	int				active;
240 };
241 
242 static int command_file_open(struct inode *inode, struct file *file)
243 {
244 	struct ibmasmfs_command_data *command_data;
245 
246 	if (!inode->i_private)
247 		return -ENODEV;
248 
249 	command_data = kmalloc(sizeof(struct ibmasmfs_command_data), GFP_KERNEL);
250 	if (!command_data)
251 		return -ENOMEM;
252 
253 	command_data->command = NULL;
254 	command_data->sp = inode->i_private;
255 	file->private_data = command_data;
256 	return 0;
257 }
258 
259 static int command_file_close(struct inode *inode, struct file *file)
260 {
261 	struct ibmasmfs_command_data *command_data = file->private_data;
262 
263 	if (command_data->command)
264 		command_put(command_data->command);
265 
266 	kfree(command_data);
267 	return 0;
268 }
269 
270 static ssize_t command_file_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
271 {
272 	struct ibmasmfs_command_data *command_data = file->private_data;
273 	struct command *cmd;
274 	int len;
275 	unsigned long flags;
276 
277 	if (*offset < 0)
278 		return -EINVAL;
279 	if (count == 0 || count > IBMASM_CMD_MAX_BUFFER_SIZE)
280 		return 0;
281 	if (*offset != 0)
282 		return 0;
283 
284 	spin_lock_irqsave(&command_data->sp->lock, flags);
285 	cmd = command_data->command;
286 	if (cmd == NULL) {
287 		spin_unlock_irqrestore(&command_data->sp->lock, flags);
288 		return 0;
289 	}
290 	command_data->command = NULL;
291 	spin_unlock_irqrestore(&command_data->sp->lock, flags);
292 
293 	if (cmd->status != IBMASM_CMD_COMPLETE) {
294 		command_put(cmd);
295 		return -EIO;
296 	}
297 	len = min(count, cmd->buffer_size);
298 	if (copy_to_user(buf, cmd->buffer, len)) {
299 		command_put(cmd);
300 		return -EFAULT;
301 	}
302 	command_put(cmd);
303 
304 	return len;
305 }
306 
307 static ssize_t command_file_write(struct file *file, const char __user *ubuff, size_t count, loff_t *offset)
308 {
309 	struct ibmasmfs_command_data *command_data = file->private_data;
310 	struct command *cmd;
311 	unsigned long flags;
312 
313 	if (*offset < 0)
314 		return -EINVAL;
315 	if (count == 0 || count > IBMASM_CMD_MAX_BUFFER_SIZE)
316 		return 0;
317 	if (*offset != 0)
318 		return 0;
319 
320 	/* commands are executed sequentially, only one command at a time */
321 	if (command_data->command)
322 		return -EAGAIN;
323 
324 	cmd = ibmasm_new_command(command_data->sp, count);
325 	if (!cmd)
326 		return -ENOMEM;
327 
328 	if (copy_from_user(cmd->buffer, ubuff, count)) {
329 		command_put(cmd);
330 		return -EFAULT;
331 	}
332 
333 	spin_lock_irqsave(&command_data->sp->lock, flags);
334 	if (command_data->command) {
335 		spin_unlock_irqrestore(&command_data->sp->lock, flags);
336 		command_put(cmd);
337 		return -EAGAIN;
338 	}
339 	command_data->command = cmd;
340 	spin_unlock_irqrestore(&command_data->sp->lock, flags);
341 
342 	ibmasm_exec_command(command_data->sp, cmd);
343 	ibmasm_wait_for_response(cmd, get_dot_command_timeout(cmd->buffer));
344 
345 	return count;
346 }
347 
348 static int event_file_open(struct inode *inode, struct file *file)
349 {
350 	struct ibmasmfs_event_data *event_data;
351 	struct service_processor *sp;
352 
353 	if (!inode->i_private)
354 		return -ENODEV;
355 
356 	sp = inode->i_private;
357 
358 	event_data = kmalloc(sizeof(struct ibmasmfs_event_data), GFP_KERNEL);
359 	if (!event_data)
360 		return -ENOMEM;
361 
362 	ibmasm_event_reader_register(sp, &event_data->reader);
363 
364 	event_data->sp = sp;
365 	event_data->active = 0;
366 	file->private_data = event_data;
367 	return 0;
368 }
369 
370 static int event_file_close(struct inode *inode, struct file *file)
371 {
372 	struct ibmasmfs_event_data *event_data = file->private_data;
373 
374 	ibmasm_event_reader_unregister(event_data->sp, &event_data->reader);
375 	kfree(event_data);
376 	return 0;
377 }
378 
379 static ssize_t event_file_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
380 {
381 	struct ibmasmfs_event_data *event_data = file->private_data;
382 	struct event_reader *reader = &event_data->reader;
383 	struct service_processor *sp = event_data->sp;
384 	int ret;
385 	unsigned long flags;
386 
387 	if (*offset < 0)
388 		return -EINVAL;
389 	if (count == 0 || count > IBMASM_EVENT_MAX_SIZE)
390 		return 0;
391 	if (*offset != 0)
392 		return 0;
393 
394 	spin_lock_irqsave(&sp->lock, flags);
395 	if (event_data->active) {
396 		spin_unlock_irqrestore(&sp->lock, flags);
397 		return -EBUSY;
398 	}
399 	event_data->active = 1;
400 	spin_unlock_irqrestore(&sp->lock, flags);
401 
402 	ret = ibmasm_get_next_event(sp, reader);
403 	if (ret <= 0)
404 		goto out;
405 
406 	if (count < reader->data_size) {
407 		ret = -EINVAL;
408 		goto out;
409 	}
410 
411         if (copy_to_user(buf, reader->data, reader->data_size)) {
412 		ret = -EFAULT;
413 		goto out;
414 	}
415 	ret = reader->data_size;
416 
417 out:
418 	event_data->active = 0;
419 	return ret;
420 }
421 
422 static ssize_t event_file_write(struct file *file, const char __user *buf, size_t count, loff_t *offset)
423 {
424 	struct ibmasmfs_event_data *event_data = file->private_data;
425 
426 	if (*offset < 0)
427 		return -EINVAL;
428 	if (count != 1)
429 		return 0;
430 	if (*offset != 0)
431 		return 0;
432 
433 	ibmasm_cancel_next_event(&event_data->reader);
434 	return 0;
435 }
436 
437 static int r_heartbeat_file_open(struct inode *inode, struct file *file)
438 {
439 	struct ibmasmfs_heartbeat_data *rhbeat;
440 
441 	if (!inode->i_private)
442 		return -ENODEV;
443 
444 	rhbeat = kmalloc(sizeof(struct ibmasmfs_heartbeat_data), GFP_KERNEL);
445 	if (!rhbeat)
446 		return -ENOMEM;
447 
448 	rhbeat->sp = inode->i_private;
449 	rhbeat->active = 0;
450 	ibmasm_init_reverse_heartbeat(rhbeat->sp, &rhbeat->heartbeat);
451 	file->private_data = rhbeat;
452 	return 0;
453 }
454 
455 static int r_heartbeat_file_close(struct inode *inode, struct file *file)
456 {
457 	struct ibmasmfs_heartbeat_data *rhbeat = file->private_data;
458 
459 	kfree(rhbeat);
460 	return 0;
461 }
462 
463 static ssize_t r_heartbeat_file_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
464 {
465 	struct ibmasmfs_heartbeat_data *rhbeat = file->private_data;
466 	unsigned long flags;
467 	int result;
468 
469 	if (*offset < 0)
470 		return -EINVAL;
471 	if (count == 0 || count > 1024)
472 		return 0;
473 	if (*offset != 0)
474 		return 0;
475 
476 	/* allow only one reverse heartbeat per process */
477 	spin_lock_irqsave(&rhbeat->sp->lock, flags);
478 	if (rhbeat->active) {
479 		spin_unlock_irqrestore(&rhbeat->sp->lock, flags);
480 		return -EBUSY;
481 	}
482 	rhbeat->active = 1;
483 	spin_unlock_irqrestore(&rhbeat->sp->lock, flags);
484 
485 	result = ibmasm_start_reverse_heartbeat(rhbeat->sp, &rhbeat->heartbeat);
486 	rhbeat->active = 0;
487 
488 	return result;
489 }
490 
491 static ssize_t r_heartbeat_file_write(struct file *file, const char __user *buf, size_t count, loff_t *offset)
492 {
493 	struct ibmasmfs_heartbeat_data *rhbeat = file->private_data;
494 
495 	if (*offset < 0)
496 		return -EINVAL;
497 	if (count != 1)
498 		return 0;
499 	if (*offset != 0)
500 		return 0;
501 
502 	if (rhbeat->active)
503 		ibmasm_stop_reverse_heartbeat(&rhbeat->heartbeat);
504 
505 	return 1;
506 }
507 
508 static int remote_settings_file_open(struct inode *inode, struct file *file)
509 {
510 	file->private_data = inode->i_private;
511 	return 0;
512 }
513 
514 static int remote_settings_file_close(struct inode *inode, struct file *file)
515 {
516 	return 0;
517 }
518 
519 static ssize_t remote_settings_file_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
520 {
521 	void __iomem *address = (void __iomem *)file->private_data;
522 	unsigned char *page;
523 	int retval;
524 	int len = 0;
525 	unsigned int value;
526 
527 	if (*offset < 0)
528 		return -EINVAL;
529 	if (count == 0 || count > 1024)
530 		return 0;
531 	if (*offset != 0)
532 		return 0;
533 
534 	page = (unsigned char *)__get_free_page(GFP_KERNEL);
535 	if (!page)
536 		return -ENOMEM;
537 
538 	value = readl(address);
539 	len = sprintf(page, "%d\n", value);
540 
541 	if (copy_to_user(buf, page, len)) {
542 		retval = -EFAULT;
543 		goto exit;
544 	}
545 	*offset += len;
546 	retval = len;
547 
548 exit:
549 	free_page((unsigned long)page);
550 	return retval;
551 }
552 
553 static ssize_t remote_settings_file_write(struct file *file, const char __user *ubuff, size_t count, loff_t *offset)
554 {
555 	void __iomem *address = (void __iomem *)file->private_data;
556 	char *buff;
557 	unsigned int value;
558 
559 	if (*offset < 0)
560 		return -EINVAL;
561 	if (count == 0 || count > 1024)
562 		return 0;
563 	if (*offset != 0)
564 		return 0;
565 
566 	buff = kmalloc (count + 1, GFP_KERNEL);
567 	if (!buff)
568 		return -ENOMEM;
569 
570 	memset(buff, 0x0, count + 1);
571 
572 	if (copy_from_user(buff, ubuff, count)) {
573 		kfree(buff);
574 		return -EFAULT;
575 	}
576 
577 	value = simple_strtoul(buff, NULL, 10);
578 	writel(value, address);
579 	kfree(buff);
580 
581 	return count;
582 }
583 
584 static const struct file_operations command_fops = {
585 	.open =		command_file_open,
586 	.release =	command_file_close,
587 	.read =		command_file_read,
588 	.write =	command_file_write,
589 };
590 
591 static const struct file_operations event_fops = {
592 	.open =		event_file_open,
593 	.release =	event_file_close,
594 	.read =		event_file_read,
595 	.write =	event_file_write,
596 };
597 
598 static const struct file_operations r_heartbeat_fops = {
599 	.open =		r_heartbeat_file_open,
600 	.release =	r_heartbeat_file_close,
601 	.read =		r_heartbeat_file_read,
602 	.write =	r_heartbeat_file_write,
603 };
604 
605 static const struct file_operations remote_settings_fops = {
606 	.open =		remote_settings_file_open,
607 	.release =	remote_settings_file_close,
608 	.read =		remote_settings_file_read,
609 	.write =	remote_settings_file_write,
610 };
611 
612 
613 static void ibmasmfs_create_files (struct super_block *sb, struct dentry *root)
614 {
615 	struct list_head *entry;
616 	struct service_processor *sp;
617 
618 	list_for_each(entry, &service_processors) {
619 		struct dentry *dir;
620 		struct dentry *remote_dir;
621 		sp = list_entry(entry, struct service_processor, node);
622 		dir = ibmasmfs_create_dir(sb, root, sp->dirname);
623 		if (!dir)
624 			continue;
625 
626 		ibmasmfs_create_file(sb, dir, "command", &command_fops, sp, S_IRUSR|S_IWUSR);
627 		ibmasmfs_create_file(sb, dir, "event", &event_fops, sp, S_IRUSR|S_IWUSR);
628 		ibmasmfs_create_file(sb, dir, "reverse_heartbeat", &r_heartbeat_fops, sp, S_IRUSR|S_IWUSR);
629 
630 		remote_dir = ibmasmfs_create_dir(sb, dir, "remote_video");
631 		if (!remote_dir)
632 			continue;
633 
634 		ibmasmfs_create_file(sb, remote_dir, "width", &remote_settings_fops, (void *)display_width(sp), S_IRUSR|S_IWUSR);
635 		ibmasmfs_create_file(sb, remote_dir, "height", &remote_settings_fops, (void *)display_height(sp), S_IRUSR|S_IWUSR);
636 		ibmasmfs_create_file(sb, remote_dir, "depth", &remote_settings_fops, (void *)display_depth(sp), S_IRUSR|S_IWUSR);
637 	}
638 }
639