Re: [PATCH net-next v5 10/17] net: pse-pd: Add support for PSE PIs

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Kory,

On Tue, Feb 27, 2024 at 03:42:52PM +0100, Kory Maincent wrote:
....

> diff --git a/drivers/net/pse-pd/pse_core.c b/drivers/net/pse-pd/pse_core.c
> index fed006cbc185..9124eb3d6492 100644
> --- a/drivers/net/pse-pd/pse_core.c
> +++ b/drivers/net/pse-pd/pse_core.c
> @@ -27,38 +27,137 @@ struct pse_control {
>  	struct kref refcnt;
>  };
>  
> -/**
> - * of_pse_zero_xlate - dummy function for controllers with one only control
> - * @pcdev: a pointer to the PSE controller device
> - * @pse_spec: PSE line specifier as found in the device tree
> - *
> - * This static translation function is used by default if of_xlate in
> - * :c:type:`pse_controller_dev` is not set. It is useful for all PSE
> - * controllers with #pse-cells = <0>.
> - */

Please replace documentation

> -static int of_pse_zero_xlate(struct pse_controller_dev *pcdev,
> -			     const struct of_phandle_args *pse_spec)
> +static int of_load_pse_pi_pairsets(struct device_node *node,
> +				   struct pse_pi *pi,
> +				   int npairsets)
>  {
> -	return 0;
> +	struct device_node *pairset_np;
> +	const char *name;
> +	int i, ret;
> +
> +	for (i = 0; i < npairsets; i++) {

please move this scope to a separate function.

> +		ret = of_property_read_string_index(node,
> +						    "pairset-names",
> +						     i, &name);
> +		if (ret)
> +			break;
> +
> +		if (strcmp(name, "alternative-a")) {

strcmp returns 0 if it matching

		if (!strcmp(name, "alternative-a")) {


> +			pi->pairset[i].pinout = ALTERNATIVE_A;
> +		} else if (strcmp(name, "alternative-b")) {

		if (!strcmp(name, "alternative-a")) {

> +			pi->pairset[i].pinout = ALTERNATIVE_B;
> +		} else {
> +			pr_err("pse: wrong pairset-names value %s\n", name);
> +			ret = -EINVAL;
> +			break;
> +		}
> +
> +		pairset_np = of_parse_phandle(node, "pairsets", i);
> +		if (!pairset_np) {
> +			ret = -ENODEV;
> +			break;
> +		}
> +
> +		pi->pairset[i].np = pairset_np;
> +	}
> +
> +	if (i == 2 && pi->pairset[0].pinout == pi->pairset[1].pinout) {
> +		pr_err("pse: two PI pairsets can not have identical pinout");
> +		ret = -EINVAL;
> +	}
> +
> +	/* If an error appears on the second pairset load, release the first
> +	 * pairset device node kref
> +	 */
> +	if (ret) {
> +		of_node_put(pi->pairset[0].np);
> +		pi->pairset[0].np = NULL;
> +		of_node_put(pi->pairset[1].np);
> +		pi->pairset[1].np = NULL;
> +	}
> +
> +	return ret;
>  }
>  
> -/**
> - * of_pse_simple_xlate - translate pse_spec to the PSE line number
> - * @pcdev: a pointer to the PSE controller device
> - * @pse_spec: PSE line specifier as found in the device tree
> - *
> - * This static translation function is used by default if of_xlate in
> - * :c:type:`pse_controller_dev` is not set. It is useful for all PSE
> - * controllers with 1:1 mapping, where PSE lines can be indexed by number
> - * without gaps.
> - */

Please replace documentation

> -static int of_pse_simple_xlate(struct pse_controller_dev *pcdev,
> -			       const struct of_phandle_args *pse_spec)
> +static int of_load_pse_pis(struct pse_controller_dev *pcdev)
>  {
> -	if (pse_spec->args[0] >= pcdev->nr_lines)
> -		return -EINVAL;
> +	struct device_node *np = pcdev->dev->of_node;
> +	struct device_node *node, *pis;
> +	int ret, i;
>  
> -	return pse_spec->args[0];
> +	if (!np)
> +		return -ENODEV;
> +
> +	pcdev->pi = kcalloc(pcdev->nr_lines, sizeof(*pcdev->pi), GFP_KERNEL);
> +	if (!pcdev->pi)
> +		return -ENOMEM;
> +
> +	pis = of_get_child_by_name(np, "pse-pis");
> +	if (!pis) {

Do we need to allocate pcdev->pi if there are no pse-pis?

> +		/* Legacy OF description of PSE PIs */
> +		pcdev->of_legacy = true;

It is not "legacy" :) PoDL do not providing definition of PSE PI since there
is only one pair. May be: single_pair, no_pse_pi or any other idea.

> +		return 0;
> +	}
> +
> +	for_each_child_of_node(pis, node) {

please move this scope to a separate function.

> +		struct pse_pi pi = {0};
> +		int npairsets;
> +		u32 id;
> +
> +		if (!of_node_name_eq(node, "pse-pi"))
> +			continue;
> +
> +		ret = of_property_read_u32(node, "reg", &id);
> +		if (ret)

error: can't get "reg" property for node "%s"

> +			goto out;
> +
> +		if (id >= pcdev->nr_lines || pcdev->pi[id].np) {

Here two different kind of errors:
- (id >= pcdev->nr_lines) reg value is out of range. print value and max
  range.
- (pcdev->pi[id].np) other node with same reg value was already
  registered... print both node names.

> +			dev_err(pcdev->dev, "wrong id of pse pi: %u\n",
> +				id);
> +			ret = -EINVAL;
> +			goto out;
> +		}
> +
> +		ret = of_property_count_strings(node, "pairset-names");
> +		if (ret <= 0)

if (ret < 0)
   error: can't get "pairset-names" property: %pe
if (ret < 1 || ret > 2)
   error: wrong number of pairset-names. Should be 1 or 2, got %i

> +			goto out;
> +		npairsets = ret;
> +
> +		ret = of_count_phandle_with_args(node, "pairsets", NULL);
> +		if (ret <= 0)

same as for pairset-names

> +			goto out;
> +
> +		/* npairsets is limited to value one or two */
> +		if (ret != npairsets || ret > 2) {

(ret > 2) will be handled by previous checks
(ret != npairsets) amount of pairsets and pairset-names is not equal %i
!= %i

> +			dev_err(pcdev->dev,
> +				"wrong number of pairsets or pairset-names for pse pi %d\n",
> +				id);
> +			ret = -EINVAL;
> +			goto out;
> +		}
> +
> +		ret = of_load_pse_pi_pairsets(node, &pi, npairsets);
> +		if (ret)
> +			goto out;
> +
> +		of_node_get(node);
> +		pi.np = node;
> +		memcpy(&pcdev->pi[id], &pi, sizeof(pi));
> +	}
> +
> +	of_node_put(pis);
> +	return 0;
> +
> +out:
> +	for (i = 0; i <= pcdev->nr_lines; i++) {
> +		of_node_put(pcdev->pi[i].pairset[0].np);
> +		of_node_put(pcdev->pi[i].pairset[1].np);
> +		of_node_put(pcdev->pi[i].np);
> +	}
> +	of_node_put(node);
> +	of_node_put(pis);
> +	kfree(pcdev->pi);
> +	return ret;
>  }
>  
>  /**
> @@ -67,16 +166,18 @@ static int of_pse_simple_xlate(struct pse_controller_dev *pcdev,
>   */
>  int pse_controller_register(struct pse_controller_dev *pcdev)
>  {
> -	if (!pcdev->of_xlate) {
> -		if (pcdev->of_pse_n_cells == 0)
> -			pcdev->of_xlate = of_pse_zero_xlate;
> -		else if (pcdev->of_pse_n_cells == 1)
> -			pcdev->of_xlate = of_pse_simple_xlate;
> -	}
> +	int ret;
>  
>  	mutex_init(&pcdev->lock);
>  	INIT_LIST_HEAD(&pcdev->pse_control_head);
>  
> +	if (!pcdev->nr_lines)
> +		pcdev->nr_lines = 1;
> +
> +	ret = of_load_pse_pis(pcdev);
> +	if (ret)
> +		return ret;
> +
>  	mutex_lock(&pse_list_mutex);
>  	list_add(&pcdev->list, &pse_controller_list);
>  	mutex_unlock(&pse_list_mutex);
> @@ -91,6 +192,14 @@ EXPORT_SYMBOL_GPL(pse_controller_register);
>   */
>  void pse_controller_unregister(struct pse_controller_dev *pcdev)
>  {
> +	int i;
> +
> +	for (i = 0; i <= pcdev->nr_lines; i++) {
> +		of_node_put(pcdev->pi[i].pairset[0].np);
> +		of_node_put(pcdev->pi[i].pairset[1].np);
> +		of_node_put(pcdev->pi[i].np);
> +	}
> +	kfree(pcdev->pi);

Same pattern was already used. It is better to move it to a separate
function.

>  	mutex_lock(&pse_list_mutex);
>  	list_del(&pcdev->list);
>  	mutex_unlock(&pse_list_mutex);
> @@ -203,8 +312,33 @@ pse_control_get_internal(struct pse_controller_dev *pcdev, unsigned int index)
>  	return psec;
>  }
>  
> -struct pse_control *
> -of_pse_control_get(struct device_node *node)
> +static int of_pse_match_pi(struct pse_controller_dev *pcdev,
> +			   struct device_node *np)
> +{
> +	int i;
> +
> +	for (i = 0; i <= pcdev->nr_lines; i++) {
> +		if (pcdev->pi[i].np == np)
> +			return i;
> +	}
> +
> +	return -EINVAL;
> +}
> +
> +static int psec_id_legacy_xlate(struct pse_controller_dev *pcdev,
> +				const struct of_phandle_args *pse_spec)

rename legacy to some other name in all places.

> +{
> +	if (!pcdev->of_pse_n_cells)
> +		return 0;
> +
> +	if (pcdev->of_pse_n_cells > 1 ||
> +	    pse_spec->args[0] >= pcdev->nr_lines)
> +		return -EINVAL;
> +
> +	return pse_spec->args[0];
> +}
> +
> +struct pse_control *of_pse_control_get(struct device_node *node)
>  {
>  	struct pse_controller_dev *r, *pcdev;
>  	struct of_phandle_args args;
> @@ -222,7 +356,14 @@ of_pse_control_get(struct device_node *node)
>  	mutex_lock(&pse_list_mutex);
>  	pcdev = NULL;
>  	list_for_each_entry(r, &pse_controller_list, list) {
> -		if (args.np == r->dev->of_node) {
> +		if (!r->of_legacy) {
> +			ret = of_pse_match_pi(r, args.np);
> +			if (ret >= 0) {
> +				pcdev = r;
> +				psec_id = ret;
> +				break;
> +			}
> +		} else if (args.np == r->dev->of_node) {
>  			pcdev = r;
>  			break;
>  		}
> @@ -238,10 +379,12 @@ of_pse_control_get(struct device_node *node)
>  		goto out;
>  	}
>  
> -	psec_id = pcdev->of_xlate(pcdev, &args);
> -	if (psec_id < 0) {
> -		psec = ERR_PTR(psec_id);
> -		goto out;
> +	if (pcdev->of_legacy) {
> +		psec_id = psec_id_legacy_xlate(pcdev, &args);
> +		if (psec_id < 0) {
> +			psec = ERR_PTR(psec_id);
> +			goto out;
> +		}
>  	}
>  
>  	/* pse_list_mutex also protects the pcdev's pse_control list */
> diff --git a/include/linux/pse-pd/pse.h b/include/linux/pse-pd/pse.h
> index 19589571157f..01b3b9adfe2a 100644
> --- a/include/linux/pse-pd/pse.h
> +++ b/include/linux/pse-pd/pse.h
> @@ -64,6 +64,36 @@ struct device_node;
>  struct of_phandle_args;
>  struct pse_control;
>  
> +/* PSE PI pairset pinout can either be Alternative A or Alternative B */
> +enum pse_pi_pairset_pinout {
> +	ALTERNATIVE_A,
> +	ALTERNATIVE_B,
> +};
> +
> +/**
> + * struct pse_pi_pairset - PSE PI pairset entity describing the pinout
> + *			   alternative ant its phandle
> + *
> + * @pinout: description of the pinout alternative
> + * @np: device node pointer describing the pairset phandle
> + */
> +struct pse_pi_pairset {
> +	enum pse_pi_pairset_pinout pinout;
> +	struct device_node *np;
> +};
> +
> +/**
> + * struct pse_pi - PSE PI (Power Interface) entity as described in
> + *		   IEEE 802.3-2022 145.2.4
> + *
> + * @pairset: table of the PSE PI pinout alternative for the two pairset
> + * @np: device node pointer of the PSE PI node
> + */
> +struct pse_pi {
> +	struct pse_pi_pairset pairset[2];
> +	struct device_node *np;
> +};
> +
>  /**
>   * struct pse_controller_dev - PSE controller entity that might
>   *                             provide multiple PSE controls
> @@ -73,11 +103,11 @@ struct pse_control;
>   * @pse_control_head: head of internal list of requested PSE controls
>   * @dev: corresponding driver model device struct
>   * @of_pse_n_cells: number of cells in PSE line specifiers
> - * @of_xlate: translation function to translate from specifier as found in the
> - *            device tree to id as given to the PSE control ops
>   * @nr_lines: number of PSE controls in this controller device
>   * @lock: Mutex for serialization access to the PSE controller
>   * @types: types of the PSE controller
> + * @pi: table of PSE PIs described in this controller device
> + * @of_legacy: flag set if the pse_pis devicetree node is not used
>   */
>  struct pse_controller_dev {
>  	const struct pse_controller_ops *ops;
> @@ -86,11 +116,11 @@ struct pse_controller_dev {
>  	struct list_head pse_control_head;
>  	struct device *dev;
>  	int of_pse_n_cells;
> -	int (*of_xlate)(struct pse_controller_dev *pcdev,
> -			const struct of_phandle_args *pse_spec);
>  	unsigned int nr_lines;
>  	struct mutex lock;
>  	enum ethtool_pse_types types;
> +	struct pse_pi *pi;
> +	bool of_legacy;
>  };
>  
>  #if IS_ENABLED(CONFIG_PSE_CONTROLLER)

Regards,
Oleksij
-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |




[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]


  Powered by Linux