[bug report] pmdomain: mediatek: Add support for MT8196 SCPSYS power domains
Dan Carpenter
dan.carpenter at linaro.org
Mon Oct 27 00:05:01 PDT 2025
Hello AngeloGioacchino Del Regno,
Commit ead9cf65d50f ("pmdomain: mediatek: Add support for MT8196
SCPSYS power domains") from Sep 25, 2025 (linux-next), leads to the
following Smatch static checker warning:
drivers/pmdomain/mediatek/mtk-pm-domains.c:865 scpsys_add_one_domain()
error: we previously assumed 'pd->data' could be null (see line 840)
drivers/pmdomain/mediatek/mtk-pm-domains.c
718 static struct
719 generic_pm_domain *scpsys_add_one_domain(struct scpsys *scpsys, struct device_node *node)
720 {
721 const struct scpsys_domain_data *domain_data;
722 const struct scpsys_hwv_domain_data *hwv_domain_data;
723 struct scpsys_domain *pd;
724 struct property *prop;
725 const char *clk_name;
726 int i, ret, num_clks;
727 struct clk *clk;
728 int clk_ind = 0;
729 u32 id;
730
731 ret = of_property_read_u32(node, "reg", &id);
732 if (ret) {
733 dev_err(scpsys->dev, "%pOF: failed to retrieve domain id from reg: %d\n",
734 node, ret);
735 return ERR_PTR(-EINVAL);
736 }
737
738 switch (scpsys->soc_data->type) {
739 case SCPSYS_MTCMOS_TYPE_DIRECT_CTL:
740 if (id >= scpsys->soc_data->num_domains) {
741 dev_err(scpsys->dev, "%pOF: invalid domain id %d\n", node, id);
742 return ERR_PTR(-EINVAL);
743 }
744
745 domain_data = &scpsys->soc_data->domains_data[id];
746 hwv_domain_data = NULL;
747
748 if (domain_data->sta_mask == 0) {
749 dev_err(scpsys->dev, "%pOF: undefined domain id %d\n", node, id);
750 return ERR_PTR(-EINVAL);
751 }
752
753 break;
754 case SCPSYS_MTCMOS_TYPE_HW_VOTER:
755 if (id >= scpsys->soc_data->num_hwv_domains) {
756 dev_err(scpsys->dev, "%pOF: invalid HWV domain id %d\n", node, id);
757 return ERR_PTR(-EINVAL);
758 }
759
760 domain_data = NULL;
NULL here.
761 hwv_domain_data = &scpsys->soc_data->hwv_domains_data[id];
762
763 break;
764 default:
765 return ERR_PTR(-EINVAL);
766 }
767
768 pd = devm_kzalloc(scpsys->dev, sizeof(*pd), GFP_KERNEL);
769 if (!pd)
770 return ERR_PTR(-ENOMEM);
771
772 pd->data = domain_data;
^^^^^^^^^^^^^^^^^^^^^^
773 pd->hwv_data = hwv_domain_data;
774 pd->scpsys = scpsys;
775
776 if (MTK_SCPD_CAPS(pd, MTK_SCPD_DOMAIN_SUPPLY)) {
777 pd->supply = devm_of_regulator_get_optional(scpsys->dev, node, "domain");
778 if (IS_ERR(pd->supply))
779 return dev_err_cast_probe(scpsys->dev, pd->supply,
780 "%pOF: failed to get power supply.\n",
781 node);
782 }
783
784 num_clks = of_clk_get_parent_count(node);
785 if (num_clks > 0) {
786 /* Calculate number of subsys_clks */
787 of_property_for_each_string(node, "clock-names", prop, clk_name) {
788 char *subsys;
789
790 subsys = strchr(clk_name, '-');
791 if (subsys)
792 pd->num_subsys_clks++;
793 else
794 pd->num_clks++;
795 }
796
797 pd->clks = devm_kcalloc(scpsys->dev, pd->num_clks, sizeof(*pd->clks), GFP_KERNEL);
798 if (!pd->clks)
799 return ERR_PTR(-ENOMEM);
800
801 pd->subsys_clks = devm_kcalloc(scpsys->dev, pd->num_subsys_clks,
802 sizeof(*pd->subsys_clks), GFP_KERNEL);
803 if (!pd->subsys_clks)
804 return ERR_PTR(-ENOMEM);
805
806 }
807
808 for (i = 0; i < pd->num_clks; i++) {
809 clk = of_clk_get(node, i);
810 if (IS_ERR(clk)) {
811 ret = PTR_ERR(clk);
812 dev_err_probe(scpsys->dev, ret,
813 "%pOF: failed to get clk at index %d\n", node, i);
814 goto err_put_clocks;
815 }
816
817 pd->clks[clk_ind++].clk = clk;
818 }
819
820 for (i = 0; i < pd->num_subsys_clks; i++) {
821 clk = of_clk_get(node, i + clk_ind);
822 if (IS_ERR(clk)) {
823 ret = PTR_ERR(clk);
824 dev_err_probe(scpsys->dev, ret,
825 "%pOF: failed to get clk at index %d\n", node,
826 i + clk_ind);
827 goto err_put_subsys_clocks;
828 }
829
830 pd->subsys_clks[i].clk = clk;
831 }
832
833 if (scpsys->domains[id]) {
834 ret = -EINVAL;
835 dev_err(scpsys->dev,
836 "power domain with id %d already exists, check your device-tree\n", id);
837 goto err_put_subsys_clocks;
838 }
839
840 if (pd->data && pd->data->name)
^^^^^^^^
Check for NULL
841 pd->genpd.name = pd->data->name;
842 else if (pd->hwv_data && pd->hwv_data->name)
843 pd->genpd.name = pd->hwv_data->name;
844 else
845 pd->genpd.name = node->name;
846
847 if (scpsys->soc_data->type == SCPSYS_MTCMOS_TYPE_DIRECT_CTL) {
848 pd->genpd.power_off = scpsys_power_off;
849 pd->genpd.power_on = scpsys_power_on;
850 } else {
851 pd->genpd.power_off = scpsys_hwv_power_off;
852 pd->genpd.power_on = scpsys_hwv_power_on;
853
854 /* HW-Voter code can be invoked in atomic context */
855 pd->genpd.flags |= GENPD_FLAG_IRQ_SAFE;
856 }
857
858 /*
859 * Initially turn on all domains to make the domains usable
860 * with !CONFIG_PM and to get the hardware in sync with the
861 * software. The unused domains will be switched off during
862 * late_init time.
863 */
864 if (MTK_SCPD_CAPS(pd, MTK_SCPD_KEEP_DEFAULT_OFF)) {
--> 865 if (scpsys_domain_is_on(pd))
^^
The patch adds an unchecked dereference of pd->data in the
scpsys_domain_is_on() function.
866 dev_warn(scpsys->dev,
867 "%pOF: A default off power domain has been ON\n", node);
868 } else {
869 ret = pd->genpd.power_on(&pd->genpd);
870 if (ret < 0) {
871 dev_err(scpsys->dev, "%pOF: failed to power on domain: %d\n", node, ret);
872 goto err_put_subsys_clocks;
873 }
874
875 if (MTK_SCPD_CAPS(pd, MTK_SCPD_ALWAYS_ON))
876 pd->genpd.flags |= GENPD_FLAG_ALWAYS_ON;
877 }
878
regards,
dan carpenter
More information about the Linux-mediatek
mailing list