Hi Gavin,

I was reading through this to understand how it all works and noticed a couple
of things, comments below.

- Alistair

On Wed, 17 Feb 2016 14:44:28 Gavin Shan wrote:

<snip>

> +
> +static void pnv_php_handle_poweron(struct pnv_php_slot *php_slot)
> +{
> +     void *fdt, *fdt1, *dt;
> +     int confirm = PNV_PHP_POWER_CONFIRMED_SUCCESS;
> +     int ret;
> +
> +     /* We don't know the FDT blob size. We try to get it through
> +      * maximal memory chunk and then copy it to another chunk that
> +      * fits the real size.
> +      */
> +     fdt1 = kzalloc(0x10000, GFP_KERNEL);
> +     if (!fdt1)
> +             goto error;
> +
> +     ret = pnv_pci_get_device_tree(php_slot->dn->phandle, fdt1, 0x10000);
> +     if (ret)
> +             goto free_fdt1;
> +
> +     fdt = kzalloc(fdt_totalsize(fdt1), GFP_KERNEL);
> +     if (!fdt)
> +             goto free_fdt1;
> +
> +     /* Unflatten device tree blob */
> +     memcpy(fdt, fdt1, fdt_totalsize(fdt1));
> +     dt = of_fdt_unflatten_tree(fdt, php_slot->dn, NULL);
> +     if (!dt) {
> +             dev_warn(&php_slot->pdev->dev, "Cannot unflatten FDT\n");
> +             goto free_fdt;
> +     }
> +
> +     /* Initialize and apply the changeset */
> +     of_changeset_init(&php_slot->ocs);
> +     ret = pnv_php_populate_changeset(&php_slot->ocs, php_slot->dn);
> +     if (ret) {
> +             dev_warn(&php_slot->pdev->dev, "Error %d populating 
> changeset\n",
> +                      ret);
> +             goto free_dt;
> +     }
> +
> +     php_slot->dn->child = NULL;
> +     ret = of_changeset_apply(&php_slot->ocs);
> +     if (ret) {
> +             dev_warn(&php_slot->pdev->dev, "Error %d applying changeset\n",
> +                      ret);
> +             goto destroy_changeset;
> +     }
> +
> +     /* Add device node firmware data */
> +     pnv_php_add_pdns(php_slot);
> +     php_slot->fdt = fdt;
> +     php_slot->dt  = dt;
> +     goto out;

Doesn't this leak memory from fdt1? I can't see where it gets freed in this
case.

> +destroy_changeset:
> +     of_changeset_destroy(&php_slot->ocs);
> +free_dt:
> +     kfree(dt);
> +     php_slot->dn->child = NULL;
> +free_fdt:
> +     kfree(fdt);
> +free_fdt1:
> +     kfree(fdt1);
> +error:
> +     confirm = PNV_PHP_POWER_CONFIRMED_FAIL;
> +out:
> +     /* Confirm status change */
> +     php_slot->power_state_confirmed = confirm;
> +     wake_up_interruptible(&php_slot->queue);
> +}
> +

<snip>

> +
> +static void __exit pnv_php_exit(void)
> +{
> +     struct device_node *dn;
> +
> +     for_each_compatible_node(dn, NULL, "ibm,ioda-phb")
> +             pnv_php_unregister(dn);
> +     for_each_compatible_node(dn, NULL, "ibm,ioda2-phb")
> +             pnv_php_unregister(dn);
> +
> +     pnv_pci_hotplug_notifier_unregister(&php_msg_nb);

Do you flush the workqueues anywhere? Usually you would stop work being queued 
and call something like flush_workqueue() to ensure no work is still
running/queued before unloading the module.

- Alistair

> +}
> +
> +module_init(pnv_php_init);
> +module_exit(pnv_php_exit);
> +
> +MODULE_VERSION(DRIVER_VERSION);
> +MODULE_LICENSE("GPL v2");
> +MODULE_AUTHOR(DRIVER_AUTHOR);
> +MODULE_DESCRIPTION(DRIVER_DESC);
> 

_______________________________________________
Linuxppc-dev mailing list
Linuxppc-dev@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/linuxppc-dev

Reply via email to