2009-12-09 19:40:00 +08:00
|
|
|
/*
|
|
|
|
* Media entity
|
|
|
|
*
|
|
|
|
* Copyright (C) 2010 Nokia Corporation
|
|
|
|
*
|
|
|
|
* Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
|
|
|
* Sakari Ailus <sakari.ailus@iki.fi>
|
|
|
|
*
|
|
|
|
* 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
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*/
|
|
|
|
|
2013-06-07 23:45:11 +08:00
|
|
|
#include <linux/bitmap.h>
|
2009-12-09 19:40:00 +08:00
|
|
|
#include <linux/module.h>
|
2017-06-15 17:17:26 +08:00
|
|
|
#include <linux/property.h>
|
2009-12-09 19:40:00 +08:00
|
|
|
#include <linux/slab.h>
|
|
|
|
#include <media/media-entity.h>
|
2010-03-08 02:04:59 +08:00
|
|
|
#include <media/media-device.h>
|
2009-12-09 19:40:00 +08:00
|
|
|
|
2015-08-14 01:42:42 +08:00
|
|
|
static inline const char *gobj_type(enum media_gobj_type type)
|
|
|
|
{
|
|
|
|
switch (type) {
|
|
|
|
case MEDIA_GRAPH_ENTITY:
|
|
|
|
return "entity";
|
|
|
|
case MEDIA_GRAPH_PAD:
|
|
|
|
return "pad";
|
|
|
|
case MEDIA_GRAPH_LINK:
|
|
|
|
return "link";
|
2015-08-20 20:07:34 +08:00
|
|
|
case MEDIA_GRAPH_INTF_DEVNODE:
|
|
|
|
return "intf-devnode";
|
2015-08-14 01:42:42 +08:00
|
|
|
default:
|
|
|
|
return "unknown";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-20 20:07:34 +08:00
|
|
|
static inline const char *intf_type(struct media_interface *intf)
|
|
|
|
{
|
|
|
|
switch (intf->type) {
|
|
|
|
case MEDIA_INTF_T_DVB_FE:
|
2016-03-05 05:14:05 +08:00
|
|
|
return "dvb-frontend";
|
2015-08-20 20:07:34 +08:00
|
|
|
case MEDIA_INTF_T_DVB_DEMUX:
|
2016-03-05 05:14:05 +08:00
|
|
|
return "dvb-demux";
|
2015-08-20 20:07:34 +08:00
|
|
|
case MEDIA_INTF_T_DVB_DVR:
|
2016-03-05 05:14:05 +08:00
|
|
|
return "dvb-dvr";
|
2015-08-20 20:07:34 +08:00
|
|
|
case MEDIA_INTF_T_DVB_CA:
|
2016-03-05 05:14:05 +08:00
|
|
|
return "dvb-ca";
|
2015-08-20 20:07:34 +08:00
|
|
|
case MEDIA_INTF_T_DVB_NET:
|
2016-03-05 05:14:05 +08:00
|
|
|
return "dvb-net";
|
2015-08-20 20:07:34 +08:00
|
|
|
case MEDIA_INTF_T_V4L_VIDEO:
|
2016-03-05 05:14:05 +08:00
|
|
|
return "v4l-video";
|
2015-08-20 20:07:34 +08:00
|
|
|
case MEDIA_INTF_T_V4L_VBI:
|
2016-03-05 05:14:05 +08:00
|
|
|
return "v4l-vbi";
|
2015-08-20 20:07:34 +08:00
|
|
|
case MEDIA_INTF_T_V4L_RADIO:
|
2016-03-05 05:14:05 +08:00
|
|
|
return "v4l-radio";
|
2015-08-20 20:07:34 +08:00
|
|
|
case MEDIA_INTF_T_V4L_SUBDEV:
|
2016-03-05 05:14:05 +08:00
|
|
|
return "v4l-subdev";
|
2015-08-20 20:07:34 +08:00
|
|
|
case MEDIA_INTF_T_V4L_SWRADIO:
|
2016-03-05 05:14:05 +08:00
|
|
|
return "v4l-swradio";
|
2016-07-19 05:10:30 +08:00
|
|
|
case MEDIA_INTF_T_V4L_TOUCH:
|
|
|
|
return "v4l-touch";
|
2015-08-20 20:07:34 +08:00
|
|
|
default:
|
|
|
|
return "unknown-intf";
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2015-12-16 21:44:32 +08:00
|
|
|
__must_check int __media_entity_enum_init(struct media_entity_enum *ent_enum,
|
|
|
|
int idx_max)
|
|
|
|
{
|
2016-01-27 22:47:54 +08:00
|
|
|
idx_max = ALIGN(idx_max, BITS_PER_LONG);
|
|
|
|
ent_enum->bmap = kcalloc(idx_max / BITS_PER_LONG, sizeof(long),
|
|
|
|
GFP_KERNEL);
|
2015-12-16 21:32:36 +08:00
|
|
|
if (!ent_enum->bmap)
|
|
|
|
return -ENOMEM;
|
2015-12-16 21:44:32 +08:00
|
|
|
|
|
|
|
bitmap_zero(ent_enum->bmap, idx_max);
|
|
|
|
ent_enum->idx_max = idx_max;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(__media_entity_enum_init);
|
|
|
|
|
|
|
|
void media_entity_enum_cleanup(struct media_entity_enum *ent_enum)
|
|
|
|
{
|
2015-12-16 21:32:36 +08:00
|
|
|
kfree(ent_enum->bmap);
|
2015-12-16 21:44:32 +08:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(media_entity_enum_cleanup);
|
|
|
|
|
2015-12-11 22:14:58 +08:00
|
|
|
/**
|
|
|
|
* dev_dbg_obj - Prints in debug mode a change on some object
|
|
|
|
*
|
|
|
|
* @event_name: Name of the event to report. Could be __func__
|
|
|
|
* @gobj: Pointer to the object
|
|
|
|
*
|
|
|
|
* Enabled only if DEBUG or CONFIG_DYNAMIC_DEBUG. Otherwise, it
|
|
|
|
* won't produce any code.
|
|
|
|
*/
|
2015-08-14 01:42:42 +08:00
|
|
|
static void dev_dbg_obj(const char *event_name, struct media_gobj *gobj)
|
|
|
|
{
|
|
|
|
#if defined(DEBUG) || defined (CONFIG_DYNAMIC_DEBUG)
|
|
|
|
switch (media_type(gobj)) {
|
|
|
|
case MEDIA_GRAPH_ENTITY:
|
|
|
|
dev_dbg(gobj->mdev->dev,
|
2015-12-17 00:28:01 +08:00
|
|
|
"%s id %u: entity '%s'\n",
|
|
|
|
event_name, media_id(gobj),
|
2015-08-14 01:42:42 +08:00
|
|
|
gobj_to_entity(gobj)->name);
|
|
|
|
break;
|
|
|
|
case MEDIA_GRAPH_LINK:
|
|
|
|
{
|
|
|
|
struct media_link *link = gobj_to_link(gobj);
|
|
|
|
|
|
|
|
dev_dbg(gobj->mdev->dev,
|
2015-12-17 00:28:01 +08:00
|
|
|
"%s id %u: %s link id %u ==> id %u\n",
|
|
|
|
event_name, media_id(gobj),
|
|
|
|
media_type(link->gobj0) == MEDIA_GRAPH_PAD ?
|
|
|
|
"data" : "interface",
|
|
|
|
media_id(link->gobj0),
|
|
|
|
media_id(link->gobj1));
|
2015-08-14 01:42:42 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case MEDIA_GRAPH_PAD:
|
|
|
|
{
|
|
|
|
struct media_pad *pad = gobj_to_pad(gobj);
|
|
|
|
|
|
|
|
dev_dbg(gobj->mdev->dev,
|
2015-12-17 00:28:01 +08:00
|
|
|
"%s id %u: %s%spad '%s':%d\n",
|
|
|
|
event_name, media_id(gobj),
|
|
|
|
pad->flags & MEDIA_PAD_FL_SINK ? "sink " : "",
|
2015-08-22 05:26:42 +08:00
|
|
|
pad->flags & MEDIA_PAD_FL_SOURCE ? "source " : "",
|
2015-08-14 01:42:42 +08:00
|
|
|
pad->entity->name, pad->index);
|
2015-08-20 20:07:34 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case MEDIA_GRAPH_INTF_DEVNODE:
|
|
|
|
{
|
|
|
|
struct media_interface *intf = gobj_to_intf(gobj);
|
|
|
|
struct media_intf_devnode *devnode = intf_to_devnode(intf);
|
|
|
|
|
|
|
|
dev_dbg(gobj->mdev->dev,
|
2015-12-17 00:28:01 +08:00
|
|
|
"%s id %u: intf_devnode %s - major: %d, minor: %d\n",
|
|
|
|
event_name, media_id(gobj),
|
2015-08-20 20:07:34 +08:00
|
|
|
intf_type(intf),
|
|
|
|
devnode->major, devnode->minor);
|
|
|
|
break;
|
2015-08-14 01:42:42 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2015-12-11 21:55:40 +08:00
|
|
|
void media_gobj_create(struct media_device *mdev,
|
2015-08-25 21:28:36 +08:00
|
|
|
enum media_gobj_type type,
|
|
|
|
struct media_gobj *gobj)
|
|
|
|
{
|
2015-08-20 07:18:35 +08:00
|
|
|
BUG_ON(!mdev);
|
|
|
|
|
2015-08-14 01:42:42 +08:00
|
|
|
gobj->mdev = mdev;
|
|
|
|
|
2015-08-14 23:47:48 +08:00
|
|
|
/* Create a per-type unique object ID */
|
2015-12-17 00:28:01 +08:00
|
|
|
gobj->id = media_gobj_gen_id(type, ++mdev->id);
|
|
|
|
|
2015-08-14 23:47:48 +08:00
|
|
|
switch (type) {
|
|
|
|
case MEDIA_GRAPH_ENTITY:
|
2015-08-23 18:51:33 +08:00
|
|
|
list_add_tail(&gobj->list, &mdev->entities);
|
2015-08-14 23:47:48 +08:00
|
|
|
break;
|
2015-08-14 23:50:08 +08:00
|
|
|
case MEDIA_GRAPH_PAD:
|
2015-08-23 19:00:33 +08:00
|
|
|
list_add_tail(&gobj->list, &mdev->pads);
|
2015-08-14 23:50:08 +08:00
|
|
|
break;
|
2015-08-14 23:54:36 +08:00
|
|
|
case MEDIA_GRAPH_LINK:
|
2015-08-23 19:00:33 +08:00
|
|
|
list_add_tail(&gobj->list, &mdev->links);
|
2015-08-14 23:54:36 +08:00
|
|
|
break;
|
2015-08-20 20:07:34 +08:00
|
|
|
case MEDIA_GRAPH_INTF_DEVNODE:
|
2015-08-23 19:00:33 +08:00
|
|
|
list_add_tail(&gobj->list, &mdev->interfaces);
|
2015-08-20 20:07:34 +08:00
|
|
|
break;
|
2015-08-14 23:47:48 +08:00
|
|
|
}
|
2015-08-23 20:40:26 +08:00
|
|
|
|
|
|
|
mdev->topology_version++;
|
|
|
|
|
2015-08-14 01:42:42 +08:00
|
|
|
dev_dbg_obj(__func__, gobj);
|
2015-08-25 21:28:36 +08:00
|
|
|
}
|
|
|
|
|
2015-12-11 21:55:40 +08:00
|
|
|
void media_gobj_destroy(struct media_gobj *gobj)
|
2015-08-25 21:28:36 +08:00
|
|
|
{
|
2016-08-10 05:32:57 +08:00
|
|
|
/* Do nothing if the object is not linked. */
|
|
|
|
if (gobj->mdev == NULL)
|
|
|
|
return;
|
|
|
|
|
2017-04-07 03:25:15 +08:00
|
|
|
dev_dbg_obj(__func__, gobj);
|
|
|
|
|
2015-08-23 20:40:26 +08:00
|
|
|
gobj->mdev->topology_version++;
|
|
|
|
|
2015-08-23 19:00:33 +08:00
|
|
|
/* Remove the object from mdev list */
|
|
|
|
list_del(&gobj->list);
|
2016-08-10 05:32:57 +08:00
|
|
|
|
|
|
|
gobj->mdev = NULL;
|
2015-08-25 21:28:36 +08:00
|
|
|
}
|
|
|
|
|
2015-10-05 23:45:29 +08:00
|
|
|
/*
|
|
|
|
* TODO: Get rid of this.
|
|
|
|
*/
|
|
|
|
#define MEDIA_ENTITY_MAX_PADS 512
|
|
|
|
|
2015-12-11 22:14:58 +08:00
|
|
|
int media_entity_pads_init(struct media_entity *entity, u16 num_pads,
|
|
|
|
struct media_pad *pads)
|
2009-12-09 19:40:00 +08:00
|
|
|
{
|
2015-09-09 01:10:56 +08:00
|
|
|
struct media_device *mdev = entity->graph_obj.mdev;
|
2009-12-09 19:40:00 +08:00
|
|
|
unsigned int i;
|
|
|
|
|
2015-10-05 23:45:29 +08:00
|
|
|
if (num_pads >= MEDIA_ENTITY_MAX_PADS)
|
|
|
|
return -E2BIG;
|
|
|
|
|
2009-12-09 19:40:00 +08:00
|
|
|
entity->num_pads = num_pads;
|
|
|
|
entity->pads = pads;
|
|
|
|
|
2015-09-09 01:10:56 +08:00
|
|
|
if (mdev)
|
[media] media-device: get rid of the spinlock
Right now, the lock schema for media_device struct is messy,
since sometimes, it is protected via a spin lock, while, for
media graph traversal, it is protected by a mutex.
Solve this conflict by always using a mutex.
As a side effect, this prevents a bug when the media notifiers
is called at atomic context, while running the notifier callback:
BUG: sleeping function called from invalid context at mm/slub.c:1289
in_atomic(): 1, irqs_disabled(): 0, pid: 3479, name: modprobe
4 locks held by modprobe/3479:
#0: (&dev->mutex){......}, at: [<ffffffff81ce8933>] __driver_attach+0xa3/0x160
#1: (&dev->mutex){......}, at: [<ffffffff81ce8941>] __driver_attach+0xb1/0x160
#2: (register_mutex#5){+.+.+.}, at: [<ffffffffa10596c7>] usb_audio_probe+0x257/0x1c90 [snd_usb_audio]
#3: (&(&mdev->lock)->rlock){+.+.+.}, at: [<ffffffffa0e6051b>] media_device_register_entity+0x1cb/0x700 [media]
CPU: 2 PID: 3479 Comm: modprobe Not tainted 4.5.0-rc3+ #49
Hardware name: /NUC5i7RYB, BIOS RYBDWi35.86A.0350.2015.0812.1722 08/12/2015
0000000000000000 ffff8803b3f6f288 ffffffff81933901 ffff8803c4bae000
ffff8803c4bae5c8 ffff8803b3f6f2b0 ffffffff811c6af5 ffff8803c4bae000
ffffffff8285d7f6 0000000000000509 ffff8803b3f6f2f0 ffffffff811c6ce5
Call Trace:
[<ffffffff81933901>] dump_stack+0x85/0xc4
[<ffffffff811c6af5>] ___might_sleep+0x245/0x3a0
[<ffffffff811c6ce5>] __might_sleep+0x95/0x1a0
[<ffffffff8155aade>] kmem_cache_alloc_trace+0x20e/0x300
[<ffffffffa0e66e3d>] ? media_add_link+0x4d/0x140 [media]
[<ffffffffa0e66e3d>] media_add_link+0x4d/0x140 [media]
[<ffffffffa0e69931>] media_create_pad_link+0xa1/0x600 [media]
[<ffffffffa0fe11b3>] au0828_media_graph_notify+0x173/0x360 [au0828]
[<ffffffffa0e68a6a>] ? media_gobj_create+0x1ba/0x480 [media]
[<ffffffffa0e606fb>] media_device_register_entity+0x3ab/0x700 [media]
Reviewed-by: Javier Martinez Canillas <javier@osg.samsung.com>
Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
2016-04-06 21:55:24 +08:00
|
|
|
mutex_lock(&mdev->graph_mutex);
|
2015-09-09 01:10:56 +08:00
|
|
|
|
2009-12-09 19:40:00 +08:00
|
|
|
for (i = 0; i < num_pads; i++) {
|
|
|
|
pads[i].entity = entity;
|
|
|
|
pads[i].index = i;
|
2015-09-09 01:10:56 +08:00
|
|
|
if (mdev)
|
2015-12-11 21:55:40 +08:00
|
|
|
media_gobj_create(mdev, MEDIA_GRAPH_PAD,
|
2015-09-09 01:10:56 +08:00
|
|
|
&entity->pads[i].graph_obj);
|
2009-12-09 19:40:00 +08:00
|
|
|
}
|
|
|
|
|
2015-09-09 01:10:56 +08:00
|
|
|
if (mdev)
|
[media] media-device: get rid of the spinlock
Right now, the lock schema for media_device struct is messy,
since sometimes, it is protected via a spin lock, while, for
media graph traversal, it is protected by a mutex.
Solve this conflict by always using a mutex.
As a side effect, this prevents a bug when the media notifiers
is called at atomic context, while running the notifier callback:
BUG: sleeping function called from invalid context at mm/slub.c:1289
in_atomic(): 1, irqs_disabled(): 0, pid: 3479, name: modprobe
4 locks held by modprobe/3479:
#0: (&dev->mutex){......}, at: [<ffffffff81ce8933>] __driver_attach+0xa3/0x160
#1: (&dev->mutex){......}, at: [<ffffffff81ce8941>] __driver_attach+0xb1/0x160
#2: (register_mutex#5){+.+.+.}, at: [<ffffffffa10596c7>] usb_audio_probe+0x257/0x1c90 [snd_usb_audio]
#3: (&(&mdev->lock)->rlock){+.+.+.}, at: [<ffffffffa0e6051b>] media_device_register_entity+0x1cb/0x700 [media]
CPU: 2 PID: 3479 Comm: modprobe Not tainted 4.5.0-rc3+ #49
Hardware name: /NUC5i7RYB, BIOS RYBDWi35.86A.0350.2015.0812.1722 08/12/2015
0000000000000000 ffff8803b3f6f288 ffffffff81933901 ffff8803c4bae000
ffff8803c4bae5c8 ffff8803b3f6f2b0 ffffffff811c6af5 ffff8803c4bae000
ffffffff8285d7f6 0000000000000509 ffff8803b3f6f2f0 ffffffff811c6ce5
Call Trace:
[<ffffffff81933901>] dump_stack+0x85/0xc4
[<ffffffff811c6af5>] ___might_sleep+0x245/0x3a0
[<ffffffff811c6ce5>] __might_sleep+0x95/0x1a0
[<ffffffff8155aade>] kmem_cache_alloc_trace+0x20e/0x300
[<ffffffffa0e66e3d>] ? media_add_link+0x4d/0x140 [media]
[<ffffffffa0e66e3d>] media_add_link+0x4d/0x140 [media]
[<ffffffffa0e69931>] media_create_pad_link+0xa1/0x600 [media]
[<ffffffffa0fe11b3>] au0828_media_graph_notify+0x173/0x360 [au0828]
[<ffffffffa0e68a6a>] ? media_gobj_create+0x1ba/0x480 [media]
[<ffffffffa0e606fb>] media_device_register_entity+0x3ab/0x700 [media]
Reviewed-by: Javier Martinez Canillas <javier@osg.samsung.com>
Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
2016-04-06 21:55:24 +08:00
|
|
|
mutex_unlock(&mdev->graph_mutex);
|
2015-09-09 01:10:56 +08:00
|
|
|
|
2009-12-09 19:40:00 +08:00
|
|
|
return 0;
|
|
|
|
}
|
2015-12-11 17:44:40 +08:00
|
|
|
EXPORT_SYMBOL_GPL(media_entity_pads_init);
|
2009-12-09 19:40:00 +08:00
|
|
|
|
2010-03-08 03:14:14 +08:00
|
|
|
/* -----------------------------------------------------------------------------
|
|
|
|
* Graph traversal
|
|
|
|
*/
|
|
|
|
|
|
|
|
static struct media_entity *
|
|
|
|
media_entity_other(struct media_entity *entity, struct media_link *link)
|
|
|
|
{
|
|
|
|
if (link->source->entity == entity)
|
|
|
|
return link->sink->entity;
|
|
|
|
else
|
|
|
|
return link->source->entity;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* push an entity to traversal stack */
|
2016-11-22 00:48:30 +08:00
|
|
|
static void stack_push(struct media_graph *graph,
|
2010-03-08 03:14:14 +08:00
|
|
|
struct media_entity *entity)
|
|
|
|
{
|
|
|
|
if (graph->top == MEDIA_ENTITY_ENUM_MAX_DEPTH - 1) {
|
|
|
|
WARN_ON(1);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
graph->top++;
|
2015-12-12 01:16:36 +08:00
|
|
|
graph->stack[graph->top].link = entity->links.next;
|
2010-03-08 03:14:14 +08:00
|
|
|
graph->stack[graph->top].entity = entity;
|
|
|
|
}
|
|
|
|
|
2016-11-22 00:48:30 +08:00
|
|
|
static struct media_entity *stack_pop(struct media_graph *graph)
|
2010-03-08 03:14:14 +08:00
|
|
|
{
|
|
|
|
struct media_entity *entity;
|
|
|
|
|
|
|
|
entity = graph->stack[graph->top].entity;
|
|
|
|
graph->top--;
|
|
|
|
|
|
|
|
return entity;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define link_top(en) ((en)->stack[(en)->top].link)
|
|
|
|
#define stack_top(en) ((en)->stack[(en)->top].entity)
|
|
|
|
|
2015-12-16 21:32:22 +08:00
|
|
|
/**
|
2016-11-22 00:48:30 +08:00
|
|
|
* media_graph_walk_init - Allocate resources for graph walk
|
2015-12-16 21:32:22 +08:00
|
|
|
* @graph: Media graph structure that will be used to walk the graph
|
|
|
|
* @mdev: Media device
|
|
|
|
*
|
|
|
|
* Reserve resources for graph walk in media device's current
|
|
|
|
* state. The memory must be released using
|
2016-11-22 00:48:30 +08:00
|
|
|
* media_graph_walk_free().
|
2015-12-16 21:32:22 +08:00
|
|
|
*
|
|
|
|
* Returns error on failure, zero on success.
|
|
|
|
*/
|
2016-11-22 00:48:30 +08:00
|
|
|
__must_check int media_graph_walk_init(
|
|
|
|
struct media_graph *graph, struct media_device *mdev)
|
2015-12-16 21:32:22 +08:00
|
|
|
{
|
2015-12-16 21:32:28 +08:00
|
|
|
return media_entity_enum_init(&graph->ent_enum, mdev);
|
2015-12-16 21:32:22 +08:00
|
|
|
}
|
2016-11-22 00:48:30 +08:00
|
|
|
EXPORT_SYMBOL_GPL(media_graph_walk_init);
|
2015-12-16 21:32:22 +08:00
|
|
|
|
|
|
|
/**
|
2016-11-22 00:48:30 +08:00
|
|
|
* media_graph_walk_cleanup - Release resources related to graph walking
|
2015-12-16 21:32:22 +08:00
|
|
|
* @graph: Media graph structure that was used to walk the graph
|
|
|
|
*/
|
2016-11-22 00:48:30 +08:00
|
|
|
void media_graph_walk_cleanup(struct media_graph *graph)
|
2015-12-16 21:32:22 +08:00
|
|
|
{
|
2015-12-16 21:32:28 +08:00
|
|
|
media_entity_enum_cleanup(&graph->ent_enum);
|
2015-12-16 21:32:22 +08:00
|
|
|
}
|
2016-11-22 00:48:30 +08:00
|
|
|
EXPORT_SYMBOL_GPL(media_graph_walk_cleanup);
|
2015-12-16 21:32:22 +08:00
|
|
|
|
2016-11-22 00:48:30 +08:00
|
|
|
void media_graph_walk_start(struct media_graph *graph,
|
|
|
|
struct media_entity *entity)
|
2010-03-08 03:14:14 +08:00
|
|
|
{
|
2015-12-16 21:32:28 +08:00
|
|
|
media_entity_enum_zero(&graph->ent_enum);
|
|
|
|
media_entity_enum_set(&graph->ent_enum, entity);
|
|
|
|
|
2010-03-08 03:14:14 +08:00
|
|
|
graph->top = 0;
|
|
|
|
graph->stack[graph->top].entity = NULL;
|
|
|
|
stack_push(graph, entity);
|
2016-07-20 23:39:02 +08:00
|
|
|
dev_dbg(entity->graph_obj.mdev->dev,
|
|
|
|
"begin graph walk at '%s'\n", entity->name);
|
2010-03-08 03:14:14 +08:00
|
|
|
}
|
2016-11-22 00:48:30 +08:00
|
|
|
EXPORT_SYMBOL_GPL(media_graph_walk_start);
|
2010-03-08 03:14:14 +08:00
|
|
|
|
2016-07-20 23:31:39 +08:00
|
|
|
static void media_graph_walk_iter(struct media_graph *graph)
|
|
|
|
{
|
|
|
|
struct media_entity *entity = stack_top(graph);
|
|
|
|
struct media_link *link;
|
|
|
|
struct media_entity *next;
|
|
|
|
|
|
|
|
link = list_entry(link_top(graph), typeof(*link), list);
|
|
|
|
|
|
|
|
/* The link is not enabled so we do not follow. */
|
|
|
|
if (!(link->flags & MEDIA_LNK_FL_ENABLED)) {
|
|
|
|
link_top(graph) = link_top(graph)->next;
|
2016-07-20 23:39:02 +08:00
|
|
|
dev_dbg(entity->graph_obj.mdev->dev,
|
|
|
|
"walk: skipping disabled link '%s':%u -> '%s':%u\n",
|
|
|
|
link->source->entity->name, link->source->index,
|
|
|
|
link->sink->entity->name, link->sink->index);
|
2016-07-20 23:31:39 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get the entity in the other end of the link . */
|
|
|
|
next = media_entity_other(entity, link);
|
|
|
|
|
|
|
|
/* Has the entity already been visited? */
|
|
|
|
if (media_entity_enum_test_and_set(&graph->ent_enum, next)) {
|
|
|
|
link_top(graph) = link_top(graph)->next;
|
2016-07-20 23:39:02 +08:00
|
|
|
dev_dbg(entity->graph_obj.mdev->dev,
|
|
|
|
"walk: skipping entity '%s' (already seen)\n",
|
|
|
|
next->name);
|
2016-07-20 23:31:39 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Push the new entity to stack and start over. */
|
|
|
|
link_top(graph) = link_top(graph)->next;
|
|
|
|
stack_push(graph, next);
|
2016-07-20 23:39:02 +08:00
|
|
|
dev_dbg(entity->graph_obj.mdev->dev, "walk: pushing '%s' on stack\n",
|
|
|
|
next->name);
|
2016-07-20 23:31:39 +08:00
|
|
|
}
|
|
|
|
|
2016-11-22 00:48:30 +08:00
|
|
|
struct media_entity *media_graph_walk_next(struct media_graph *graph)
|
2010-03-08 03:14:14 +08:00
|
|
|
{
|
2016-07-20 23:39:02 +08:00
|
|
|
struct media_entity *entity;
|
|
|
|
|
2010-03-08 03:14:14 +08:00
|
|
|
if (stack_top(graph) == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Depth first search. Push entity to stack and continue from
|
|
|
|
* top of the stack until no more entities on the level can be
|
|
|
|
* found.
|
|
|
|
*/
|
2016-07-20 23:31:39 +08:00
|
|
|
while (link_top(graph) != &stack_top(graph)->links)
|
|
|
|
media_graph_walk_iter(graph);
|
2010-03-08 03:14:14 +08:00
|
|
|
|
2016-07-20 23:39:02 +08:00
|
|
|
entity = stack_pop(graph);
|
|
|
|
dev_dbg(entity->graph_obj.mdev->dev,
|
|
|
|
"walk: returning entity '%s'\n", entity->name);
|
|
|
|
|
|
|
|
return entity;
|
2010-03-08 03:14:14 +08:00
|
|
|
}
|
2016-11-22 00:48:30 +08:00
|
|
|
EXPORT_SYMBOL_GPL(media_graph_walk_next);
|
2010-03-08 03:14:14 +08:00
|
|
|
|
2017-06-15 17:17:26 +08:00
|
|
|
int media_entity_get_fwnode_pad(struct media_entity *entity,
|
|
|
|
struct fwnode_handle *fwnode,
|
|
|
|
unsigned long direction_flags)
|
|
|
|
{
|
|
|
|
struct fwnode_endpoint endpoint;
|
|
|
|
unsigned int i;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (!entity->ops || !entity->ops->get_fwnode_pad) {
|
|
|
|
for (i = 0; i < entity->num_pads; i++) {
|
|
|
|
if (entity->pads[i].flags & direction_flags)
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -ENXIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = fwnode_graph_parse_endpoint(fwnode, &endpoint);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
ret = entity->ops->get_fwnode_pad(&endpoint);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
if (ret >= entity->num_pads)
|
|
|
|
return -ENXIO;
|
|
|
|
|
|
|
|
if (!(entity->pads[ret].flags & direction_flags))
|
|
|
|
return -ENXIO;
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(media_entity_get_fwnode_pad);
|
|
|
|
|
2010-08-25 20:00:41 +08:00
|
|
|
/* -----------------------------------------------------------------------------
|
|
|
|
* Pipeline management
|
|
|
|
*/
|
|
|
|
|
2016-11-22 00:48:30 +08:00
|
|
|
__must_check int __media_pipeline_start(struct media_entity *entity,
|
|
|
|
struct media_pipeline *pipe)
|
2010-08-25 20:00:41 +08:00
|
|
|
{
|
2015-08-19 23:35:21 +08:00
|
|
|
struct media_device *mdev = entity->graph_obj.mdev;
|
2016-11-22 00:48:30 +08:00
|
|
|
struct media_graph *graph = &pipe->graph;
|
2012-01-11 17:25:15 +08:00
|
|
|
struct media_entity *entity_err = entity;
|
[media] media: convert links from array to list
The entire logic that represent graph links were developed on a
time where there were no needs to dynamic remove links. So,
although links are created/removed one by one via some
functions, they're stored as an array inside the entity struct.
As the array may grow, there's a logic inside the code that
checks if the amount of space is not enough to store
the needed links. If it isn't the core uses krealloc()
to change the size of the link, with is bad, as it
leaves the memory fragmented.
So, convert links into a list.
Also, currently, both source and sink entities need the link
at the graph traversal logic inside media_entity. So there's
a logic duplicating all links. That makes it to spend
twice the memory needed. This is not a big deal for today's
usage, where the number of links are not big.
Yet, if during the MC workshop discussions, it was said that
IIO graphs could have up to 4,000 entities. So, we may
want to remove the duplication on some future. The problem
is that it would require a separate linked list to store
the backlinks inside the entity, or to use a more complex
algorithm to do graph backlink traversal, with is something
that the current graph traversal inside the core can't cope
with. So, let's postpone a such change if/when it is actually
needed.
It should also be noticed that the media_link structure uses
44 bytes on 32-bit architectures and 84 bytes on 64-bit
architecture. It will thus be allocated out of the 64-bytes and
96-bytes pools respectively. That's a 12.5% memory waste on
64-bit architectures and 31.25% on 32-bit architecture.
A linked list is less efficient than an array in this case, but
this could later be optimized if we can get rid of the reverse
links (with would reduce memory allocation by 50%).
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
2015-08-07 17:55:40 +08:00
|
|
|
struct media_link *link;
|
2012-01-11 17:25:15 +08:00
|
|
|
int ret;
|
2010-08-25 20:00:41 +08:00
|
|
|
|
2015-12-16 21:32:29 +08:00
|
|
|
if (!pipe->streaming_count++) {
|
2016-11-22 00:48:30 +08:00
|
|
|
ret = media_graph_walk_init(&pipe->graph, mdev);
|
2015-12-16 21:32:29 +08:00
|
|
|
if (ret)
|
|
|
|
goto error_graph_walk_start;
|
2015-12-16 21:32:23 +08:00
|
|
|
}
|
|
|
|
|
2016-11-22 00:48:30 +08:00
|
|
|
media_graph_walk_start(&pipe->graph, entity);
|
2010-08-25 20:00:41 +08:00
|
|
|
|
2016-11-22 00:48:30 +08:00
|
|
|
while ((entity = media_graph_walk_next(graph))) {
|
2015-10-02 05:07:53 +08:00
|
|
|
DECLARE_BITMAP(active, MEDIA_ENTITY_MAX_PADS);
|
|
|
|
DECLARE_BITMAP(has_no_links, MEDIA_ENTITY_MAX_PADS);
|
2012-01-11 17:25:15 +08:00
|
|
|
|
2010-08-25 20:00:41 +08:00
|
|
|
entity->stream_count++;
|
2015-11-30 03:20:02 +08:00
|
|
|
|
|
|
|
if (WARN_ON(entity->pipe && entity->pipe != pipe)) {
|
|
|
|
ret = -EBUSY;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2010-08-25 20:00:41 +08:00
|
|
|
entity->pipe = pipe;
|
2012-01-11 17:25:15 +08:00
|
|
|
|
|
|
|
/* Already streaming --- no need to check. */
|
|
|
|
if (entity->stream_count > 1)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!entity->ops || !entity->ops->link_validate)
|
|
|
|
continue;
|
|
|
|
|
2013-10-13 19:00:26 +08:00
|
|
|
bitmap_zero(active, entity->num_pads);
|
|
|
|
bitmap_fill(has_no_links, entity->num_pads);
|
|
|
|
|
[media] media: convert links from array to list
The entire logic that represent graph links were developed on a
time where there were no needs to dynamic remove links. So,
although links are created/removed one by one via some
functions, they're stored as an array inside the entity struct.
As the array may grow, there's a logic inside the code that
checks if the amount of space is not enough to store
the needed links. If it isn't the core uses krealloc()
to change the size of the link, with is bad, as it
leaves the memory fragmented.
So, convert links into a list.
Also, currently, both source and sink entities need the link
at the graph traversal logic inside media_entity. So there's
a logic duplicating all links. That makes it to spend
twice the memory needed. This is not a big deal for today's
usage, where the number of links are not big.
Yet, if during the MC workshop discussions, it was said that
IIO graphs could have up to 4,000 entities. So, we may
want to remove the duplication on some future. The problem
is that it would require a separate linked list to store
the backlinks inside the entity, or to use a more complex
algorithm to do graph backlink traversal, with is something
that the current graph traversal inside the core can't cope
with. So, let's postpone a such change if/when it is actually
needed.
It should also be noticed that the media_link structure uses
44 bytes on 32-bit architectures and 84 bytes on 64-bit
architecture. It will thus be allocated out of the 64-bytes and
96-bytes pools respectively. That's a 12.5% memory waste on
64-bit architectures and 31.25% on 32-bit architecture.
A linked list is less efficient than an array in this case, but
this could later be optimized if we can get rid of the reverse
links (with would reduce memory allocation by 50%).
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
2015-08-07 17:55:40 +08:00
|
|
|
list_for_each_entry(link, &entity->links, list) {
|
2013-10-13 19:00:26 +08:00
|
|
|
struct media_pad *pad = link->sink->entity == entity
|
|
|
|
? link->sink : link->source;
|
|
|
|
|
|
|
|
/* Mark that a pad is connected by a link. */
|
|
|
|
bitmap_clear(has_no_links, pad->index, 1);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Pads that either do not need to connect or
|
|
|
|
* are connected through an enabled link are
|
|
|
|
* fine.
|
|
|
|
*/
|
|
|
|
if (!(pad->flags & MEDIA_PAD_FL_MUST_CONNECT) ||
|
|
|
|
link->flags & MEDIA_LNK_FL_ENABLED)
|
|
|
|
bitmap_set(active, pad->index, 1);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Link validation will only take place for
|
|
|
|
* sink ends of the link that are enabled.
|
|
|
|
*/
|
|
|
|
if (link->sink != pad ||
|
|
|
|
!(link->flags & MEDIA_LNK_FL_ENABLED))
|
2012-01-11 17:25:15 +08:00
|
|
|
continue;
|
|
|
|
|
|
|
|
ret = entity->ops->link_validate(link);
|
2014-10-29 07:35:04 +08:00
|
|
|
if (ret < 0 && ret != -ENOIOCTLCMD) {
|
2015-08-19 23:35:21 +08:00
|
|
|
dev_dbg(entity->graph_obj.mdev->dev,
|
2016-12-08 23:22:29 +08:00
|
|
|
"link validation failed for '%s':%u -> '%s':%u, error %d\n",
|
2015-02-12 21:43:11 +08:00
|
|
|
link->source->entity->name,
|
|
|
|
link->source->index,
|
|
|
|
entity->name, link->sink->index, ret);
|
2012-01-11 17:25:15 +08:00
|
|
|
goto error;
|
2014-10-29 07:35:04 +08:00
|
|
|
}
|
2012-01-11 17:25:15 +08:00
|
|
|
}
|
2013-10-13 19:00:26 +08:00
|
|
|
|
|
|
|
/* Either no links or validated links are fine. */
|
|
|
|
bitmap_or(active, active, has_no_links, entity->num_pads);
|
|
|
|
|
|
|
|
if (!bitmap_full(active, entity->num_pads)) {
|
2015-06-29 03:14:10 +08:00
|
|
|
ret = -ENOLINK;
|
2015-08-19 23:35:21 +08:00
|
|
|
dev_dbg(entity->graph_obj.mdev->dev,
|
2016-12-08 23:22:29 +08:00
|
|
|
"'%s':%u must be connected by an enabled link\n",
|
2014-10-29 07:35:04 +08:00
|
|
|
entity->name,
|
2014-11-04 04:55:51 +08:00
|
|
|
(unsigned)find_first_zero_bit(
|
|
|
|
active, entity->num_pads));
|
2013-10-13 19:00:26 +08:00
|
|
|
goto error;
|
|
|
|
}
|
2010-08-25 20:00:41 +08:00
|
|
|
}
|
|
|
|
|
2012-01-11 17:25:15 +08:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
error:
|
|
|
|
/*
|
|
|
|
* Link validation on graph failed. We revert what we did and
|
|
|
|
* return the error.
|
|
|
|
*/
|
2016-11-22 00:48:30 +08:00
|
|
|
media_graph_walk_start(graph, entity_err);
|
2012-01-11 17:25:15 +08:00
|
|
|
|
2016-11-22 00:48:30 +08:00
|
|
|
while ((entity_err = media_graph_walk_next(graph))) {
|
2016-07-20 20:19:03 +08:00
|
|
|
/* Sanity check for negative stream_count */
|
|
|
|
if (!WARN_ON_ONCE(entity_err->stream_count <= 0)) {
|
2016-01-31 04:10:52 +08:00
|
|
|
entity_err->stream_count--;
|
|
|
|
if (entity_err->stream_count == 0)
|
|
|
|
entity_err->pipe = NULL;
|
|
|
|
}
|
2012-01-11 17:25:15 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* We haven't increased stream_count further than this
|
|
|
|
* so we quit here.
|
|
|
|
*/
|
|
|
|
if (entity_err == entity)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2015-12-16 21:32:29 +08:00
|
|
|
error_graph_walk_start:
|
|
|
|
if (!--pipe->streaming_count)
|
2016-11-22 00:48:30 +08:00
|
|
|
media_graph_walk_cleanup(graph);
|
2015-12-16 21:32:23 +08:00
|
|
|
|
2016-02-12 07:41:24 +08:00
|
|
|
return ret;
|
|
|
|
}
|
2016-11-22 00:48:30 +08:00
|
|
|
EXPORT_SYMBOL_GPL(__media_pipeline_start);
|
2012-01-11 17:25:15 +08:00
|
|
|
|
2016-11-22 00:48:30 +08:00
|
|
|
__must_check int media_pipeline_start(struct media_entity *entity,
|
|
|
|
struct media_pipeline *pipe)
|
2016-02-12 07:41:24 +08:00
|
|
|
{
|
|
|
|
struct media_device *mdev = entity->graph_obj.mdev;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
mutex_lock(&mdev->graph_mutex);
|
2016-11-22 00:48:30 +08:00
|
|
|
ret = __media_pipeline_start(entity, pipe);
|
2016-02-12 07:41:24 +08:00
|
|
|
mutex_unlock(&mdev->graph_mutex);
|
2012-01-11 17:25:15 +08:00
|
|
|
return ret;
|
2010-08-25 20:00:41 +08:00
|
|
|
}
|
2016-11-22 00:48:30 +08:00
|
|
|
EXPORT_SYMBOL_GPL(media_pipeline_start);
|
2010-08-25 20:00:41 +08:00
|
|
|
|
2016-11-22 00:48:30 +08:00
|
|
|
void __media_pipeline_stop(struct media_entity *entity)
|
2010-08-25 20:00:41 +08:00
|
|
|
{
|
2016-11-22 00:48:30 +08:00
|
|
|
struct media_graph *graph = &entity->pipe->graph;
|
2015-12-16 21:32:29 +08:00
|
|
|
struct media_pipeline *pipe = entity->pipe;
|
2010-08-25 20:00:41 +08:00
|
|
|
|
2017-01-03 21:12:11 +08:00
|
|
|
/*
|
|
|
|
* If the following check fails, the driver has performed an
|
|
|
|
* unbalanced call to media_pipeline_stop()
|
|
|
|
*/
|
|
|
|
if (WARN_ON(!pipe))
|
|
|
|
return;
|
2010-08-25 20:00:41 +08:00
|
|
|
|
2016-11-22 00:48:30 +08:00
|
|
|
media_graph_walk_start(graph, entity);
|
2010-08-25 20:00:41 +08:00
|
|
|
|
2016-11-22 00:48:30 +08:00
|
|
|
while ((entity = media_graph_walk_next(graph))) {
|
2016-07-20 20:19:03 +08:00
|
|
|
/* Sanity check for negative stream_count */
|
|
|
|
if (!WARN_ON_ONCE(entity->stream_count <= 0)) {
|
2016-01-31 04:10:52 +08:00
|
|
|
entity->stream_count--;
|
|
|
|
if (entity->stream_count == 0)
|
|
|
|
entity->pipe = NULL;
|
|
|
|
}
|
2010-08-25 20:00:41 +08:00
|
|
|
}
|
|
|
|
|
2015-12-16 21:32:29 +08:00
|
|
|
if (!--pipe->streaming_count)
|
2016-11-22 00:48:30 +08:00
|
|
|
media_graph_walk_cleanup(graph);
|
2015-12-16 21:32:23 +08:00
|
|
|
|
2016-02-12 07:41:24 +08:00
|
|
|
}
|
2016-11-22 00:48:30 +08:00
|
|
|
EXPORT_SYMBOL_GPL(__media_pipeline_stop);
|
2016-02-12 07:41:24 +08:00
|
|
|
|
2016-11-22 00:48:30 +08:00
|
|
|
void media_pipeline_stop(struct media_entity *entity)
|
2016-02-12 07:41:24 +08:00
|
|
|
{
|
|
|
|
struct media_device *mdev = entity->graph_obj.mdev;
|
|
|
|
|
|
|
|
mutex_lock(&mdev->graph_mutex);
|
2016-11-22 00:48:30 +08:00
|
|
|
__media_pipeline_stop(entity);
|
2010-08-25 20:00:41 +08:00
|
|
|
mutex_unlock(&mdev->graph_mutex);
|
|
|
|
}
|
2016-11-22 00:48:30 +08:00
|
|
|
EXPORT_SYMBOL_GPL(media_pipeline_stop);
|
2010-08-25 20:00:41 +08:00
|
|
|
|
2010-03-08 02:04:59 +08:00
|
|
|
/* -----------------------------------------------------------------------------
|
|
|
|
* Module use count
|
|
|
|
*/
|
|
|
|
|
|
|
|
struct media_entity *media_entity_get(struct media_entity *entity)
|
|
|
|
{
|
|
|
|
if (entity == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
2015-08-19 23:35:21 +08:00
|
|
|
if (entity->graph_obj.mdev->dev &&
|
|
|
|
!try_module_get(entity->graph_obj.mdev->dev->driver->owner))
|
2010-03-08 02:04:59 +08:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return entity;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(media_entity_get);
|
|
|
|
|
|
|
|
void media_entity_put(struct media_entity *entity)
|
|
|
|
{
|
|
|
|
if (entity == NULL)
|
|
|
|
return;
|
|
|
|
|
2015-08-19 23:35:21 +08:00
|
|
|
if (entity->graph_obj.mdev->dev)
|
|
|
|
module_put(entity->graph_obj.mdev->dev->driver->owner);
|
2010-03-08 02:04:59 +08:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(media_entity_put);
|
|
|
|
|
2010-03-08 03:14:14 +08:00
|
|
|
/* -----------------------------------------------------------------------------
|
|
|
|
* Links management
|
|
|
|
*/
|
|
|
|
|
2015-08-20 19:21:35 +08:00
|
|
|
static struct media_link *media_add_link(struct list_head *head)
|
2009-12-09 19:40:00 +08:00
|
|
|
{
|
[media] media: convert links from array to list
The entire logic that represent graph links were developed on a
time where there were no needs to dynamic remove links. So,
although links are created/removed one by one via some
functions, they're stored as an array inside the entity struct.
As the array may grow, there's a logic inside the code that
checks if the amount of space is not enough to store
the needed links. If it isn't the core uses krealloc()
to change the size of the link, with is bad, as it
leaves the memory fragmented.
So, convert links into a list.
Also, currently, both source and sink entities need the link
at the graph traversal logic inside media_entity. So there's
a logic duplicating all links. That makes it to spend
twice the memory needed. This is not a big deal for today's
usage, where the number of links are not big.
Yet, if during the MC workshop discussions, it was said that
IIO graphs could have up to 4,000 entities. So, we may
want to remove the duplication on some future. The problem
is that it would require a separate linked list to store
the backlinks inside the entity, or to use a more complex
algorithm to do graph backlink traversal, with is something
that the current graph traversal inside the core can't cope
with. So, let's postpone a such change if/when it is actually
needed.
It should also be noticed that the media_link structure uses
44 bytes on 32-bit architectures and 84 bytes on 64-bit
architecture. It will thus be allocated out of the 64-bytes and
96-bytes pools respectively. That's a 12.5% memory waste on
64-bit architectures and 31.25% on 32-bit architecture.
A linked list is less efficient than an array in this case, but
this could later be optimized if we can get rid of the reverse
links (with would reduce memory allocation by 50%).
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
2015-08-07 17:55:40 +08:00
|
|
|
struct media_link *link;
|
2009-12-09 19:40:00 +08:00
|
|
|
|
[media] media: convert links from array to list
The entire logic that represent graph links were developed on a
time where there were no needs to dynamic remove links. So,
although links are created/removed one by one via some
functions, they're stored as an array inside the entity struct.
As the array may grow, there's a logic inside the code that
checks if the amount of space is not enough to store
the needed links. If it isn't the core uses krealloc()
to change the size of the link, with is bad, as it
leaves the memory fragmented.
So, convert links into a list.
Also, currently, both source and sink entities need the link
at the graph traversal logic inside media_entity. So there's
a logic duplicating all links. That makes it to spend
twice the memory needed. This is not a big deal for today's
usage, where the number of links are not big.
Yet, if during the MC workshop discussions, it was said that
IIO graphs could have up to 4,000 entities. So, we may
want to remove the duplication on some future. The problem
is that it would require a separate linked list to store
the backlinks inside the entity, or to use a more complex
algorithm to do graph backlink traversal, with is something
that the current graph traversal inside the core can't cope
with. So, let's postpone a such change if/when it is actually
needed.
It should also be noticed that the media_link structure uses
44 bytes on 32-bit architectures and 84 bytes on 64-bit
architecture. It will thus be allocated out of the 64-bytes and
96-bytes pools respectively. That's a 12.5% memory waste on
64-bit architectures and 31.25% on 32-bit architecture.
A linked list is less efficient than an array in this case, but
this could later be optimized if we can get rid of the reverse
links (with would reduce memory allocation by 50%).
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
2015-08-07 17:55:40 +08:00
|
|
|
link = kzalloc(sizeof(*link), GFP_KERNEL);
|
|
|
|
if (link == NULL)
|
|
|
|
return NULL;
|
2009-12-09 19:40:00 +08:00
|
|
|
|
2015-08-20 19:21:35 +08:00
|
|
|
list_add_tail(&link->list, head);
|
2009-12-09 19:40:00 +08:00
|
|
|
|
[media] media: convert links from array to list
The entire logic that represent graph links were developed on a
time where there were no needs to dynamic remove links. So,
although links are created/removed one by one via some
functions, they're stored as an array inside the entity struct.
As the array may grow, there's a logic inside the code that
checks if the amount of space is not enough to store
the needed links. If it isn't the core uses krealloc()
to change the size of the link, with is bad, as it
leaves the memory fragmented.
So, convert links into a list.
Also, currently, both source and sink entities need the link
at the graph traversal logic inside media_entity. So there's
a logic duplicating all links. That makes it to spend
twice the memory needed. This is not a big deal for today's
usage, where the number of links are not big.
Yet, if during the MC workshop discussions, it was said that
IIO graphs could have up to 4,000 entities. So, we may
want to remove the duplication on some future. The problem
is that it would require a separate linked list to store
the backlinks inside the entity, or to use a more complex
algorithm to do graph backlink traversal, with is something
that the current graph traversal inside the core can't cope
with. So, let's postpone a such change if/when it is actually
needed.
It should also be noticed that the media_link structure uses
44 bytes on 32-bit architectures and 84 bytes on 64-bit
architecture. It will thus be allocated out of the 64-bytes and
96-bytes pools respectively. That's a 12.5% memory waste on
64-bit architectures and 31.25% on 32-bit architecture.
A linked list is less efficient than an array in this case, but
this could later be optimized if we can get rid of the reverse
links (with would reduce memory allocation by 50%).
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
2015-08-07 17:55:40 +08:00
|
|
|
return link;
|
2009-12-09 19:40:00 +08:00
|
|
|
}
|
|
|
|
|
[media] media: convert links from array to list
The entire logic that represent graph links were developed on a
time where there were no needs to dynamic remove links. So,
although links are created/removed one by one via some
functions, they're stored as an array inside the entity struct.
As the array may grow, there's a logic inside the code that
checks if the amount of space is not enough to store
the needed links. If it isn't the core uses krealloc()
to change the size of the link, with is bad, as it
leaves the memory fragmented.
So, convert links into a list.
Also, currently, both source and sink entities need the link
at the graph traversal logic inside media_entity. So there's
a logic duplicating all links. That makes it to spend
twice the memory needed. This is not a big deal for today's
usage, where the number of links are not big.
Yet, if during the MC workshop discussions, it was said that
IIO graphs could have up to 4,000 entities. So, we may
want to remove the duplication on some future. The problem
is that it would require a separate linked list to store
the backlinks inside the entity, or to use a more complex
algorithm to do graph backlink traversal, with is something
that the current graph traversal inside the core can't cope
with. So, let's postpone a such change if/when it is actually
needed.
It should also be noticed that the media_link structure uses
44 bytes on 32-bit architectures and 84 bytes on 64-bit
architecture. It will thus be allocated out of the 64-bytes and
96-bytes pools respectively. That's a 12.5% memory waste on
64-bit architectures and 31.25% on 32-bit architecture.
A linked list is less efficient than an array in this case, but
this could later be optimized if we can get rid of the reverse
links (with would reduce memory allocation by 50%).
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
2015-08-07 17:55:40 +08:00
|
|
|
static void __media_entity_remove_link(struct media_entity *entity,
|
2015-12-11 21:19:38 +08:00
|
|
|
struct media_link *link)
|
|
|
|
{
|
|
|
|
struct media_link *rlink, *tmp;
|
|
|
|
struct media_entity *remote;
|
|
|
|
|
|
|
|
if (link->source->entity == entity)
|
|
|
|
remote = link->sink->entity;
|
|
|
|
else
|
|
|
|
remote = link->source->entity;
|
|
|
|
|
|
|
|
list_for_each_entry_safe(rlink, tmp, &remote->links, list) {
|
2015-12-11 21:25:23 +08:00
|
|
|
if (rlink != link->reverse)
|
2015-12-11 21:19:38 +08:00
|
|
|
continue;
|
|
|
|
|
|
|
|
if (link->source->entity == entity)
|
|
|
|
remote->num_backlinks--;
|
|
|
|
|
|
|
|
/* Remove the remote link */
|
|
|
|
list_del(&rlink->list);
|
2015-12-11 21:55:40 +08:00
|
|
|
media_gobj_destroy(&rlink->graph_obj);
|
2015-12-11 21:19:38 +08:00
|
|
|
kfree(rlink);
|
|
|
|
|
|
|
|
if (--remote->num_links == 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
list_del(&link->list);
|
2015-12-11 21:55:40 +08:00
|
|
|
media_gobj_destroy(&link->graph_obj);
|
2015-12-11 21:19:38 +08:00
|
|
|
kfree(link);
|
|
|
|
}
|
[media] media: convert links from array to list
The entire logic that represent graph links were developed on a
time where there were no needs to dynamic remove links. So,
although links are created/removed one by one via some
functions, they're stored as an array inside the entity struct.
As the array may grow, there's a logic inside the code that
checks if the amount of space is not enough to store
the needed links. If it isn't the core uses krealloc()
to change the size of the link, with is bad, as it
leaves the memory fragmented.
So, convert links into a list.
Also, currently, both source and sink entities need the link
at the graph traversal logic inside media_entity. So there's
a logic duplicating all links. That makes it to spend
twice the memory needed. This is not a big deal for today's
usage, where the number of links are not big.
Yet, if during the MC workshop discussions, it was said that
IIO graphs could have up to 4,000 entities. So, we may
want to remove the duplication on some future. The problem
is that it would require a separate linked list to store
the backlinks inside the entity, or to use a more complex
algorithm to do graph backlink traversal, with is something
that the current graph traversal inside the core can't cope
with. So, let's postpone a such change if/when it is actually
needed.
It should also be noticed that the media_link structure uses
44 bytes on 32-bit architectures and 84 bytes on 64-bit
architecture. It will thus be allocated out of the 64-bytes and
96-bytes pools respectively. That's a 12.5% memory waste on
64-bit architectures and 31.25% on 32-bit architecture.
A linked list is less efficient than an array in this case, but
this could later be optimized if we can get rid of the reverse
links (with would reduce memory allocation by 50%).
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
2015-08-07 17:55:40 +08:00
|
|
|
|
2009-12-09 19:40:00 +08:00
|
|
|
int
|
2015-08-07 19:14:38 +08:00
|
|
|
media_create_pad_link(struct media_entity *source, u16 source_pad,
|
2009-12-09 19:40:00 +08:00
|
|
|
struct media_entity *sink, u16 sink_pad, u32 flags)
|
|
|
|
{
|
|
|
|
struct media_link *link;
|
|
|
|
struct media_link *backlink;
|
|
|
|
|
|
|
|
BUG_ON(source == NULL || sink == NULL);
|
|
|
|
BUG_ON(source_pad >= source->num_pads);
|
|
|
|
BUG_ON(sink_pad >= sink->num_pads);
|
|
|
|
|
2015-08-20 19:21:35 +08:00
|
|
|
link = media_add_link(&source->links);
|
2009-12-09 19:40:00 +08:00
|
|
|
if (link == NULL)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
link->source = &source->pads[source_pad];
|
|
|
|
link->sink = &sink->pads[sink_pad];
|
2015-12-12 04:09:13 +08:00
|
|
|
link->flags = flags & ~MEDIA_LNK_FL_INTERFACE_LINK;
|
2009-12-09 19:40:00 +08:00
|
|
|
|
2015-08-14 23:54:36 +08:00
|
|
|
/* Initialize graph object embedded at the new link */
|
2015-12-11 21:55:40 +08:00
|
|
|
media_gobj_create(source->graph_obj.mdev, MEDIA_GRAPH_LINK,
|
2015-08-19 23:35:21 +08:00
|
|
|
&link->graph_obj);
|
2015-08-14 23:54:36 +08:00
|
|
|
|
2009-12-09 19:40:00 +08:00
|
|
|
/* Create the backlink. Backlinks are used to help graph traversal and
|
|
|
|
* are not reported to userspace.
|
|
|
|
*/
|
2015-08-20 19:21:35 +08:00
|
|
|
backlink = media_add_link(&sink->links);
|
2009-12-09 19:40:00 +08:00
|
|
|
if (backlink == NULL) {
|
[media] media: convert links from array to list
The entire logic that represent graph links were developed on a
time where there were no needs to dynamic remove links. So,
although links are created/removed one by one via some
functions, they're stored as an array inside the entity struct.
As the array may grow, there's a logic inside the code that
checks if the amount of space is not enough to store
the needed links. If it isn't the core uses krealloc()
to change the size of the link, with is bad, as it
leaves the memory fragmented.
So, convert links into a list.
Also, currently, both source and sink entities need the link
at the graph traversal logic inside media_entity. So there's
a logic duplicating all links. That makes it to spend
twice the memory needed. This is not a big deal for today's
usage, where the number of links are not big.
Yet, if during the MC workshop discussions, it was said that
IIO graphs could have up to 4,000 entities. So, we may
want to remove the duplication on some future. The problem
is that it would require a separate linked list to store
the backlinks inside the entity, or to use a more complex
algorithm to do graph backlink traversal, with is something
that the current graph traversal inside the core can't cope
with. So, let's postpone a such change if/when it is actually
needed.
It should also be noticed that the media_link structure uses
44 bytes on 32-bit architectures and 84 bytes on 64-bit
architecture. It will thus be allocated out of the 64-bytes and
96-bytes pools respectively. That's a 12.5% memory waste on
64-bit architectures and 31.25% on 32-bit architecture.
A linked list is less efficient than an array in this case, but
this could later be optimized if we can get rid of the reverse
links (with would reduce memory allocation by 50%).
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
2015-08-07 17:55:40 +08:00
|
|
|
__media_entity_remove_link(source, link);
|
2009-12-09 19:40:00 +08:00
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
backlink->source = &source->pads[source_pad];
|
|
|
|
backlink->sink = &sink->pads[sink_pad];
|
|
|
|
backlink->flags = flags;
|
2015-08-30 20:53:57 +08:00
|
|
|
backlink->is_backlink = true;
|
2009-12-09 19:40:00 +08:00
|
|
|
|
2015-08-14 23:54:36 +08:00
|
|
|
/* Initialize graph object embedded at the new link */
|
2015-12-11 21:55:40 +08:00
|
|
|
media_gobj_create(sink->graph_obj.mdev, MEDIA_GRAPH_LINK,
|
2015-08-19 23:35:21 +08:00
|
|
|
&backlink->graph_obj);
|
2015-08-14 23:54:36 +08:00
|
|
|
|
2009-12-09 19:40:00 +08:00
|
|
|
link->reverse = backlink;
|
|
|
|
backlink->reverse = link;
|
|
|
|
|
|
|
|
sink->num_backlinks++;
|
[media] media: convert links from array to list
The entire logic that represent graph links were developed on a
time where there were no needs to dynamic remove links. So,
although links are created/removed one by one via some
functions, they're stored as an array inside the entity struct.
As the array may grow, there's a logic inside the code that
checks if the amount of space is not enough to store
the needed links. If it isn't the core uses krealloc()
to change the size of the link, with is bad, as it
leaves the memory fragmented.
So, convert links into a list.
Also, currently, both source and sink entities need the link
at the graph traversal logic inside media_entity. So there's
a logic duplicating all links. That makes it to spend
twice the memory needed. This is not a big deal for today's
usage, where the number of links are not big.
Yet, if during the MC workshop discussions, it was said that
IIO graphs could have up to 4,000 entities. So, we may
want to remove the duplication on some future. The problem
is that it would require a separate linked list to store
the backlinks inside the entity, or to use a more complex
algorithm to do graph backlink traversal, with is something
that the current graph traversal inside the core can't cope
with. So, let's postpone a such change if/when it is actually
needed.
It should also be noticed that the media_link structure uses
44 bytes on 32-bit architectures and 84 bytes on 64-bit
architecture. It will thus be allocated out of the 64-bytes and
96-bytes pools respectively. That's a 12.5% memory waste on
64-bit architectures and 31.25% on 32-bit architecture.
A linked list is less efficient than an array in this case, but
this could later be optimized if we can get rid of the reverse
links (with would reduce memory allocation by 50%).
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
2015-08-07 17:55:40 +08:00
|
|
|
sink->num_links++;
|
|
|
|
source->num_links++;
|
2009-12-09 19:40:00 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2015-08-07 19:14:38 +08:00
|
|
|
EXPORT_SYMBOL_GPL(media_create_pad_link);
|
2009-12-09 19:40:03 +08:00
|
|
|
|
2015-12-30 19:45:48 +08:00
|
|
|
int media_create_pad_links(const struct media_device *mdev,
|
|
|
|
const u32 source_function,
|
|
|
|
struct media_entity *source,
|
|
|
|
const u16 source_pad,
|
|
|
|
const u32 sink_function,
|
|
|
|
struct media_entity *sink,
|
|
|
|
const u16 sink_pad,
|
|
|
|
u32 flags,
|
|
|
|
const bool allow_both_undefined)
|
|
|
|
{
|
|
|
|
struct media_entity *entity;
|
|
|
|
unsigned function;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
/* Trivial case: 1:1 relation */
|
|
|
|
if (source && sink)
|
|
|
|
return media_create_pad_link(source, source_pad,
|
|
|
|
sink, sink_pad, flags);
|
|
|
|
|
|
|
|
/* Worse case scenario: n:n relation */
|
|
|
|
if (!source && !sink) {
|
|
|
|
if (!allow_both_undefined)
|
|
|
|
return 0;
|
|
|
|
media_device_for_each_entity(source, mdev) {
|
|
|
|
if (source->function != source_function)
|
|
|
|
continue;
|
|
|
|
media_device_for_each_entity(sink, mdev) {
|
|
|
|
if (sink->function != sink_function)
|
|
|
|
continue;
|
|
|
|
ret = media_create_pad_link(source, source_pad,
|
|
|
|
sink, sink_pad,
|
|
|
|
flags);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
flags &= ~(MEDIA_LNK_FL_ENABLED |
|
|
|
|
MEDIA_LNK_FL_IMMUTABLE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Handle 1:n and n:1 cases */
|
|
|
|
if (source)
|
|
|
|
function = sink_function;
|
|
|
|
else
|
|
|
|
function = source_function;
|
|
|
|
|
|
|
|
media_device_for_each_entity(entity, mdev) {
|
|
|
|
if (entity->function != function)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (source)
|
|
|
|
ret = media_create_pad_link(source, source_pad,
|
|
|
|
entity, sink_pad, flags);
|
|
|
|
else
|
|
|
|
ret = media_create_pad_link(entity, source_pad,
|
|
|
|
sink, sink_pad, flags);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
flags &= ~(MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(media_create_pad_links);
|
|
|
|
|
[media] media: convert links from array to list
The entire logic that represent graph links were developed on a
time where there were no needs to dynamic remove links. So,
although links are created/removed one by one via some
functions, they're stored as an array inside the entity struct.
As the array may grow, there's a logic inside the code that
checks if the amount of space is not enough to store
the needed links. If it isn't the core uses krealloc()
to change the size of the link, with is bad, as it
leaves the memory fragmented.
So, convert links into a list.
Also, currently, both source and sink entities need the link
at the graph traversal logic inside media_entity. So there's
a logic duplicating all links. That makes it to spend
twice the memory needed. This is not a big deal for today's
usage, where the number of links are not big.
Yet, if during the MC workshop discussions, it was said that
IIO graphs could have up to 4,000 entities. So, we may
want to remove the duplication on some future. The problem
is that it would require a separate linked list to store
the backlinks inside the entity, or to use a more complex
algorithm to do graph backlink traversal, with is something
that the current graph traversal inside the core can't cope
with. So, let's postpone a such change if/when it is actually
needed.
It should also be noticed that the media_link structure uses
44 bytes on 32-bit architectures and 84 bytes on 64-bit
architecture. It will thus be allocated out of the 64-bytes and
96-bytes pools respectively. That's a 12.5% memory waste on
64-bit architectures and 31.25% on 32-bit architecture.
A linked list is less efficient than an array in this case, but
this could later be optimized if we can get rid of the reverse
links (with would reduce memory allocation by 50%).
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
2015-08-07 17:55:40 +08:00
|
|
|
void __media_entity_remove_links(struct media_entity *entity)
|
|
|
|
{
|
|
|
|
struct media_link *link, *tmp;
|
2013-05-09 19:29:32 +08:00
|
|
|
|
[media] media: convert links from array to list
The entire logic that represent graph links were developed on a
time where there were no needs to dynamic remove links. So,
although links are created/removed one by one via some
functions, they're stored as an array inside the entity struct.
As the array may grow, there's a logic inside the code that
checks if the amount of space is not enough to store
the needed links. If it isn't the core uses krealloc()
to change the size of the link, with is bad, as it
leaves the memory fragmented.
So, convert links into a list.
Also, currently, both source and sink entities need the link
at the graph traversal logic inside media_entity. So there's
a logic duplicating all links. That makes it to spend
twice the memory needed. This is not a big deal for today's
usage, where the number of links are not big.
Yet, if during the MC workshop discussions, it was said that
IIO graphs could have up to 4,000 entities. So, we may
want to remove the duplication on some future. The problem
is that it would require a separate linked list to store
the backlinks inside the entity, or to use a more complex
algorithm to do graph backlink traversal, with is something
that the current graph traversal inside the core can't cope
with. So, let's postpone a such change if/when it is actually
needed.
It should also be noticed that the media_link structure uses
44 bytes on 32-bit architectures and 84 bytes on 64-bit
architecture. It will thus be allocated out of the 64-bytes and
96-bytes pools respectively. That's a 12.5% memory waste on
64-bit architectures and 31.25% on 32-bit architecture.
A linked list is less efficient than an array in this case, but
this could later be optimized if we can get rid of the reverse
links (with would reduce memory allocation by 50%).
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
2015-08-07 17:55:40 +08:00
|
|
|
list_for_each_entry_safe(link, tmp, &entity->links, list)
|
|
|
|
__media_entity_remove_link(entity, link);
|
2013-05-09 19:29:32 +08:00
|
|
|
|
|
|
|
entity->num_links = 0;
|
|
|
|
entity->num_backlinks = 0;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(__media_entity_remove_links);
|
|
|
|
|
|
|
|
void media_entity_remove_links(struct media_entity *entity)
|
|
|
|
{
|
2015-12-15 18:01:13 +08:00
|
|
|
struct media_device *mdev = entity->graph_obj.mdev;
|
|
|
|
|
2013-05-09 19:29:32 +08:00
|
|
|
/* Do nothing if the entity is not registered. */
|
2015-12-15 18:01:13 +08:00
|
|
|
if (mdev == NULL)
|
2013-05-09 19:29:32 +08:00
|
|
|
return;
|
|
|
|
|
[media] media-device: get rid of the spinlock
Right now, the lock schema for media_device struct is messy,
since sometimes, it is protected via a spin lock, while, for
media graph traversal, it is protected by a mutex.
Solve this conflict by always using a mutex.
As a side effect, this prevents a bug when the media notifiers
is called at atomic context, while running the notifier callback:
BUG: sleeping function called from invalid context at mm/slub.c:1289
in_atomic(): 1, irqs_disabled(): 0, pid: 3479, name: modprobe
4 locks held by modprobe/3479:
#0: (&dev->mutex){......}, at: [<ffffffff81ce8933>] __driver_attach+0xa3/0x160
#1: (&dev->mutex){......}, at: [<ffffffff81ce8941>] __driver_attach+0xb1/0x160
#2: (register_mutex#5){+.+.+.}, at: [<ffffffffa10596c7>] usb_audio_probe+0x257/0x1c90 [snd_usb_audio]
#3: (&(&mdev->lock)->rlock){+.+.+.}, at: [<ffffffffa0e6051b>] media_device_register_entity+0x1cb/0x700 [media]
CPU: 2 PID: 3479 Comm: modprobe Not tainted 4.5.0-rc3+ #49
Hardware name: /NUC5i7RYB, BIOS RYBDWi35.86A.0350.2015.0812.1722 08/12/2015
0000000000000000 ffff8803b3f6f288 ffffffff81933901 ffff8803c4bae000
ffff8803c4bae5c8 ffff8803b3f6f2b0 ffffffff811c6af5 ffff8803c4bae000
ffffffff8285d7f6 0000000000000509 ffff8803b3f6f2f0 ffffffff811c6ce5
Call Trace:
[<ffffffff81933901>] dump_stack+0x85/0xc4
[<ffffffff811c6af5>] ___might_sleep+0x245/0x3a0
[<ffffffff811c6ce5>] __might_sleep+0x95/0x1a0
[<ffffffff8155aade>] kmem_cache_alloc_trace+0x20e/0x300
[<ffffffffa0e66e3d>] ? media_add_link+0x4d/0x140 [media]
[<ffffffffa0e66e3d>] media_add_link+0x4d/0x140 [media]
[<ffffffffa0e69931>] media_create_pad_link+0xa1/0x600 [media]
[<ffffffffa0fe11b3>] au0828_media_graph_notify+0x173/0x360 [au0828]
[<ffffffffa0e68a6a>] ? media_gobj_create+0x1ba/0x480 [media]
[<ffffffffa0e606fb>] media_device_register_entity+0x3ab/0x700 [media]
Reviewed-by: Javier Martinez Canillas <javier@osg.samsung.com>
Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
2016-04-06 21:55:24 +08:00
|
|
|
mutex_lock(&mdev->graph_mutex);
|
2013-05-09 19:29:32 +08:00
|
|
|
__media_entity_remove_links(entity);
|
[media] media-device: get rid of the spinlock
Right now, the lock schema for media_device struct is messy,
since sometimes, it is protected via a spin lock, while, for
media graph traversal, it is protected by a mutex.
Solve this conflict by always using a mutex.
As a side effect, this prevents a bug when the media notifiers
is called at atomic context, while running the notifier callback:
BUG: sleeping function called from invalid context at mm/slub.c:1289
in_atomic(): 1, irqs_disabled(): 0, pid: 3479, name: modprobe
4 locks held by modprobe/3479:
#0: (&dev->mutex){......}, at: [<ffffffff81ce8933>] __driver_attach+0xa3/0x160
#1: (&dev->mutex){......}, at: [<ffffffff81ce8941>] __driver_attach+0xb1/0x160
#2: (register_mutex#5){+.+.+.}, at: [<ffffffffa10596c7>] usb_audio_probe+0x257/0x1c90 [snd_usb_audio]
#3: (&(&mdev->lock)->rlock){+.+.+.}, at: [<ffffffffa0e6051b>] media_device_register_entity+0x1cb/0x700 [media]
CPU: 2 PID: 3479 Comm: modprobe Not tainted 4.5.0-rc3+ #49
Hardware name: /NUC5i7RYB, BIOS RYBDWi35.86A.0350.2015.0812.1722 08/12/2015
0000000000000000 ffff8803b3f6f288 ffffffff81933901 ffff8803c4bae000
ffff8803c4bae5c8 ffff8803b3f6f2b0 ffffffff811c6af5 ffff8803c4bae000
ffffffff8285d7f6 0000000000000509 ffff8803b3f6f2f0 ffffffff811c6ce5
Call Trace:
[<ffffffff81933901>] dump_stack+0x85/0xc4
[<ffffffff811c6af5>] ___might_sleep+0x245/0x3a0
[<ffffffff811c6ce5>] __might_sleep+0x95/0x1a0
[<ffffffff8155aade>] kmem_cache_alloc_trace+0x20e/0x300
[<ffffffffa0e66e3d>] ? media_add_link+0x4d/0x140 [media]
[<ffffffffa0e66e3d>] media_add_link+0x4d/0x140 [media]
[<ffffffffa0e69931>] media_create_pad_link+0xa1/0x600 [media]
[<ffffffffa0fe11b3>] au0828_media_graph_notify+0x173/0x360 [au0828]
[<ffffffffa0e68a6a>] ? media_gobj_create+0x1ba/0x480 [media]
[<ffffffffa0e606fb>] media_device_register_entity+0x3ab/0x700 [media]
Reviewed-by: Javier Martinez Canillas <javier@osg.samsung.com>
Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
2016-04-06 21:55:24 +08:00
|
|
|
mutex_unlock(&mdev->graph_mutex);
|
2013-05-09 19:29:32 +08:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(media_entity_remove_links);
|
|
|
|
|
2009-12-09 19:40:03 +08:00
|
|
|
static int __media_entity_setup_link_notify(struct media_link *link, u32 flags)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
/* Notify both entities. */
|
|
|
|
ret = media_entity_call(link->source->entity, link_setup,
|
|
|
|
link->source, link->sink, flags);
|
|
|
|
if (ret < 0 && ret != -ENOIOCTLCMD)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
ret = media_entity_call(link->sink->entity, link_setup,
|
|
|
|
link->sink, link->source, flags);
|
|
|
|
if (ret < 0 && ret != -ENOIOCTLCMD) {
|
|
|
|
media_entity_call(link->source->entity, link_setup,
|
|
|
|
link->source, link->sink, link->flags);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2011-03-11 22:34:35 +08:00
|
|
|
link->flags = flags;
|
2009-12-09 19:40:03 +08:00
|
|
|
link->reverse->flags = link->flags;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int __media_entity_setup_link(struct media_link *link, u32 flags)
|
|
|
|
{
|
2011-03-11 22:34:35 +08:00
|
|
|
const u32 mask = MEDIA_LNK_FL_ENABLED;
|
2009-12-09 19:40:03 +08:00
|
|
|
struct media_device *mdev;
|
|
|
|
struct media_entity *source, *sink;
|
|
|
|
int ret = -EBUSY;
|
|
|
|
|
|
|
|
if (link == NULL)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2011-03-11 22:34:35 +08:00
|
|
|
/* The non-modifiable link flags must not be modified. */
|
|
|
|
if ((link->flags & ~mask) != (flags & ~mask))
|
|
|
|
return -EINVAL;
|
|
|
|
|
2009-12-09 19:40:03 +08:00
|
|
|
if (link->flags & MEDIA_LNK_FL_IMMUTABLE)
|
|
|
|
return link->flags == flags ? 0 : -EINVAL;
|
|
|
|
|
|
|
|
if (link->flags == flags)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
source = link->source->entity;
|
|
|
|
sink = link->sink->entity;
|
|
|
|
|
2010-08-25 20:00:41 +08:00
|
|
|
if (!(link->flags & MEDIA_LNK_FL_DYNAMIC) &&
|
|
|
|
(source->stream_count || sink->stream_count))
|
|
|
|
return -EBUSY;
|
|
|
|
|
2015-08-19 23:35:21 +08:00
|
|
|
mdev = source->graph_obj.mdev;
|
2009-12-09 19:40:03 +08:00
|
|
|
|
2015-11-03 10:27:51 +08:00
|
|
|
if (mdev->ops && mdev->ops->link_notify) {
|
|
|
|
ret = mdev->ops->link_notify(link, flags,
|
|
|
|
MEDIA_DEV_NOTIFY_PRE_LINK_CH);
|
2009-12-09 19:40:03 +08:00
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = __media_entity_setup_link_notify(link, flags);
|
|
|
|
|
2015-11-03 10:27:51 +08:00
|
|
|
if (mdev->ops && mdev->ops->link_notify)
|
|
|
|
mdev->ops->link_notify(link, flags,
|
|
|
|
MEDIA_DEV_NOTIFY_POST_LINK_CH);
|
2009-12-09 19:40:03 +08:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
2016-02-12 07:41:23 +08:00
|
|
|
EXPORT_SYMBOL_GPL(__media_entity_setup_link);
|
2009-12-09 19:40:03 +08:00
|
|
|
|
|
|
|
int media_entity_setup_link(struct media_link *link, u32 flags)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
2015-12-15 17:58:18 +08:00
|
|
|
mutex_lock(&link->graph_obj.mdev->graph_mutex);
|
2009-12-09 19:40:03 +08:00
|
|
|
ret = __media_entity_setup_link(link, flags);
|
2015-12-15 17:58:18 +08:00
|
|
|
mutex_unlock(&link->graph_obj.mdev->graph_mutex);
|
2009-12-09 19:40:03 +08:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(media_entity_setup_link);
|
|
|
|
|
|
|
|
struct media_link *
|
|
|
|
media_entity_find_link(struct media_pad *source, struct media_pad *sink)
|
|
|
|
{
|
|
|
|
struct media_link *link;
|
|
|
|
|
[media] media: convert links from array to list
The entire logic that represent graph links were developed on a
time where there were no needs to dynamic remove links. So,
although links are created/removed one by one via some
functions, they're stored as an array inside the entity struct.
As the array may grow, there's a logic inside the code that
checks if the amount of space is not enough to store
the needed links. If it isn't the core uses krealloc()
to change the size of the link, with is bad, as it
leaves the memory fragmented.
So, convert links into a list.
Also, currently, both source and sink entities need the link
at the graph traversal logic inside media_entity. So there's
a logic duplicating all links. That makes it to spend
twice the memory needed. This is not a big deal for today's
usage, where the number of links are not big.
Yet, if during the MC workshop discussions, it was said that
IIO graphs could have up to 4,000 entities. So, we may
want to remove the duplication on some future. The problem
is that it would require a separate linked list to store
the backlinks inside the entity, or to use a more complex
algorithm to do graph backlink traversal, with is something
that the current graph traversal inside the core can't cope
with. So, let's postpone a such change if/when it is actually
needed.
It should also be noticed that the media_link structure uses
44 bytes on 32-bit architectures and 84 bytes on 64-bit
architecture. It will thus be allocated out of the 64-bytes and
96-bytes pools respectively. That's a 12.5% memory waste on
64-bit architectures and 31.25% on 32-bit architecture.
A linked list is less efficient than an array in this case, but
this could later be optimized if we can get rid of the reverse
links (with would reduce memory allocation by 50%).
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
2015-08-07 17:55:40 +08:00
|
|
|
list_for_each_entry(link, &source->entity->links, list) {
|
2009-12-09 19:40:03 +08:00
|
|
|
if (link->source->entity == source->entity &&
|
|
|
|
link->source->index == source->index &&
|
|
|
|
link->sink->entity == sink->entity &&
|
|
|
|
link->sink->index == sink->index)
|
|
|
|
return link;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(media_entity_find_link);
|
|
|
|
|
2017-07-03 20:08:11 +08:00
|
|
|
struct media_pad *media_entity_remote_pad(const struct media_pad *pad)
|
2009-12-09 19:40:03 +08:00
|
|
|
{
|
[media] media: convert links from array to list
The entire logic that represent graph links were developed on a
time where there were no needs to dynamic remove links. So,
although links are created/removed one by one via some
functions, they're stored as an array inside the entity struct.
As the array may grow, there's a logic inside the code that
checks if the amount of space is not enough to store
the needed links. If it isn't the core uses krealloc()
to change the size of the link, with is bad, as it
leaves the memory fragmented.
So, convert links into a list.
Also, currently, both source and sink entities need the link
at the graph traversal logic inside media_entity. So there's
a logic duplicating all links. That makes it to spend
twice the memory needed. This is not a big deal for today's
usage, where the number of links are not big.
Yet, if during the MC workshop discussions, it was said that
IIO graphs could have up to 4,000 entities. So, we may
want to remove the duplication on some future. The problem
is that it would require a separate linked list to store
the backlinks inside the entity, or to use a more complex
algorithm to do graph backlink traversal, with is something
that the current graph traversal inside the core can't cope
with. So, let's postpone a such change if/when it is actually
needed.
It should also be noticed that the media_link structure uses
44 bytes on 32-bit architectures and 84 bytes on 64-bit
architecture. It will thus be allocated out of the 64-bytes and
96-bytes pools respectively. That's a 12.5% memory waste on
64-bit architectures and 31.25% on 32-bit architecture.
A linked list is less efficient than an array in this case, but
this could later be optimized if we can get rid of the reverse
links (with would reduce memory allocation by 50%).
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
2015-08-07 17:55:40 +08:00
|
|
|
struct media_link *link;
|
2009-12-09 19:40:03 +08:00
|
|
|
|
[media] media: convert links from array to list
The entire logic that represent graph links were developed on a
time where there were no needs to dynamic remove links. So,
although links are created/removed one by one via some
functions, they're stored as an array inside the entity struct.
As the array may grow, there's a logic inside the code that
checks if the amount of space is not enough to store
the needed links. If it isn't the core uses krealloc()
to change the size of the link, with is bad, as it
leaves the memory fragmented.
So, convert links into a list.
Also, currently, both source and sink entities need the link
at the graph traversal logic inside media_entity. So there's
a logic duplicating all links. That makes it to spend
twice the memory needed. This is not a big deal for today's
usage, where the number of links are not big.
Yet, if during the MC workshop discussions, it was said that
IIO graphs could have up to 4,000 entities. So, we may
want to remove the duplication on some future. The problem
is that it would require a separate linked list to store
the backlinks inside the entity, or to use a more complex
algorithm to do graph backlink traversal, with is something
that the current graph traversal inside the core can't cope
with. So, let's postpone a such change if/when it is actually
needed.
It should also be noticed that the media_link structure uses
44 bytes on 32-bit architectures and 84 bytes on 64-bit
architecture. It will thus be allocated out of the 64-bytes and
96-bytes pools respectively. That's a 12.5% memory waste on
64-bit architectures and 31.25% on 32-bit architecture.
A linked list is less efficient than an array in this case, but
this could later be optimized if we can get rid of the reverse
links (with would reduce memory allocation by 50%).
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
2015-08-07 17:55:40 +08:00
|
|
|
list_for_each_entry(link, &pad->entity->links, list) {
|
2009-12-09 19:40:03 +08:00
|
|
|
if (!(link->flags & MEDIA_LNK_FL_ENABLED))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (link->source == pad)
|
|
|
|
return link->sink;
|
|
|
|
|
|
|
|
if (link->sink == pad)
|
|
|
|
return link->source;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
}
|
2013-06-03 16:16:13 +08:00
|
|
|
EXPORT_SYMBOL_GPL(media_entity_remote_pad);
|
2015-08-20 20:07:34 +08:00
|
|
|
|
2015-08-29 02:43:36 +08:00
|
|
|
static void media_interface_init(struct media_device *mdev,
|
|
|
|
struct media_interface *intf,
|
|
|
|
u32 gobj_type,
|
|
|
|
u32 intf_type, u32 flags)
|
|
|
|
{
|
|
|
|
intf->type = intf_type;
|
|
|
|
intf->flags = flags;
|
|
|
|
INIT_LIST_HEAD(&intf->links);
|
|
|
|
|
2015-12-11 21:55:40 +08:00
|
|
|
media_gobj_create(mdev, gobj_type, &intf->graph_obj);
|
2015-08-29 02:43:36 +08:00
|
|
|
}
|
|
|
|
|
2015-08-20 20:07:34 +08:00
|
|
|
/* Functions related to the media interface via device nodes */
|
|
|
|
|
|
|
|
struct media_intf_devnode *media_devnode_create(struct media_device *mdev,
|
|
|
|
u32 type, u32 flags,
|
2015-09-09 19:19:25 +08:00
|
|
|
u32 major, u32 minor)
|
2015-08-20 20:07:34 +08:00
|
|
|
{
|
|
|
|
struct media_intf_devnode *devnode;
|
|
|
|
|
2015-09-09 19:19:25 +08:00
|
|
|
devnode = kzalloc(sizeof(*devnode), GFP_KERNEL);
|
2015-08-20 20:07:34 +08:00
|
|
|
if (!devnode)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
devnode->major = major;
|
|
|
|
devnode->minor = minor;
|
|
|
|
|
2015-08-29 02:43:36 +08:00
|
|
|
media_interface_init(mdev, &devnode->intf, MEDIA_GRAPH_INTF_DEVNODE,
|
|
|
|
type, flags);
|
2015-08-20 20:07:34 +08:00
|
|
|
|
|
|
|
return devnode;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(media_devnode_create);
|
|
|
|
|
|
|
|
void media_devnode_remove(struct media_intf_devnode *devnode)
|
|
|
|
{
|
2015-08-24 19:46:46 +08:00
|
|
|
media_remove_intf_links(&devnode->intf);
|
2015-12-11 21:55:40 +08:00
|
|
|
media_gobj_destroy(&devnode->intf.graph_obj);
|
2015-08-20 20:07:34 +08:00
|
|
|
kfree(devnode);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(media_devnode_remove);
|
2015-08-07 21:36:25 +08:00
|
|
|
|
|
|
|
struct media_link *media_create_intf_link(struct media_entity *entity,
|
|
|
|
struct media_interface *intf,
|
|
|
|
u32 flags)
|
|
|
|
{
|
|
|
|
struct media_link *link;
|
|
|
|
|
|
|
|
link = media_add_link(&intf->links);
|
|
|
|
if (link == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
link->intf = intf;
|
|
|
|
link->entity = entity;
|
2015-12-12 04:09:13 +08:00
|
|
|
link->flags = flags | MEDIA_LNK_FL_INTERFACE_LINK;
|
2015-08-07 21:36:25 +08:00
|
|
|
|
|
|
|
/* Initialize graph object embedded at the new link */
|
2015-12-11 21:55:40 +08:00
|
|
|
media_gobj_create(intf->graph_obj.mdev, MEDIA_GRAPH_LINK,
|
2015-08-07 21:36:25 +08:00
|
|
|
&link->graph_obj);
|
|
|
|
|
|
|
|
return link;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(media_create_intf_link);
|
|
|
|
|
2015-08-30 08:23:44 +08:00
|
|
|
void __media_remove_intf_link(struct media_link *link)
|
2015-08-07 21:36:25 +08:00
|
|
|
{
|
2015-08-30 08:23:44 +08:00
|
|
|
list_del(&link->list);
|
2015-12-11 21:55:40 +08:00
|
|
|
media_gobj_destroy(&link->graph_obj);
|
2015-08-07 21:36:25 +08:00
|
|
|
kfree(link);
|
|
|
|
}
|
2015-08-30 08:23:44 +08:00
|
|
|
EXPORT_SYMBOL_GPL(__media_remove_intf_link);
|
2015-08-07 21:36:25 +08:00
|
|
|
|
|
|
|
void media_remove_intf_link(struct media_link *link)
|
|
|
|
{
|
2015-12-15 18:01:13 +08:00
|
|
|
struct media_device *mdev = link->graph_obj.mdev;
|
|
|
|
|
|
|
|
/* Do nothing if the intf is not registered. */
|
|
|
|
if (mdev == NULL)
|
|
|
|
return;
|
|
|
|
|
[media] media-device: get rid of the spinlock
Right now, the lock schema for media_device struct is messy,
since sometimes, it is protected via a spin lock, while, for
media graph traversal, it is protected by a mutex.
Solve this conflict by always using a mutex.
As a side effect, this prevents a bug when the media notifiers
is called at atomic context, while running the notifier callback:
BUG: sleeping function called from invalid context at mm/slub.c:1289
in_atomic(): 1, irqs_disabled(): 0, pid: 3479, name: modprobe
4 locks held by modprobe/3479:
#0: (&dev->mutex){......}, at: [<ffffffff81ce8933>] __driver_attach+0xa3/0x160
#1: (&dev->mutex){......}, at: [<ffffffff81ce8941>] __driver_attach+0xb1/0x160
#2: (register_mutex#5){+.+.+.}, at: [<ffffffffa10596c7>] usb_audio_probe+0x257/0x1c90 [snd_usb_audio]
#3: (&(&mdev->lock)->rlock){+.+.+.}, at: [<ffffffffa0e6051b>] media_device_register_entity+0x1cb/0x700 [media]
CPU: 2 PID: 3479 Comm: modprobe Not tainted 4.5.0-rc3+ #49
Hardware name: /NUC5i7RYB, BIOS RYBDWi35.86A.0350.2015.0812.1722 08/12/2015
0000000000000000 ffff8803b3f6f288 ffffffff81933901 ffff8803c4bae000
ffff8803c4bae5c8 ffff8803b3f6f2b0 ffffffff811c6af5 ffff8803c4bae000
ffffffff8285d7f6 0000000000000509 ffff8803b3f6f2f0 ffffffff811c6ce5
Call Trace:
[<ffffffff81933901>] dump_stack+0x85/0xc4
[<ffffffff811c6af5>] ___might_sleep+0x245/0x3a0
[<ffffffff811c6ce5>] __might_sleep+0x95/0x1a0
[<ffffffff8155aade>] kmem_cache_alloc_trace+0x20e/0x300
[<ffffffffa0e66e3d>] ? media_add_link+0x4d/0x140 [media]
[<ffffffffa0e66e3d>] media_add_link+0x4d/0x140 [media]
[<ffffffffa0e69931>] media_create_pad_link+0xa1/0x600 [media]
[<ffffffffa0fe11b3>] au0828_media_graph_notify+0x173/0x360 [au0828]
[<ffffffffa0e68a6a>] ? media_gobj_create+0x1ba/0x480 [media]
[<ffffffffa0e606fb>] media_device_register_entity+0x3ab/0x700 [media]
Reviewed-by: Javier Martinez Canillas <javier@osg.samsung.com>
Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
2016-04-06 21:55:24 +08:00
|
|
|
mutex_lock(&mdev->graph_mutex);
|
2015-08-07 21:36:25 +08:00
|
|
|
__media_remove_intf_link(link);
|
[media] media-device: get rid of the spinlock
Right now, the lock schema for media_device struct is messy,
since sometimes, it is protected via a spin lock, while, for
media graph traversal, it is protected by a mutex.
Solve this conflict by always using a mutex.
As a side effect, this prevents a bug when the media notifiers
is called at atomic context, while running the notifier callback:
BUG: sleeping function called from invalid context at mm/slub.c:1289
in_atomic(): 1, irqs_disabled(): 0, pid: 3479, name: modprobe
4 locks held by modprobe/3479:
#0: (&dev->mutex){......}, at: [<ffffffff81ce8933>] __driver_attach+0xa3/0x160
#1: (&dev->mutex){......}, at: [<ffffffff81ce8941>] __driver_attach+0xb1/0x160
#2: (register_mutex#5){+.+.+.}, at: [<ffffffffa10596c7>] usb_audio_probe+0x257/0x1c90 [snd_usb_audio]
#3: (&(&mdev->lock)->rlock){+.+.+.}, at: [<ffffffffa0e6051b>] media_device_register_entity+0x1cb/0x700 [media]
CPU: 2 PID: 3479 Comm: modprobe Not tainted 4.5.0-rc3+ #49
Hardware name: /NUC5i7RYB, BIOS RYBDWi35.86A.0350.2015.0812.1722 08/12/2015
0000000000000000 ffff8803b3f6f288 ffffffff81933901 ffff8803c4bae000
ffff8803c4bae5c8 ffff8803b3f6f2b0 ffffffff811c6af5 ffff8803c4bae000
ffffffff8285d7f6 0000000000000509 ffff8803b3f6f2f0 ffffffff811c6ce5
Call Trace:
[<ffffffff81933901>] dump_stack+0x85/0xc4
[<ffffffff811c6af5>] ___might_sleep+0x245/0x3a0
[<ffffffff811c6ce5>] __might_sleep+0x95/0x1a0
[<ffffffff8155aade>] kmem_cache_alloc_trace+0x20e/0x300
[<ffffffffa0e66e3d>] ? media_add_link+0x4d/0x140 [media]
[<ffffffffa0e66e3d>] media_add_link+0x4d/0x140 [media]
[<ffffffffa0e69931>] media_create_pad_link+0xa1/0x600 [media]
[<ffffffffa0fe11b3>] au0828_media_graph_notify+0x173/0x360 [au0828]
[<ffffffffa0e68a6a>] ? media_gobj_create+0x1ba/0x480 [media]
[<ffffffffa0e606fb>] media_device_register_entity+0x3ab/0x700 [media]
Reviewed-by: Javier Martinez Canillas <javier@osg.samsung.com>
Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
2016-04-06 21:55:24 +08:00
|
|
|
mutex_unlock(&mdev->graph_mutex);
|
2015-08-07 21:36:25 +08:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(media_remove_intf_link);
|
2015-08-24 19:46:46 +08:00
|
|
|
|
|
|
|
void __media_remove_intf_links(struct media_interface *intf)
|
|
|
|
{
|
|
|
|
struct media_link *link, *tmp;
|
|
|
|
|
|
|
|
list_for_each_entry_safe(link, tmp, &intf->links, list)
|
|
|
|
__media_remove_intf_link(link);
|
|
|
|
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(__media_remove_intf_links);
|
|
|
|
|
|
|
|
void media_remove_intf_links(struct media_interface *intf)
|
|
|
|
{
|
2015-12-15 18:01:13 +08:00
|
|
|
struct media_device *mdev = intf->graph_obj.mdev;
|
|
|
|
|
2015-08-24 19:46:46 +08:00
|
|
|
/* Do nothing if the intf is not registered. */
|
2015-12-15 18:01:13 +08:00
|
|
|
if (mdev == NULL)
|
2015-08-24 19:46:46 +08:00
|
|
|
return;
|
|
|
|
|
[media] media-device: get rid of the spinlock
Right now, the lock schema for media_device struct is messy,
since sometimes, it is protected via a spin lock, while, for
media graph traversal, it is protected by a mutex.
Solve this conflict by always using a mutex.
As a side effect, this prevents a bug when the media notifiers
is called at atomic context, while running the notifier callback:
BUG: sleeping function called from invalid context at mm/slub.c:1289
in_atomic(): 1, irqs_disabled(): 0, pid: 3479, name: modprobe
4 locks held by modprobe/3479:
#0: (&dev->mutex){......}, at: [<ffffffff81ce8933>] __driver_attach+0xa3/0x160
#1: (&dev->mutex){......}, at: [<ffffffff81ce8941>] __driver_attach+0xb1/0x160
#2: (register_mutex#5){+.+.+.}, at: [<ffffffffa10596c7>] usb_audio_probe+0x257/0x1c90 [snd_usb_audio]
#3: (&(&mdev->lock)->rlock){+.+.+.}, at: [<ffffffffa0e6051b>] media_device_register_entity+0x1cb/0x700 [media]
CPU: 2 PID: 3479 Comm: modprobe Not tainted 4.5.0-rc3+ #49
Hardware name: /NUC5i7RYB, BIOS RYBDWi35.86A.0350.2015.0812.1722 08/12/2015
0000000000000000 ffff8803b3f6f288 ffffffff81933901 ffff8803c4bae000
ffff8803c4bae5c8 ffff8803b3f6f2b0 ffffffff811c6af5 ffff8803c4bae000
ffffffff8285d7f6 0000000000000509 ffff8803b3f6f2f0 ffffffff811c6ce5
Call Trace:
[<ffffffff81933901>] dump_stack+0x85/0xc4
[<ffffffff811c6af5>] ___might_sleep+0x245/0x3a0
[<ffffffff811c6ce5>] __might_sleep+0x95/0x1a0
[<ffffffff8155aade>] kmem_cache_alloc_trace+0x20e/0x300
[<ffffffffa0e66e3d>] ? media_add_link+0x4d/0x140 [media]
[<ffffffffa0e66e3d>] media_add_link+0x4d/0x140 [media]
[<ffffffffa0e69931>] media_create_pad_link+0xa1/0x600 [media]
[<ffffffffa0fe11b3>] au0828_media_graph_notify+0x173/0x360 [au0828]
[<ffffffffa0e68a6a>] ? media_gobj_create+0x1ba/0x480 [media]
[<ffffffffa0e606fb>] media_device_register_entity+0x3ab/0x700 [media]
Reviewed-by: Javier Martinez Canillas <javier@osg.samsung.com>
Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
2016-04-06 21:55:24 +08:00
|
|
|
mutex_lock(&mdev->graph_mutex);
|
2015-08-24 19:46:46 +08:00
|
|
|
__media_remove_intf_links(intf);
|
[media] media-device: get rid of the spinlock
Right now, the lock schema for media_device struct is messy,
since sometimes, it is protected via a spin lock, while, for
media graph traversal, it is protected by a mutex.
Solve this conflict by always using a mutex.
As a side effect, this prevents a bug when the media notifiers
is called at atomic context, while running the notifier callback:
BUG: sleeping function called from invalid context at mm/slub.c:1289
in_atomic(): 1, irqs_disabled(): 0, pid: 3479, name: modprobe
4 locks held by modprobe/3479:
#0: (&dev->mutex){......}, at: [<ffffffff81ce8933>] __driver_attach+0xa3/0x160
#1: (&dev->mutex){......}, at: [<ffffffff81ce8941>] __driver_attach+0xb1/0x160
#2: (register_mutex#5){+.+.+.}, at: [<ffffffffa10596c7>] usb_audio_probe+0x257/0x1c90 [snd_usb_audio]
#3: (&(&mdev->lock)->rlock){+.+.+.}, at: [<ffffffffa0e6051b>] media_device_register_entity+0x1cb/0x700 [media]
CPU: 2 PID: 3479 Comm: modprobe Not tainted 4.5.0-rc3+ #49
Hardware name: /NUC5i7RYB, BIOS RYBDWi35.86A.0350.2015.0812.1722 08/12/2015
0000000000000000 ffff8803b3f6f288 ffffffff81933901 ffff8803c4bae000
ffff8803c4bae5c8 ffff8803b3f6f2b0 ffffffff811c6af5 ffff8803c4bae000
ffffffff8285d7f6 0000000000000509 ffff8803b3f6f2f0 ffffffff811c6ce5
Call Trace:
[<ffffffff81933901>] dump_stack+0x85/0xc4
[<ffffffff811c6af5>] ___might_sleep+0x245/0x3a0
[<ffffffff811c6ce5>] __might_sleep+0x95/0x1a0
[<ffffffff8155aade>] kmem_cache_alloc_trace+0x20e/0x300
[<ffffffffa0e66e3d>] ? media_add_link+0x4d/0x140 [media]
[<ffffffffa0e66e3d>] media_add_link+0x4d/0x140 [media]
[<ffffffffa0e69931>] media_create_pad_link+0xa1/0x600 [media]
[<ffffffffa0fe11b3>] au0828_media_graph_notify+0x173/0x360 [au0828]
[<ffffffffa0e68a6a>] ? media_gobj_create+0x1ba/0x480 [media]
[<ffffffffa0e606fb>] media_device_register_entity+0x3ab/0x700 [media]
Reviewed-by: Javier Martinez Canillas <javier@osg.samsung.com>
Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
2016-04-06 21:55:24 +08:00
|
|
|
mutex_unlock(&mdev->graph_mutex);
|
2015-08-24 19:46:46 +08:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(media_remove_intf_links);
|