> -----Original Message-----
> From: [email protected] [mailto:platform-driver-
> [email protected]] On Behalf Of
> [email protected]
> Sent: Tuesday, August 1, 2017 11:44 PM
> To: [email protected]; [email protected]; Zha, Qipeng
> <[email protected]>; [email protected]; [email protected];
> [email protected]; [email protected]
> Cc: [email protected]; [email protected];
> [email protected]; Kuppuswamy Sathyanarayanan
> <[email protected]>
> Subject: [RFC v1 3/6] platform/x86: intel_pmc_ipc: Use MFD framework to
> create dependent devices
> 
> From: Kuppuswamy Sathyanarayanan
> <[email protected]>
> 
> Currently, we have lot of repetitive code in dependent device resource
> allocation and device creation handling code. This logic can be improved if
> we use MFD framework for dependent device creation. This patch adds this
> support.
> 
> Signed-off-by: Kuppuswamy Sathyanarayanan
> <[email protected]>
> ---
>  drivers/platform/x86/intel_pmc_ipc.c | 376 +++++++++++++-------------------
> ---
>  1 file changed, 141 insertions(+), 235 deletions(-)
> 
> diff --git a/drivers/platform/x86/intel_pmc_ipc.c
> b/drivers/platform/x86/intel_pmc_ipc.c
> index ad0416e..43533ec 100644
> --- a/drivers/platform/x86/intel_pmc_ipc.c
> +++ b/drivers/platform/x86/intel_pmc_ipc.c
> @@ -33,6 +33,7 @@
>  #include <linux/suspend.h>
>  #include <linux/acpi.h>
>  #include <linux/io-64-nonatomic-lo-hi.h>
> +#include <linux/mfd/core.h>
> 
>  #include <asm/intel_pmc_ipc.h>
> 
> @@ -105,8 +106,6 @@
>  #define TELEM_SSRAM_SIZE             240
>  #define TELEM_PMC_SSRAM_OFFSET               0x1B00
>  #define TELEM_PUNIT_SSRAM_OFFSET     0x1A00
> -#define TCO_PMC_OFFSET                       0x8
> -#define TCO_PMC_SIZE                 0x4
> 
>  /* PMC register bit definitions */
> 
> @@ -115,6 +114,13 @@
>  #define PMC_CFG_NO_REBOOT_EN         (1 << 4)
>  #define PMC_CFG_NO_REBOOT_DIS                (0 << 4)
> 
> +enum {
> +     PMC_IPC_PUNIT_MFD_BLOCK,
> +     PMC_IPC_WATCHDOG_MFD_BLOCK,
> +     PMC_IPC_TELEMETRY_MFD_BLOCK,
> +     PMC_IPC_MAX_MFD_BLOCK
> +};
> +
>  static struct intel_pmc_ipc_dev {
>       struct device *dev;
>       void __iomem *ipc_base;
> @@ -123,25 +129,12 @@ static struct intel_pmc_ipc_dev {
>       int cmd;
>       struct completion cmd_complete;
> 
> -     /* The following PMC BARs share the same ACPI device with the IPC
> */
> -     resource_size_t acpi_io_base;
> -     int acpi_io_size;
> -     struct platform_device *tco_dev;
> -
>       /* gcr */
>       void __iomem *gcr_mem_base;
>       bool has_gcr_regs;
> 
> -     /* punit */
> -     struct platform_device *punit_dev;
> -
>       /* Telemetry */
> -     resource_size_t telem_pmc_ssram_base;
> -     resource_size_t telem_punit_ssram_base;
> -     int telem_pmc_ssram_size;
> -     int telem_punit_ssram_size;
>       u8 telem_res_inval;
> -     struct platform_device *telemetry_dev;
>  } ipcdev;
> 
>  static char *ipc_err_sources[] = {
> @@ -613,7 +606,7 @@ static const struct attribute_group intel_ipc_group
> = {
>       .attrs = intel_ipc_attrs,
>  };
> 
> -static struct resource punit_res_array[] = {
> +static struct resource punit_ipc_resources[] = {
>       /* Punit BIOS */
>       {
>               .flags = IORESOURCE_MEM,
> @@ -637,10 +630,7 @@ static struct resource punit_res_array[] = {
>       },
>  };
> 
> -#define TCO_RESOURCE_ACPI_IO         0
> -#define TCO_RESOURCE_SMI_EN_IO               1
> -#define TCO_RESOURCE_GCR_MEM         2
> -static struct resource tco_res[] = {
> +static struct resource watchdog_ipc_resources[] = {
>       /* ACPI - TCO */
>       {
>               .flags = IORESOURCE_IO,
> @@ -658,9 +648,7 @@ static struct itco_wdt_platform_data tco_info = {
>       .update_no_reboot_bit = update_no_reboot_bit,  };
> 
> -#define TELEMETRY_RESOURCE_PUNIT_SSRAM       0
> -#define TELEMETRY_RESOURCE_PMC_SSRAM 1
> -static struct resource telemetry_res[] = {
> +static struct resource telemetry_ipc_resources[] = {
>       /*Telemetry*/
>       {
>               .flags = IORESOURCE_MEM,
> @@ -670,224 +658,152 @@ static struct resource telemetry_res[] = {
>       },
>  };
> 
> -static int ipc_create_punit_device(void) -{
> -     struct platform_device *pdev;
> -     const struct platform_device_info pdevinfo = {
> -             .parent = ipcdev.dev,
> -             .name = PUNIT_DEVICE_NAME,
> -             .id = -1,
> -             .res = punit_res_array,
> -             .num_res = ARRAY_SIZE(punit_res_array),
> -             };
> -
> -     pdev = platform_device_register_full(&pdevinfo);
> -     if (IS_ERR(pdev))
> -             return PTR_ERR(pdev);
> -
> -     ipcdev.punit_dev = pdev;
> -
> -     return 0;
> -}
> -
> -static int ipc_create_tco_device(void)
> -{
> -     struct platform_device *pdev;
> -     struct resource *res;
> -     const struct platform_device_info pdevinfo = {
> -             .parent = ipcdev.dev,
> -             .name = TCO_DEVICE_NAME,
> -             .id = -1,
> -             .res = tco_res,
> -             .num_res = ARRAY_SIZE(tco_res),
> -             .data = &tco_info,
> -             .size_data = sizeof(tco_info),
> -             };
> -
> -     res = tco_res + TCO_RESOURCE_ACPI_IO;
> -     res->start = ipcdev.acpi_io_base + TCO_BASE_OFFSET;
> -     res->end = res->start + TCO_REGS_SIZE - 1;
> -
> -     res = tco_res + TCO_RESOURCE_SMI_EN_IO;
> -     res->start = ipcdev.acpi_io_base + SMI_EN_OFFSET;
> -     res->end = res->start + SMI_EN_SIZE - 1;
> -
> -     pdev = platform_device_register_full(&pdevinfo);
> -     if (IS_ERR(pdev))
> -             return PTR_ERR(pdev);
> -
> -     ipcdev.tco_dev = pdev;
> -
> -     return 0;
> -}
> -
> -static int ipc_create_telemetry_device(void) -{
> -     struct platform_device *pdev;
> -     struct resource *res;
> -     const struct platform_device_info pdevinfo = {
> -             .parent = ipcdev.dev,
> -             .name = TELEMETRY_DEVICE_NAME,
> -             .id = -1,
> -             .res = telemetry_res,
> -             .num_res = ARRAY_SIZE(telemetry_res),
> -             };
> -
> -     res = telemetry_res + TELEMETRY_RESOURCE_PUNIT_SSRAM;
> -     res->start = ipcdev.telem_punit_ssram_base;
> -     res->end = res->start + ipcdev.telem_punit_ssram_size - 1;
> -
> -     res = telemetry_res + TELEMETRY_RESOURCE_PMC_SSRAM;
> -     res->start = ipcdev.telem_pmc_ssram_base;
> -     res->end = res->start + ipcdev.telem_pmc_ssram_size - 1;
> -
> -     pdev = platform_device_register_full(&pdevinfo);
> -     if (IS_ERR(pdev))
> -             return PTR_ERR(pdev);
> -
> -     ipcdev.telemetry_dev = pdev;
> -
> -     return 0;
> -}
> -
> -static int ipc_create_pmc_devices(void)
> +static int ipc_create_pmc_devices(struct platform_device *pdev)
>  {
> -     int ret;
> -
> -     /* If we have ACPI based watchdog use that instead */
> +     u8 n = 0;
> +     struct mfd_cell *pmc_mfd_cells;
> +
> +     pmc_mfd_cells = devm_kzalloc(&pdev->dev,
> +                     (sizeof(*pmc_mfd_cells) *
> PMC_IPC_MAX_MFD_BLOCK),
> +                     GFP_KERNEL);
> +     if (!pmc_mfd_cells)
> +             return -ENOMEM;
> +
> +     /* Create PUNIT IPC MFD cell */
> +     pmc_mfd_cells[n].name = PUNIT_DEVICE_NAME;
> +     pmc_mfd_cells[n].id = -1;
> +     pmc_mfd_cells[n].num_resources =
> ARRAY_SIZE(punit_ipc_resources);
> +     pmc_mfd_cells[n].resources = punit_ipc_resources;
> +     pmc_mfd_cells[n].ignore_resource_conflicts = 1;
> +     n++;

Since it's not really a loop, cant the enum values of MFD block be used instead 
of 'n'? Will be more readable/intuitive.

> +
> +     /* If we have ACPI based watchdog use that instead, othewise
> create
> +      * a MFD cell for iTCO watchdog*/
>       if (!acpi_has_watchdog()) {
> -             ret = ipc_create_tco_device();
> -             if (ret) {
> -                     dev_err(ipcdev.dev, "Failed to add tco platform
> device\n");
> -                     return ret;
> -             }
> -     }
> -
> -     ret = ipc_create_punit_device();
> -     if (ret) {
> -             dev_err(ipcdev.dev, "Failed to add punit platform
> device\n");
> -             platform_device_unregister(ipcdev.tco_dev);
> +             pmc_mfd_cells[n].name = TCO_DEVICE_NAME;
> +             pmc_mfd_cells[n].id = -1;
> +             pmc_mfd_cells[n].platform_data = &tco_info;
> +             pmc_mfd_cells[n].pdata_size = sizeof(tco_info);
> +             pmc_mfd_cells[n].num_resources =
> +                     ARRAY_SIZE(watchdog_ipc_resources);
> +             pmc_mfd_cells[n].resources = watchdog_ipc_resources;
> +             pmc_mfd_cells[n].ignore_resource_conflicts = 1;
> +             n++;

Same as above.

>       }
> 
>       if (!ipcdev.telem_res_inval) {
> -             ret = ipc_create_telemetry_device();
> -             if (ret)
> -                     dev_warn(ipcdev.dev,
> -                             "Failed to add telemetry platform
> device\n");
> +             pmc_mfd_cells[n].name = TELEMETRY_DEVICE_NAME;
> +             pmc_mfd_cells[n].id = -1;
> +             pmc_mfd_cells[n].num_resources =
> +                     ARRAY_SIZE(telemetry_ipc_resources);
> +             pmc_mfd_cells[n].resources = telemetry_ipc_resources;
> +             pmc_mfd_cells[n].ignore_resource_conflicts = 1;
> +             n++;

Same as above.

>       }
> 
> -     return ret;
> +     return devm_mfd_add_devices(&pdev->dev, -1, pmc_mfd_cells, n,
> NULL,
> +                                 0, NULL);
>  }
> 
>  static int ipc_plat_get_res(struct platform_device *pdev)  {
> -     struct resource *res, *punit_res;
> +     struct resource *res;
>       void __iomem *addr;
> -     int size;
> +     int mindex, pindex = 0;
> 
> +     /* Get iTCO watchdog resources */
>       res = platform_get_resource(pdev, IORESOURCE_IO,
>                                   PLAT_RESOURCE_ACPI_IO_INDEX);
>       if (!res) {
>               dev_err(&pdev->dev, "Failed to get io resource\n");
>               return -ENXIO;
>       }
> -     size = resource_size(res);
> -     ipcdev.acpi_io_base = res->start;
> -     ipcdev.acpi_io_size = size;
> -     dev_info(&pdev->dev, "io res: %pR\n", res);
> -
> -     punit_res = punit_res_array;
> -     /* This is index 0 to cover BIOS data register */
> -     res = platform_get_resource(pdev, IORESOURCE_MEM,
> -                                 PLAT_RESOURCE_BIOS_DATA_INDEX);
> -     if (!res) {
> -             dev_err(&pdev->dev, "Failed to get res of punit BIOS
> data\n");
> -             return -ENXIO;
> -     }
> -     *punit_res = *res;
> -     dev_info(&pdev->dev, "punit BIOS data res: %pR\n", res);
> -
> -     /* This is index 1 to cover BIOS interface register */
> -     res = platform_get_resource(pdev, IORESOURCE_MEM,
> -                                 PLAT_RESOURCE_BIOS_IFACE_INDEX);
> -     if (!res) {
> -             dev_err(&pdev->dev, "Failed to get res of punit BIOS
> iface\n");
> -             return -ENXIO;
> -     }
> -     *++punit_res = *res;
> -     dev_info(&pdev->dev, "punit BIOS interface res: %pR\n", res);
> -
> -     /* This is index 2 to cover ISP data register, optional */
> -     res = platform_get_resource(pdev, IORESOURCE_MEM,
> -                                 PLAT_RESOURCE_ISP_DATA_INDEX);
> -     ++punit_res;
> -     if (res) {
> -             *punit_res = *res;
> -             dev_info(&pdev->dev, "punit ISP data res: %pR\n", res);
> -     }
> 
> -     /* This is index 3 to cover ISP interface register, optional */
> -     res = platform_get_resource(pdev, IORESOURCE_MEM,
> -                                 PLAT_RESOURCE_ISP_IFACE_INDEX);
> -     ++punit_res;
> -     if (res) {
> -             *punit_res = *res;
> -             dev_info(&pdev->dev, "punit ISP interface res: %pR\n", res);
> -     }
> -
> -     /* This is index 4 to cover GTD data register, optional */
> -     res = platform_get_resource(pdev, IORESOURCE_MEM,
> -                                 PLAT_RESOURCE_GTD_DATA_INDEX);
> -     ++punit_res;
> -     if (res) {
> -             *punit_res = *res;
> -             dev_info(&pdev->dev, "punit GTD data res: %pR\n", res);
> -     }
> -
> -     /* This is index 5 to cover GTD interface register, optional */
> -     res = platform_get_resource(pdev, IORESOURCE_MEM,
> -                                 PLAT_RESOURCE_GTD_IFACE_INDEX);
> -     ++punit_res;
> -     if (res) {
> -             *punit_res = *res;
> -             dev_info(&pdev->dev, "punit GTD interface res: %pR\n",
> res);
> -     }
> -
> -     res = platform_get_resource(pdev, IORESOURCE_MEM,
> -                                 PLAT_RESOURCE_IPC_INDEX);
> -     if (!res) {
> -             dev_err(&pdev->dev, "Failed to get ipc resource\n");
> -             return -ENXIO;
> -     }
> -     res->end = (res->start + PLAT_RESOURCE_IPC_SIZE +
> -                 PLAT_RESOURCE_GCR_SIZE - 1);
> -
> -     addr = devm_ioremap_resource(&pdev->dev, res);
> -     if (IS_ERR(addr)) {
> -             dev_err(&pdev->dev,
> -                     "PMC I/O memory remapping failed\n");
> -             return PTR_ERR(addr);
> -     }
> -
> -     ipcdev.ipc_base = addr;
> -
> -     ipcdev.gcr_mem_base = addr + PLAT_RESOURCE_GCR_OFFSET;
> -     dev_info(&pdev->dev, "ipc res: %pR\n", res);
> -
> -     ipcdev.telem_res_inval = 0;
> -     res = platform_get_resource(pdev, IORESOURCE_MEM,
> -                                 PLAT_RESOURCE_TELEM_SSRAM_INDEX);
> -     if (!res) {
> -             dev_err(&pdev->dev, "Failed to get telemetry ssram
> resource\n");
> -             ipcdev.telem_res_inval = 1;
> -     } else {
> -             ipcdev.telem_punit_ssram_base = res->start +
> -
>       TELEM_PUNIT_SSRAM_OFFSET;
> -             ipcdev.telem_punit_ssram_size = TELEM_SSRAM_SIZE;
> -             ipcdev.telem_pmc_ssram_base = res->start +
> -
>       TELEM_PMC_SSRAM_OFFSET;
> -             ipcdev.telem_pmc_ssram_size = TELEM_SSRAM_SIZE;
> -             dev_info(&pdev->dev, "telemetry ssram res: %pR\n", res);
> +     watchdog_ipc_resources[0].start = res->start + TCO_BASE_OFFSET;
> +     watchdog_ipc_resources[0].end = res->start +
> +             TCO_BASE_OFFSET + TCO_REGS_SIZE - 1;
> +     watchdog_ipc_resources[1].start = res->start + SMI_EN_OFFSET;
> +     watchdog_ipc_resources[1].end = res->start +
> +             SMI_EN_OFFSET + SMI_EN_SIZE - 1;

The 0/1 magic may be replaced with MACROS here and elsewhere.

> +
> +     dev_info(&pdev->dev, "watchdog res 0: %pR\n",
> +                     &watchdog_ipc_resources[0]);
> +     dev_info(&pdev->dev, "watchdog res 1: %pR\n",
> +                     &watchdog_ipc_resources[1]);
> +
> +     for (mindex = 0; mindex <= PLAT_RESOURCE_GTD_IFACE_INDEX;
> mindex++) {

Here we are relying on the fact that the GTD_IFACE_INDEX is at offset 7. It's 
however not by design but a side-effect of how the BIOS places the resources.
So perhaps not a good idea to use it, since GTD_IFACE is not meant to be a 
terminator/max delimiter.

> +
> +             res = platform_get_resource(pdev, IORESOURCE_MEM,
> mindex);
> +
> +             switch (mindex) {
> +             /* Get PUNIT resources */
> +             case PLAT_RESOURCE_BIOS_DATA_INDEX:
> +             case PLAT_RESOURCE_BIOS_IFACE_INDEX:
> +                     /* BIOS resources are required, so return error if not
> +                      * available */
> +                     if (!res) {
> +                             dev_err(&pdev->dev,
> +                                     "Failed to get punit mem resource
> %d\n",
> +                                     pindex);
> +                             return -ENXIO;
> +                     }
> +             case PLAT_RESOURCE_ISP_DATA_INDEX:
> +             case PLAT_RESOURCE_ISP_IFACE_INDEX:
> +             case PLAT_RESOURCE_GTD_DATA_INDEX:
> +             case PLAT_RESOURCE_GTD_IFACE_INDEX:
> +                     /* if not valid resource, skip the rest of steps */
> +                     if (!res) {
> +                             pindex++;
> +                             continue;
> +                     }
> +                     memcpy(&punit_ipc_resources[pindex], res,
> +                                     sizeof(*res));
> +                     dev_info(&pdev->dev, "PUNIT memory res: %pR\n",
> +                                     &punit_ipc_resources[pindex]);
> +                     pindex++;
> +                     break;
> +             /* Get Telemetry resources */
> +             case PLAT_RESOURCE_TELEM_SSRAM_INDEX:
> +                     if (!res) {
> +                             dev_warn(&pdev->dev,
> +                                     "Failed to get telemtry sram res\n");
> +                             ipcdev.telem_res_inval = 1;
> +                             continue;
> +                     }
> +                     telemetry_ipc_resources[0].start = res->start +
> +                             TELEM_PUNIT_SSRAM_OFFSET;
> +                     telemetry_ipc_resources[0].end = res->start +
> +                             TELEM_PUNIT_SSRAM_OFFSET +
> TELEM_SSRAM_SIZE - 1;
> +                     telemetry_ipc_resources[1].start = res->start +
> +                             TELEM_PMC_SSRAM_OFFSET;
> +                     telemetry_ipc_resources[1].end = res->start +
> +                             TELEM_PMC_SSRAM_OFFSET +
> TELEM_SSRAM_SIZE - 1;
> +
> +                     dev_info(&pdev->dev, "telemetry punit ssram res:
> %pR\n",
> +                                     &telemetry_ipc_resources[0]);
> +                     dev_info(&pdev->dev, "telemetry pmc ssram res:
> %pR\n",
> +                                     &telemetry_ipc_resources[1]);
> +                     break;
> +             /* Get IPC resources */
> +             case PLAT_RESOURCE_IPC_INDEX:
> +                     if (!res) {
> +                             dev_err(&pdev->dev,
> +                                     "Failed to get IPC resources\n");
> +                             return -ENXIO;
> +                     }
> +                     res->end = (res->start + PLAT_RESOURCE_IPC_SIZE +
> +                                 PLAT_RESOURCE_GCR_SIZE - 1);
> +                     addr = devm_ioremap_resource(&pdev->dev, res);
> +                     if (IS_ERR(addr)) {
> +                             dev_err(&pdev->dev,
> +                                     "PMC I/O memory remapping
> failed\n");
> +                             return PTR_ERR(addr);
> +                     }
> +                     ipcdev.ipc_base = addr;
> +                     ipcdev.gcr_mem_base = addr +
> PLAT_RESOURCE_GCR_OFFSET;
> +                     dev_info(&pdev->dev, "PMC IPC resource %pR\n",
> res);
> +                     break;
> +             };
>       }
> 
>       return 0;
> @@ -943,7 +859,7 @@ static int ipc_plat_probe(struct platform_device
> *pdev)
>               return ret;
>       }
> 
> -     ret = ipc_create_pmc_devices();
> +     ret = ipc_create_pmc_devices(pdev);
>       if (ret) {
>               dev_err(&pdev->dev, "Failed to create pmc devices\n");
>               return ret;
> @@ -952,36 +868,26 @@ static int ipc_plat_probe(struct platform_device
> *pdev)
>       if (devm_request_irq(&pdev->dev, ipcdev.irq, ioc,
> IRQF_NO_SUSPEND,
>                            "intel_pmc_ipc", &ipcdev)) {
>               dev_err(&pdev->dev, "Failed to request irq\n");
> -             ret = -EBUSY;
> -             goto unregister_devices;
> +             return -EBUSY;
>       }
> 
>       ret = sysfs_create_group(&pdev->dev.kobj, &intel_ipc_group);
>       if (ret) {
>               dev_err(&pdev->dev, "Failed to create sysfs group %d\n",
>                       ret);
> -             goto unregister_devices;
> +             return ret;
>       }
> 
>       ipcdev.has_gcr_regs = true;
> 
>       return 0;
> -
> -unregister_devices:
> -     platform_device_unregister(ipcdev.tco_dev);
> -     platform_device_unregister(ipcdev.punit_dev);
> -     platform_device_unregister(ipcdev.telemetry_dev);
> -
> -     return ret;
>  }
> 
>  static int ipc_plat_remove(struct platform_device *pdev)  {
>       sysfs_remove_group(&pdev->dev.kobj, &intel_ipc_group);
> -     platform_device_unregister(ipcdev.tco_dev);
> -     platform_device_unregister(ipcdev.punit_dev);
> -     platform_device_unregister(ipcdev.telemetry_dev);
>       ipcdev.dev = NULL;
> +
>       return 0;
>  }
> 
> --
> 2.7.4

Reply via email to