Skip to content

Commit 4a83abc

Browse files
kmaincentkuba-moo
authored andcommitted
net: pse-pd: Add new power limit get and set c33 features
This patch add a way to get and set the power limit of a PSE PI. For that it uses regulator API callbacks wrapper like get_voltage() and get/set_current_limit() as power is simply V * I. We used mW unit as defined by the IEEE 802.3-2022 standards. set_current_limit() uses the voltage return by get_voltage() and the desired power limit to calculate the current limit. get_voltage() callback is then mandatory to set the power limit. get_current_limit() callback is by default looking at a driver callback and fallback to extracting the current limit from _pse_ethtool_get_status() if the driver does not set its callback. We prefer let the user the choice because ethtool_get_status return much more information than the current limit. expand pse status with c33_pw_limit_ranges to return the ranges available to configure the power limit. Reviewed-by: Sai Krishna <[email protected]> Acked-by: Oleksij Rempel <[email protected]> Signed-off-by: Kory Maincent <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent ae37dc5 commit 4a83abc

File tree

2 files changed

+204
-11
lines changed

2 files changed

+204
-11
lines changed

drivers/net/pse-pd/pse_core.c

Lines changed: 161 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -265,10 +265,113 @@ static int pse_pi_disable(struct regulator_dev *rdev)
265265
return ret;
266266
}
267267

268+
static int _pse_pi_get_voltage(struct regulator_dev *rdev)
269+
{
270+
struct pse_controller_dev *pcdev = rdev_get_drvdata(rdev);
271+
const struct pse_controller_ops *ops;
272+
int id;
273+
274+
ops = pcdev->ops;
275+
if (!ops->pi_get_voltage)
276+
return -EOPNOTSUPP;
277+
278+
id = rdev_get_id(rdev);
279+
return ops->pi_get_voltage(pcdev, id);
280+
}
281+
282+
static int pse_pi_get_voltage(struct regulator_dev *rdev)
283+
{
284+
struct pse_controller_dev *pcdev = rdev_get_drvdata(rdev);
285+
int ret;
286+
287+
mutex_lock(&pcdev->lock);
288+
ret = _pse_pi_get_voltage(rdev);
289+
mutex_unlock(&pcdev->lock);
290+
291+
return ret;
292+
}
293+
294+
static int _pse_ethtool_get_status(struct pse_controller_dev *pcdev,
295+
int id,
296+
struct netlink_ext_ack *extack,
297+
struct pse_control_status *status);
298+
299+
static int pse_pi_get_current_limit(struct regulator_dev *rdev)
300+
{
301+
struct pse_controller_dev *pcdev = rdev_get_drvdata(rdev);
302+
const struct pse_controller_ops *ops;
303+
struct netlink_ext_ack extack = {};
304+
struct pse_control_status st = {};
305+
int id, uV, ret;
306+
s64 tmp_64;
307+
308+
ops = pcdev->ops;
309+
id = rdev_get_id(rdev);
310+
mutex_lock(&pcdev->lock);
311+
if (ops->pi_get_current_limit) {
312+
ret = ops->pi_get_current_limit(pcdev, id);
313+
goto out;
314+
}
315+
316+
/* If pi_get_current_limit() callback not populated get voltage
317+
* from pi_get_voltage() and power limit from ethtool_get_status()
318+
* to calculate current limit.
319+
*/
320+
ret = _pse_pi_get_voltage(rdev);
321+
if (!ret) {
322+
dev_err(pcdev->dev, "Voltage null\n");
323+
ret = -ERANGE;
324+
goto out;
325+
}
326+
if (ret < 0)
327+
goto out;
328+
uV = ret;
329+
330+
ret = _pse_ethtool_get_status(pcdev, id, &extack, &st);
331+
if (ret)
332+
goto out;
333+
334+
if (!st.c33_avail_pw_limit) {
335+
ret = -ENODATA;
336+
goto out;
337+
}
338+
339+
tmp_64 = st.c33_avail_pw_limit;
340+
tmp_64 *= 1000000000ull;
341+
/* uA = mW * 1000000000 / uV */
342+
ret = DIV_ROUND_CLOSEST_ULL(tmp_64, uV);
343+
344+
out:
345+
mutex_unlock(&pcdev->lock);
346+
return ret;
347+
}
348+
349+
static int pse_pi_set_current_limit(struct regulator_dev *rdev, int min_uA,
350+
int max_uA)
351+
{
352+
struct pse_controller_dev *pcdev = rdev_get_drvdata(rdev);
353+
const struct pse_controller_ops *ops;
354+
int id, ret;
355+
356+
ops = pcdev->ops;
357+
if (!ops->pi_set_current_limit)
358+
return -EOPNOTSUPP;
359+
360+
id = rdev_get_id(rdev);
361+
mutex_lock(&pcdev->lock);
362+
ret = ops->pi_set_current_limit(pcdev, id, max_uA);
363+
mutex_unlock(&pcdev->lock);
364+
365+
return ret;
366+
}
367+
268368
static const struct regulator_ops pse_pi_ops = {
269369
.is_enabled = pse_pi_is_enabled,
270370
.enable = pse_pi_enable,
271371
.disable = pse_pi_disable,
372+
.get_voltage = pse_pi_get_voltage,
373+
.get_current_limit = pse_pi_get_current_limit,
374+
.set_current_limit = pse_pi_set_current_limit,
272375
};
273376

