Hi Kieran, On Tue, May 16, 2017 at 01:56:05PM +0100, Kieran Bingham wrote: ... > >>>> +static int adv748x_afe_g_input_status(struct v4l2_subdev *sd, u32 *status) > >>>> +{ > >>>> + struct adv748x_state *state = adv748x_afe_to_state(sd); > >>>> + int ret; > >>>> + > >>>> + ret = mutex_lock_interruptible(&state->mutex); > >>> > >>> I wonder if this is necessary. Do you expect the mutex to be taken for > >>> extended periods of time? > >> > >> It looks like the only other adv* driver to take a lock here is the 7180. > >> Perhaps that is where the heritage of this code derived from. > >> > >> I don't think the locking should be held for a long time anywhere, but I will > >> try to go through and consider all the locking throughout the code base. > >> > >> At the moment I think anything that calls adv748x_afe_status() should be locked > >> to ensure serialisation through adv748x_afe_read_ro_map(). > > > > I meant whether you need the "_interruptible" part. It's quite a bit of > > repeating error handling that looks mostly unnecessary. > > > > Aha - I see what you mean now... > > Most of these use I2C transactions though, so that would be our source of any delay. > > If it's acceptable to expect an I2C bus to never hang, or if the I2C subsystem > can handle that, then we can chop the interruptible ... but I'm not sure I2C bus > transactions are guaranteed like that ? Don't things like clock stretching, and > unreliable hardware leave us vulnerable there... $ git grep mutex_lock_interruptible -- drivers/media/i2c/ drivers/media/i2c/adv7180.c: int err = mutex_lock_interruptible(&state->mutex); drivers/media/i2c/adv7180.c: int ret = mutex_lock_interruptible(&state->mutex); drivers/media/i2c/adv7180.c: int ret = mutex_lock_interruptible(&state->mutex); drivers/media/i2c/adv7180.c: int ret = mutex_lock_interruptible(&state->mutex); drivers/media/i2c/adv7180.c: ret = mutex_lock_interruptible(&state->mutex); drivers/media/i2c/adv7180.c: int ret = mutex_lock_interruptible(&state->mutex); drivers/media/i2c/adv7180.c: ret = mutex_lock_interruptible(&state->mutex); That's all. ... > >>>> +int adv748x_afe_probe(struct adv748x_state *state, struct device_node *ep) > >>>> +{ > >>>> + int ret; > >>>> + unsigned int i; > >>>> + > >>>> + state->afe.streaming = false; > >>>> + state->afe.curr_norm = V4L2_STD_ALL; > >>>> + > >>>> + adv748x_subdev_init(&state->afe.sd, state, &adv748x_afe_ops, "afe"); > >>>> + > >>>> + /* Ensure that matching is based upon the endpoint fwnodes */ > >>>> + state->afe.sd.fwnode = &ep->fwnode; > >>> > >>> I wonder if you really need to convert all users of async matching to use > >>> endpoints --- could you opportunistically peek if the device node matches, > >>> just in case? You can't have an accidental positive match anyway. > >>> > >>> So, the match is now for plain fwnode pointers, and it would be: > >>> > >>> return async->fwnode == fwnode || > >>> port_parent(parent(async->fwnode)) == fwnode || > >>> async->fwnode == port_parent(parent(fwnode)); > >> > >> > >> If we adapt the core to match against endpoint comparisons and device node > >> comparisons then yes we wouldn't have to adapt everything, I.e. we wouldn't have > >> to change all the async devices - but we would have to adapt all the bus/bridge > >> drivers (those who perform the v4l2_async_notifier_register() call) as they must > >> register their notifier against an endpoint if they are to ever be able to > >> connect to an ADV748x or other device which will rely upon multiple endpoints. > > > > If there really is a need to, we can add a new framework helper function for > > that --- as I think Niklas proposed. I'm not really sure it should be really > > needed though; e.g. the omap3isp driver does without that. > > > > I'm afraid I don't understand what you mean by omap3isp doing without ... Sorry. I think I lost you somewhere --- I meant matching in the few drivers that compare fwnodes. That'd break as a result unless the matching was updated accordingly. It'd be nice to remove that matching as well though but I think it'd be safer not to. > > In omap3isp/isp.c: isp_fwnodes_parse() the async notifier is registered looking > at the endpoints parent fwnode: > > isd->asd.match.fwnode.fwnode = > fwnode_graph_get_remote_port_parent(fwnode); > > This would therefore not support ADV748x ... (it wouldn't know which TX/CSI > entity to match against) > > So the way I see it is that all devices which currently register an async > notifier should now register the match against the endpoint instead of the > parent device: > > - isd->asd.match.fwnode.fwnode = fwnode_graph_get_remote_port_parent(fwnode); > + isd->asd.match.fwnode.fwnode = fwnode; > > And then if we adapt the match to check against: > fwnode == fwnode || fwnode == fwnode_graph_get_remote_port_parent(fwnode); That's not enough as a master driver may use device node whereas the sub-device driver uses endpoint node. You need to do it both ways. It's port parent, not endpoint's. There is / will be fwnode_get_port_parent(), too. > > This would then support existing sensor/remote devices which still store their > (default) device fwnode, but also match specifically against devices which store > their endpoint fwnode... > > So this looks like the following drivers would need to be updated: > > (users of fwnode.fwnode:) > drivers/media/platform/am437x/am437x-vpfe > drivers/media/platform/atmel/atmel-isc.c > drivers/media/platform/exynos4-is/media-dev.c > drivers/media/platform/omap3isp/isp.c > drivers/media/platform/pxa_camera.c > drivers/media/platform/rcar-vin > drivers/media/platform/soc_camera/soc_camera.c > drivers/media/platform/ti-vpe/cal.c > drivers/media/platform/xilinx/xilinx-vipp.c Sounds good to me. ... > >>>> +static int adv748x_parse_dt(struct adv748x_state *state) > >>>> +{ > >>>> + struct device_node *ep_np = NULL; > >>>> + struct of_endpoint ep; > >>>> + unsigned int found = 0; > >>>> + int ret; > >>>> + > >>> > >>> Would of_graph_get_remote_node() do this more simple? Not necessarily, just > >>> wondering. > >> > >> I'm not certain I understand, but I don't think so. > >> > >> Up to 12 ports could potentially be mapped in the DT. I want to enumerate all of > >> them: > >> > >> enum adv748x_ports { > >> ADV748X_PORT_HDMI = 0, > >> ADV748X_PORT_AIN1 = 1, > >> ADV748X_PORT_AIN2 = 2, > >> ADV748X_PORT_AIN3 = 3, > >> ADV748X_PORT_AIN4 = 4, > >> ADV748X_PORT_AIN5 = 5, > >> ADV748X_PORT_AIN6 = 6, > >> ADV748X_PORT_AIN7 = 7, > >> ADV748X_PORT_AIN8 = 8, > >> ADV748X_PORT_TTL = 9, > >> ADV748X_PORT_TXA = 10, > >> ADV748X_PORT_TXB = 11, > >> ADV748X_PORT_MAX = 12, > >> }; > >> > >> Whilst currently we are hardwired to input from AIN8 on the AFE (a Todo to > >> adapt), I would envisage that there might be entities described in the DT to > >> state which ports have connections on them. > > > > Indeed. I was thinking of this code would look like if one was using > > of_graph_get_remote_node(). > > > >> Rob was pushing for that and I argued against. ;-) But please use it if it works better. As an interface it is more simple, but there's a number of ports to check. It made a bunch of drivers cleaner but then again V4L2 fwnode parses a lot of this already. > >> (available) inputs as well - but that's out of scope for now - and we don't have > >> a way to forward the 'inputs' through to the master driver. > >> > >>>> + for_each_endpoint_of_node(state->dev->of_node, ep_np) { > >>>> + ret = of_graph_parse_endpoint(ep_np, &ep); > > > > of_graph_parse_endpoint() always succeeds. > > > > Do you call it for other purposes than to print information on the endpoint? > > To get the port and verify it. > > Now I think I see where you were going with of_graph_get_remote_node(). > This could just loop through 'known port' values instead... removing the need to > parse_endpoint, and have other error checks... > > > > >>>> + if (!ret) { > >>>> + adv_info(state, "Endpoint %s on port %d", > >>>> + of_node_full_name(ep.local_node), > >>>> + ep.port); > >>>> + > >>>> + if (ep.port > ADV748X_PORT_MAX) { > >>>> + adv_err(state, "Invalid endpoint %s on port %d", > >>>> + of_node_full_name(ep.local_node), > >>>> + ep.port); > >>>> + > >>>> + continue; > >>>> + } > >>>> + > >>>> + state->endpoints[ep.port] = ep_np; > >>>> + found++; > >>>> + } > >>>> + } > >>>> + > >>>> + return found ? 0 : -ENODEV; > >>>> +} > >>>> + > > > > ... > > > >>>> diff --git a/drivers/media/i2c/adv748x/adv748x-csi2.c b/drivers/media/i2c/adv748x/adv748x-csi2.c > >>>> new file mode 100644 > >>>> index 000000000000..d0a0fcfeae2e > >>>> --- /dev/null > >>>> +++ b/drivers/media/i2c/adv748x/adv748x-csi2.c ... > >>>> +/* ----------------------------------------------------------------------------- > >>>> + * v4l2_subdev_internal_ops > >>>> + * > >>>> + * We use the internal registered operation to be able to ensure that our > >>>> + * incremental subdevices (not connected in the forward path) can be registered > >>>> + * against the resulting video path and media device. > >>>> + */ > >>>> + > >>>> +static int adv748x_csi2_notify_complete(struct v4l2_async_notifier *notifier) > >>>> +{ > >>>> + struct adv748x_csi2 *tx = notifier_to_csi2(notifier); > >>>> + struct adv748x_state *state = tx->state; > >>>> + int ret; > >>>> + > >>>> + ret = v4l2_device_register_subdev_nodes(tx->sd.v4l2_dev); > >>>> + if (ret) { > >>>> + adv_err(state, "Failed to register subdev nodes\n"); > >>>> + return ret; > >>>> + } > >>>> + > >>>> + /* Return early until we register TXB */ > >>>> + if (is_txa(tx)) > >>>> + return ret; > >>>> + > >>>> + ret = adv748x_setup_links(state); > >>> > >>> Could you set up links first? It'd be really annoying to clean up the mess > >>> after the sub-device nodes have been registered. Actually --- it's not even > >>> doable at the moment. > >> > >> No - I don't think I can set up links until the devices are registered so that I > >> have access to the media-dev. > >> > >> I think I've already tried that :) > > > > You still don't need to register the sub-device nodes, do you? The > > sub-devices are already registered before > > v4l2_device_register_subdev_nodes(), right? > > > > Don't worry about the code above - It's all been deleted. > > I realised I was using the async notifiers to register the AFE/HDMI entities but > it was completely overkill. Ack. Good. Sometimes you figure out how best do something while explaining it to others... :-) (I was happy to listen.) ... > >>>> diff --git a/drivers/media/i2c/adv748x/adv748x-hdmi.c b/drivers/media/i2c/adv748x/adv748x-hdmi.c > >>>> new file mode 100644 > >>>> index 000000000000..19c1bd41cc6c > >>>> --- /dev/null > >>>> +++ b/drivers/media/i2c/adv748x/adv748x-hdmi.c > >>>> @@ -0,0 +1,671 @@ > > > > ... > > > >>>> +static const struct v4l2_dv_timings_cap adv748x_hdmi_timings_cap = { > >>>> + .type = V4L2_DV_BT_656_1120, > >>>> + /* keep this initialization for compatibility with GCC < 4.4.6 */ > >>>> + .reserved = { 0 }, > >>> > >>> Is this necessary? Aren't the uninitialised fields zeroed if any field in a > >>> struct is initialised, also on those versions of GCC? (Of course there have > >>> been bugs, but nothing rings a bell.) > >> > >> Looks like it is necessary: > >> https://patchwork.kernel.org/patch/2851851/ > > > > This is related to the anonymous union. What I'm saying appears unrelated > > --- if any struct field is initialised, then the rest of the fields of the > > struct are initialised to zero by the compiler (unless explicitly > > initialised to something else). > > > > I.e. you can drop ".reserved = { 0 }," line. > > In that patch I referenced, (several of the drivers were all updated in a > similar fashion) Gianluca mentioned the following: > > > > > Please note that I have also to init the reserved space as otherwise GCC fails with this error: > > > > CC [M] adv7842.o > > adv7842.c:549: error: field name not in record or union initializer > > adv7842.c:549: error: (near initialization for 'adv7842_timings_cap_analog.reserved') > > adv7842.c:549: warning: braces around scalar initializer > > adv7842.c:549: warning: (near initialization for 'adv7842_timings_cap_analog.reserved[0]') I had to test that here. :-) Ouch. And I'm left wondering how does the initialisation of the reserved field get things working again... Anyway, please ignore the original comment. > > Therefore my understanding was that it was necessary. > > If not - then we can remove from the following drivers too: > > git grep ".reserved = { 0 }" > drivers/media/i2c/ad9389b.c: .reserved = { 0 }, > drivers/media/i2c/adv7511.c: .reserved = { 0 }, > drivers/media/i2c/adv7604.c: .reserved = { 0 }, > drivers/media/i2c/adv7604.c: .reserved = { 0 }, > drivers/media/i2c/adv7842.c: .reserved = { 0 }, > drivers/media/i2c/adv7842.c: .reserved = { 0 }, > drivers/media/i2c/tc358743.c: .reserved = { 0 }, > drivers/media/i2c/ths8200.c: .reserved = { 0 }, > drivers/media/platform/vivid/vivid-vid-common.c: .reserved = { 0 }, > drivers/media/spi/gs1662.c: .reserved = { 0 }, > samples/v4l/v4l2-pci-skeleton.c: .reserved = { 0 }, > > But maybe we should test with an older compiler to verify this... > > Is there a cut-off point where we would stop supporting older compilers? I guess when people stop submitting patches to support them? :-) Documentation/admin-guide/README.rst says that at least GCC 3.2 should be used. That's very, very old. I wonder if anyone has recently used such an old version... -- Regards, Sakari Ailus e-mail: sakari.ailus@xxxxxx XMPP: sailus@xxxxxxxxxxxxxx