1*2aefbef0SMatt Redfearn /* 2*2aefbef0SMatt Redfearn * Remote Processor Framework 3*2aefbef0SMatt Redfearn * 4*2aefbef0SMatt Redfearn * This program is free software; you can redistribute it and/or 5*2aefbef0SMatt Redfearn * modify it under the terms of the GNU General Public License 6*2aefbef0SMatt Redfearn * version 2 as published by the Free Software Foundation. 7*2aefbef0SMatt Redfearn * 8*2aefbef0SMatt Redfearn * This program is distributed in the hope that it will be useful, 9*2aefbef0SMatt Redfearn * but WITHOUT ANY WARRANTY; without even the implied warranty of 10*2aefbef0SMatt Redfearn * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11*2aefbef0SMatt Redfearn * GNU General Public License for more details. 12*2aefbef0SMatt Redfearn */ 13*2aefbef0SMatt Redfearn 14*2aefbef0SMatt Redfearn #include <linux/remoteproc.h> 15*2aefbef0SMatt Redfearn 16*2aefbef0SMatt Redfearn #include "remoteproc_internal.h" 17*2aefbef0SMatt Redfearn 18*2aefbef0SMatt Redfearn #define to_rproc(d) container_of(d, struct rproc, dev) 19*2aefbef0SMatt Redfearn 20*2aefbef0SMatt Redfearn /* Expose the loaded / running firmware name via sysfs */ 21*2aefbef0SMatt Redfearn static ssize_t firmware_show(struct device *dev, struct device_attribute *attr, 22*2aefbef0SMatt Redfearn char *buf) 23*2aefbef0SMatt Redfearn { 24*2aefbef0SMatt Redfearn struct rproc *rproc = to_rproc(dev); 25*2aefbef0SMatt Redfearn 26*2aefbef0SMatt Redfearn return sprintf(buf, "%s\n", rproc->firmware); 27*2aefbef0SMatt Redfearn } 28*2aefbef0SMatt Redfearn 29*2aefbef0SMatt Redfearn /* Change firmware name via sysfs */ 30*2aefbef0SMatt Redfearn static ssize_t firmware_store(struct device *dev, 31*2aefbef0SMatt Redfearn struct device_attribute *attr, 32*2aefbef0SMatt Redfearn const char *buf, size_t count) 33*2aefbef0SMatt Redfearn { 34*2aefbef0SMatt Redfearn struct rproc *rproc = to_rproc(dev); 35*2aefbef0SMatt Redfearn char *p; 36*2aefbef0SMatt Redfearn int err, len = count; 37*2aefbef0SMatt Redfearn 38*2aefbef0SMatt Redfearn err = mutex_lock_interruptible(&rproc->lock); 39*2aefbef0SMatt Redfearn if (err) { 40*2aefbef0SMatt Redfearn dev_err(dev, "can't lock rproc %s: %d\n", rproc->name, err); 41*2aefbef0SMatt Redfearn return -EINVAL; 42*2aefbef0SMatt Redfearn } 43*2aefbef0SMatt Redfearn 44*2aefbef0SMatt Redfearn if (rproc->state != RPROC_OFFLINE) { 45*2aefbef0SMatt Redfearn dev_err(dev, "can't change firmware while running\n"); 46*2aefbef0SMatt Redfearn err = -EBUSY; 47*2aefbef0SMatt Redfearn goto out; 48*2aefbef0SMatt Redfearn } 49*2aefbef0SMatt Redfearn 50*2aefbef0SMatt Redfearn len = strcspn(buf, "\n"); 51*2aefbef0SMatt Redfearn 52*2aefbef0SMatt Redfearn p = kstrndup(buf, len, GFP_KERNEL); 53*2aefbef0SMatt Redfearn if (!p) { 54*2aefbef0SMatt Redfearn err = -ENOMEM; 55*2aefbef0SMatt Redfearn goto out; 56*2aefbef0SMatt Redfearn } 57*2aefbef0SMatt Redfearn 58*2aefbef0SMatt Redfearn kfree(rproc->firmware); 59*2aefbef0SMatt Redfearn rproc->firmware = p; 60*2aefbef0SMatt Redfearn out: 61*2aefbef0SMatt Redfearn mutex_unlock(&rproc->lock); 62*2aefbef0SMatt Redfearn 63*2aefbef0SMatt Redfearn return err ? err : count; 64*2aefbef0SMatt Redfearn } 65*2aefbef0SMatt Redfearn static DEVICE_ATTR_RW(firmware); 66*2aefbef0SMatt Redfearn 67*2aefbef0SMatt Redfearn /* 68*2aefbef0SMatt Redfearn * A state-to-string lookup table, for exposing a human readable state 69*2aefbef0SMatt Redfearn * via sysfs. Always keep in sync with enum rproc_state 70*2aefbef0SMatt Redfearn */ 71*2aefbef0SMatt Redfearn static const char * const rproc_state_string[] = { 72*2aefbef0SMatt Redfearn [RPROC_OFFLINE] = "offline", 73*2aefbef0SMatt Redfearn [RPROC_SUSPENDED] = "suspended", 74*2aefbef0SMatt Redfearn [RPROC_RUNNING] = "running", 75*2aefbef0SMatt Redfearn [RPROC_CRASHED] = "crashed", 76*2aefbef0SMatt Redfearn [RPROC_LAST] = "invalid", 77*2aefbef0SMatt Redfearn }; 78*2aefbef0SMatt Redfearn 79*2aefbef0SMatt Redfearn /* Expose the state of the remote processor via sysfs */ 80*2aefbef0SMatt Redfearn static ssize_t state_show(struct device *dev, struct device_attribute *attr, 81*2aefbef0SMatt Redfearn char *buf) 82*2aefbef0SMatt Redfearn { 83*2aefbef0SMatt Redfearn struct rproc *rproc = to_rproc(dev); 84*2aefbef0SMatt Redfearn unsigned int state; 85*2aefbef0SMatt Redfearn 86*2aefbef0SMatt Redfearn state = rproc->state > RPROC_LAST ? RPROC_LAST : rproc->state; 87*2aefbef0SMatt Redfearn return sprintf(buf, "%s\n", rproc_state_string[state]); 88*2aefbef0SMatt Redfearn } 89*2aefbef0SMatt Redfearn 90*2aefbef0SMatt Redfearn /* Change remote processor state via sysfs */ 91*2aefbef0SMatt Redfearn static ssize_t state_store(struct device *dev, 92*2aefbef0SMatt Redfearn struct device_attribute *attr, 93*2aefbef0SMatt Redfearn const char *buf, size_t count) 94*2aefbef0SMatt Redfearn { 95*2aefbef0SMatt Redfearn struct rproc *rproc = to_rproc(dev); 96*2aefbef0SMatt Redfearn int ret = 0; 97*2aefbef0SMatt Redfearn 98*2aefbef0SMatt Redfearn if (sysfs_streq(buf, "start")) { 99*2aefbef0SMatt Redfearn if (rproc->state == RPROC_RUNNING) 100*2aefbef0SMatt Redfearn return -EBUSY; 101*2aefbef0SMatt Redfearn 102*2aefbef0SMatt Redfearn ret = rproc_boot(rproc); 103*2aefbef0SMatt Redfearn if (ret) 104*2aefbef0SMatt Redfearn dev_err(&rproc->dev, "Boot failed: %d\n", ret); 105*2aefbef0SMatt Redfearn } else if (sysfs_streq(buf, "stop")) { 106*2aefbef0SMatt Redfearn if (rproc->state != RPROC_RUNNING) 107*2aefbef0SMatt Redfearn return -EINVAL; 108*2aefbef0SMatt Redfearn 109*2aefbef0SMatt Redfearn rproc_shutdown(rproc); 110*2aefbef0SMatt Redfearn } else { 111*2aefbef0SMatt Redfearn dev_err(&rproc->dev, "Unrecognised option: %s\n", buf); 112*2aefbef0SMatt Redfearn ret = -EINVAL; 113*2aefbef0SMatt Redfearn } 114*2aefbef0SMatt Redfearn return ret ? ret : count; 115*2aefbef0SMatt Redfearn } 116*2aefbef0SMatt Redfearn static DEVICE_ATTR_RW(state); 117*2aefbef0SMatt Redfearn 118*2aefbef0SMatt Redfearn static struct attribute *rproc_attrs[] = { 119*2aefbef0SMatt Redfearn &dev_attr_firmware.attr, 120*2aefbef0SMatt Redfearn &dev_attr_state.attr, 121*2aefbef0SMatt Redfearn NULL 122*2aefbef0SMatt Redfearn }; 123*2aefbef0SMatt Redfearn 124*2aefbef0SMatt Redfearn static const struct attribute_group rproc_devgroup = { 125*2aefbef0SMatt Redfearn .attrs = rproc_attrs 126*2aefbef0SMatt Redfearn }; 127*2aefbef0SMatt Redfearn 128*2aefbef0SMatt Redfearn static const struct attribute_group *rproc_devgroups[] = { 129*2aefbef0SMatt Redfearn &rproc_devgroup, 130*2aefbef0SMatt Redfearn NULL 131*2aefbef0SMatt Redfearn }; 132*2aefbef0SMatt Redfearn 133*2aefbef0SMatt Redfearn struct class rproc_class = { 134*2aefbef0SMatt Redfearn .name = "remoteproc", 135*2aefbef0SMatt Redfearn .dev_groups = rproc_devgroups, 136*2aefbef0SMatt Redfearn }; 137*2aefbef0SMatt Redfearn 138*2aefbef0SMatt Redfearn int __init rproc_init_sysfs(void) 139*2aefbef0SMatt Redfearn { 140*2aefbef0SMatt Redfearn /* create remoteproc device class for sysfs */ 141*2aefbef0SMatt Redfearn int err = class_register(&rproc_class); 142*2aefbef0SMatt Redfearn 143*2aefbef0SMatt Redfearn if (err) 144*2aefbef0SMatt Redfearn pr_err("remoteproc: unable to register class\n"); 145*2aefbef0SMatt Redfearn return err; 146*2aefbef0SMatt Redfearn } 147*2aefbef0SMatt Redfearn 148*2aefbef0SMatt Redfearn void __exit rproc_exit_sysfs(void) 149*2aefbef0SMatt Redfearn { 150*2aefbef0SMatt Redfearn class_unregister(&rproc_class); 151*2aefbef0SMatt Redfearn } 152