Skip to content

Commit d1dcd67

Browse files
committed
fsi: Add cfam char devices
This aims to deprecate the "raw" sysfs file used for directly accessing the CFAM and instead use a char device like the other sub drivers. Since it reworks the slave creation code and adds a cfam device type, we also use the opportunity to convert the attributes to attribute groups and add a couple more. Signed-off-by: Benjamin Herrenschmidt <[email protected]>
1 parent d8f4587 commit d1dcd67

File tree

1 file changed

+213
-51
lines changed

1 file changed

+213
-51
lines changed

drivers/fsi/fsi-core.c

Lines changed: 213 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@
1111
* but WITHOUT ANY WARRANTY; without even the implied warranty of
1212
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1313
* GNU General Public License for more details.
14+
*
15+
* TODO:
16+
* - Rework topology
17+
* - s/chip_id/chip_loc
18+
* - s/cfam/chip (cfam_id -> chip_id etc...)
1419
*/
1520

1621
#include <linux/crc4.h>
@@ -21,6 +26,9 @@
2126
#include <linux/of.h>
2227
#include <linux/slab.h>
2328
#include <linux/bitops.h>
29+
#include <linux/cdev.h>
30+
#include <linux/fs.h>
31+
#include <linux/uaccess.h>
2432

2533
#include "fsi-master.h"
2634

