[Freedreno] [PATCH v5 2/4] drm: introduce drm_writeback_connector_init_with_encoder() API
Liviu Dudau
liviu.dudau at arm.com
Fri Mar 25 10:19:39 UTC 2022
On Thu, Mar 24, 2022 at 09:36:50AM -0700, Abhinav Kumar wrote:
> Hi Liviu
Hello,
>
> Thanks for the response.
>
> On 3/24/2022 3:12 AM, Liviu Dudau wrote:
> > On Wed, Mar 23, 2022 at 11:28:56AM -0700, Abhinav Kumar wrote:
> > > Hi Liviu
> >
> > Hello,
> >
> > >
> > > Thanks for the review.
> > >
> > > On 3/23/2022 9:46 AM, Liviu Dudau wrote:
> > > > On Mon, Mar 21, 2022 at 04:56:43PM -0700, Abhinav Kumar wrote:
> > > > > For vendors drivers which pass an already allocated and
> > > > > initialized encoder especially for cases where the encoder
> > > > > hardware is shared OR the writeback encoder shares the resources
> > > > > with the rest of the display pipeline introduce a new API,
> > > > > drm_writeback_connector_init_with_encoder() which expects
> > > > > an initialized encoder as a parameter and only sets up the
> > > > > writeback connector.
> > > > >
> > > > > changes in v5:
> > > > > - reorder this change to come before in the series
> > > > > to avoid incorrect functionality in subsequent changes
> > > > > - continue using struct drm_encoder instead of
> > > > > struct drm_encoder * and switch it in next change
> > > > >
> > > > > Signed-off-by: Abhinav Kumar <quic_abhinavk at quicinc.com>
> > > >
> > > > Hi Abhinav,
> > > >
> > > > > ---
> > > > > drivers/gpu/drm/drm_writeback.c | 143 ++++++++++++++++++++++++++++------------
> > > > > include/drm/drm_writeback.h | 5 ++
> > > > > 2 files changed, 106 insertions(+), 42 deletions(-)
> > > > >
> > > > > diff --git a/drivers/gpu/drm/drm_writeback.c b/drivers/gpu/drm/drm_writeback.c
> > > > > index dc2ef12..abe78b9 100644
> > > > > --- a/drivers/gpu/drm/drm_writeback.c
> > > > > +++ b/drivers/gpu/drm/drm_writeback.c
> > > > > @@ -149,37 +149,15 @@ static const struct drm_encoder_funcs drm_writeback_encoder_funcs = {
> > > > > .destroy = drm_encoder_cleanup,
> > > > > };
> > > > > -/**
> > > > > - * drm_writeback_connector_init - Initialize a writeback connector and its properties
> > > > > - * @dev: DRM device
> > > > > - * @wb_connector: Writeback connector to initialize
> > > > > - * @con_funcs: Connector funcs vtable
> > > > > - * @enc_helper_funcs: Encoder helper funcs vtable to be used by the internal encoder
> > > > > - * @formats: Array of supported pixel formats for the writeback engine
> > > > > - * @n_formats: Length of the formats array
> > > > > - * @possible_crtcs: possible crtcs for the internal writeback encoder
> > > > > - *
> > > > > - * This function creates the writeback-connector-specific properties if they
> > > > > - * have not been already created, initializes the connector as
> > > > > - * type DRM_MODE_CONNECTOR_WRITEBACK, and correctly initializes the property
> > > > > - * values. It will also create an internal encoder associated with the
> > > > > - * drm_writeback_connector and set it to use the @enc_helper_funcs vtable for
> > > > > - * the encoder helper.
> > > > > - *
> > > > > - * Drivers should always use this function instead of drm_connector_init() to
> > > > > - * set up writeback connectors.
> > > > > - *
> > > > > - * Returns: 0 on success, or a negative error code
> > > > > - */
> > > > > -int drm_writeback_connector_init(struct drm_device *dev,
> > > > > - struct drm_writeback_connector *wb_connector,
> > > > > - const struct drm_connector_funcs *con_funcs,
> > > > > - const struct drm_encoder_helper_funcs *enc_helper_funcs,
> > > > > - const u32 *formats, int n_formats, uint32_t possible_crtcs)
> > > > > +static int drm_writeback_connector_setup(struct drm_device *dev,
> > > > > + struct drm_writeback_connector *wb_connector,
> > > > > + const struct drm_connector_funcs *con_funcs, const u32 *formats,
> > > > > + int n_formats)
> > > > > {
> > > > > struct drm_property_blob *blob;
> > > > > - struct drm_connector *connector = &wb_connector->base;
> > > > > struct drm_mode_config *config = &dev->mode_config;
> > > > > + struct drm_connector *connector = &wb_connector->base;
> > > > > +
> > > >
> > > > Point of this reordering the statements is...?
> > > This diff can be avoided. There was no reason to reorder this. I will remove
> > > this re-order.
> > > >
> > > > > int ret = create_writeback_properties(dev);
> > > > > if (ret != 0)
> > > > > @@ -187,18 +165,10 @@ int drm_writeback_connector_init(struct drm_device *dev,
> > > > > blob = drm_property_create_blob(dev, n_formats * sizeof(*formats),
> > > > > formats);
> > > > > - if (IS_ERR(blob))
> > > > > - return PTR_ERR(blob);
> > > > > -
> > > > > - drm_encoder_helper_add(&wb_connector->encoder, enc_helper_funcs);
> > > > > -
> > > > > - wb_connector->encoder.possible_crtcs = possible_crtcs;
> > > > > -
> > > > > - ret = drm_encoder_init(dev, &wb_connector->encoder,
> > > > > - &drm_writeback_encoder_funcs,
> > > > > - DRM_MODE_ENCODER_VIRTUAL, NULL);
> > > > > - if (ret)
> > > > > - goto fail;
> > > > > + if (IS_ERR(blob)) {
> > > > > + ret = PTR_ERR(blob);
> > > > > + return ret;
> > > > > + }
> > > >
> > > > I don't see why you have changed the earlier code to store the result of PTR_ERR into
> > > > ret other than to help your debugging. I suggest that you keep the existing code that
> > > > returns PTR_ERR(blob) directly and you will have a nicer diff stat as well.
> > > Sure, i can fix this for a smaller diff stat.
> > > >
> > > > > connector->interlace_allowed = 0;
> > > > > @@ -237,13 +207,102 @@ int drm_writeback_connector_init(struct drm_device *dev,
> > > > > attach_fail:
> > > > > drm_connector_cleanup(connector);
> > > > > connector_fail:
> > > > > - drm_encoder_cleanup(&wb_connector->encoder);
> > > > > -fail:
> > > > > drm_property_blob_put(blob);
> > > > > return ret;
> > > > > }
> > > > > +
> > > > > +/**
> > > > > + * drm_writeback_connector_init - Initialize a writeback connector and its properties
> > > > > + * @dev: DRM device
> > > > > + * @wb_connector: Writeback connector to initialize
> > > > > + * @con_funcs: Connector funcs vtable
> > > > > + * @enc_helper_funcs: Encoder helper funcs vtable to be used by the internal encoder
> > > > > + * @formats: Array of supported pixel formats for the writeback engine
> > > > > + * @n_formats: Length of the formats array
> > > > > + * @possible_crtcs: possible crtcs for the internal writeback encoder
> > > > > + *
> > > > > + * This function creates the writeback-connector-specific properties if they
> > > > > + * have not been already created, initializes the connector as
> > > > > + * type DRM_MODE_CONNECTOR_WRITEBACK, and correctly initializes the property
> > > > > + * values. It will also create an internal encoder associated with the
> > > > > + * drm_writeback_connector and set it to use the @enc_helper_funcs vtable for
> > > > > + * the encoder helper.
> > > > > + *
> > > > > + * Drivers should always use this function instead of drm_connector_init() to
> > > > > + * set up writeback connectors.
> > > > > + *
> > > > > + * Returns: 0 on success, or a negative error code
> > > > > + */
> > > > > +int drm_writeback_connector_init(struct drm_device *dev,
> > > > > + struct drm_writeback_connector *wb_connector,
> > > > > + const struct drm_connector_funcs *con_funcs,
> > > > > + const struct drm_encoder_helper_funcs *enc_helper_funcs,
> > > > > + const u32 *formats, int n_formats, uint32_t possible_crtcs)
> > > > > +{
> > > > > + int ret = 0;
> > > > > +
> > > > > + drm_encoder_helper_add(&wb_connector->encoder, enc_helper_funcs);
> > > > > +
> > > > > + wb_connector->encoder.possible_crtcs = possible_crtcs;
> > > > > +
> > > > > + ret = drm_encoder_init(dev, &wb_connector->encoder,
> > > > > + &drm_writeback_encoder_funcs,
> > > > > + DRM_MODE_ENCODER_VIRTUAL, NULL);
> > > > > + if (ret)
> > > > > + return ret;
> > > > > +
> > > > > + ret = drm_writeback_connector_setup(dev, wb_connector, con_funcs, formats,
> > > > > + n_formats);
> > > > > +
> > > > > + if (ret)
> > > > > + drm_encoder_cleanup(&wb_connector->encoder);
> > > > > +
> > > > > + return ret;
> > > > > +}
> > > > > EXPORT_SYMBOL(drm_writeback_connector_init);
> > > > > +/**
> > > > > + * drm_writeback_connector_init_with_encoder - Initialize a writeback connector and its properties
> > > > > + * using the encoder which already assigned and initialized
> > > > > + *
> > > > > + * @dev: DRM device
> > > > > + * @wb_connector: Writeback connector to initialize
> > > > > + * @con_funcs: Connector funcs vtable
> > > > > + * @enc_helper_funcs: Encoder helper funcs vtable to be used by the internal encoder
> > > > > + * @formats: Array of supported pixel formats for the writeback engine
> > > > > + * @n_formats: Length of the formats array
> > > > > + *
> > > > > + * This function creates the writeback-connector-specific properties if they
> > > > > + * have not been already created, initializes the connector as
> > > > > + * type DRM_MODE_CONNECTOR_WRITEBACK, and correctly initializes the property
> > > > > + * values.
> > > > > + *
> > > > > + * This function assumes that the drm_writebac_connector's encoder has already been
> > > >
> > > > spelling: writeback
> > > Ack. will fix this.
> > > >
> > > > > + * created and initialized before invoking this function.
> > > > > + *
> > > > > + * In addition, this function also assumes that callers of this API will manage
> > > > > + * assigning the encoder helper functions, possible_crtcs and any other encoder
> > > > > + * specific operation which is otherwise handled by drm_writeback_connector_init().
> > > > > + *
> > > > > + * Drivers should always use this function instead of drm_connector_init() to
> > > > > + * set up writeback connectors.
> > > >
> > > > .... if they want to manage themselves the lifetime of the associated encoder.
> > > >
> > > > We're not trying to replace drm_writeback_connector_init() function here, only to
> > > > provide an alternative function to call for special cases.
> > >
> > > Yes, we are trying to provide an alternative function call for special case
> > > where the encoder is a shared encoder and/or where the resources of the
> > > writeback encoder are shared with other hardware blocks.
> > >
> > > I can add that comment to this function's doc.
> > >
> > > >
> > > > > + *
> > > > > + * Returns: 0 on success, or a negative error code
> > > > > + */
> > > > > +int drm_writeback_connector_init_with_encoder(struct drm_device *dev,
> > > > > + struct drm_writeback_connector *wb_connector,
> > > > > + const struct drm_connector_funcs *con_funcs, const u32 *formats,
> > > > > + int n_formats)
> > > >
> > > > Where is the encoder parameter? Isn't that the reason why the function is called
> > > > `_with_encoder`?
> > > The encoder parameter is skipped here because this function assumes that
> > > wb_connector->encoder has already been initialized, setup with functions and
> > > its possible_crts have already been set prior to calling this function like
> > > the vc4 example shows. So this function doesnt need an explicit encoder
> > > parameter. Let me know if thats a concern.
> > > >
> > > > I think there might have been too many version of these patchsets and things are
> > > > starting to be confusing. Please revisit the series without rushing and come up with
> > > > a plan of action. My understanding of watching this series has been that you're
> > > > trying to come up with a function that does *connector* initialisation but skips the
> > > > *encoder* initialisation because it might have been already done by the driver. The
> > > > idea will be then to have a function `drm_writeback_connector_init_with_encoder()`
> > > > that does *all* the work that `drm_writeback_connector_init()` does at the moment minus
> > > > the encoder initialisation part. Then `drm_writeback_connector_init()` only
> > > > initialises the internal encoder and calls `drm_writeback_connector_init_with_encoder()`.
> > > > There is no need to have the `drm_writeback_connector_setup()` function at all.
> > > >
> > > > Best regards,
> > > > Liviu
> > > >
> > >
> > > I agree there have been a 4 revisions prior to this because of the way this
> > > affects the existing writeback drivers. So initial revision was a bit
> > > intrusive into other drivers (which was just mostly a take over from the
> > > previous patchset posted by the Co-developer ) and since rev3 we have
> > > decided to have a separate API drm_writeback_connector_init_with_encoder()
> > > so that existing clients are unaffected and it works seamlessly under the
> > > hood.
> > >
> > > Only clients which already embed an encoder (vc4) and the new ones which
> > > have special encoder requirements like the MSM driver for which I am
> > > preparing these changes for will use the new API.
> > >
> > > Apologies for the revisions, but thanks to some great feedback from you and
> > > laurent its shaping up nicely and reaching its conclusion I feel.
> >
> > I think it is only natural that there will be some iterations. If I remember
> > correctly, the initial writeback series has something like 13 revisions :)
> >
> > >
> > > So i think this revision is pretty close to being clean thanks to the
> > > feedback you gave on rev4. Between rev4 and this one I didnt drastically
> > > change the design other than re-ordering the changes to avoid the
> > > intermediate patches having an incorrect state for the vc4 encoder. So all
> > > your comments related to the encoder_cleanup() and vc4's encoder not getting
> > > initialized would have gotten addressed but overall concept remained same.
> > >
> > > You are right, we are trying to come up with a function which does connector
> > > initialization but skips the encoder part because that has already been done
> > > in the client side of this API ( hence _with_encoder() name ). The
> > > "_with_encoder" indicates that the caller already has an encoder for the
> > > writeback connector which is being passed so there is no need to pass the
> > > encoder again.
> > >
> > > I thought this addresses all the concerns posted in the previous series.
> > >
> > > So are you suggesting something like below?
> > >
> > > 1) rename drm_writeback_connector_setup() to
> > > drm_writeback_connector_init_with_encoder()
> > > (essentially thats what will end up happening )
> >
> > Correct. Without the pointless reordering of code it should be about 3 lines of code
> > that get removed (the calls to drm_encoder_helper_add() and drm_encoder_init()).
> >
>
> But isnt thats how it already looks.
>
> int drm_writeback_connector_init(struct drm_device *dev,
> struct drm_writeback_connector *wb_connector,
> const struct drm_connector_funcs *con_funcs,
> const struct drm_encoder_helper_funcs *enc_helper_funcs,
> const u32 *formats, int n_formats, uint32_t possible_crtcs)
> {
> int ret = 0;
>
> wb_connector->encoder = &wb_connector->internal_encoder;
>
> drm_encoder_helper_add(wb_connector->encoder, enc_helper_funcs);
>
> wb_connector->encoder->possible_crtcs = possible_crtcs;
>
> ret = drm_encoder_init(dev, wb_connector->encoder,
> &drm_writeback_encoder_funcs,
> DRM_MODE_ENCODER_VIRTUAL, NULL);
> if (ret)
> return ret;
>
> ret = drm_writeback_connector_setup(dev, wb_connector, con_funcs,
> formats,
> n_formats);
>
> So the only change you are requesting is that, instead of having a new
> drm_writeback_connector_setup(), just call
> drm_writeback_connector_init_with_encoder().
>
> It will essentially look like
>
> int drm_writeback_connector_init(struct drm_device *dev,
> struct drm_writeback_connector *wb_connector,
> const struct drm_connector_funcs *con_funcs,
> const struct drm_encoder_helper_funcs *enc_helper_funcs,
> const u32 *formats, int n_formats, uint32_t possible_crtcs)
> {
> int ret = 0;
>
> wb_connector->encoder = &wb_connector->internal_encoder;
(1)
>
> drm_encoder_helper_add(wb_connector->encoder, enc_helper_funcs);
>
> wb_connector->encoder->possible_crtcs = possible_crtcs;
>
> ret = drm_encoder_init(dev, wb_connector->encoder,
> &drm_writeback_encoder_funcs,
> DRM_MODE_ENCODER_VIRTUAL, NULL);
> if (ret)
> return ret;
>
> ret = drm_writeback_connector_init_with_encoder(dev, wb_connector,
> con_funcs, formats,
> n_formats);
Yes, this is exactly what I had in mind.
>
> drm_writeback_connector_init_with_encoder() will still not have an encoder
> parameter because of what I wrote previously.
But in your patch drm_writeback_connector_init_with_encoder() still has an
encoder_funcs pointer which is useless, as the expectations are (AFAII) that the
whole encoder init dance has already happened. And while you have a point that you
can set the encoder pointer in the connector before calling
drm_writeback_connector_init_with_encoder() I think it would be easier to read if you
pass the encoder explicitly in the parameter list and skip the assignment in (1) and
do it inside drm_writeback_connector_init_with_encoder(). Again, your code is not
wrong, I just think we should be explicit so that code is easier to read.
>
> Hope this is what you had in mind as well.
>
> > >
> > > 2) Inside drm_writeback_connector_init() check:
> > >
> > > drm_writeback_connector_init(.....)
> > > {
> > > if (!wb_conn->encoder)
> > > initialize the encoder
> >
> > No, the assumption of drm_writeback_connector_init() is that we will provide the
> > encoder, so no need to check that one is already provided. What you could do is:
> >
> > WARN_ON(wb_conn->encoder);
> >
>
> Got it, i will add a warning inside drm_writeback_connector_init() to
> emphasize that its only meant for cases where an encoder is not provided.
>
> > before we overwrite the encoder. That way we will get a nice warning in the kernel
> > log if someone tries to call drm_writeback_connector_init() with a preset encoder.
> >
> > >
> > > call drm_writeback_**_init_with_encoder()
> > > }
> > >
> > > This will also work but have the foll concerns/questions:
> > >
> > > 1) Will drm_writeback_connector_init_with_encoder() be exported if we change
> > > as per your suggestion or will all clients continue to use
> > > drm_writeback_connector_init() only? We wanted to have a separate function
> > > for new clients.
> >
> > Yes, we will need to export drm_writeback_connector_init_with_encoder() as well.
> >
> Alright, so vc4 and new vendors which provide their own encoder will use
> this one. So no changes to the rest of the series.
>
> > >
> > > 2) How will we detect that encoder needs to be initialized without it being
> > > a pointer which happens in the later change. So ordering becomes an issue.
> >
> > I think the init problem is simple. You either call drm_writeback_connector_init()
> > and the framework provides you with an encoder, or you call
> > drm_writeback_connector_init_with_encoder() and the framework will use yours. The
> > problems will show up on the cleanup and exit codes, where we need to be able to skip
> > the cleanup if the encoder pointer is not the internal one. I think a simple
> >
> > if (connector->encoder == &connector->internal_encoder)
> > do_encoder_cleanup_work_here()
> >
> > should work.
>
> Sorry, I am missing something here.
>
> Even in this current patch, the drm_encoder_cleanup() is done only inside
> drm_writeback_connector_init() where internal_encoder is used.
>
> For drm_writeback_connector_init_with_encoder(), we dont do the cleanup and
> expect the caller to do it like vc4 does in the next patch.
>
> So why do we need such a condition?
You're right. I was thinking that at cleanup time we also need to do work with the
right encoder, but that should accomplished by passing the right .destroy hook in the
drm_encoder_funcs pointer via drm_encoder_init. So if the special drivers to the
initialisation correctly it should all work fine, please disregard my comments.
Best regards,
Liviu
>
> >
> > >
> > > Thats why I thought this is the best way to address the comments and keep
> > > the functionality intact with each change.
> > >
> > > Let me know if I have misunderstood some comment or idea.
> >
> > I hope that with these clarifications we are both on the same page.
> >
> > Best regards,
> > Liviu
> >
> >
> >
> > >
> > >
> > >
> > > >
> > > > > +{
> > > > > + int ret = 0;
> > > > > +
> > > > > + ret = drm_writeback_connector_setup(dev, wb_connector, con_funcs, formats,
> > > > > + n_formats);
> > > > > +
> > > > > + return ret;
> > > > > +}
> > > > > +EXPORT_SYMBOL(drm_writeback_connector_init_with_encoder);
> > > > > +
> > > > > int drm_writeback_set_fb(struct drm_connector_state *conn_state,
> > > > > struct drm_framebuffer *fb)
> > > > > {
> > > > > diff --git a/include/drm/drm_writeback.h b/include/drm/drm_writeback.h
> > > > > index db6214f..0093bab 100644
> > > > > --- a/include/drm/drm_writeback.h
> > > > > +++ b/include/drm/drm_writeback.h
> > > > > @@ -152,6 +152,11 @@ int drm_writeback_connector_init(struct drm_device *dev,
> > > > > const struct drm_encoder_helper_funcs *enc_helper_funcs,
> > > > > const u32 *formats, int n_formats, uint32_t possible_crtcs);
> > > > > +int drm_writeback_connector_init_with_encoder(struct drm_device *dev,
> > > > > + struct drm_writeback_connector *wb_connector,
> > > > > + const struct drm_connector_funcs *con_funcs, const u32 *formats,
> > > > > + int n_formats);
> > > > > +
> > > > > int drm_writeback_set_fb(struct drm_connector_state *conn_state,
> > > > > struct drm_framebuffer *fb);
> > > > > --
> > > > > 2.7.4
> > > > >
> > > >
> >
--
====================
| I would like to |
| fix the world, |
| but they're not |
| giving me the |
\ source code! /
---------------
¯\_(ツ)_/¯
More information about the Freedreno
mailing list