Message ID | 1454646882-24369-9-git-send-email-okaya@codeaurora.org (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Hi Alex, On 2/4/2016 11:34 PM, Sinan Kaya wrote: > The code is using the compatible DT string to associate a reset driver with > the actual device itself. The compatible string does not exist on ACPI > based systems. HID is the unique identifier for a device driver instead. > The change allows a driver to register with DT compatible string or ACPI > HID and then match the object with one of these conditions. > > Rules for loading the reset driver are as follow: > - ACPI HID needs match for ACPI systems > - DT compat needs to match for OF systems > > Tested-by: Eric Auger <eric.auger@linaro.org> (device tree only) > Tested-by: Shanker Donthineni <shankerd@codeaurora.org> (ACPI only) > Signed-off-by: Sinan Kaya <okaya@codeaurora.org> > --- > .../vfio/platform/reset/vfio_platform_amdxgbe.c | 3 +- > .../platform/reset/vfio_platform_calxedaxgmac.c | 3 +- > drivers/vfio/platform/vfio_platform_common.c | 80 +++++++++++++++++++--- > drivers/vfio/platform/vfio_platform_private.h | 41 ++++++----- > 4 files changed, 96 insertions(+), 31 deletions(-) > > diff --git a/drivers/vfio/platform/reset/vfio_platform_amdxgbe.c b/drivers/vfio/platform/reset/vfio_platform_amdxgbe.c > index d4030d0..cc5b4fa 100644 > --- a/drivers/vfio/platform/reset/vfio_platform_amdxgbe.c > +++ b/drivers/vfio/platform/reset/vfio_platform_amdxgbe.c > @@ -119,7 +119,8 @@ int vfio_platform_amdxgbe_reset(struct vfio_platform_device *vdev) > return 0; > } > > -module_vfio_reset_handler("amd,xgbe-seattle-v1a", vfio_platform_amdxgbe_reset); > +module_vfio_reset_handler("amd,xgbe-seattle-v1a", NULL, > + vfio_platform_amdxgbe_reset); > > MODULE_VERSION("0.1"); > MODULE_LICENSE("GPL v2"); > diff --git a/drivers/vfio/platform/reset/vfio_platform_calxedaxgmac.c b/drivers/vfio/platform/reset/vfio_platform_calxedaxgmac.c > index e3d3d94..0e57529 100644 > --- a/drivers/vfio/platform/reset/vfio_platform_calxedaxgmac.c > +++ b/drivers/vfio/platform/reset/vfio_platform_calxedaxgmac.c > @@ -77,7 +77,8 @@ int vfio_platform_calxedaxgmac_reset(struct vfio_platform_device *vdev) > return 0; > } > > -module_vfio_reset_handler("calxeda,hb-xgmac", vfio_platform_calxedaxgmac_reset); > +module_vfio_reset_handler("calxeda,hb-xgmac", NULL, > + vfio_platform_calxedaxgmac_reset); > > MODULE_VERSION(DRIVER_VERSION); > MODULE_LICENSE("GPL v2"); > diff --git a/drivers/vfio/platform/vfio_platform_common.c b/drivers/vfio/platform/vfio_platform_common.c > index 418cdd9..5b42e93 100644 > --- a/drivers/vfio/platform/vfio_platform_common.c > +++ b/drivers/vfio/platform/vfio_platform_common.c > @@ -13,6 +13,7 @@ > */ > > #include <linux/device.h> > +#include <linux/acpi.h> > #include <linux/iommu.h> > #include <linux/module.h> > #include <linux/mutex.h> > @@ -31,14 +32,22 @@ static LIST_HEAD(reset_list); > static DEFINE_MUTEX(driver_lock); > > static vfio_platform_reset_fn_t vfio_platform_lookup_reset(const char *compat, > - struct module **module) > + const char *acpihid, struct module **module) > { > struct vfio_platform_reset_node *iter; > vfio_platform_reset_fn_t reset_fn = NULL; > > mutex_lock(&driver_lock); > list_for_each_entry(iter, &reset_list, link) { > - if (!strcmp(iter->compat, compat) && > + if (acpihid && iter->acpihid && > + !strcmp(iter->acpihid, acpihid) && > + try_module_get(iter->owner)) { > + *module = iter->owner; > + reset_fn = iter->reset; > + break; > + } > + if (compat && iter->compat && > + !strcmp(iter->compat, compat) && > try_module_get(iter->owner)) { > *module = iter->owner; > reset_fn = iter->reset; > @@ -51,11 +60,12 @@ static vfio_platform_reset_fn_t vfio_platform_lookup_reset(const char *compat, > > static void vfio_platform_get_reset(struct vfio_platform_device *vdev) > { > - vdev->reset = vfio_platform_lookup_reset(vdev->compat, > - &vdev->reset_module); > + vdev->reset = vfio_platform_lookup_reset(vdev->compat, vdev->acpihid, > + &vdev->reset_module); > if (!vdev->reset) { > request_module("vfio-reset:%s", vdev->compat); > vdev->reset = vfio_platform_lookup_reset(vdev->compat, > + vdev->acpihid, > &vdev->reset_module); > } > } > @@ -541,6 +551,46 @@ static const struct vfio_device_ops vfio_platform_ops = { > .mmap = vfio_platform_mmap, > }; > > +#ifdef CONFIG_ACPI > +int vfio_platform_probe_acpi(struct vfio_platform_device *vdev, > + struct device *dev) > +{ > + struct acpi_device *adev = ACPI_COMPANION(dev); > + > + if (!adev) > + return -EINVAL; > + > + vdev->acpihid = acpi_device_hid(adev); > + if (!vdev->acpihid) { > + pr_err("VFIO: cannot find ACPI HID for %s\n", > + vdev->name); > + return -EINVAL; > + } > + return 0; > +} > +#else > +int vfio_platform_probe_acpi(struct vfio_platform_device *vdev, > + struct device *dev) > +{ > + return -EINVAL; > +} > +#endif > + > +int vfio_platform_probe_of(struct vfio_platform_device *vdev, > + struct device *dev) > +{ > + int ret; > + > + ret = device_property_read_string(dev, "compatible", > + &vdev->compat); > + if (ret) { > + pr_err("VFIO: cannot retrieve compat for %s\n", > + vdev->name); > + return -EINVAL; > + } > + return 0; > +} > + > int vfio_platform_probe_common(struct vfio_platform_device *vdev, > struct device *dev) > { > @@ -550,14 +600,14 @@ int vfio_platform_probe_common(struct vfio_platform_device *vdev, > if (!vdev) > return -EINVAL; > > - ret = device_property_read_string(dev, "compatible", &vdev->compat); > - if (ret) { > - pr_err("VFIO: cannot retrieve compat for %s\n", vdev->name); > - return -EINVAL; > - } > + ret = vfio_platform_probe_acpi(vdev, dev); > + if (ret) > + ret = vfio_platform_probe_of(vdev, dev); > > - vdev->device = dev; > + if (ret) > + return ret; > > + vdev->device = dev; > group = iommu_group_get(dev); > if (!group) { > pr_err("VFIO: No IOMMU group for device %s\n", vdev->name); > @@ -602,13 +652,21 @@ void __vfio_platform_register_reset(struct vfio_platform_reset_node *node) > EXPORT_SYMBOL_GPL(__vfio_platform_register_reset); > > void vfio_platform_unregister_reset(const char *compat, > + const char *acpihid, > vfio_platform_reset_fn_t fn) > { > struct vfio_platform_reset_node *iter, *temp; > > mutex_lock(&driver_lock); > list_for_each_entry_safe(iter, temp, &reset_list, link) { > - if (!strcmp(iter->compat, compat) && (iter->reset == fn)) { > + if (acpihid && iter->acpihid && > + !strcmp(iter->acpihid, acpihid) && (iter->reset == fn)) { > + list_del(&iter->link); > + break; > + } > + > + if (compat && iter->compat && > + !strcmp(iter->compat, compat) && (iter->reset == fn)) { > list_del(&iter->link); > break; > } > diff --git a/drivers/vfio/platform/vfio_platform_private.h b/drivers/vfio/platform/vfio_platform_private.h > index 42816dd..32feba3 100644 > --- a/drivers/vfio/platform/vfio_platform_private.h > +++ b/drivers/vfio/platform/vfio_platform_private.h > @@ -58,6 +58,7 @@ struct vfio_platform_device { > struct mutex igate; > struct module *parent_module; > const char *compat; > + const char *acpihid; > struct module *reset_module; > struct device *device; > > @@ -79,6 +80,7 @@ typedef int (*vfio_platform_reset_fn_t)(struct vfio_platform_device *vdev); > struct vfio_platform_reset_node { > struct list_head link; > char *compat; > + char *acpihid; > struct module *owner; > vfio_platform_reset_fn_t reset; > }; > @@ -98,27 +100,30 @@ extern int vfio_platform_set_irqs_ioctl(struct vfio_platform_device *vdev, > > extern void __vfio_platform_register_reset(struct vfio_platform_reset_node *n); > extern void vfio_platform_unregister_reset(const char *compat, > + const char *acpihid, > vfio_platform_reset_fn_t fn); > -#define vfio_platform_register_reset(__compat, __reset) \ > -static struct vfio_platform_reset_node __reset ## _node = { \ > - .owner = THIS_MODULE, \ > - .compat = __compat, \ > - .reset = __reset, \ > -}; \ > + > +#define vfio_platform_register_reset(__compat, __acpihid, __reset) \ > +static struct vfio_platform_reset_node __reset ## _node = { \ > + .owner = THIS_MODULE, \ > + .compat = __compat, \ > + .acpihid = __acpihid, \ > + .reset = __reset, \ > +}; \ > __vfio_platform_register_reset(&__reset ## _node) > > -#define module_vfio_reset_handler(compat, reset) \ > -MODULE_ALIAS("vfio-reset:" compat); \ > -static int __init reset ## _module_init(void) \ > -{ \ > - vfio_platform_register_reset(compat, reset); \ > - return 0; \ > -}; \ > -static void __exit reset ## _module_exit(void) \ > -{ \ > - vfio_platform_unregister_reset(compat, reset); \ > -}; \ > -module_init(reset ## _module_init); \ > +#define module_vfio_reset_handler(compat, acpihid, reset) \ > +MODULE_ALIAS("vfio-reset:" compat); \ > +static int __init reset ## _module_init(void) \ > +{ \ > + vfio_platform_register_reset(compat, acpihid, reset); \ > + return 0; \ > +}; \ > +static void __exit reset ## _module_exit(void) \ > +{ \ > + vfio_platform_unregister_reset(compat, acpihid, reset); \ > +}; \ > +module_init(reset ## _module_init); \ > module_exit(reset ## _module_exit) > > #endif /* VFIO_PLATFORM_PRIVATE_H */ > I believe these two reviews need to be reviewed by you as they are in the VFIO world. Would you please take a look? [PATCH V14 8/9] vfio, platform: add support for ACPI while detecting the reset driver [PATCH V14 9/9] vfio, platform: add QTI HIDMA reset driver Sinan
Hi Sinan, On 02/05/2016 05:34 AM, Sinan Kaya wrote: > The code is using the compatible DT string to associate a reset driver with > the actual device itself. The compatible string does not exist on ACPI > based systems. HID is the unique identifier for a device driver instead. > The change allows a driver to register with DT compatible string or ACPI > HID and then match the object with one of these conditions. > > Rules for loading the reset driver are as follow: > - ACPI HID needs match for ACPI systems > - DT compat needs to match for OF systems > > Tested-by: Eric Auger <eric.auger@linaro.org> (device tree only) > Tested-by: Shanker Donthineni <shankerd@codeaurora.org> (ACPI only) > Signed-off-by: Sinan Kaya <okaya@codeaurora.org> > --- > .../vfio/platform/reset/vfio_platform_amdxgbe.c | 3 +- > .../platform/reset/vfio_platform_calxedaxgmac.c | 3 +- > drivers/vfio/platform/vfio_platform_common.c | 80 +++++++++++++++++++--- > drivers/vfio/platform/vfio_platform_private.h | 41 ++++++----- > 4 files changed, 96 insertions(+), 31 deletions(-) > > diff --git a/drivers/vfio/platform/reset/vfio_platform_amdxgbe.c b/drivers/vfio/platform/reset/vfio_platform_amdxgbe.c > index d4030d0..cc5b4fa 100644 > --- a/drivers/vfio/platform/reset/vfio_platform_amdxgbe.c > +++ b/drivers/vfio/platform/reset/vfio_platform_amdxgbe.c > @@ -119,7 +119,8 @@ int vfio_platform_amdxgbe_reset(struct vfio_platform_device *vdev) > return 0; > } > > -module_vfio_reset_handler("amd,xgbe-seattle-v1a", vfio_platform_amdxgbe_reset); > +module_vfio_reset_handler("amd,xgbe-seattle-v1a", NULL, > + vfio_platform_amdxgbe_reset); > > MODULE_VERSION("0.1"); > MODULE_LICENSE("GPL v2"); > diff --git a/drivers/vfio/platform/reset/vfio_platform_calxedaxgmac.c b/drivers/vfio/platform/reset/vfio_platform_calxedaxgmac.c > index e3d3d94..0e57529 100644 > --- a/drivers/vfio/platform/reset/vfio_platform_calxedaxgmac.c > +++ b/drivers/vfio/platform/reset/vfio_platform_calxedaxgmac.c > @@ -77,7 +77,8 @@ int vfio_platform_calxedaxgmac_reset(struct vfio_platform_device *vdev) > return 0; > } > > -module_vfio_reset_handler("calxeda,hb-xgmac", vfio_platform_calxedaxgmac_reset); > +module_vfio_reset_handler("calxeda,hb-xgmac", NULL, > + vfio_platform_calxedaxgmac_reset); > > MODULE_VERSION(DRIVER_VERSION); > MODULE_LICENSE("GPL v2"); > diff --git a/drivers/vfio/platform/vfio_platform_common.c b/drivers/vfio/platform/vfio_platform_common.c > index 418cdd9..5b42e93 100644 > --- a/drivers/vfio/platform/vfio_platform_common.c > +++ b/drivers/vfio/platform/vfio_platform_common.c > @@ -13,6 +13,7 @@ > */ > > #include <linux/device.h> > +#include <linux/acpi.h> > #include <linux/iommu.h> > #include <linux/module.h> > #include <linux/mutex.h> > @@ -31,14 +32,22 @@ static LIST_HEAD(reset_list); > static DEFINE_MUTEX(driver_lock); > > static vfio_platform_reset_fn_t vfio_platform_lookup_reset(const char *compat, > - struct module **module) > + const char *acpihid, struct module **module) > { > struct vfio_platform_reset_node *iter; > vfio_platform_reset_fn_t reset_fn = NULL; > > mutex_lock(&driver_lock); > list_for_each_entry(iter, &reset_list, link) { > - if (!strcmp(iter->compat, compat) && > + if (acpihid && iter->acpihid && > + !strcmp(iter->acpihid, acpihid) && > + try_module_get(iter->owner)) { > + *module = iter->owner; > + reset_fn = iter->reset; > + break; > + } > + if (compat && iter->compat && > + !strcmp(iter->compat, compat) && > try_module_get(iter->owner)) { > *module = iter->owner; > reset_fn = iter->reset; > @@ -51,11 +60,12 @@ static vfio_platform_reset_fn_t vfio_platform_lookup_reset(const char *compat, > > static void vfio_platform_get_reset(struct vfio_platform_device *vdev) > { > - vdev->reset = vfio_platform_lookup_reset(vdev->compat, > - &vdev->reset_module); > + vdev->reset = vfio_platform_lookup_reset(vdev->compat, vdev->acpihid, > + &vdev->reset_module); > if (!vdev->reset) { > request_module("vfio-reset:%s", vdev->compat); > vdev->reset = vfio_platform_lookup_reset(vdev->compat, > + vdev->acpihid, > &vdev->reset_module); > } > } > @@ -541,6 +551,46 @@ static const struct vfio_device_ops vfio_platform_ops = { > .mmap = vfio_platform_mmap, > }; > > +#ifdef CONFIG_ACPI > +int vfio_platform_probe_acpi(struct vfio_platform_device *vdev, > + struct device *dev) > +{ > + struct acpi_device *adev = ACPI_COMPANION(dev); > + > + if (!adev) > + return -EINVAL; -ENODEV seems to be commonly used in that case > + > + vdev->acpihid = acpi_device_hid(adev); > + if (!vdev->acpihid) { can it return NULL? Seems to return dummy "device" or actual hid > + pr_err("VFIO: cannot find ACPI HID for %s\n", > + vdev->name); > + return -EINVAL; -ENODEV too? > + } > + return 0; > +} > +#else > +int vfio_platform_probe_acpi(struct vfio_platform_device *vdev, > + struct device *dev) > +{ > + return -EINVAL; > +} > +#endif > + > +int vfio_platform_probe_of(struct vfio_platform_device *vdev, > + struct device *dev) > +{ > + int ret; > + > + ret = device_property_read_string(dev, "compatible", > + &vdev->compat); > + if (ret) { > + pr_err("VFIO: cannot retrieve compat for %s\n", > + vdev->name); > + return -EINVAL; return ret instead. > + } > + return 0; > +} > + > int vfio_platform_probe_common(struct vfio_platform_device *vdev, > struct device *dev) > { > @@ -550,14 +600,14 @@ int vfio_platform_probe_common(struct vfio_platform_device *vdev, > if (!vdev) > return -EINVAL; > > - ret = device_property_read_string(dev, "compatible", &vdev->compat); > - if (ret) { > - pr_err("VFIO: cannot retrieve compat for %s\n", vdev->name); > - return -EINVAL; > - } > + ret = vfio_platform_probe_acpi(vdev, dev); > + if (ret) > + ret = vfio_platform_probe_of(vdev, dev); > > - vdev->device = dev; > + if (ret) > + return ret; > > + vdev->device = dev; > group = iommu_group_get(dev); > if (!group) { > pr_err("VFIO: No IOMMU group for device %s\n", vdev->name); > @@ -602,13 +652,21 @@ void __vfio_platform_register_reset(struct vfio_platform_reset_node *node) > EXPORT_SYMBOL_GPL(__vfio_platform_register_reset); > > void vfio_platform_unregister_reset(const char *compat, > + const char *acpihid, > vfio_platform_reset_fn_t fn) > { > struct vfio_platform_reset_node *iter, *temp; > > mutex_lock(&driver_lock); > list_for_each_entry_safe(iter, temp, &reset_list, link) { > - if (!strcmp(iter->compat, compat) && (iter->reset == fn)) { > + if (acpihid && iter->acpihid && > + !strcmp(iter->acpihid, acpihid) && (iter->reset == fn)) { > + list_del(&iter->link); > + break; > + } > + > + if (compat && iter->compat && > + !strcmp(iter->compat, compat) && (iter->reset == fn)) { > list_del(&iter->link); > break; > } in vfio_platform_get_reset, if the 1st vfio_platform_lookup_reset call does not return anything then we currently call request_module("vfio-reset:%s", vdev->compat); you need to handle the case where compat is not set but vdev->acpihid is, instead. currently the module alias is constructed with the compat only MODULE_ALIAS("vfio-reset:" compat); Looks you can define several ones ( for instance in drivers/block/xen-blkfront.c). If I am not wrong this currently would not work with vfio-platform-qcomhidma compiled as a module. > diff --git a/drivers/vfio/platform/vfio_platform_private.h b/drivers/vfio/platform/vfio_platform_private.h > index 42816dd..32feba3 100644 > --- a/drivers/vfio/platform/vfio_platform_private.h > +++ b/drivers/vfio/platform/vfio_platform_private.h > @@ -58,6 +58,7 @@ struct vfio_platform_device { > struct mutex igate; > struct module *parent_module; > const char *compat; > + const char *acpihid; > struct module *reset_module; > struct device *device; > > @@ -79,6 +80,7 @@ typedef int (*vfio_platform_reset_fn_t)(struct vfio_platform_device *vdev); > struct vfio_platform_reset_node { > struct list_head link; > char *compat; > + char *acpihid; > struct module *owner; > vfio_platform_reset_fn_t reset; > }; > @@ -98,27 +100,30 @@ extern int vfio_platform_set_irqs_ioctl(struct vfio_platform_device *vdev, > > extern void __vfio_platform_register_reset(struct vfio_platform_reset_node *n); > extern void vfio_platform_unregister_reset(const char *compat, > + const char *acpihid, > vfio_platform_reset_fn_t fn); > -#define vfio_platform_register_reset(__compat, __reset) \ > -static struct vfio_platform_reset_node __reset ## _node = { \ > - .owner = THIS_MODULE, \ > - .compat = __compat, \ > - .reset = __reset, \ > -}; \ > + > +#define vfio_platform_register_reset(__compat, __acpihid, __reset) \ > +static struct vfio_platform_reset_node __reset ## _node = { \ > + .owner = THIS_MODULE, \ > + .compat = __compat, \ > + .acpihid = __acpihid, \ > + .reset = __reset, \ > +}; \ > __vfio_platform_register_reset(&__reset ## _node) > > -#define module_vfio_reset_handler(compat, reset) \ > -MODULE_ALIAS("vfio-reset:" compat); \ > -static int __init reset ## _module_init(void) \ > -{ \ > - vfio_platform_register_reset(compat, reset); \ > - return 0; \ > -}; \ > -static void __exit reset ## _module_exit(void) \ > -{ \ > - vfio_platform_unregister_reset(compat, reset); \ > -}; \ > -module_init(reset ## _module_init); \ > +#define module_vfio_reset_handler(compat, acpihid, reset) \ > +MODULE_ALIAS("vfio-reset:" compat); \ Here you need to handle alias for hid case I think Best Regards Eric > +static int __init reset ## _module_init(void) \ > +{ \ > + vfio_platform_register_reset(compat, acpihid, reset); \ > + return 0; \ > +}; \ > +static void __exit reset ## _module_exit(void) \ > +{ \ > + vfio_platform_unregister_reset(compat, acpihid, reset); \ > +}; \ > +module_init(reset ## _module_init); \ > module_exit(reset ## _module_exit) > > #endif /* VFIO_PLATFORM_PRIVATE_H */ >
>> +#ifdef CONFIG_ACPI >> +int vfio_platform_probe_acpi(struct vfio_platform_device *vdev, >> + struct device *dev) >> +{ >> + struct acpi_device *adev = ACPI_COMPANION(dev); >> + >> + if (!adev) >> + return -EINVAL; > -ENODEV seems to be commonly used in that case ok >> + >> + vdev->acpihid = acpi_device_hid(adev); >> + if (!vdev->acpihid) { > can it return NULL? Seems to return dummy "device" or actual hid >> + pr_err("VFIO: cannot find ACPI HID for %s\n", >> + vdev->name); >> + return -EINVAL; > -ENODEV too? sure >> + } >> + return 0; >> +} >> +#else >> +int vfio_platform_probe_acpi(struct vfio_platform_device *vdev, >> + struct device *dev) >> +{ >> + return -EINVAL; >> +} >> +#endif >> + >> +int vfio_platform_probe_of(struct vfio_platform_device *vdev, >> + struct device *dev) >> +{ >> + int ret; >> + >> + ret = device_property_read_string(dev, "compatible", >> + &vdev->compat); >> + if (ret) { >> + pr_err("VFIO: cannot retrieve compat for %s\n", >> + vdev->name); >> + return -EINVAL; > return ret instead. ok >> + } >> + return 0; >> +} >> + >> int vfio_platform_probe_common(struct vfio_platform_device *vdev, >> struct device *dev) >> { >> @@ -550,14 +600,14 @@ int vfio_platform_probe_common(struct vfio_platform_device *vdev, >> if (!vdev) >> return -EINVAL; >> >> - ret = device_property_read_string(dev, "compatible", &vdev->compat); >> - if (ret) { >> - pr_err("VFIO: cannot retrieve compat for %s\n", vdev->name); >> - return -EINVAL; >> - } >> + ret = vfio_platform_probe_acpi(vdev, dev); >> + if (ret) >> + ret = vfio_platform_probe_of(vdev, dev); >> >> - vdev->device = dev; >> + if (ret) >> + return ret; >> >> + vdev->device = dev; >> group = iommu_group_get(dev); >> if (!group) { >> pr_err("VFIO: No IOMMU group for device %s\n", vdev->name); >> @@ -602,13 +652,21 @@ void __vfio_platform_register_reset(struct vfio_platform_reset_node *node) >> EXPORT_SYMBOL_GPL(__vfio_platform_register_reset); >> >> void vfio_platform_unregister_reset(const char *compat, >> + const char *acpihid, >> vfio_platform_reset_fn_t fn) >> { >> struct vfio_platform_reset_node *iter, *temp; >> >> mutex_lock(&driver_lock); >> list_for_each_entry_safe(iter, temp, &reset_list, link) { >> - if (!strcmp(iter->compat, compat) && (iter->reset == fn)) { >> + if (acpihid && iter->acpihid && >> + !strcmp(iter->acpihid, acpihid) && (iter->reset == fn)) { >> + list_del(&iter->link); >> + break; >> + } >> + >> + if (compat && iter->compat && >> + !strcmp(iter->compat, compat) && (iter->reset == fn)) { >> list_del(&iter->link); >> break; >> } > > in vfio_platform_get_reset, if the 1st vfio_platform_lookup_reset call > does not return anything then we currently call > request_module("vfio-reset:%s", vdev->compat); > > you need to handle the case where compat is not set but vdev->acpihid > is, instead. > > currently the module alias is constructed with the compat only > MODULE_ALIAS("vfio-reset:" compat); > > Looks you can define several ones ( for instance in > drivers/block/xen-blkfront.c). > > If I am not wrong this currently would not work with > vfio-platform-qcomhidma compiled as a module. > Good point. I happen to have both defined as the driver support both ACPI and device-tree. That's why, I have never seen the problem during testing. >> >> -#define module_vfio_reset_handler(compat, reset) \ >> -MODULE_ALIAS("vfio-reset:" compat); \ >> -static int __init reset ## _module_init(void) \ >> -{ \ >> - vfio_platform_register_reset(compat, reset); \ >> - return 0; \ >> -}; \ >> -static void __exit reset ## _module_exit(void) \ >> -{ \ >> - vfio_platform_unregister_reset(compat, reset); \ >> -}; \ >> -module_init(reset ## _module_init); \ >> +#define module_vfio_reset_handler(compat, acpihid, reset) \ >> +MODULE_ALIAS("vfio-reset:" compat); \ > Here you need to handle alias for hid case I think > I'll add this and test different combinations where compat and acpihid are null. #define module_vfio_reset_handler(compat, acpihid, reset) \ MODULE_ALIAS("vfio-reset:" compat); \ MODULE_ALIAS("vfio-reset:" acpihid); \
On 2/26/2016 12:15 PM, Eric Auger wrote: >> -module_init(reset ## _module_init); \ >> > +#define module_vfio_reset_handler(compat, acpihid, reset) \ >> > +MODULE_ALIAS("vfio-reset:" compat); \ > Here you need to handle alias for hid case I think I'm wondering what happens when Compat or ACPI string is NULL. MODULE_ALIAS("vfio-reset:" NULL) Would the kernel like it? I'd rather create an alias only when the string is not NULL. Given this is a macro, I believe it won't work. Can you think of any other way in the code to create the alias?
Hi Sinan, On 03/02/2016 07:34 PM, Sinan Kaya wrote: > On 2/26/2016 12:15 PM, Eric Auger wrote: >>> -module_init(reset ## _module_init); \ >>>> +#define module_vfio_reset_handler(compat, acpihid, reset) \ >>>> +MODULE_ALIAS("vfio-reset:" compat); \ >> Here you need to handle alias for hid case I think > > I'm wondering what happens when Compat or ACPI string is NULL. > > MODULE_ALIAS("vfio-reset:" NULL) > > Would the kernel like it? > > I'd rather create an alias only when the string is not NULL. Given > this is a macro, I believe it won't work. Indeed I think we should create an alias only for the supported case or 2 aliases if both are supported. > > Can you think of any other way in the code to create the alias? > To be honest I did not find any elegant solution either. Personally I would move the MODULE_ALIAS for compat/acpihid outside of module_vfio_reset_handler macro, directly in the reset module. But maybe someone will propose a better solution? Best Regards Eric
On 3/3/2016 6:14 PM, Eric Auger wrote: > Hi Sinan, > On 03/02/2016 07:34 PM, Sinan Kaya wrote: >> On 2/26/2016 12:15 PM, Eric Auger wrote: >>>> -module_init(reset ## _module_init); \ >>>>> +#define module_vfio_reset_handler(compat, acpihid, reset) \ >>>>> +MODULE_ALIAS("vfio-reset:" compat); \ >>> Here you need to handle alias for hid case I think >> >> I'm wondering what happens when Compat or ACPI string is NULL. >> >> MODULE_ALIAS("vfio-reset:" NULL) >> >> Would the kernel like it? > >> >> I'd rather create an alias only when the string is not NULL. Given >> this is a macro, I believe it won't work. > > Indeed I think we should create an alias only for the supported case or > 2 aliases if both are supported. >> >> Can you think of any other way in the code to create the alias? >> > To be honest I did not find any elegant solution either. Personally I > would move the MODULE_ALIAS for compat/acpihid outside of > module_vfio_reset_handler macro, directly in the reset module. But maybe > someone will propose a better solution? > I briefly looked at this. #define MODULE_ALIAS(_alias) MODULE_INFO(alias, _alias) #define MODULE_INFO(tag, info) __MODULE_INFO(tag, tag, info) and it eventually becomes this #define __MODULE_INFO(tag, name, info) \ static const char __UNIQUE_ID(name)[] \ __used __attribute__((section(".modinfo"), unused, aligned(1))) \ = __stringify(tag) "=" info Since the info is on the right side of the equation, I'm allowed to add some conditionals. #define module_vfio_reset_handler(compat, acpihid, reset) \ MODULE_ALIAS("vfio-reset:" acpihid? acpihid: compat); \ This way, we'll create an alias with one of the provided strings.
Hi Sinan, On 03/04/2016 06:20 AM, Sinan Kaya wrote: > On 3/3/2016 6:14 PM, Eric Auger wrote: >> Hi Sinan, >> On 03/02/2016 07:34 PM, Sinan Kaya wrote: >>> On 2/26/2016 12:15 PM, Eric Auger wrote: >>>>> -module_init(reset ## _module_init); \ >>>>>> +#define module_vfio_reset_handler(compat, acpihid, reset) \ >>>>>> +MODULE_ALIAS("vfio-reset:" compat); \ >>>> Here you need to handle alias for hid case I think >>> >>> I'm wondering what happens when Compat or ACPI string is NULL. >>> >>> MODULE_ALIAS("vfio-reset:" NULL) >>> >>> Would the kernel like it? >> >>> >>> I'd rather create an alias only when the string is not NULL. Given >>> this is a macro, I believe it won't work. >> >> Indeed I think we should create an alias only for the supported case or >> 2 aliases if both are supported. >>> >>> Can you think of any other way in the code to create the alias? >>> >> To be honest I did not find any elegant solution either. Personally I >> would move the MODULE_ALIAS for compat/acpihid outside of >> module_vfio_reset_handler macro, directly in the reset module. But maybe >> someone will propose a better solution? >> > > I briefly looked at this. > > #define MODULE_ALIAS(_alias) MODULE_INFO(alias, _alias) > #define MODULE_INFO(tag, info) __MODULE_INFO(tag, tag, info) > > and it eventually becomes this > > #define __MODULE_INFO(tag, name, info) \ > static const char __UNIQUE_ID(name)[] \ > __used __attribute__((section(".modinfo"), unused, aligned(1))) \ > = __stringify(tag) "=" info > > Since the info is on the right side of the equation, I'm allowed to add some > conditionals. > > #define module_vfio_reset_handler(compat, acpihid, reset) \ > MODULE_ALIAS("vfio-reset:" acpihid? acpihid: compat); \ > > This way, we'll create an alias with one of the provided strings. What if you want to use vfio platform driver for HiDMA in dt mode? the HiDma reset module advertises both acpihid and dt compat support but an alias module will be created only for acpihid. Then I think we will not be able to load the reset module in dt mode with existing code. This could work however with some rework in vfio_platform_common.c. In vfio_platform_get_reset we should try to load the module using the acpihid if the module load using compat alias fails. In the look-up table we can find the acpihid corresponding to the dt compat. Any thought? Best Regards Eric > > >
diff --git a/drivers/vfio/platform/reset/vfio_platform_amdxgbe.c b/drivers/vfio/platform/reset/vfio_platform_amdxgbe.c index d4030d0..cc5b4fa 100644 --- a/drivers/vfio/platform/reset/vfio_platform_amdxgbe.c +++ b/drivers/vfio/platform/reset/vfio_platform_amdxgbe.c @@ -119,7 +119,8 @@ int vfio_platform_amdxgbe_reset(struct vfio_platform_device *vdev) return 0; } -module_vfio_reset_handler("amd,xgbe-seattle-v1a", vfio_platform_amdxgbe_reset); +module_vfio_reset_handler("amd,xgbe-seattle-v1a", NULL, + vfio_platform_amdxgbe_reset); MODULE_VERSION("0.1"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/vfio/platform/reset/vfio_platform_calxedaxgmac.c b/drivers/vfio/platform/reset/vfio_platform_calxedaxgmac.c index e3d3d94..0e57529 100644 --- a/drivers/vfio/platform/reset/vfio_platform_calxedaxgmac.c +++ b/drivers/vfio/platform/reset/vfio_platform_calxedaxgmac.c @@ -77,7 +77,8 @@ int vfio_platform_calxedaxgmac_reset(struct vfio_platform_device *vdev) return 0; } -module_vfio_reset_handler("calxeda,hb-xgmac", vfio_platform_calxedaxgmac_reset); +module_vfio_reset_handler("calxeda,hb-xgmac", NULL, + vfio_platform_calxedaxgmac_reset); MODULE_VERSION(DRIVER_VERSION); MODULE_LICENSE("GPL v2"); diff --git a/drivers/vfio/platform/vfio_platform_common.c b/drivers/vfio/platform/vfio_platform_common.c index 418cdd9..5b42e93 100644 --- a/drivers/vfio/platform/vfio_platform_common.c +++ b/drivers/vfio/platform/vfio_platform_common.c @@ -13,6 +13,7 @@ */ #include <linux/device.h> +#include <linux/acpi.h> #include <linux/iommu.h> #include <linux/module.h> #include <linux/mutex.h> @@ -31,14 +32,22 @@ static LIST_HEAD(reset_list); static DEFINE_MUTEX(driver_lock); static vfio_platform_reset_fn_t vfio_platform_lookup_reset(const char *compat, - struct module **module) + const char *acpihid, struct module **module) { struct vfio_platform_reset_node *iter; vfio_platform_reset_fn_t reset_fn = NULL; mutex_lock(&driver_lock); list_for_each_entry(iter, &reset_list, link) { - if (!strcmp(iter->compat, compat) && + if (acpihid && iter->acpihid && + !strcmp(iter->acpihid, acpihid) && + try_module_get(iter->owner)) { + *module = iter->owner; + reset_fn = iter->reset; + break; + } + if (compat && iter->compat && + !strcmp(iter->compat, compat) && try_module_get(iter->owner)) { *module = iter->owner; reset_fn = iter->reset; @@ -51,11 +60,12 @@ static vfio_platform_reset_fn_t vfio_platform_lookup_reset(const char *compat, static void vfio_platform_get_reset(struct vfio_platform_device *vdev) { - vdev->reset = vfio_platform_lookup_reset(vdev->compat, - &vdev->reset_module); + vdev->reset = vfio_platform_lookup_reset(vdev->compat, vdev->acpihid, + &vdev->reset_module); if (!vdev->reset) { request_module("vfio-reset:%s", vdev->compat); vdev->reset = vfio_platform_lookup_reset(vdev->compat, + vdev->acpihid, &vdev->reset_module); } } @@ -541,6 +551,46 @@ static const struct vfio_device_ops vfio_platform_ops = { .mmap = vfio_platform_mmap, }; +#ifdef CONFIG_ACPI +int vfio_platform_probe_acpi(struct vfio_platform_device *vdev, + struct device *dev) +{ + struct acpi_device *adev = ACPI_COMPANION(dev); + + if (!adev) + return -EINVAL; + + vdev->acpihid = acpi_device_hid(adev); + if (!vdev->acpihid) { + pr_err("VFIO: cannot find ACPI HID for %s\n", + vdev->name); + return -EINVAL; + } + return 0; +} +#else +int vfio_platform_probe_acpi(struct vfio_platform_device *vdev, + struct device *dev) +{ + return -EINVAL; +} +#endif + +int vfio_platform_probe_of(struct vfio_platform_device *vdev, + struct device *dev) +{ + int ret; + + ret = device_property_read_string(dev, "compatible", + &vdev->compat); + if (ret) { + pr_err("VFIO: cannot retrieve compat for %s\n", + vdev->name); + return -EINVAL; + } + return 0; +} + int vfio_platform_probe_common(struct vfio_platform_device *vdev, struct device *dev) { @@ -550,14 +600,14 @@ int vfio_platform_probe_common(struct vfio_platform_device *vdev, if (!vdev) return -EINVAL; - ret = device_property_read_string(dev, "compatible", &vdev->compat); - if (ret) { - pr_err("VFIO: cannot retrieve compat for %s\n", vdev->name); - return -EINVAL; - } + ret = vfio_platform_probe_acpi(vdev, dev); + if (ret) + ret = vfio_platform_probe_of(vdev, dev); - vdev->device = dev; + if (ret) + return ret; + vdev->device = dev; group = iommu_group_get(dev); if (!group) { pr_err("VFIO: No IOMMU group for device %s\n", vdev->name); @@ -602,13 +652,21 @@ void __vfio_platform_register_reset(struct vfio_platform_reset_node *node) EXPORT_SYMBOL_GPL(__vfio_platform_register_reset); void vfio_platform_unregister_reset(const char *compat, + const char *acpihid, vfio_platform_reset_fn_t fn) { struct vfio_platform_reset_node *iter, *temp; mutex_lock(&driver_lock); list_for_each_entry_safe(iter, temp, &reset_list, link) { - if (!strcmp(iter->compat, compat) && (iter->reset == fn)) { + if (acpihid && iter->acpihid && + !strcmp(iter->acpihid, acpihid) && (iter->reset == fn)) { + list_del(&iter->link); + break; + } + + if (compat && iter->compat && + !strcmp(iter->compat, compat) && (iter->reset == fn)) { list_del(&iter->link); break; } diff --git a/drivers/vfio/platform/vfio_platform_private.h b/drivers/vfio/platform/vfio_platform_private.h index 42816dd..32feba3 100644 --- a/drivers/vfio/platform/vfio_platform_private.h +++ b/drivers/vfio/platform/vfio_platform_private.h @@ -58,6 +58,7 @@ struct vfio_platform_device { struct mutex igate; struct module *parent_module; const char *compat; + const char *acpihid; struct module *reset_module; struct device *device; @@ -79,6 +80,7 @@ typedef int (*vfio_platform_reset_fn_t)(struct vfio_platform_device *vdev); struct vfio_platform_reset_node { struct list_head link; char *compat; + char *acpihid; struct module *owner; vfio_platform_reset_fn_t reset; }; @@ -98,27 +100,30 @@ extern int vfio_platform_set_irqs_ioctl(struct vfio_platform_device *vdev, extern void __vfio_platform_register_reset(struct vfio_platform_reset_node *n); extern void vfio_platform_unregister_reset(const char *compat, + const char *acpihid, vfio_platform_reset_fn_t fn); -#define vfio_platform_register_reset(__compat, __reset) \ -static struct vfio_platform_reset_node __reset ## _node = { \ - .owner = THIS_MODULE, \ - .compat = __compat, \ - .reset = __reset, \ -}; \ + +#define vfio_platform_register_reset(__compat, __acpihid, __reset) \ +static struct vfio_platform_reset_node __reset ## _node = { \ + .owner = THIS_MODULE, \ + .compat = __compat, \ + .acpihid = __acpihid, \ + .reset = __reset, \ +}; \ __vfio_platform_register_reset(&__reset ## _node) -#define module_vfio_reset_handler(compat, reset) \ -MODULE_ALIAS("vfio-reset:" compat); \ -static int __init reset ## _module_init(void) \ -{ \ - vfio_platform_register_reset(compat, reset); \ - return 0; \ -}; \ -static void __exit reset ## _module_exit(void) \ -{ \ - vfio_platform_unregister_reset(compat, reset); \ -}; \ -module_init(reset ## _module_init); \ +#define module_vfio_reset_handler(compat, acpihid, reset) \ +MODULE_ALIAS("vfio-reset:" compat); \ +static int __init reset ## _module_init(void) \ +{ \ + vfio_platform_register_reset(compat, acpihid, reset); \ + return 0; \ +}; \ +static void __exit reset ## _module_exit(void) \ +{ \ + vfio_platform_unregister_reset(compat, acpihid, reset); \ +}; \ +module_init(reset ## _module_init); \ module_exit(reset ## _module_exit) #endif /* VFIO_PLATFORM_PRIVATE_H */