Skip to content

Commit 5287078

Browse files
westerirafaeljw
authored andcommitted
ACPI: Use ACPI companion to match only the first physical device
Commit 6ab3430 ("mfd: Add ACPI support") made the MFD subdevices share the parent MFD ACPI companion if no _HID/_CID is specified for the subdevice in mfd_cell description. However, since all the subdevices share the ACPI companion, the match and modalias generation logic started to use the ACPI companion as well resulting this: # cat /sys/bus/platform/devices/HID-SENSOR-200041.6.auto/modalias acpi:INT33D1:PNP0C50: instead of the expected one # cat /sys/bus/platform/devices/HID-SENSOR-200041.6.auto/modalias platform:HID-SENSOR-200041 In other words the subdevice modalias is overwritten by the one taken from ACPI companion. This causes udev not to load the driver anymore. It is useful to be able to share the ACPI companion so that MFD subdevices (and possibly other devices as well) can access the ACPI resources even if they do not have ACPI representation in the namespace themselves. An example where this is used is Minnowboard LPC driver that creates GPIO as a subdevice among other things. Without the ACPI companion gpiolib is not able to lookup the corresponding GPIO controller from ACPI GpioIo resource. To fix this, restrict the match and modalias logic to be limited to the first (primary) physical device associated with the given ACPI comapnion. The secondary devices will still be able to access the ACPI companion, but they will be matched in a different way. Fixes: 6ab3430 (mfd: Add ACPI support) Reported-by: Jarkko Nikula <jarkko.nikula@linux.intel.com> Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
1 parent cac7f24 commit 5287078

File tree

1 file changed

+54
-16
lines changed

1 file changed

+54
-16
lines changed

drivers/acpi/scan.c

Lines changed: 54 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,53 @@ static int create_modalias(struct acpi_device *acpi_dev, char *modalias,
141141
return len;
142142
}
143143

144+
/*
145+
* acpi_companion_match() - Can we match via ACPI companion device
146+
* @dev: Device in question
147+
*
148+
* Check if the given device has an ACPI companion and if that companion has
149+
* a valid list of PNP IDs, and if the device is the first (primary) physical
150+
* device associated with it.
151+
*
152+
* If multiple physical devices are attached to a single ACPI companion, we need
153+
* to be careful. The usage scenario for this kind of relationship is that all
154+
* of the physical devices in question use resources provided by the ACPI
155+
* companion. A typical case is an MFD device where all the sub-devices share
156+
* the parent's ACPI companion. In such cases we can only allow the primary
157+
* (first) physical device to be matched with the help of the companion's PNP
158+
* IDs.
159+
*
160+
* Additional physical devices sharing the ACPI companion can still use
161+
* resources available from it but they will be matched normally using functions
162+
* provided by their bus types (and analogously for their modalias).
163+
*/
164+
static bool acpi_companion_match(const struct device *dev)
165+
{
166+
struct acpi_device *adev;
167+
bool ret;
168+
169+
adev = ACPI_COMPANION(dev);
170+
if (!adev)
171+
return false;
172+
173+
if (list_empty(&adev->pnp.ids))
174+
return false;
175+
176+
mutex_lock(&adev->physical_node_lock);
177+
if (list_empty(&adev->physical_node_list)) {
178+
ret = false;
179+
} else {
180+
const struct acpi_device_physical_node *node;
181+
182+
node = list_first_entry(&adev->physical_node_list,
183+
struct acpi_device_physical_node, node);
184+
ret = node->dev == dev;
185+
}
186+
mutex_unlock(&adev->physical_node_lock);
187+
188+
return ret;
189+
}
190+
144191
/*
145192
* Creates uevent modalias field for ACPI enumerated devices.
146193
* Because the other buses does not support ACPI HIDs & CIDs.
@@ -149,20 +196,14 @@ static int create_modalias(struct acpi_device *acpi_dev, char *modalias,
149196
*/
150197
int acpi_device_uevent_modalias(struct device *dev, struct kobj_uevent_env *env)
151198
{
152-
struct acpi_device *acpi_dev;
153199
int len;
154200

155-
acpi_dev = ACPI_COMPANION(dev);
156-
if (!acpi_dev)
157-
return -ENODEV;
158-
159-
/* Fall back to bus specific way of modalias exporting */
160-
if (list_empty(&acpi_dev->pnp.ids))
201+
if (!acpi_companion_match(dev))
161202
return -ENODEV;
162203

163204
if (add_uevent_var(env, "MODALIAS="))
164205
return -ENOMEM;
165-
len = create_modalias(acpi_dev, &env->buf[env->buflen - 1],
206+
len = create_modalias(ACPI_COMPANION(dev), &env->buf[env->buflen - 1],
166207
sizeof(env->buf) - env->buflen);
167208
if (len <= 0)
168209
return len;
@@ -179,18 +220,12 @@ EXPORT_SYMBOL_GPL(acpi_device_uevent_modalias);
179220
*/
180221
int acpi_device_modalias(struct device *dev, char *buf, int size)
181222
{
182-
struct acpi_device *acpi_dev;
183223
int len;
184224

185-
acpi_dev = ACPI_COMPANION(dev);
186-
if (!acpi_dev)
225+
if (!acpi_companion_match(dev))
187226
return -ENODEV;
188227

189-
/* Fall back to bus specific way of modalias exporting */
190-
if (list_empty(&acpi_dev->pnp.ids))
191-
return -ENODEV;
192-
193-
len = create_modalias(acpi_dev, buf, size -1);
228+
len = create_modalias(ACPI_COMPANION(dev), buf, size -1);
194229
if (len <= 0)
195230
return len;
196231
buf[len++] = '\n';
@@ -853,6 +888,9 @@ const struct acpi_device_id *acpi_match_device(const struct acpi_device_id *ids,
853888
if (!ids || !handle || acpi_bus_get_device(handle, &adev))
854889
return NULL;
855890

891+
if (!acpi_companion_match(dev))
892+
return NULL;
893+
856894
return __acpi_match_device(adev, ids);
857895
}
858896
EXPORT_SYMBOL_GPL(acpi_match_device);

0 commit comments

Comments
 (0)