Re: [PATCH 1/3] ACPI / dock: Rework the handling of notifications

From: Rafael J. Wysocki
Date: Mon Jul 01 2013 - 21:19:20 EST


On Monday, July 01, 2013 02:21:45 PM Bjorn Helgaas wrote:
> On Fri, Jun 28, 2013 at 4:53 PM, Rafael J. Wysocki <rjw@xxxxxxx> wrote:
> > From: Rafael J. Wysocki <rafael.j.wysocki@xxxxxxxxx>
> >
> > The ACPI dock driver uses register_acpi_bus_notifier() which
> > installs a notifier triggered globally for all system notifications.
> > That first of all is inefficient, because the dock driver is only
> > interested in notifications associated with the devices it handles,
> > but it has to handle all system notifies for all devices. Moreover,
> > it does that even if no docking stations are present in the system
> > (CONFIG_ACPI_DOCK set is sufficient for that to happen). Besides,
> > that is inconvenient, because it requires the driver to do extra work
> > for each notification to find the target dock station object.
> >
> > For these reasons, rework the dock driver to install a notify
> > handler individually for each dock station in the system using
> > acpi_install_notify_handler(). This allows the dock station
> > object to be passed directly to the notify handler and makes it
> > possible to simplify the dock driver quite a bit. It also
> > reduces the overhead related to the handling of all system
> > notifies when CONFIG_ACPI_DOCK is set.
>
> I fully support what you're doing, even though I haven't read it in
> enough detail to actually review it. I'm pretty sure that whatever
> you do, you won't make things worse :)

Well, fair enough. :-)

> It sounds like you are keeping the approach of "look for certain AML
> features to identify a dock, and install notify handlers when you find
> one." I think acpiphp uses a similar approach, and I'm not sure it's
> a good one. The spec is not explicit about how the AML should be
> organized, and AML writers are very creative. I think acpiphp suffers
> because it only works with certain arrangements of _ADR, _EJ0, _RMV,
> etc., and I think that has led to a brittle design and possibly more
> separation between dock and acpiphp than is necessary.

I generally agree that this is not a robust approach, but for now I'm avoiding
making changes that may just go too far.

> I think it would be better if we *always* had a more generic notify
> handler installed and figured out where to route the notification
> based on its type and what services are configured in. The ultimate
> handler might do different things based on what methods are present,
> of course.
>
> I don't know if this rambling makes sense for docks (or even for
> acpiphp), so if it doesn't, feel free to just ignore it :)

Well, ideally, it would be great if we could handle all of the bus check,
device check and eject notifications through something like
acpi_hotplug_notify_cb() and dispatch more specific handling from
there depending on what's represented by the target handle. That's why I
introduced hotplug profiles.

That said it's a long way to that point from where we are now. :-)

Thanks,
Rafael


> > Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@xxxxxxxxx>
> > ---
> > drivers/acpi/dock.c | 69 ++++++++++++++++++----------------------------------
> > 1 file changed, 25 insertions(+), 44 deletions(-)
> >
> > Index: linux-pm/drivers/acpi/dock.c
> > ===================================================================
> > --- linux-pm.orig/drivers/acpi/dock.c
> > +++ linux-pm/drivers/acpi/dock.c
> > @@ -718,18 +718,17 @@ static int handle_eject_request(struct d
> >
> > /**
> > * dock_notify - act upon an acpi dock notification
> > - * @handle: the dock station handle
> > + * @ds: dock station
> > * @event: the acpi event
> > - * @data: our driver data struct
> > *
> > * If we are notified to dock, then check to see if the dock is
> > * present and then dock. Notify all drivers of the dock event,
> > * and then hotplug and devices that may need hotplugging.
> > */
> > -static void dock_notify(acpi_handle handle, u32 event, void *data)
> > +static void dock_notify(struct dock_station *ds, u32 event)
> > {
> > - struct dock_station *ds = data;
> > - struct acpi_device *tmp;
> > + acpi_handle handle = ds->handle;
> > + struct acpi_device *ad;
> > int surprise_removal = 0;
> >
> > /*
> > @@ -752,8 +751,7 @@ static void dock_notify(acpi_handle hand
> > switch (event) {
> > case ACPI_NOTIFY_BUS_CHECK:
> > case ACPI_NOTIFY_DEVICE_CHECK:
> > - if (!dock_in_progress(ds) && acpi_bus_get_device(ds->handle,
> > - &tmp)) {
> > + if (!dock_in_progress(ds) && acpi_bus_get_device(handle, &ad)) {
> > begin_dock(ds);
> > dock(ds);
> > if (!dock_present(ds)) {
> > @@ -790,9 +788,8 @@ static void dock_notify(acpi_handle hand
> > }
> >
> > struct dock_data {
> > - acpi_handle handle;
> > - unsigned long event;
> > struct dock_station *ds;
> > + u32 event;
> > };
> >
> > static void acpi_dock_deferred_cb(void *context)
> > @@ -800,52 +797,31 @@ static void acpi_dock_deferred_cb(void *
> > struct dock_data *data = context;
> >
> > acpi_scan_lock_acquire();
> > - dock_notify(data->handle, data->event, data->ds);
> > + dock_notify(data->ds, data->event);
> > acpi_scan_lock_release();
> > kfree(data);
> > }
> >
> > -static int acpi_dock_notifier_call(struct notifier_block *this,
> > - unsigned long event, void *data)
> > +static void dock_notify_handler(acpi_handle handle, u32 event, void *data)
> > {
> > - struct dock_station *dock_station;
> > - acpi_handle handle = data;
> > + struct dock_data *dd;
> >
> > if (event != ACPI_NOTIFY_BUS_CHECK && event != ACPI_NOTIFY_DEVICE_CHECK
> > && event != ACPI_NOTIFY_EJECT_REQUEST)
> > - return 0;
> > -
> > - acpi_scan_lock_acquire();
> > + return;
> >
> > - list_for_each_entry(dock_station, &dock_stations, sibling) {
> > - if (dock_station->handle == handle) {
> > - struct dock_data *dd;
> > - acpi_status status;
> > -
> > - dd = kmalloc(sizeof(*dd), GFP_KERNEL);
> > - if (!dd)
> > - break;
> > -
> > - dd->handle = handle;
> > - dd->event = event;
> > - dd->ds = dock_station;
> > - status = acpi_os_hotplug_execute(acpi_dock_deferred_cb,
> > - dd);
> > - if (ACPI_FAILURE(status))
> > - kfree(dd);
> > -
> > - break;
> > - }
> > + dd = kmalloc(sizeof(*dd), GFP_KERNEL);
> > + if (dd) {
> > + acpi_status status;
> > +
> > + dd->ds = data;
> > + dd->event = event;
> > + status = acpi_os_hotplug_execute(acpi_dock_deferred_cb, dd);
> > + if (ACPI_FAILURE(status))
> > + kfree(dd);
> > }
> > -
> > - acpi_scan_lock_release();
> > - return 0;
> > }
> >
> > -static struct notifier_block dock_acpi_notifier = {
> > - .notifier_call = acpi_dock_notifier_call,
> > -};
> > -
> > /**
> > * find_dock_devices - find devices on the dock station
> > * @handle: the handle of the device we are examining
> > @@ -979,6 +955,7 @@ static int __init dock_add(acpi_handle h
> > int ret, id;
> > struct dock_station ds, *dock_station;
> > struct platform_device *dd;
> > + acpi_status status;
> >
> > id = dock_station_count;
> > memset(&ds, 0, sizeof(ds));
> > @@ -1021,6 +998,11 @@ static int __init dock_add(acpi_handle h
> > if (ret)
> > goto err_rmgroup;
> >
> > + status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
> > + dock_notify_handler, dock_station);
> > + if (ACPI_FAILURE(status))
> > + goto err_rmgroup;
> > +
> > dock_station_count++;
> > list_add(&dock_station->sibling, &dock_stations);
> > return 0;
> > @@ -1065,7 +1047,6 @@ int __init acpi_dock_init(void)
> > return 0;
> > }
> >
> > - register_acpi_bus_notifier(&dock_acpi_notifier);
> > pr_info(PREFIX "%s: %d docks/bays found\n",
> > ACPI_DOCK_DRIVER_DESCRIPTION, dock_station_count);
> > return 0;
> >
--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/