@@ -78,8 +86,11 @@ static DEFINE_IDA(master_ida);
7886
struct fsi_slave {
7987
struct device dev;
8088
struct fsi_master *master;
81-
int id;
82-
int link;
89+
struct cdev cdev;
90+
int cdev_idx;
91+
int id; /* FSI address */
92+
int link; /* FSI link# */
93+
u32 cfam_id;
8394
int chip_id;
8495
uint32_t size; /* size of slave address space */
8596
u8 t_send_delay;
@@ -607,29 +618,6 @@ static const struct bin_attribute fsi_slave_raw_attr = {
607618
.write = fsi_slave_sysfs_raw_write,
608619
};
609620

610-
static ssize_t fsi_slave_sysfs_term_write(struct file *file,
611-
struct kobject *kobj, struct bin_attribute *attr,
612-
char *buf, loff_t off, size_t count)
613-
{
614-
struct fsi_slave *slave = to_fsi_slave(kobj_to_dev(kobj));
615-
struct fsi_master *master = slave->master;
616-
617-
if (!master->term)
618-
return -ENODEV;
619-
620-
master->term(master, slave->link, slave->id);
621-
return count;
622-
}
623-
624-
static const struct bin_attribute fsi_slave_term_attr = {
625-
.attr = {
626-
.name = "term",
627-
.mode = 0200,
628-
},
629-
.size = 0,
630-
.write = fsi_slave_sysfs_term_write,
631-
};
632-
633621
static void fsi_slave_release(struct device *dev)
634622
{
635623
struct fsi_slave *slave = to_fsi_slave(dev);
@@ -682,6 +670,127 @@ static struct device_node *fsi_slave_find_of_node(struct fsi_master *master,
682670
return NULL;
683671
}
684672

673+
static ssize_t cfam_read(struct file *filep, char __user *buf, size_t count,
674+
loff_t *offset)
675+
{
676+
struct fsi_slave *slave = filep->private_data;
677+
size_t total_len, read_len;
678+
loff_t off = *offset;
679+
ssize_t rc;
680+
681+
if (off < 0)
682+
return -EINVAL;
683+
684+
if (off > 0xffffffff || count > 0xffffffff || off + count > 0xffffffff)
685+
return -EINVAL;
686+
687+
for (total_len = 0; total_len < count; total_len += read_len) {
688+
__be32 data;
689+
690+
read_len = min_t(size_t, count, 4);
691+
read_len -= off & 0x3;
692+
693+
rc = fsi_slave_read(slave, off, &data, read_len);
694+
if (rc)
695+
goto fail;
696+
rc = copy_to_user(buf + total_len, &data, read_len);
697+
if (rc) {
698+
rc = -EFAULT;
699+
goto fail;
700+
}
701+
off += read_len;
702+
}
703+
rc = count;
704+
fail:
705+
*offset = off;
706+
return count;
707+
}
708+
709+
static ssize_t cfam_write(struct file *filep, const char __user *buf,
710+
size_t count, loff_t *offset)
711+
{
712+
struct fsi_slave *slave = filep->private_data;
713+
size_t total_len, write_len;
714+
loff_t off = *offset;
715+
ssize_t rc;
716+
717+
718+
if (off < 0)
719+
return -EINVAL;
720+
721+
if (off > 0xffffffff || count > 0xffffffff || off + count > 0xffffffff)
722+
return -EINVAL;
723+
724+
for (total_len = 0; total_len < count; total_len += write_len) {
725+
__be32 data;
726+
727+
write_len = min_t(size_t, count, 4);
728+
write_len -= off & 0x3;
729+
730+
rc = copy_from_user(&data, buf + total_len, write_len);
731+
if (rc) {
732+
rc = -EFAULT;
733+
goto fail;
734+
}
735+
rc = fsi_slave_write(slave, off, &data, write_len);
736+
if (rc)
737+
goto fail;
738+
off += write_len;
739+
}
740+
rc = count;
741+
fail:
742+
*offset = off;
743+
return count;
744+
}
745+
746+
static loff_t cfam_llseek(struct file *file, loff_t offset, int whence)
747+
{
748+
switch (whence) {
749+
case SEEK_CUR:
750+
break;
751+
case SEEK_SET:
752+
file->f_pos = offset;
753+
break;
754+
default:
755+
return -EINVAL;
756+
}
757+
758+
return offset;
759+
}
760+
761+
static int cfam_open(struct inode *inode, struct file *file)
762+
{
763+
struct fsi_slave *slave = container_of(inode->i_cdev, struct fsi_slave, cdev);
764+
765+
file->private_data = slave;
766+
767+
return 0;
768+
}
769+
770+
static const struct file_operations cfam_fops = {
771+
.owner = THIS_MODULE,
772+
.open = cfam_open,
773+
.llseek = cfam_llseek,
774+
.read = cfam_read,
775+
.write = cfam_write,
776+
};
777+
778+
static ssize_t send_term_store(struct device *dev,
779+
struct device_attribute *attr,
780+
const char *buf, size_t count)
781+
{
782+
struct fsi_slave *slave = to_fsi_slave(dev);
783+
struct fsi_master *master = slave->master;
784+
785+
if (!master->term)
786+
return -ENODEV;
787+
788+
master->term(master, slave->link, slave->id);
789+
return count;
790+
}
791+
792+
static DEVICE_ATTR_WO(send_term);
793+
685794
static ssize_t slave_send_echo_show(struct device *dev,
686795
struct device_attribute *attr,
687796
char *buf)
@@ -737,6 +846,52 @@ static ssize_t chip_id_show(struct device *dev,
737846

738847
static DEVICE_ATTR_RO(chip_id);
739848

849+
static ssize_t cfam_id_show(struct device *dev,
850+
struct device_attribute *attr,
851+
char *buf)
852+
{
853+
struct fsi_slave *slave = to_fsi_slave(dev);
854+
855+
return sprintf(buf, "0x%x\n", slave->cfam_id);
856+
}
857+
858+
static DEVICE_ATTR_RO(cfam_id);
859+
860+
static struct attribute *cfam_attr[] = {
861+
&dev_attr_send_echo_delays.attr,
862+
&dev_attr_chip_id.attr,
863+
&dev_attr_cfam_id.attr,
864+
&dev_attr_send_term.attr,
865+
NULL,
866+
};
867+
868+
static const struct attribute_group cfam_attr_group = {
869+
.attrs = cfam_attr,
870+
};
871+
872+
static const struct attribute_group *cfam_attr_groups[] = {
873+
&cfam_attr_group,
874+
NULL,
875+
};
876+
877+
static char *cfam_devnode(struct device *dev, umode_t *mode,
878+
kuid_t *uid, kgid_t *gid)
879+
{
880+
struct fsi_slave *slave = to_fsi_slave(dev);
881+
882+
#ifdef CONFIG_FSI_NEW_DEV_NODE
883+
return kasprintf(GFP_KERNEL, "fsi/cfam%d", slave->cdev_idx);
884+
#else
885+
return kasprintf(GFP_KERNEL, "cfam%d", slave->cdev_idx);
886+
#endif
887+
}
888+
889+
static const struct device_type cfam_type = {
890+
.name = "cfam",
891+
.devnode = cfam_devnode,
892+
.groups = cfam_attr_groups
893+
};
894+
740895
static char *fsi_cdev_devnode(struct device *dev, umode_t *mode,
741896
kuid_t *uid, kgid_t *gid)
742897
{
@@ -808,7 +963,7 @@ EXPORT_SYMBOL_GPL(fsi_free_minor);
808963

809964
static int fsi_slave_init(struct fsi_master *master, int link, uint8_t id)
810965
{
811-
uint32_t chip_id;
966+
uint32_t cfam_id;
812967
struct fsi_slave *slave;
813968
uint8_t crc;
814969
__be32 data, llmode;
@@ -826,17 +981,17 @@ static int fsi_slave_init(struct fsi_master *master, int link, uint8_t id)
826981
link, id, rc);
827982
return -ENODEV;
828983
}
829-
chip_id = be32_to_cpu(data);
984+
cfam_id = be32_to_cpu(data);
830985

831-
crc = crc4(0, chip_id, 32);
986+
crc = crc4(0, cfam_id, 32);
832987
if (crc) {
833-
dev_warn(&master->dev, "slave %02x:%02x invalid chip id CRC!\n",
988+
dev_warn(&master->dev, "slave %02x:%02x invalid cfam id CRC!\n",
834989
link, id);
835990
return -EIO;
836991
}
837992

838993
dev_dbg(&master->dev, "fsi: found chip %08x at %02x:%02x:%02x\n",
839-
chip_id, master->idx, link, id);
994+
cfam_id, master->idx, link, id);
840995

841996
/* If we're behind a master that doesn't provide a self-running bus
842997
* clock, put the slave into async mode
@@ -859,10 +1014,14 @@ static int fsi_slave_init(struct fsi_master *master, int link, uint8_t id)
8591014
if (!slave)
8601015
return -ENOMEM;
8611016

862-
slave->master = master;
1017+
dev_set_name(&slave->dev, "slave@%02x:%02x", link, id);
1018+
slave->dev.type = &cfam_type;
8631019
slave->dev.parent = &master->dev;
8641020
slave->dev.of_node = fsi_slave_find_of_node(master, link, id);
8651021
slave->dev.release = fsi_slave_release;
1022+
device_initialize(&slave->dev);
1023+
slave->cfam_id = cfam_id;
1024+
slave->master = master;
8661025
slave->link = link;
8671026
slave->id = id;
8681027
slave->size = FSI_SLAVE_SIZE_23b;
@@ -877,6 +1036,21 @@ static int fsi_slave_init(struct fsi_master *master, int link, uint8_t id)
8771036
slave->chip_id = prop;
8781037

8791038
}
1039+
1040+
/* Allocate a minor in the FSI space */
1041+
rc = __fsi_get_new_minor(slave, fsi_dev_cfam, &slave->dev.devt,
1042+
&slave->cdev_idx);
1043+
if (rc)
1044+
goto err_free;
1045+
1046+
/* Create chardev for userspace access */
1047+
cdev_init(&slave->cdev, &cfam_fops);
1048+
rc = cdev_device_add(&slave->cdev, &slave->dev);
1049+
if (rc) {
1050+
dev_err(&slave->dev, "Error %d creating slave device\n", rc);
1051+
goto err_free;
1052+
}
1053+
8801054
rc = fsi_slave_set_smode(slave);
8811055
if (rc) {
8821056
dev_warn(&master->dev,
@@ -890,37 +1064,22 @@ static int fsi_slave_init(struct fsi_master *master, int link, uint8_t id)
8901064
slave->t_send_delay,
8911065
slave->t_echo_delay);
8921066

893-
dev_set_name(&slave->dev, "slave@%02x:%02x", link, id);
894-
rc = device_register(&slave->dev);
895-
if (rc < 0) {
896-
dev_warn(&master->dev, "failed to create slave device: %d\n",
897-
rc);
898-
put_device(&slave->dev);
899-
return rc;
900-
}
901-
1067+
/* Legacy raw file -> to be removed */
9021068
rc = device_create_bin_file(&slave->dev, &fsi_slave_raw_attr);
9031069
if (rc)
9041070
dev_warn(&slave->dev, "failed to create raw attr: %d\n", rc);
9051071

906-
rc = device_create_bin_file(&slave->dev, &fsi_slave_term_attr);
907-
if (rc)
908-
dev_warn(&slave->dev, "failed to create term attr: %d\n", rc);
909-
910-
rc = device_create_file(&slave->dev, &dev_attr_send_echo_delays);
911-
if (rc)
912-
dev_warn(&slave->dev, "failed to create delay attr: %d\n", rc);
913-
914-
rc = device_create_file(&slave->dev, &dev_attr_chip_id);
915-
if (rc)
916-
dev_warn(&slave->dev, "failed to create chip id: %d\n", rc);
9171072

9181073
rc = fsi_slave_scan(slave);
9191074
if (rc)
9201075
dev_dbg(&master->dev, "failed during slave scan with: %d\n",
9211076
rc);
9221077

9231078
return rc;
1079+
1080+
err_free:
1081+
put_device(&slave->dev);
1082+
return rc;
9241083
}
9251084

9261085
/* FSI master support */
@@ -1029,7 +1188,10 @@ static int fsi_slave_remove_device(struct device *dev, void *arg)
10291188

10301189
static int fsi_master_remove_slave(struct device *dev, void *arg)
10311190
{
1191+
struct fsi_slave *slave = to_fsi_slave(dev);
1192+
10321193
device_for_each_child(dev, NULL, fsi_slave_remove_device);
1194+
cdev_device_del(&slave->cdev, &slave->dev);
10331195
put_device(dev);
10341196
return 0;
10351197
}

0 commit comments

Comments
 (0)