On Tue, Jul 22, 2025 at 04:08:09PM +0200, Greg Kroah-Hartman wrote:
> On Tue, Jul 22, 2025 at 03:56:40PM +0200, Thierry Reding wrote:
> > On Sat, Jul 19, 2025 at 08:52:41AM +0200, Greg Kroah-Hartman wrote:
> > > On Fri, Jul 18, 2025 at 03:49:37PM +0200, Thierry Reding wrote:
> > > > On Thu, Jul 17, 2025 at 02:11:41PM +0200, Greg Kroah-Hartman wrote:
> > > > > On Thu, Jul 17, 2025 at 12:32:34PM +0200, Thierry Reding wrote:
> > [...]
> > > >         struct syscore;
> > > > 
> > > >         struct syscore_ops {
> > > >                 int (*suspend)(struct syscore *syscore);
> > > >                 void (*resume)(struct syscore *syscore);
> > > >                 void (*shutdown)(struct syscore *syscore);
> > > >         };
> > > > 
> > > >         struct syscore {
> > > >                 const struct syscore_ops *ops;
> > > >                 struct list_head node;
> > > >         };
> > > > 
> > > > Is that what you had in mind?
> > > 
> > > I missed the list_head, so yes, this would be better, but don't pass
> > > back the syscore structure, how about just a void * instead, making the
> > > whole container_of() stuff go away?
> > 
> > Yeah, that's a possibility. I personally don't like passing the void *
> > around because it's easier to make mistakes that way. I also find it
> > unintuitive because it doesn't immediately show you what the functions
> > expect.
> > 
> > My understanding is that the container_of() should get optimized away
> > most of the time, so there aren't any obvious downsides that I can see.
> 
> container_of() is just pointer math, but a cast is even faster :)
> 
> > But I don't feel very strongly, so if you have a strong preference for
> > void pointers, I can do that.
> 
> That's what you really want to have here, it's a syscore data type
> thing, that the callback wants to reference.  Just like a irqrequest_t
> function passes back a void * that the handler "knows" how to deal with
> properly.

IRQ handlers are different, though, because you pass the void * data
when you register the interrupt. That void * then gets stored and passed
to the handler when the interrupt is processed.

We'd have to change it to something like this:

        struct syscore_ops {
                /* parameters now changed to driver-specific data */
                int (*suspend)(void *data);
                void (*resume)(void *data);
                void (*shutdown)(void *data);
        };

        struct syscore {
                const struct syscore_ops *ops;
                struct list_head node;
                /* NEW driver-specific data */
                void *data;
        };

It ends up increasing the syscore structure's size, about 33%, though
given that there aren't a lot of these that's probably negligible.

What I think is a bit more unnatural about it in this case is that we
embed the struct syscore into some driver-private data anyway so that
it becomes per instance, and then we have a circular reference:

        foo->syscore.ops = &foo_syscore_ops;
        foo->syscore.data = foo;

Which looks kind of weird. Alternatively I suppose we could completely
rework it and make register_syscore_ops() allocate struct syscore, and
hide the internals from drivers completely:

        err = register_syscore(&foo_syscore_ops, foo);

With that it may be problematic that register_syscore() can now fail.

Thierry

Attachment: signature.asc
Description: PGP signature

Reply via email to