cregit-Linux how code gets into the kernel

Release 4.14 drivers/fsi/fsi-scom.c

Directory: drivers/fsi
/*
 * SCOM FSI Client device driver
 *
 * Copyright (C) IBM Corporation 2016
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERGCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#include <linux/fsi.h>
#include <linux/module.h>
#include <linux/cdev.h>
#include <linux/delay.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
#include <linux/miscdevice.h>
#include <linux/list.h>
#include <linux/idr.h>


#define FSI_ENGID_SCOM		0x5


#define SCOM_FSI2PIB_DELAY	50

/* SCOM engine register set */

#define SCOM_DATA0_REG		0x00

#define SCOM_DATA1_REG		0x04

#define SCOM_CMD_REG		0x08

#define SCOM_RESET_REG		0x1C


#define SCOM_RESET_CMD		0x80000000

#define SCOM_WRITE_CMD		0x80000000


struct scom_device {
	
struct list_head link;
	
struct fsi_device *fsi_dev;
	
struct miscdevice mdev;
	
char	name[32];
	
int idx;
};


#define to_scom_dev(x)		container_of((x), struct scom_device, mdev)


static struct list_head scom_devices;

static DEFINE_IDA(scom_ida);


static int put_scom(struct scom_device *scom_dev, uint64_t value, uint32_t addr) { int rc; uint32_t data; data = cpu_to_be32((value >> 32) & 0xffffffff); rc = fsi_device_write(scom_dev->fsi_dev, SCOM_DATA0_REG, &data, sizeof(uint32_t)); if (rc) return rc; data = cpu_to_be32(value & 0xffffffff); rc = fsi_device_write(scom_dev->fsi_dev, SCOM_DATA1_REG, &data, sizeof(uint32_t)); if (rc) return rc; data = cpu_to_be32(SCOM_WRITE_CMD | addr); return fsi_device_write(scom_dev->fsi_dev, SCOM_CMD_REG, &data, sizeof(uint32_t)); }

Contributors

PersonTokensPropCommitsCommitProp
Christopher Bostic124100.00%1100.00%
Total124100.00%1100.00%


