lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Sun, 10 Jan 2021 08:39:21 +0800
From:   kernel test robot <lkp@...el.com>
To:     AngeloGioacchino Del Regno 
        <angelogioacchino.delregno@...ainline.org>,
        linux-arm-msm@...r.kernel.org
Cc:     kbuild-all@...ts.01.org, konrad.dybcio@...ainline.org,
        marijn.suijten@...ainline.org, martin.botka@...ainline.org,
        phone-devel@...r.kernel.org, linux-kernel@...r.kernel.org,
        robh+dt@...nel.org, rjw@...ysocki.net, viresh.kumar@...aro.org,
        nks@...wful.org
Subject: Re: [PATCH v2 09/15] soc: qcom: Add support for Core Power Reduction
 v3, v4 and Hardened

Hi AngeloGioacchino,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on pm/linux-next]
[also build test WARNING on robh/for-next linux/master linus/master v5.11-rc2 next-20210108]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/AngeloGioacchino-Del-Regno/Enable-CPRh-3-4-CPU-Scaling-on-various-QCOM-SoCs/20210110-021002
base:   https://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git linux-next
config: arm64-allyesconfig (attached as .config)
compiler: aarch64-linux-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/f7b151e3b7c4b04b3333508e6ff13738de070041
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review AngeloGioacchino-Del-Regno/Enable-CPRh-3-4-CPU-Scaling-on-various-QCOM-SoCs/20210110-021002
        git checkout f7b151e3b7c4b04b3333508e6ff13738de070041
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=arm64 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@...el.com>

All warnings (new ones prefixed by >>):

   drivers/soc/qcom/cpr3.c: In function 'cpr3_corner_init':
>> drivers/soc/qcom/cpr3.c:1673:17: warning: variable 'min_quot_val' set but not used [-Wunused-but-set-variable]
    1673 |   int ring_osc, min_quot_val;
         |                 ^~~~~~~~~~~~
>> drivers/soc/qcom/cpr3.c:1316:7: warning: variable 'apply_scaling' set but not used [-Wunused-but-set-variable]
    1316 |  bool apply_scaling;
         |       ^~~~~~~~~~~~~