274377
static int
@@ -298,7 +401,9 @@ devm_pse_pi_regulator_register(struct pse_controller_dev *pcdev,
298401
rdesc->ops = &pse_pi_ops;
299402
rdesc->owner = pcdev->owner;
300403

301-
rinit_data->constraints.valid_ops_mask = REGULATOR_CHANGE_STATUS;
404+
rinit_data->constraints.valid_ops_mask = REGULATOR_CHANGE_STATUS |
405+
REGULATOR_CHANGE_CURRENT;
406+
rinit_data->constraints.max_uA = MAX_PI_CURRENT;
302407
rinit_data->supply_regulator = "vpwr";
303408

304409
rconfig.dev = pcdev->dev;
@@ -626,6 +731,23 @@ struct pse_control *of_pse_control_get(struct device_node *node)
626731
}
627732
EXPORT_SYMBOL_GPL(of_pse_control_get);
628733

734+
static int _pse_ethtool_get_status(struct pse_controller_dev *pcdev,
735+
int id,
736+
struct netlink_ext_ack *extack,
737+
struct pse_control_status *status)
738+
{
739+
const struct pse_controller_ops *ops;
740+
741+
ops = pcdev->ops;
742+
if (!ops->ethtool_get_status) {
743+
NL_SET_ERR_MSG(extack,
744+
"PSE driver does not support status report");
745+
return -EOPNOTSUPP;
746+
}
747+
748+
return ops->ethtool_get_status(pcdev, id, extack, status);
749+
}
750+
629751
/**
630752
* pse_ethtool_get_status - get status of PSE control
631753
* @psec: PSE control pointer
@@ -638,19 +760,10 @@ int pse_ethtool_get_status(struct pse_control *psec,
638760
struct netlink_ext_ack *extack,
639761
struct pse_control_status *status)
640762
{
641-
const struct pse_controller_ops *ops;
642763
int err;
643764

644-
ops = psec->pcdev->ops;
645-
646-
if (!ops->ethtool_get_status) {
647-
NL_SET_ERR_MSG(extack,
648-
"PSE driver does not support status report");
649-
return -EOPNOTSUPP;
650-
}
651-
652765
mutex_lock(&psec->pcdev->lock);
653-
err = ops->ethtool_get_status(psec->pcdev, psec->id, extack, status);
766+
err = _pse_ethtool_get_status(psec->pcdev, psec->id, extack, status);
654767
mutex_unlock(&psec->pcdev->lock);
655768

656769
return err;
@@ -732,6 +845,43 @@ int pse_ethtool_set_config(struct pse_control *psec,
732845
}
733846
EXPORT_SYMBOL_GPL(pse_ethtool_set_config);
734847

848+
/**
849+
* pse_ethtool_set_pw_limit - set PSE control power limit
850+
* @psec: PSE control pointer
851+
* @extack: extack for reporting useful error messages
852+
* @pw_limit: power limit value in mW
853+
*
854+
* Return: 0 on success and failure value on error
855+
*/
856+
int pse_ethtool_set_pw_limit(struct pse_control *psec,
857+
struct netlink_ext_ack *extack,
858+
const unsigned int pw_limit)
859+
{
860+
int uV, uA, ret;
861+
s64 tmp_64;
862+
863+
ret = regulator_get_voltage(psec->ps);
864+
if (!ret) {
865+
NL_SET_ERR_MSG(extack,
866+
"Can't calculate the current, PSE voltage read is 0");
867+
return -ERANGE;
868+
}
869+
if (ret < 0) {
870+
NL_SET_ERR_MSG(extack,
871+
"Error reading PSE voltage");
872+
return ret;
873+
}
874+
uV = ret;
875+
876+
tmp_64 = pw_limit;
877+
tmp_64 *= 1000000000ull;
878+
/* uA = mW * 1000000000 / uV */
879+
uA = DIV_ROUND_CLOSEST_ULL(tmp_64, uV);
880+
881+
return regulator_set_current_limit(psec->ps, 0, uA);
882+
}
883+
EXPORT_SYMBOL_GPL(pse_ethtool_set_pw_limit);
884+
735885
bool pse_has_podl(struct pse_control *psec)
736886
{
737887
return psec->pcdev->types & ETHTOOL_PSE_PODL;

include/linux/pse-pd/pse.h

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
#include <linux/list.h>
1010
#include <uapi/linux/ethtool.h>
1111

12+
/* Maximum current in uA according to IEEE 802.3-2022 Table 145-1 */
13+
#define MAX_PI_CURRENT 1920000
14+
1215
struct phy_device;
1316
struct pse_controller_dev;
1417

@@ -41,6 +44,12 @@ struct pse_control_config {
4144
* @c33_actual_pw: power currently delivered by the PSE in mW
4245
* IEEE 802.3-2022 30.9.1.1.23 aPSEActualPower
4346
* @c33_ext_state_info: extended state information of the PSE
47+
* @c33_avail_pw_limit: available power limit of the PSE in mW
48+
* IEEE 802.3-2022 145.2.5.4 pse_avail_pwr
49+
* @c33_pw_limit_ranges: supported power limit configuration range. The driver
50+
* is in charge of the memory allocation.
51+
* @c33_pw_limit_nb_ranges: number of supported power limit configuration
52+
* ranges
4453
*/
4554
struct pse_control_status {
4655
enum ethtool_podl_pse_admin_state podl_admin_state;
@@ -50,6 +59,9 @@ struct pse_control_status {
5059
u32 c33_pw_class;
5160
u32 c33_actual_pw;
5261
struct ethtool_c33_pse_ext_state_info c33_ext_state_info;
62+
u32 c33_avail_pw_limit;
63+
struct ethtool_c33_pse_pw_limit_range *c33_pw_limit_ranges;
64+
u32 c33_pw_limit_nb_ranges;
5365
};
5466

5567
/**
@@ -61,6 +73,14 @@ struct pse_control_status {
6173
* May also return negative errno.
6274
* @pi_enable: Configure the PSE PI as enabled.
6375
* @pi_disable: Configure the PSE PI as disabled.
76+
* @pi_get_voltage: Return voltage similarly to get_voltage regulator
77+
* callback.
78+
* @pi_get_current_limit: Get the configured current limit similarly to
79+
* get_current_limit regulator callback.
80+
* @pi_set_current_limit: Configure the current limit similarly to
81+
* set_current_limit regulator callback.
82+
* Should not return an error in case of MAX_PI_CURRENT
83+
* current value set.
6484
*/
6585
struct pse_controller_ops {
6686
int (*ethtool_get_status)(struct pse_controller_dev *pcdev,
@@ -70,6 +90,11 @@ struct pse_controller_ops {
7090
int (*pi_is_enabled)(struct pse_controller_dev *pcdev, int id);
7191
int (*pi_enable)(struct pse_controller_dev *pcdev, int id);
7292
int (*pi_disable)(struct pse_controller_dev *pcdev, int id);
93+
int (*pi_get_voltage)(struct pse_controller_dev *pcdev, int id);
94+
int (*pi_get_current_limit)(struct pse_controller_dev *pcdev,
95+
int id);
96+
int (*pi_set_current_limit)(struct pse_controller_dev *pcdev,
97+
int id, int max_uA);
7398
};
7499

75100
struct module;
@@ -156,6 +181,11 @@ int pse_ethtool_get_status(struct pse_control *psec,
156181
int pse_ethtool_set_config(struct pse_control *psec,
157182
struct netlink_ext_ack *extack,
158183
const struct pse_control_config *config);
184+
int pse_ethtool_set_pw_limit(struct pse_control *psec,
185+
struct netlink_ext_ack *extack,
186+
const unsigned int pw_limit);
187+
int pse_ethtool_get_pw_limit(struct pse_control *psec,
188+
struct netlink_ext_ack *extack);
159189

160190
bool pse_has_podl(struct pse_control *psec);
161191
bool pse_has_c33(struct pse_control *psec);
@@ -185,6 +215,19 @@ static inline int pse_ethtool_set_config(struct pse_control *psec,
185215
return -EOPNOTSUPP;
186216
}
187217

218+
static inline int pse_ethtool_set_pw_limit(struct pse_control *psec,
219+
struct netlink_ext_ack *extack,
220+
const unsigned int pw_limit)
221+
{
222+
return -EOPNOTSUPP;
223+
}
224+
225+
static inline int pse_ethtool_get_pw_limit(struct pse_control *psec,
226+
struct netlink_ext_ack *extack)
227+
{
228+
return -EOPNOTSUPP;
229+
}
230+
188231
static inline bool pse_has_podl(struct pse_control *psec)
189232
{
190233
return false;

0 commit comments

Comments
 (0)