From d635711daa98be86d4c7fd01499c34f566b54ccb Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Fri, 10 Jun 2016 05:30:17 -0300 Subject: Linux-libre 4.6.2-gnu --- drivers/staging/most/mostcore/core.c | 194 +++++++++++++---------------------- 1 file changed, 72 insertions(+), 122 deletions(-) (limited to 'drivers/staging/most/mostcore/core.c') diff --git a/drivers/staging/most/mostcore/core.c b/drivers/staging/most/mostcore/core.c index ed1ed25b6..7c619feb1 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) -- cgit v1.2.3-54-g00ecf