vim +/min_quot_val +1673 drivers/soc/qcom/cpr3.c

  1284	
  1285	/**
  1286	 * cpr3_corner_init - Calculate and set-up corners for the CPR HW
  1287	 * @thread: Structure holding CPR thread-specific parameters
  1288	 *
  1289	 * This function calculates all the corner parameters by comparing
  1290	 * and interpolating the values read from the various set-points
  1291	 * read from the fuses (also called "fuse corners") to generate and
  1292	 * program to the CPR a lookup table that describes each voltage
  1293	 * step, mapped to a performance level (or corner number).
  1294	 *
  1295	 * It also programs other essential parameters on the CPR and - if
  1296	 * we are dealing with CPR-Hardened, it will also enable the internal
  1297	 * interface between the Operating State Manager (OSM) and the CPRh
  1298	 * in order to achieve CPU DVFS.
  1299	 *
  1300	 * Returns: Zero for success, negative number on error
  1301	 */
  1302	static int cpr3_corner_init(struct cpr_thread *thread)
  1303	{
  1304		struct cpr_drv *drv = thread->drv;
  1305		const struct cpr_desc *desc = drv->desc;
  1306		const struct cpr_thread_desc *tdesc = thread->desc;
  1307		const struct cpr_fuse *fuses = thread->cpr_fuses;
  1308		int i, ret, total_corners, extra_corners, level, scaling = 0;
  1309		unsigned int fnum, fc;
  1310		const char *quot_offset;
  1311		const struct fuse_corner_data *fdata;
  1312		struct fuse_corner *fuse, *prev_fuse;
  1313		struct corner *corner, *prev_corner, *end;
  1314		struct corner_data *cdata;
  1315		struct dev_pm_opp *opp;
  1316		bool apply_scaling;
  1317		unsigned long freq;
  1318		u32 ring_osc_mask = CPR3_RO_MASK, min_quotient = U32_MAX;
  1319	
  1320		corner = thread->corners;
  1321		prev_corner = &thread->corners[0];
  1322		end = &corner[thread->num_corners - 1];
  1323	
  1324		cdata = devm_kcalloc(drv->dev,
  1325				     thread->num_corners + drv->extra_corners,
  1326				     sizeof(struct corner_data),
  1327				     GFP_KERNEL);
  1328		if (!cdata)
  1329			return -ENOMEM;
  1330	
  1331		for (level = 1; level <= thread->num_corners; level++) {
  1332			opp = dev_pm_opp_find_level_exact(&thread->pd.dev, level);
  1333			if (IS_ERR(opp))
  1334				return -EINVAL;
  1335	
  1336			/*
  1337			 * If there is only one specified qcom,opp-fuse-level, then
  1338			 * it is assumed that this only one is global and valid for
  1339			 * all IDs, so try to get the specific one but, on failure,
  1340			 * go for the global one.
  1341			 */
  1342			fc = cpr_get_fuse_corner(opp, thread->id);
  1343			if (fc == 0) {
  1344				fc = cpr_get_fuse_corner(opp, 0);
  1345				if (fc == 0) {
  1346					dev_err(drv->dev,
  1347						"qcom,opp-fuse-level is missing!\n");
  1348					dev_pm_opp_put(opp);
  1349					return -EINVAL;
  1350				}
  1351			}
  1352			fnum = fc - 1;
  1353	
  1354			freq = cpr_get_opp_hz_for_req(opp, thread->attached_cpu_dev);
  1355			if (!freq) {
  1356				thread->num_corners = max(level - 1, 0);
  1357				end = &thread->corners[thread->num_corners - 1];
  1358				break;
  1359			}
  1360	
  1361			/*
  1362			 * If any post-vadj (open/closed loop) is not specified, then
  1363			 * it's zero, meaning that it is not required for this corner.
  1364			 */
  1365			cpr_get_corner_post_vadj(opp, thread->id,
  1366						 &cdata[level - 1].oloop_vadj,
  1367						 &cdata[level - 1].cloop_vadj);
  1368			cdata[level - 1].fuse_corner = fnum;
  1369			cdata[level - 1].freq = freq;
  1370	
  1371			fuse = &thread->fuse_corners[fnum];
  1372			dev_dbg(drv->dev, "freq: %lu level: %u fuse level: %u\n",
  1373				freq, dev_pm_opp_get_level(opp) - 1, fnum);
  1374			if (freq > fuse->max_freq)
  1375				fuse->max_freq = freq;
  1376			dev_pm_opp_put(opp);
  1377	
  1378			/*
  1379			 * Make sure that the frequencies in the table are in ascending
  1380			 * order, as this is critical for the algorithm to work.
  1381			 */
  1382			if (cdata[level - 2].freq > freq) {
  1383				dev_err(drv->dev,
  1384					"Frequency table not in ascending order.\n");
  1385				return -EINVAL;
  1386			}
  1387		}
  1388	
  1389		if (thread->num_corners < 2) {
  1390			dev_err(drv->dev, "need at least 2 OPPs to use CPR\n");
  1391			return -EINVAL;
  1392		}
  1393	
  1394		/*
  1395		 * Get the quotient adjustment scaling factor, according to:
  1396		 *
  1397		 * scaling = min(1000 * (QUOT(corner_N) - QUOT(corner_N-1))
  1398		 *		/ (freq(corner_N) - freq(corner_N-1)), max_factor)
  1399		 *
  1400		 * QUOT(corner_N):	quotient read from fuse for fuse corner N
  1401		 * QUOT(corner_N-1):	quotient read from fuse for fuse corner (N - 1)
  1402		 * freq(corner_N):	max frequency in MHz supported by fuse corner N
  1403		 * freq(corner_N-1):	max frequency in MHz supported by fuse corner
  1404		 *			 (N - 1)
  1405		 *
  1406		 * Then walk through the corners mapped to each fuse corner
  1407		 * and calculate the quotient adjustment for each one using the
  1408		 * following formula:
  1409		 *
  1410		 * quot_adjust = (freq_max - freq_corner) * scaling / 1000
  1411		 *
  1412		 * freq_max: max frequency in MHz supported by the fuse corner
  1413		 * freq_corner: frequency in MHz corresponding to the corner
  1414		 * scaling: calculated from above equation
  1415		 *
  1416		 *
  1417		 *     +                           +
  1418		 *     |                         v |
  1419		 *   q |           f c           o |           f c
  1420		 *   u |         c               l |         c
  1421		 *   o |       f                 t |       f
  1422		 *   t |     c                   a |     c
  1423		 *     | c f                     g | c f
  1424		 *     |                         e |
  1425		 *     +---------------            +----------------
  1426		 *       0 1 2 3 4 5 6               0 1 2 3 4 5 6
  1427		 *          corner                      corner
  1428		 *
  1429		 *    c = corner
  1430		 *    f = fuse corner
  1431		 *
  1432		 */
  1433		for (apply_scaling = false, i = 0; corner <= end; corner++, i++) {
  1434			unsigned long freq_diff_mhz;
  1435			int ro_fac, vadj, prev_quot;
  1436	
  1437			fnum = cdata[i].fuse_corner;
  1438			fdata = &tdesc->fuse_corner_data[fnum];
  1439			quot_offset = fuses[fnum].quotient_offset;
  1440			fuse = &thread->fuse_corners[fnum];
  1441			ring_osc_mask &= (u16)(~BIT(fuse->ring_osc_idx));
  1442			if (fnum)
  1443				prev_fuse = &thread->fuse_corners[fnum - 1];
  1444			else
  1445				prev_fuse = NULL;
  1446	
  1447			corner->fuse_corner = fuse;
  1448			corner->freq = cdata[i].freq;
  1449			corner->uV = fuse->uV;
  1450	
  1451			if (prev_fuse) {
  1452				if (prev_fuse->ring_osc_idx == fuse->ring_osc_idx)
  1453					quot_offset = NULL;
  1454	
  1455				scaling = cpr_calculate_scaling(quot_offset, drv->dev,
  1456								fdata, corner);
  1457				if (scaling < 0)
  1458					return scaling;
  1459	
  1460				freq_diff_mhz = fuse->max_freq - corner->freq;
  1461				do_div(freq_diff_mhz, 1000000); /* now in MHz */
  1462	
  1463				corner->quot_adjust = scaling * freq_diff_mhz;
  1464				do_div(corner->quot_adjust, 1000);
  1465	
  1466				/* Fine-tune QUOT (closed-loop) based on fixed values */
  1467				ro_fac = cpr_get_ro_factor(tdesc, fnum, fuse->ring_osc_idx);
  1468				vadj = cdata[i].cloop_vadj;
  1469				corner->quot_adjust -= cpr3_adjust_quot(ro_fac, vadj);
  1470				dev_vdbg(drv->dev,
  1471					 "Quot fine-tuning to %d for post-vadj=%d\n",
  1472					 corner->quot_adjust, vadj);
  1473	
  1474				/*
  1475				 * Make sure that we scale (up) monotonically.
  1476				 * P.S.: Fuse quots can never be descending.
  1477				 */
  1478				prev_quot = prev_corner->fuse_corner->quot;
  1479				prev_quot -= prev_corner->quot_adjust;
  1480				if (fuse->quot - corner->quot_adjust < prev_quot) {
  1481					int new_adj = prev_corner->fuse_corner->quot;
  1482					new_adj -= fuse->quot;
  1483					dev_vdbg(drv->dev,
  1484						 "Monotonic increase forced: %d->%d\n",
  1485						 corner->quot_adjust, new_adj);
  1486					corner->quot_adjust = new_adj;
  1487				}
  1488	
  1489				corner->uV = cpr_interpolate(corner,
  1490							     drv->vreg_step, fdata);
  1491			} else if (corner->freq == fuse->max_freq) {
  1492				/* This is a fuse corner; don't scale anything */
  1493				apply_scaling = false;
  1494			}
  1495			/* Negative fuse quotients are nonsense. */
  1496			if (fuse->quot < corner->quot_adjust)
  1497				return -EINVAL;
  1498	
  1499			min_quotient = min(min_quotient,
  1500					   (u32)(fuse->quot - corner->quot_adjust));
  1501	
  1502			/* Fine-tune voltages (open-loop) based on fixed values */
  1503			corner->uV += cdata[i].oloop_vadj;
  1504			dev_dbg(drv->dev,
  1505				 "Voltage fine-tuning to %d for post-vadj=%d\n",
  1506				 corner->uV, cdata[i].oloop_vadj);
  1507	
  1508			corner->max_uV = fuse->max_uV;
  1509			corner->min_uV = fuse->min_uV;
  1510			corner->uV = clamp(corner->uV, corner->min_uV, corner->max_uV);
  1511			dev_vdbg(drv->dev, "Clamped after interpolation: [%d %d %d]\n",
  1512				corner->min_uV, corner->uV, corner->max_uV);
  1513	
  1514			/* Make sure that we scale monotonically here, too. */
  1515			if (corner->uV < prev_corner->uV)
  1516				corner->uV = prev_corner->uV;
  1517	
  1518			corner->last_uV = corner->uV;
  1519	
  1520			/* Reduce the ceiling voltage if needed */
  1521			if (desc->reduce_to_corner_uV && corner->uV < corner->max_uV)
  1522				corner->max_uV = corner->uV;
  1523			else if (desc->reduce_to_fuse_uV && fuse->uV < corner->max_uV)
  1524				corner->max_uV = max(corner->min_uV, fuse->uV);
  1525	
  1526			corner->min_uV = max(corner->max_uV - fdata->range_uV,
  1527					     corner->min_uV);
  1528	
  1529			/*
  1530			 * Adjust per-corner floor and ceiling voltages so that
  1531			 * they do not overlap the memory Array Power Mux (APM)
  1532			 * nor the Memory Accelerator (MEM-ACC) threshold voltages.
  1533			 */
  1534			if (desc->apm_threshold)
  1535				cpr3_restrict_corner(corner, desc->apm_threshold,
  1536						     desc->apm_hysteresis,
  1537						     drv->vreg_step);
  1538			if (desc->mem_acc_threshold)
  1539				cpr3_restrict_corner(corner, desc->mem_acc_threshold,
  1540						     0, drv->vreg_step);
  1541	
  1542			prev_corner = corner;
  1543			dev_dbg(drv->dev, "corner %d: [%d %d %d] scaling %d quot %d\n", i,
  1544				corner->min_uV, corner->uV, corner->max_uV, scaling,
  1545				fuse->quot - corner->quot_adjust);
  1546		}
  1547	
  1548		/* Additional setup for CPRh only */
  1549		if (desc->cpr_type < CTRL_TYPE_CPRH)
  1550			return 0;
  1551	
  1552		/* If the OPPs can't be adjusted, programming the CPRh is useless */
  1553		ret = cprh_corner_adjust_opps(thread);
  1554		if (ret) {
  1555			dev_err(drv->dev, "Cannot adjust CPU OPP voltages: %d\n", ret);
  1556			return ret;
  1557		}
  1558	
  1559		total_corners = thread->num_corners;
  1560		extra_corners = drv->extra_corners;
  1561	
  1562		/* If the APM extra corner exists, add it now. */
  1563		if (desc->apm_crossover && desc->apm_threshold && extra_corners) {
  1564			/* Program the APM crossover corner on the CPR-Hardened */
  1565			thread->corners[total_corners].uV = desc->apm_crossover;
  1566			thread->corners[total_corners].min_uV = desc->apm_crossover;
  1567			thread->corners[total_corners].max_uV = desc->apm_crossover;
  1568			thread->corners[total_corners].is_open_loop = true;
  1569	
  1570			/*
  1571			 * Also add and disable an opp with zero frequency: other
  1572			 * drivers will need to know what is the APM *threshold*
  1573			 * voltage.
  1574			 */
  1575			ret = dev_pm_opp_add(thread->attached_cpu_dev, 0,
  1576					     desc->apm_threshold);
  1577			if (ret)
  1578				return ret;
  1579	
  1580			ret = dev_pm_opp_disable(thread->attached_cpu_dev, 0);
  1581			if (ret)
  1582				return ret;
  1583	
  1584			dev_dbg(drv->dev, "corner %d (APM): [%d %d %d] Open-Loop\n",
  1585				total_corners, desc->apm_crossover,
  1586				desc->apm_crossover, desc->apm_crossover);
  1587	
  1588			total_corners++;
  1589			extra_corners--;
  1590		}
  1591	
  1592		if (desc->mem_acc_threshold && extra_corners) {
  1593			/* Program the Memory Accelerator threshold corner to CPRh */
  1594			thread->corners[total_corners].uV = desc->mem_acc_threshold;
  1595			thread->corners[total_corners].min_uV = desc->mem_acc_threshold;
  1596			thread->corners[total_corners].max_uV = desc->mem_acc_threshold;
  1597			thread->corners[total_corners].is_open_loop = true;
  1598	
  1599			/*
  1600			 * Add and disable an opp with zero frequency: other
  1601			 * drivers will also need to know about any mem-acc
  1602			 * threshold to respect.
  1603			 */
  1604			ret = dev_pm_opp_add(thread->attached_cpu_dev, 1,
  1605					     desc->mem_acc_threshold);
  1606			if (ret)
  1607				return ret;
  1608	
  1609			ret = dev_pm_opp_disable(thread->attached_cpu_dev, 1);
  1610			if (ret)
  1611				return ret;
  1612	
  1613			dev_dbg(drv->dev, "corner %d (MEMACC): [%d %d %d] Open-Loop\n",
  1614				total_corners, desc->mem_acc_threshold,
  1615				desc->mem_acc_threshold, desc->mem_acc_threshold);
  1616	
  1617			total_corners++;
  1618			extra_corners--;
  1619		}
  1620	
  1621		/*
  1622		 * If there are any extra corners left, it means that even though we
  1623		 * expect to fill in both APM and MEM-ACC crossovers, one couldn't
  1624		 * satisfy requirements, which means that the specified parameters
  1625		 * are wrong: in this case, inform the user and bail out, otherwise
  1626		 * if we go on writing the (invalid) table to the CPR-Hardened, the
  1627		 * hardware (in this case, the CPU) will surely freeze and crash.
  1628		 */
  1629		if (unlikely(extra_corners)) {
  1630			dev_err(drv->dev, "APM/MEM-ACC corners: bad parameters.\n");
  1631			return -EINVAL;
  1632		}
  1633		/* Reassign extra_corners, as we have to exclude delta_quot for them */
  1634		extra_corners = drv->extra_corners;
  1635	
  1636		/* Disable the interface between OSM and CPRh */
  1637		cpr_masked_write(thread, drv->reg_ctl,
  1638				 CPRH_CTL_OSM_ENABLED, 0);
  1639	
  1640		/* Program the GCNT before unmasking ring oscillator(s) */
  1641		for (i = 0; i < CPR3_RO_COUNT; i++) {
  1642			if (!(ring_osc_mask & BIT(i))) {
  1643				cpr_write(thread, CPR3_REG_GCNT(i), drv->gcnt);
  1644				dev_vdbg(drv->dev, "RO%d gcnt=%d\n", i, drv->gcnt);
  1645			}
  1646		}
  1647	
  1648		/*
  1649		 * Unmask the ring oscillator(s) that we're going to use: it seems
  1650		 * to be mandatory to do this *before* sending the rest of the
  1651		 * CPRhardened specific configuration.
  1652		 */
  1653		dev_dbg(drv->dev,
  1654			"Unmasking ring oscillators with mask 0x%x\n", ring_osc_mask);
  1655		cpr_write(thread, CPR3_REG_RO_MASK(tdesc->hw_tid), ring_osc_mask);
  1656	
  1657		/* Setup minimum quotients for ring oscillators */
  1658		for (i = 0; i < CPR3_RO_COUNT; i++) {
  1659			u32 tgt_quot_reg = CPR3_REG_TARGET_QUOT(tdesc->hw_tid, i);
  1660			u32 tgt_quot_val = 0;
  1661	
  1662			if (!(ring_osc_mask & BIT(i)))
  1663				tgt_quot_val = min_quotient;
  1664	
  1665			cpr_write(thread, tgt_quot_reg, tgt_quot_val);
  1666			dev_vdbg(drv->dev,
  1667				 "Programmed min quotient %u for Ring Oscillator %d\n",
  1668				 tgt_quot_val, tgt_quot_reg);
  1669		}
  1670	
  1671		for (i = 0; i < total_corners; i++) {
  1672			int volt_oloop_steps, volt_floor_steps, delta_quot_steps;
> 1673			int ring_osc, min_quot_val;
  1674			u32 val;
  1675	
  1676			fnum = cdata[i].fuse_corner;
  1677			fuse = &thread->fuse_corners[fnum];
  1678	
  1679			val = thread->corners[i].uV - desc->cpr_base_voltage;
  1680			volt_oloop_steps = DIV_ROUND_UP(val, drv->vreg_step);
  1681	
  1682			val = thread->corners[i].min_uV - desc->cpr_base_voltage;
  1683			volt_floor_steps = DIV_ROUND_UP(val, drv->vreg_step);
  1684	
  1685			if (i >= (total_corners - extra_corners)) {
  1686				delta_quot_steps = 0;
  1687				min_quot_val = 0;
  1688			} else {
  1689				min_quot_val = min_quotient;
  1690				val = fuse->quot - thread->corners[i].quot_adjust;
  1691				val -= min_quotient;
  1692				delta_quot_steps = DIV_ROUND_UP(val,
  1693							CPRH_DELTA_QUOT_STEP_FACTOR);
  1694			}
  1695	
  1696			/*
  1697			 * If we are accessing corners that are not used as
  1698			 * an active DCVS set-point, then always select RO 0
  1699			 * and zero out the delta quotient.
  1700			 */
  1701			if (i >= thread->num_corners) {
  1702				ring_osc = 0;
  1703				delta_quot_steps = 0;
  1704			} else {
  1705				ring_osc = fuse->ring_osc_idx;
  1706			}
  1707	
  1708			if (volt_oloop_steps > CPRH_CORNER_INIT_VOLTAGE_MAX_VALUE  ||
  1709			    volt_floor_steps > CPRH_CORNER_FLOOR_VOLTAGE_MAX_VALUE ||
  1710			    delta_quot_steps > CPRH_CORNER_QUOT_DELTA_MAX_VALUE) {
  1711				dev_err(drv->dev,
  1712					"Invalid cfg: oloop=%d, floor=%d, delta=%d\n",
  1713					volt_oloop_steps, volt_floor_steps,
  1714					delta_quot_steps);
  1715				return -EINVAL;
  1716			}
  1717			/* Green light: Go, Go, Go! */
  1718	
  1719			/* Set number of open-loop steps */
  1720			val = volt_oloop_steps << CPRH_CORNER_INIT_VOLTAGE_SHIFT;
  1721			val &= CPRH_CORNER_INIT_VOLTAGE_MASK;
  1722	
  1723			/* Set number of floor voltage steps */
  1724			val |= (volt_floor_steps << CPRH_CORNER_FLOOR_VOLTAGE_SHIFT) &
  1725			       CPRH_CORNER_FLOOR_VOLTAGE_MASK;
  1726	
  1727			/* Set number of target quotient delta steps */
  1728			val |= (delta_quot_steps << CPRH_CORNER_QUOT_DELTA_SHIFT) &
  1729			       CPRH_CORNER_QUOT_DELTA_MASK;
  1730	
  1731			/* Select ring oscillator for this corner */
  1732			val |= (ring_osc << CPRH_CORNER_RO_SEL_SHIFT) &
  1733			       CPRH_CORNER_RO_SEL_MASK;
  1734	
  1735			/* Open loop corner is usually APM/ACC crossover */
  1736			if (thread->corners[i].is_open_loop) {
  1737				dev_dbg(drv->dev,
  1738					"Disabling Closed-Loop on corner %d\n", i);
  1739				val |= CPRH_CORNER_CPR_CL_DISABLE;
  1740			}
  1741			cpr_write(thread, CPRH_REG_CORNER(drv, tdesc->hw_tid, i), val);
  1742	
  1743			dev_dbg(drv->dev,
  1744				"steps [%d]: open-loop %d, floor %d, delta_quot %d\n",
  1745				i, volt_oloop_steps, volt_floor_steps,
  1746				delta_quot_steps);
  1747		}
  1748	
  1749		/* YAY! Setup is done! Enable the internal loop to start CPR. */
  1750		cpr_masked_write(thread, CPR3_REG_CPR_CTL,
  1751				CPR3_CPR_CTL_LOOP_EN_MASK,
  1752				CPR3_CPR_CTL_LOOP_EN_MASK);
  1753	
  1754		/*
  1755		 * Make sure that all the writes go through before enabling
  1756		 * internal communication between the OSM and the CPRh
  1757		 * controllers, otherwise there is a high risk of hardware
  1758		 * lockups due to under-voltage for the selected CPU clock.
  1759		 *
  1760		 * Please note that the CPR-hardened gets set-up in Linux but
  1761		 * then gets actually used in firmware (and only by the OSM);
  1762		 * after handing it off we will have no more control on it,
  1763		 * hence the only way to get things up properly for sure here
  1764		 * is a write barrier.
  1765		 */
  1766		wmb();
  1767	
  1768		/* Enable the interface between OSM and CPRh */
  1769		cpr_masked_write(thread, drv->reg_ctl,
  1770				 CPRH_CTL_OSM_ENABLED,
  1771				 CPRH_CTL_OSM_ENABLED);
  1772	
  1773		/* On success, free cdata manually */
  1774		devm_kfree(drv->dev, cdata);
  1775		return 0;
  1776	}
  1777	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org

Download attachment ".config.gz" of type "application/gzip" (76497 bytes)

Powered by blists - more mailing lists