static int get_scom(struct scom_device *scom_dev, uint64_t *value, uint32_t addr) { uint32_t result, data; int rc; *value = 0ULL; data = cpu_to_be32(addr); rc = fsi_device_write(scom_dev->fsi_dev, SCOM_CMD_REG, &data, sizeof(uint32_t)); if (rc) return rc; rc = fsi_device_read(scom_dev->fsi_dev, SCOM_DATA0_REG, &result, sizeof(uint32_t)); if (rc) return rc; *value |= (uint64_t)cpu_to_be32(result) << 32; rc = fsi_device_read(scom_dev->fsi_dev, SCOM_DATA1_REG, &result, sizeof(uint32_t)); if (rc) return rc; *value |= cpu_to_be32(result); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Christopher Bostic140100.00%1100.00%
Total140100.00%1100.00%


static ssize_t scom_read(struct file *filep, char __user *buf, size_t len, loff_t *offset) { int rc; struct miscdevice *mdev = (struct miscdevice *)filep->private_data; struct scom_device *scom = to_scom_dev(mdev); struct device *dev = &scom->fsi_dev->dev; uint64_t val; if (len != sizeof(uint64_t)) return -EINVAL; rc = get_scom(scom, &val, *offset); if (rc) { dev_dbg(dev, "get_scom fail:%d\n", rc); return rc; } rc = copy_to_user(buf, &val, len); if (rc) dev_dbg(dev, "copy to user failed:%d\n", rc); return rc ? rc : len; }

Contributors

PersonTokensPropCommitsCommitProp
Christopher Bostic141100.00%1100.00%
Total141100.00%1100.00%


static ssize_t scom_write(struct file *filep, const char __user *buf, size_t len, loff_t *offset) { int rc; struct miscdevice *mdev = filep->private_data; struct scom_device *scom = to_scom_dev(mdev); struct device *dev = &scom->fsi_dev->dev; uint64_t val; if (len != sizeof(uint64_t)) return -EINVAL; rc = copy_from_user(&val, buf, len); if (rc) { dev_dbg(dev, "copy from user failed:%d\n", rc); return -EINVAL; } rc = put_scom(scom, val, *offset); if (rc) { dev_dbg(dev, "put_scom failed with:%d\n", rc); return rc; } return len; }

Contributors

PersonTokensPropCommitsCommitProp
Christopher Bostic138100.00%1100.00%
Total138100.00%1100.00%


static loff_t scom_llseek(struct file *file, loff_t offset, int whence) { switch (whence) { case SEEK_CUR: break; case SEEK_SET: file->f_pos = offset; break; default: return -EINVAL; } return offset; }

Contributors

PersonTokensPropCommitsCommitProp
Christopher Bostic45100.00%1100.00%
Total45100.00%1100.00%

static const struct file_operations scom_fops = { .owner = THIS_MODULE, .llseek = scom_llseek, .read = scom_read, .write = scom_write, };
static int scom_probe(struct device *dev) { uint32_t data; struct fsi_device *fsi_dev = to_fsi_dev(dev); struct scom_device *scom; scom = devm_kzalloc(dev, sizeof(*scom), GFP_KERNEL); if (!scom) return -ENOMEM; scom->idx = ida_simple_get(&scom_ida, 1, INT_MAX, GFP_KERNEL); snprintf(scom->name, sizeof(scom->name), "scom%d", scom->idx); scom->fsi_dev = fsi_dev; scom->mdev.minor = MISC_DYNAMIC_MINOR; scom->mdev.fops = &scom_fops; scom->mdev.name = scom->name; scom->mdev.parent = dev; list_add(&scom->link, &scom_devices); data = cpu_to_be32(SCOM_RESET_CMD); fsi_device_write(fsi_dev, SCOM_RESET_REG, &data, sizeof(uint32_t)); return misc_register(&scom->mdev); }

Contributors

PersonTokensPropCommitsCommitProp
Christopher Bostic14785.47%150.00%
Edward A. James2514.53%150.00%
Total172100.00%2100.00%


static int scom_remove(struct device *dev) { struct scom_device *scom, *scom_tmp; struct fsi_device *fsi_dev = to_fsi_dev(dev); list_for_each_entry_safe(scom, scom_tmp, &scom_devices, link) { if (scom->fsi_dev == fsi_dev) { list_del(&scom->link); ida_simple_remove(&scom_ida, scom->idx); misc_deregister(&scom->mdev); } } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Christopher Bostic80100.00%1100.00%
Total80100.00%1100.00%

static struct fsi_device_id scom_ids[] = { { .engine_type = FSI_ENGID_SCOM, .version = FSI_VERSION_ANY, }, { 0 } }; static struct fsi_driver scom_drv = { .id_table = scom_ids, .drv = { .name = "scom", .bus = &fsi_bus_type, .probe = scom_probe, .remove = scom_remove, } };
static int scom_init(void) { INIT_LIST_HEAD(&scom_devices); return fsi_driver_register(&scom_drv); }

Contributors

PersonTokensPropCommitsCommitProp
Christopher Bostic21100.00%1100.00%
Total21100.00%1100.00%


static void scom_exit(void) { struct list_head *pos; struct scom_device *scom; list_for_each(pos, &scom_devices) { scom = list_entry(pos, struct scom_device, link); misc_deregister(&scom->mdev); devm_kfree(&scom->fsi_dev->dev, scom); } fsi_driver_unregister(&scom_drv); }

Contributors

PersonTokensPropCommitsCommitProp
Christopher Bostic64100.00%1100.00%
Total64100.00%1100.00%

module_init(scom_init); module_exit(scom_exit); MODULE_LICENSE("GPL");

Overall Contributors

PersonTokensPropCommitsCommitProp
Christopher Bostic111497.81%150.00%
Edward A. James252.19%150.00%
Total1139100.00%2100.00%
Directory: drivers/fsi
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.