aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/most/mostcore/core.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/most/mostcore/core.c')
-rw-r--r--drivers/staging/most/mostcore/core.c194
1 files changed, 72 insertions, 122 deletions
diff --git a/drivers/staging/most/mostcore/core.c b/drivers/staging/most/mostcore/core.c
index ed1ed25b6d1d..7c619feb12d3 100644
--- a/drivers/staging/most/mostcore/core.c
+++ b/drivers/staging/most/mostcore/core.c
@@ -35,7 +35,6 @@
static struct class *most_class;
static struct device *class_glue_dir;
static struct ida mdev_id;
-static int modref;
static int dummy_num_buffers;
struct most_c_aim_obj {
@@ -66,7 +65,6 @@ struct most_c_obj {
struct most_c_aim_obj aim1;
struct list_head trash_fifo;
struct task_struct *hdm_enqueue_task;
- struct mutex stop_task_mutex;
wait_queue_head_t hdm_fifo_wq;
};
@@ -74,7 +72,6 @@ struct most_c_obj {
struct most_inst_obj {
int dev_id;
- atomic_t tainted;
struct most_interface *iface;
struct list_head channel_list;
struct most_c_obj *channel[MAX_CHANNELS];
@@ -82,6 +79,14 @@ struct most_inst_obj {
struct list_head list;
};
+static const struct {
+ int most_ch_data_type;
+ char *name;
+} ch_data_type[] = { { MOST_CH_CONTROL, "control\n" },
+ { MOST_CH_ASYNC, "async\n" },
+ { MOST_CH_SYNC, "sync\n" },
+ { MOST_CH_ISOC_AVP, "isoc_avp\n"} };
+
#define to_inst_obj(d) container_of(d, struct most_inst_obj, kobj)
/**
@@ -95,8 +100,6 @@ struct most_inst_obj {
_mbo; \
})
-static struct mutex deregister_mutex;
-
/* ___ ___
* ___C H A N N E L___
*/
@@ -414,14 +417,12 @@ static ssize_t show_set_datatype(struct most_c_obj *c,
struct most_c_attr *attr,
char *buf)
{
- if (c->cfg.data_type & MOST_CH_CONTROL)
- return snprintf(buf, PAGE_SIZE, "control\n");
- else if (c->cfg.data_type & MOST_CH_ASYNC)
- return snprintf(buf, PAGE_SIZE, "async\n");
- else if (c->cfg.data_type & MOST_CH_SYNC)
- return snprintf(buf, PAGE_SIZE, "sync\n");
- else if (c->cfg.data_type & MOST_CH_ISOC_AVP)
- return snprintf(buf, PAGE_SIZE, "isoc_avp\n");
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ch_data_type); i++) {
+ if (c->cfg.data_type & ch_data_type[i].most_ch_data_type)
+ return snprintf(buf, PAGE_SIZE, ch_data_type[i].name);
+ }
return snprintf(buf, PAGE_SIZE, "unconfigured\n");
}
@@ -430,15 +431,16 @@ static ssize_t store_set_datatype(struct most_c_obj *c,
const char *buf,
size_t count)
{
- if (!strcmp(buf, "control\n")) {
- c->cfg.data_type = MOST_CH_CONTROL;
- } else if (!strcmp(buf, "async\n")) {
- c->cfg.data_type = MOST_CH_ASYNC;
- } else if (!strcmp(buf, "sync\n")) {
- c->cfg.data_type = MOST_CH_SYNC;
- } else if (!strcmp(buf, "isoc_avp\n")) {
- c->cfg.data_type = MOST_CH_ISOC_AVP;
- } else {
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ch_data_type); i++) {
+ if (!strcmp(buf, ch_data_type[i].name)) {
+ c->cfg.data_type = ch_data_type[i].most_ch_data_type;
+ break;
+ }
+ }
+
+ if (i == ARRAY_SIZE(ch_data_type)) {
pr_info("WARN: invalid attribute settings\n");
return -EINVAL;
}
@@ -551,29 +553,6 @@ create_most_c_obj(const char *name, struct kobject *parent)
return c;
}
-/**
- * destroy_most_c_obj - channel release function
- * @c: pointer to channel object
- *
- * This decrements the reference counter of the channel object.
- * If the reference count turns zero, its release function is called.
- */
-static void destroy_most_c_obj(struct most_c_obj *c)
-{
- if (c->aim0.ptr)
- c->aim0.ptr->disconnect_channel(c->iface, c->channel_id);
- if (c->aim1.ptr)
- c->aim1.ptr->disconnect_channel(c->iface, c->channel_id);
- c->aim0.ptr = NULL;
- c->aim1.ptr = NULL;
-
- mutex_lock(&deregister_mutex);
- flush_trash_fifo(c);
- flush_channel_fifos(c);
- mutex_unlock(&deregister_mutex);
- kobject_put(&c->kobj);
-}
-
/* ___ ___
* ___I N S T A N C E___
*/
@@ -761,12 +740,10 @@ static void destroy_most_inst_obj(struct most_inst_obj *inst)
{
struct most_c_obj *c, *tmp;
- /* need to destroy channels first, since
- * each channel incremented the
- * reference count of the inst->kobj
- */
list_for_each_entry_safe(c, tmp, &inst->channel_list, list) {
- destroy_most_c_obj(c);
+ flush_trash_fifo(c);
+ flush_channel_fifos(c);
+ kobject_put(&c->kobj);
}
kobject_put(&inst->kobj);
}
@@ -1006,11 +983,14 @@ static ssize_t store_add_link(struct most_aim_obj *aim_obj,
else
return -ENOSPC;
+ *aim_ptr = aim_obj->driver;
ret = aim_obj->driver->probe_channel(c->iface, c->channel_id,
&c->cfg, &c->kobj, mdev_devnod);
- if (ret)
+ if (ret) {
+ *aim_ptr = NULL;
return ret;
- *aim_ptr = aim_obj->driver;
+ }
+
return len;
}
@@ -1056,12 +1036,12 @@ static ssize_t store_remove_link(struct most_aim_obj *aim_obj,
if (IS_ERR(c))
return -ENODEV;
+ if (aim_obj->driver->disconnect_channel(c->iface, c->channel_id))
+ return -EIO;
if (c->aim0.ptr == aim_obj->driver)
c->aim0.ptr = NULL;
if (c->aim1.ptr == aim_obj->driver)
c->aim1.ptr = NULL;
- if (aim_obj->driver->disconnect_channel(c->iface, c->channel_id))
- return -EIO;
return len;
}
@@ -1279,7 +1259,6 @@ static int arm_mbo_chain(struct most_c_obj *c, int dir,
for (i = 0; i < c->cfg.num_buffers; i++) {
mbo = kzalloc(sizeof(*mbo), GFP_KERNEL);
if (!mbo) {
- pr_info("WARN: Allocation of MBO failed.\n");
retval = i;
goto _exit;
}
@@ -1319,18 +1298,10 @@ _exit:
*/
int most_submit_mbo(struct mbo *mbo)
{
- struct most_c_obj *c;
- struct most_inst_obj *i;
-
if (unlikely((!mbo) || (!mbo->context))) {
pr_err("Bad MBO or missing channel reference\n");
return -EINVAL;
}
- c = mbo->context;
- i = c->inst;
-
- if (unlikely(atomic_read(&i->tainted)))
- return -ENODEV;
nq_hdm_mbo(mbo);
return 0;
@@ -1387,7 +1358,7 @@ most_c_obj *get_channel_by_iface(struct most_interface *iface, int id)
return i->channel[id];
}
-int channel_has_mbo(struct most_interface *iface, int id)
+int channel_has_mbo(struct most_interface *iface, int id, struct most_aim *aim)
{
struct most_c_obj *c = get_channel_by_iface(iface, id);
unsigned long flags;
@@ -1396,6 +1367,11 @@ int channel_has_mbo(struct most_interface *iface, int id)
if (unlikely(!c))
return -EINVAL;
+ if (c->aim0.refs && c->aim1.refs &&
+ ((aim == c->aim0.ptr && c->aim0.num_buffers <= 0) ||
+ (aim == c->aim1.ptr && c->aim1.num_buffers <= 0)))
+ return 0;
+
spin_lock_irqsave(&c->fifo_lock, flags);
empty = list_empty(&c->fifo);
spin_unlock_irqrestore(&c->fifo_lock, flags);
@@ -1456,17 +1432,8 @@ EXPORT_SYMBOL_GPL(most_get_mbo);
*/
void most_put_mbo(struct mbo *mbo)
{
- struct most_c_obj *c;
- struct most_inst_obj *i;
-
- c = mbo->context;
- i = c->inst;
+ struct most_c_obj *c = mbo->context;
- if (unlikely(atomic_read(&i->tainted))) {
- mbo->status = MBO_E_CLOSE;
- trash_mbo(mbo);
- return;
- }
if (c->cfg.direction == MOST_CH_TX) {
arm_mbo(mbo);
return;
@@ -1546,7 +1513,6 @@ int most_start_channel(struct most_interface *iface, int id,
mutex_unlock(&c->start_mutex);
return -ENOLCK;
}
- modref++;
c->cfg.extra_len = 0;
if (c->iface->configure(c->iface, c->channel_id, &c->cfg)) {
@@ -1588,7 +1554,6 @@ out:
error:
module_put(iface->mod);
- modref--;
mutex_unlock(&c->start_mutex);
return ret;
}
@@ -1616,24 +1581,12 @@ int most_stop_channel(struct most_interface *iface, int id,
if (c->aim0.refs + c->aim1.refs >= 2)
goto out;
- mutex_lock(&c->stop_task_mutex);
if (c->hdm_enqueue_task)
kthread_stop(c->hdm_enqueue_task);
c->hdm_enqueue_task = NULL;
- mutex_unlock(&c->stop_task_mutex);
- mutex_lock(&deregister_mutex);
- if (atomic_read(&c->inst->tainted)) {
- mutex_unlock(&deregister_mutex);
- mutex_unlock(&c->start_mutex);
- return -ENODEV;
- }
- mutex_unlock(&deregister_mutex);
-
- if (iface->mod && modref) {
+ if (iface->mod)
module_put(iface->mod);
- modref--;
- }
c->is_poisoned = true;
if (c->iface->poison_channel(c->iface, c->channel_id)) {
@@ -1762,6 +1715,7 @@ struct kobject *most_register_interface(struct most_interface *iface)
inst = create_most_inst_obj(name);
if (!inst) {
pr_info("Failed to allocate interface instance\n");
+ ida_simple_remove(&mdev_id, id);
return ERR_PTR(-ENOMEM);
}
@@ -1769,7 +1723,6 @@ struct kobject *most_register_interface(struct most_interface *iface)
INIT_LIST_HEAD(&inst->channel_list);
inst->iface = iface;
inst->dev_id = id;
- atomic_set(&inst->tainted, 0);
list_add_tail(&inst->list, &instance_list);
for (i = 0; i < iface->num_channels; i++) {
@@ -1808,7 +1761,6 @@ struct kobject *most_register_interface(struct most_interface *iface)
init_completion(&c->cleanup);
atomic_set(&c->mbo_ref, 0);
mutex_init(&c->start_mutex);
- mutex_init(&c->stop_task_mutex);
list_add_tail(&c->list, &inst->channel_list);
}
pr_info("registered new MOST device mdev%d (%s)\n",
@@ -1818,6 +1770,7 @@ struct kobject *most_register_interface(struct most_interface *iface)
free_instance:
pr_info("Failed allocate channel(s)\n");
list_del(&inst->list);
+ ida_simple_remove(&mdev_id, id);
destroy_most_inst_obj(inst);
return ERR_PTR(-ENOMEM);
}
@@ -1835,37 +1788,24 @@ void most_deregister_interface(struct most_interface *iface)
struct most_inst_obj *i = iface->priv;
struct most_c_obj *c;
- mutex_lock(&deregister_mutex);
if (unlikely(!i)) {
pr_info("Bad Interface\n");
- mutex_unlock(&deregister_mutex);
return;
}
pr_info("deregistering MOST device %s (%s)\n", i->kobj.name,
iface->description);
- atomic_set(&i->tainted, 1);
- mutex_unlock(&deregister_mutex);
-
- while (modref) {
- if (iface->mod && modref)
- module_put(iface->mod);
- modref--;
- }
-
list_for_each_entry(c, &i->channel_list, list) {
- if (c->aim0.refs + c->aim1.refs <= 0)
- continue;
-
- mutex_lock(&c->stop_task_mutex);
- if (c->hdm_enqueue_task)
- kthread_stop(c->hdm_enqueue_task);
- c->hdm_enqueue_task = NULL;
- mutex_unlock(&c->stop_task_mutex);
-
- if (iface->poison_channel(iface, c->channel_id))
- pr_err("Can't poison channel %d\n", c->channel_id);
+ if (c->aim0.ptr)
+ c->aim0.ptr->disconnect_channel(c->iface,
+ c->channel_id);
+ if (c->aim1.ptr)
+ c->aim1.ptr->disconnect_channel(c->iface,
+ c->channel_id);
+ c->aim0.ptr = NULL;
+ c->aim1.ptr = NULL;
}
+
ida_simple_remove(&mdev_id, i->dev_id);
list_del(&i->list);
destroy_most_inst_obj(i);
@@ -1913,41 +1853,52 @@ EXPORT_SYMBOL_GPL(most_resume_enqueue);
static int __init most_init(void)
{
+ int err;
+
pr_info("init()\n");
INIT_LIST_HEAD(&instance_list);
INIT_LIST_HEAD(&aim_list);
- mutex_init(&deregister_mutex);
ida_init(&mdev_id);
- if (bus_register(&most_bus)) {
+ err = bus_register(&most_bus);
+ if (err) {
pr_info("Cannot register most bus\n");
- goto exit;
+ return err;
}
most_class = class_create(THIS_MODULE, "most");
if (IS_ERR(most_class)) {
pr_info("No udev support.\n");
+ err = PTR_ERR(most_class);
goto exit_bus;
}
- if (driver_register(&mostcore)) {
+
+ err = driver_register(&mostcore);
+ if (err) {
pr_info("Cannot register core driver\n");
goto exit_class;
}
class_glue_dir =
device_create(most_class, NULL, 0, NULL, "mostcore");
- if (!class_glue_dir)
+ if (IS_ERR(class_glue_dir)) {
+ err = PTR_ERR(class_glue_dir);
goto exit_driver;
+ }
most_aim_kset =
kset_create_and_add("aims", NULL, &class_glue_dir->kobj);
- if (!most_aim_kset)
+ if (!most_aim_kset) {
+ err = -ENOMEM;
goto exit_class_container;
+ }
most_inst_kset =
kset_create_and_add("devices", NULL, &class_glue_dir->kobj);
- if (!most_inst_kset)
+ if (!most_inst_kset) {
+ err = -ENOMEM;
goto exit_driver_kset;
+ }
return 0;
@@ -1961,8 +1912,7 @@ exit_class:
class_destroy(most_class);
exit_bus:
bus_unregister(&most_bus);
-exit:
- return -ENOMEM;
+ return err;
}
static void __exit most_exit(void)