Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

soc: mediatek: mtk-dvfsrc: Rework bandwidth calculations

The code, as it is, plays fast and loose with bandwidth units. It also
doesn't specify its constraints in the actual maximum hardware value,
but as some roundabout thing that then ends up multiplied into the
actual hardware value constraint after some indirections. In part, this
is due to the use of individual members for storing each limit, instead
of making it possible to index them by type.

Rework all of this by adding const array members indexed by the
bandwidth type enum to the soc_data struct. This array expresses the
actual hardware value limitations, not a factor thereof.

Use the clamp function macro to clamp the values between the minimum and
maximum constraints after all the calculations, which also means the
code doesn't write nonsense to a hardware register when the math is
wrong, as it'll constrain after all the calculations.

Pass the type as the actual enum type as well, and not as an int. If
there's some type checking that can be extracted from the function
signature, then we may as well use it.

Don't needlessly explicitly cast return values to the return type
either; this is both unnecessary and makes it harder to spot type safety
issues.

Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>

authored by

Nicolas Frattaroli and committed by
AngeloGioacchino Del Regno
3da293d7 39aa8c4e

+67 -40
+67 -40
drivers/soc/mediatek/mtk-dvfsrc.c
··· 64 64 DVFSRC_BW_MAX, 65 65 }; 66 66 67 - struct dvfsrc_bw_constraints { 68 - u16 max_dram_nom_bw; 69 - u16 max_dram_peak_bw; 70 - u16 max_dram_hrt_bw; 71 - }; 72 - 73 67 struct dvfsrc_opp { 74 68 u32 vcore_opp; 75 69 u32 dram_opp; ··· 92 98 const u8 *bw_units; 93 99 const bool has_emi_ddr; 94 100 const struct dvfsrc_opp_desc *opps_desc; 95 - u32 (*calc_dram_bw)(struct mtk_dvfsrc *dvfsrc, int type, u64 bw); 101 + u32 (*calc_dram_bw)(struct mtk_dvfsrc *dvfsrc, enum mtk_dvfsrc_bw_type type, u64 bw); 96 102 u32 (*get_target_level)(struct mtk_dvfsrc *dvfsrc); 97 103 u32 (*get_current_level)(struct mtk_dvfsrc *dvfsrc); 98 104 u32 (*get_vcore_level)(struct mtk_dvfsrc *dvfsrc); ··· 107 113 void (*set_vscp_level)(struct mtk_dvfsrc *dvfsrc, u32 level); 108 114 int (*wait_for_opp_level)(struct mtk_dvfsrc *dvfsrc, u32 level); 109 115 int (*wait_for_vcore_level)(struct mtk_dvfsrc *dvfsrc, u32 level); 110 - const struct dvfsrc_bw_constraints *bw_constraints; 116 + 117 + /** 118 + * @bw_max_constraints - array of maximum bandwidth for this hardware 119 + * 120 + * indexed by &enum mtk_dvfsrc_bw_type, storing the maximum permissible 121 + * hardware value for each bandwidth type. 122 + */ 123 + const u32 *const bw_max_constraints; 124 + 125 + /** 126 + * @bw_min_constraints - array of minimum bandwidth for this hardware 127 + * 128 + * indexed by &enum mtk_dvfsrc_bw_type, storing the minimum permissible 129 + * hardware value for each bandwidth type. 130 + */ 131 + const u32 *const bw_min_constraints; 111 132 }; 112 133 113 134 static u32 dvfsrc_readl(struct mtk_dvfsrc *dvfs, u32 offset) ··· 392 383 return FIELD_GET(DVFSRC_V4_BASIC_CTRL_OPP_COUNT, val) + 1; 393 384 } 394 385 395 - static u32 dvfsrc_calc_dram_bw_v1(struct mtk_dvfsrc *dvfsrc, int type, u64 bw) 386 + static u32 387 + dvfsrc_calc_dram_bw_v1(struct mtk_dvfsrc *dvfsrc, enum mtk_dvfsrc_bw_type type, u64 bw) 396 388 { 397 - return (u32)div_u64(bw, 100 * 1000); 389 + return clamp_val(div_u64(bw, 100 * 1000), dvfsrc->dvd->bw_min_constraints[type], 390 + dvfsrc->dvd->bw_max_constraints[type]); 398 391 } 399 392 400 - static u32 dvfsrc_calc_dram_bw_v4(struct mtk_dvfsrc *dvfsrc, int type, u64 bw) 393 + /** 394 + * dvfsrc_calc_dram_bw_v4 - convert kbps to hardware register bandwidth value 395 + * @dvfsrc: pointer to the &struct mtk_dvfsrc of this driver instance 396 + * @type: one of %DVFSRC_BW_AVG, %DVFSRC_BW_PEAK, or %DVFSRC_BW_HRT 397 + * @bw: the bandwidth in kilobits per second 398 + * 399 + * Returns the hardware register value appropriate for expressing @bw, clamped 400 + * to hardware limits. 401 + */ 402 + static u32 403 + dvfsrc_calc_dram_bw_v4(struct mtk_dvfsrc *dvfsrc, enum mtk_dvfsrc_bw_type type, u64 bw) 401 404 { 402 405 u8 bw_unit = dvfsrc->dvd->bw_units[type]; 403 406 u64 bw_mbps; 407 + u32 bw_hw; 404 408 405 409 if (type < DVFSRC_BW_AVG || type >= DVFSRC_BW_MAX) 406 410 return 0; 407 411 408 412 bw_mbps = div_u64(bw, 1000); 409 - return (u32)div_u64((bw_mbps + bw_unit - 1), bw_unit); 413 + bw_hw = div_u64((bw_mbps + bw_unit - 1), bw_unit); 414 + return clamp_val(bw_hw, dvfsrc->dvd->bw_min_constraints[type], 415 + dvfsrc->dvd->bw_max_constraints[type]); 410 416 } 411 417 412 418 static void __dvfsrc_set_dram_bw_v1(struct mtk_dvfsrc *dvfsrc, u32 reg, 413 - int type, u16 max_bw, u16 min_bw, u64 bw) 419 + enum mtk_dvfsrc_bw_type type, u64 bw) 414 420 { 415 - u32 new_bw = dvfsrc->dvd->calc_dram_bw(dvfsrc, type, bw); 421 + u32 bw_hw = dvfsrc->dvd->calc_dram_bw(dvfsrc, type, bw); 416 422 417 - /* If bw constraints (in mbps) are defined make sure to respect them */ 418 - if (max_bw) 419 - new_bw = min(new_bw, max_bw); 420 - if (min_bw && new_bw > 0) 421 - new_bw = max(new_bw, min_bw); 422 - 423 - dvfsrc_writel(dvfsrc, reg, new_bw); 423 + dvfsrc_writel(dvfsrc, reg, bw_hw); 424 424 425 425 if (type == DVFSRC_BW_AVG && dvfsrc->dvd->has_emi_ddr) 426 - dvfsrc_writel(dvfsrc, DVFSRC_SW_EMI_BW, bw); 426 + dvfsrc_writel(dvfsrc, DVFSRC_SW_EMI_BW, bw_hw); 427 427 } 428 428 429 429 static void dvfsrc_set_dram_bw_v1(struct mtk_dvfsrc *dvfsrc, u64 bw) 430 430 { 431 - u64 max_bw = dvfsrc->dvd->bw_constraints->max_dram_nom_bw; 432 - 433 - __dvfsrc_set_dram_bw_v1(dvfsrc, DVFSRC_SW_BW, DVFSRC_BW_AVG, max_bw, 0, bw); 431 + __dvfsrc_set_dram_bw_v1(dvfsrc, DVFSRC_SW_BW, DVFSRC_BW_AVG, bw); 434 432 }; 435 433 436 434 static void dvfsrc_set_dram_peak_bw_v1(struct mtk_dvfsrc *dvfsrc, u64 bw) 437 435 { 438 - u64 max_bw = dvfsrc->dvd->bw_constraints->max_dram_peak_bw; 439 - 440 - __dvfsrc_set_dram_bw_v1(dvfsrc, DVFSRC_SW_PEAK_BW, DVFSRC_BW_PEAK, max_bw, 0, bw); 436 + __dvfsrc_set_dram_bw_v1(dvfsrc, DVFSRC_SW_PEAK_BW, DVFSRC_BW_PEAK, bw); 441 437 } 442 438 443 439 static void dvfsrc_set_dram_hrt_bw_v1(struct mtk_dvfsrc *dvfsrc, u64 bw) 444 440 { 445 - u64 max_bw = dvfsrc->dvd->bw_constraints->max_dram_hrt_bw; 446 - 447 - __dvfsrc_set_dram_bw_v1(dvfsrc, DVFSRC_SW_HRT_BW, DVFSRC_BW_HRT, max_bw, 0, bw); 441 + __dvfsrc_set_dram_bw_v1(dvfsrc, DVFSRC_SW_HRT_BW, DVFSRC_BW_HRT, bw); 448 442 } 449 443 450 444 static void dvfsrc_set_opp_level_v1(struct mtk_dvfsrc *dvfsrc, u32 level) ··· 700 688 return 0; 701 689 } 702 690 703 - static const struct dvfsrc_bw_constraints dvfsrc_bw_constr_v1 = { 0, 0, 0 }; 704 - static const struct dvfsrc_bw_constraints dvfsrc_bw_constr_v2 = { 705 - .max_dram_nom_bw = 255, 706 - .max_dram_peak_bw = 255, 707 - .max_dram_hrt_bw = 1023, 691 + static const u32 dvfsrc_bw_min_constr_none[DVFSRC_BW_MAX] = { 692 + [DVFSRC_BW_AVG] = 0, 693 + [DVFSRC_BW_PEAK] = 0, 694 + [DVFSRC_BW_HRT] = 0, 695 + }; 696 + 697 + static const u32 dvfsrc_bw_max_constr_v1[DVFSRC_BW_MAX] = { 698 + [DVFSRC_BW_AVG] = U32_MAX, 699 + [DVFSRC_BW_PEAK] = U32_MAX, 700 + [DVFSRC_BW_HRT] = U32_MAX, 701 + }; 702 + 703 + static const u32 dvfsrc_bw_max_constr_v2[DVFSRC_BW_MAX] = { 704 + [DVFSRC_BW_AVG] = 65535, 705 + [DVFSRC_BW_PEAK] = 65535, 706 + [DVFSRC_BW_HRT] = 1023, 708 707 }; 709 708 710 709 static const struct dvfsrc_opp dvfsrc_opp_mt6893_lp4[] = { ··· 748 725 .set_vscp_level = dvfsrc_set_vscp_level_v2, 749 726 .wait_for_opp_level = dvfsrc_wait_for_opp_level_v2, 750 727 .wait_for_vcore_level = dvfsrc_wait_for_vcore_level_v1, 751 - .bw_constraints = &dvfsrc_bw_constr_v2, 728 + .bw_max_constraints = dvfsrc_bw_max_constr_v2, 729 + .bw_min_constraints = dvfsrc_bw_min_constr_none, 752 730 }; 753 731 754 732 static const struct dvfsrc_opp dvfsrc_opp_mt8183_lp4[] = { ··· 787 763 .set_vcore_level = dvfsrc_set_vcore_level_v1, 788 764 .wait_for_opp_level = dvfsrc_wait_for_opp_level_v1, 789 765 .wait_for_vcore_level = dvfsrc_wait_for_vcore_level_v1, 790 - .bw_constraints = &dvfsrc_bw_constr_v1, 766 + .bw_max_constraints = dvfsrc_bw_max_constr_v1, 767 + .bw_min_constraints = dvfsrc_bw_min_constr_none, 791 768 }; 792 769 793 770 static const struct dvfsrc_opp dvfsrc_opp_mt8195_lp4[] = { ··· 822 797 .set_vscp_level = dvfsrc_set_vscp_level_v2, 823 798 .wait_for_opp_level = dvfsrc_wait_for_opp_level_v2, 824 799 .wait_for_vcore_level = dvfsrc_wait_for_vcore_level_v1, 825 - .bw_constraints = &dvfsrc_bw_constr_v2, 800 + .bw_max_constraints = dvfsrc_bw_max_constr_v2, 801 + .bw_min_constraints = dvfsrc_bw_min_constr_none, 826 802 }; 827 803 828 804 static const u8 mt8196_bw_units[] = { ··· 851 825 .set_vscp_level = dvfsrc_set_vscp_level_v2, 852 826 .wait_for_opp_level = dvfsrc_wait_for_opp_level_v4, 853 827 .wait_for_vcore_level = dvfsrc_wait_for_vcore_level_v4, 854 - .bw_constraints = &dvfsrc_bw_constr_v1, 828 + .bw_max_constraints = dvfsrc_bw_max_constr_v2, 829 + .bw_min_constraints = dvfsrc_bw_min_constr_none, 855 830 }; 856 831 857 832 static const struct of_device_id mtk_dvfsrc_of_match[] = {