root/drivers/misc/ibmasm/ibmasmfs.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ibmasmfs_get_tree
  2. ibmasmfs_init_fs_context
  3. ibmasmfs_fill_super
  4. ibmasmfs_make_inode
  5. ibmasmfs_create_file
  6. ibmasmfs_create_dir
  7. ibmasmfs_register
  8. ibmasmfs_unregister
  9. ibmasmfs_add_sp
  10. command_file_open
  11. command_file_close
  12. command_file_read
  13. command_file_write
  14. event_file_open
  15. event_file_close
  16. event_file_read
  17. event_file_write
  18. r_heartbeat_file_open
  19. r_heartbeat_file_close
  20. r_heartbeat_file_read
  21. r_heartbeat_file_write
  22. remote_settings_file_close
  23. remote_settings_file_read
  24. remote_settings_file_write
  25. ibmasmfs_create_files

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

/* [<][>][^][v][top][bottom][index][help] */