[dpdk-dev,v6,3/8] ethdev: add generic create/destroy ethdev APIs

Message ID 20180328135433.20203-4-declan.doherty@intel.com (mailing list archive)
State Superseded, archived
Delegated to: Ferruh Yigit
Headers

Checks

Context Check Description
ci/checkpatch success coding style OK
ci/Intel-compilation fail Compilation issues

Commit Message

Doherty, Declan March 28, 2018, 1:54 p.m. UTC
Add new bus generic ethdev create/destroy APIs which are bus independent
and provide hooks for bus specific initialisation.

Signed-off-by: Declan Doherty <declan.doherty@intel.com>
---
 lib/librte_ether/Makefile                 |  1 +
 lib/librte_ether/meson.build              |  1 +
 lib/librte_ether/rte_ethdev.c             | 96 ++++++++++++++++++++++++++++++-
 lib/librte_ether/rte_ethdev_driver.h      | 57 ++++++++++++++++++
 lib/librte_ether/rte_ethdev_pci.h         | 12 ++++
 lib/librte_ether/rte_ethdev_representor.h | 28 +++++++++
 lib/librte_ether/rte_ethdev_version.map   |  8 +++
 7 files changed, 202 insertions(+), 1 deletion(-)
 create mode 100644 lib/librte_ether/rte_ethdev_representor.h
  

Comments

Shahaf Shuler March 29, 2018, 6:13 a.m. UTC | #1
Wednesday, March 28, 2018 4:54 PM, Declan Doherty:
> Subject: [dpdk-dev][PATCH v6 3/8] ethdev: add generic create/destroy
> ethdev APIs
> 
> Add new bus generic ethdev create/destroy APIs which are bus independent
> and provide hooks for bus specific initialisation.
> 
> Signed-off-by: Declan Doherty <declan.doherty@intel.com>
> ---
>  lib/librte_ether/Makefile                 |  1 +
>  lib/librte_ether/meson.build              |  1 +
>  lib/librte_ether/rte_ethdev.c             | 96
> ++++++++++++++++++++++++++++++-
>  lib/librte_ether/rte_ethdev_driver.h      | 57 ++++++++++++++++++
>  lib/librte_ether/rte_ethdev_pci.h         | 12 ++++
>  lib/librte_ether/rte_ethdev_representor.h | 28 +++++++++
>  lib/librte_ether/rte_ethdev_version.map   |  8 +++
>  7 files changed, 202 insertions(+), 1 deletion(-)  create mode 100644
> lib/librte_ether/rte_ethdev_representor.h
> 
> diff --git a/lib/librte_ether/Makefile b/lib/librte_ether/Makefile index
> 3ca5782bb..5698cd47b 100644
> --- a/lib/librte_ether/Makefile
> +++ b/lib/librte_ether/Makefile
> @@ -32,6 +32,7 @@ SYMLINK-y-include += rte_ethdev_driver.h  SYMLINK-y-
> include += rte_ethdev_core.h  SYMLINK-y-include += rte_ethdev_pci.h
> SYMLINK-y-include += rte_ethdev_vdev.h
> +SYMLINK-y-include += rte_ethdev_representor.h
>  SYMLINK-y-include += rte_eth_ctrl.h
>  SYMLINK-y-include += rte_dev_info.h
>  SYMLINK-y-include += rte_flow.h
> diff --git a/lib/librte_ether/meson.build b/lib/librte_ether/meson.build
> index 7fed86056..163891556 100644
> --- a/lib/librte_ether/meson.build
> +++ b/lib/librte_ether/meson.build
> @@ -15,6 +15,7 @@ headers = files('rte_ethdev.h',
>  	'rte_ethdev_core.h',
>  	'rte_ethdev_pci.h',
>  	'rte_ethdev_vdev.h',
> +	'rte_ethdev_representor.h',
>  	'rte_eth_ctrl.h',
>  	'rte_dev_info.h',
>  	'rte_flow.h',
> diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
> index f32d18cad..c719f84a3 100644
> --- a/lib/librte_ether/rte_ethdev.c
> +++ b/lib/librte_ether/rte_ethdev.c
> @@ -345,7 +345,8 @@ rte_eth_dev_release_port(struct rte_eth_dev
> *eth_dev)
>  	rte_eth_dev_shared_data_prepare();
> 
>  	rte_spinlock_lock(&rte_eth_dev_shared_data->ownership_lock);
> -
> +	eth_dev->device = NULL;
> +	eth_dev->intr_handle = NULL;
>  	eth_dev->state = RTE_ETH_DEV_UNUSED;
> 
>  	memset(eth_dev->data, 0, sizeof(struct rte_eth_dev_data)); @@ -
> 3403,6 +3404,99 @@ rte_eth_dma_zone_reserve(const struct rte_eth_dev
> *dev, const char *ring_name,
>  	return rte_memzone_reserve_aligned(z_name, size, socket_id, 0,
> align);  }
> 
> +int __rte_experimental
> +rte_eth_dev_create(struct rte_device *device, const char *name,
> +	size_t priv_data_size,
> +	ethdev_bus_specific_init ethdev_bus_specific_init,
> +	void *bus_init_params,
> +	ethdev_init_t ethdev_init, void *init_params) {
> +	struct rte_eth_dev *ethdev;
> +	int retval;
> +
> +	if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
> +		ethdev = rte_eth_dev_allocate(name);
> +		if (!ethdev) {
> +			retval = -ENODEV;
> +			goto probe_failed;
> +		}
> +
> +		if (priv_data_size) {
> +			ethdev->data->dev_private = rte_zmalloc_socket(
> +				name, priv_data_size,
> RTE_CACHE_LINE_SIZE,
> +				device->numa_node);
> +
> +			if (!ethdev->data->dev_private) {
> +				RTE_LOG(ERR, EAL, "failed to allocate private
> data");
> +				retval = -ENOMEM;
> +				goto probe_failed;
> +			}
> +		}
> +	} else {
> +		ethdev = rte_eth_dev_attach_secondary(name);
> +		if (!ethdev) {
> +			RTE_LOG(ERR, EAL, "secondary process attach failed,
> "
> +				"ethdev doesn't exist");
> +			retval = -ENODEV;
> +			goto probe_failed;
> +		}
> +	}
> +
> +	ethdev->device = device;
> +
> +	if (ethdev_bus_specific_init) {
> +		retval = ethdev_bus_specific_init(ethdev, bus_init_params);
> +		if (retval) {
> +			RTE_LOG(ERR, EAL,
> +				"ethdev bus specific initialisation failed");
> +			goto probe_failed;
> +		}
> +	}
> +
> +	RTE_FUNC_PTR_OR_ERR_RET(*ethdev_init, -EINVAL);
> +	retval = ethdev_init(ethdev, init_params);
> +	if (retval) {
> +		RTE_LOG(ERR, EAL, "ethdev initialisation failed");
> +		goto probe_failed;
> +	}
> +
> +	return retval;
> +probe_failed:
> +	/* free ports private data if primary process */
> +	if (rte_eal_process_type() == RTE_PROC_PRIMARY)
> +		rte_free(ethdev->data->dev_private);
> +
> +	rte_eth_dev_release_port(ethdev);
> +
> +	return retval;
> +}
> +
> +int  __rte_experimental
> +rte_eth_dev_destroy(struct rte_eth_dev *ethdev,
> +	ethdev_uninit_t ethdev_uninit)
> +{
> +	int ret;
> +
> +	ethdev = rte_eth_dev_allocated(ethdev->data->name);
> +	if (!ethdev)
> +		return -ENODEV;
> +
> +	RTE_FUNC_PTR_OR_ERR_RET(*ethdev_uninit, -EINVAL);
> +	if (ethdev_uninit) {
> +		ret = ethdev_uninit(ethdev);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	if (rte_eal_process_type() == RTE_PROC_PRIMARY)
> +		rte_free(ethdev->data->dev_private);
> +
> +	ethdev->data->dev_private = NULL;
> +
> +	return rte_eth_dev_release_port(ethdev); }
> +
> +
>  int
>  rte_eth_dev_rx_intr_ctl_q(uint16_t port_id, uint16_t queue_id,
>  			  int epfd, int op, void *data)
> diff --git a/lib/librte_ether/rte_ethdev_driver.h
> b/lib/librte_ether/rte_ethdev_driver.h
> index 45f08c65e..4896cea93 100644
> --- a/lib/librte_ether/rte_ethdev_driver.h
> +++ b/lib/librte_ether/rte_ethdev_driver.h
> @@ -125,6 +125,63 @@ rte_eth_dma_zone_reserve(const struct
> rte_eth_dev *eth_dev, const char *name,
>  			 uint16_t queue_id, size_t size,
>  			 unsigned align, int socket_id);
> 
> +
> +typedef int (*ethdev_init_t)(struct rte_eth_dev *ethdev, void
> +*init_params); typedef int (*ethdev_bus_specific_init)(struct rte_eth_dev
> *ethdev,
> +	void *bus_specific_init_params);
> +
> +/**
> + * @warning
> + * @b EXPERIMENTAL: this API may change without prior notice.
> + *
> + * PMD helper function for the creation of a new ethdev ports.
> + *
> + * @param device
> + *  rte_device handle.
> + * @param	name
> + *  port name.
> + * @param priv_data_size
> + *  size of private data required for port.
> + * @param bus_specific_init
> + *  port bus specific initialisation callback function
> + * @param bus_init_params
> + *  port bus specific initialisation parameters
> + * @param ethdev_init
> + *  device specific port initialization callback function
> + * @param init_params
> + *  port initialisation parameters
> + *
> + * @return
> + *   Negative errno value on error, 0 on success.
> + */
> +int __rte_experimental
> +rte_eth_dev_create(struct rte_device *device, const char *name,
> +	size_t priv_data_size,
> +	ethdev_bus_specific_init bus_specific_init, void *bus_init_params,
> +	ethdev_init_t ethdev_init, void *init_params);
> +
> +
> +typedef int (*ethdev_uninit_t)(struct rte_eth_dev *ethdev);
> +
> +/**
> + * @warning
> + * @b EXPERIMENTAL: this API may change without prior notice.
> + *
> + * PMD helper function for cleaing up the resources of a ethdev port on
> +it's
> + * destruction.
> + *
> + * @param ethdev
> + *   ethdev handle of port.
> + * @param ethdev
> + *   device specific port un-initialise callback function
> + *
> + * @return
> + *   Negative errno value on error, 0 on success.
> + */
> +int __rte_experimental
> +rte_eth_dev_destroy(struct rte_eth_dev *ethdev,
> +	ethdev_uninit_t ethdev_uninit);
> +
>  #ifdef __cplusplus
>  }
>  #endif
> diff --git a/lib/librte_ether/rte_ethdev_pci.h
> b/lib/librte_ether/rte_ethdev_pci.h
> index 897ce5b41..8604a0474 100644
> --- a/lib/librte_ether/rte_ethdev_pci.h
> +++ b/lib/librte_ether/rte_ethdev_pci.h
> @@ -70,6 +70,18 @@ rte_eth_copy_pci_info(struct rte_eth_dev *eth_dev,
>  	eth_dev->data->numa_node = pci_dev->device.numa_node;  }
> 
> +static inline int
> +eth_dev_pci_specific_init(struct rte_eth_dev *eth_dev, void *bus_device)
> {
> +	struct rte_pci_device *pci_dev = bus_device;
> +
> +	if (!pci_dev)
> +		return -ENODEV;
> +
> +	rte_eth_copy_pci_info(eth_dev, pci_dev);
> +
> +	return 0;
> +}
> +
>  /**
>   * @internal
>   * Allocates a new ethdev slot for an ethernet device and returns the pointer
> diff --git a/lib/librte_ether/rte_ethdev_representor.h
> b/lib/librte_ether/rte_ethdev_representor.h
> new file mode 100644
> index 000000000..cbc1f2855
> --- /dev/null
> +++ b/lib/librte_ether/rte_ethdev_representor.h
> @@ -0,0 +1,28 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2018 Intel Corporation.
> + */
> +
> +
> +#ifndef _RTE_ETHDEV_REPRESENTOR_H_
> +#define _RTE_ETHDEV_REPRESENTOR_H_
> +
> +#include <rte_ethdev_driver.h>
> +
> +static int
> +eth_dev_representor_port_init(struct rte_eth_dev *ethdev, void
> +*init_params) {
> +	struct rte_eth_dev *base_ethdev = init_params;
> +
> +	if (!ethdev || !base_ethdev)
> +		return -ENODEV;
> +
> +	/** representor shares same driver as it's base device */
> +	ethdev->device->driver = base_ethdev->device->driver;
> +
> +	/** representor inherits the switch id of it's base device */
> +	ethdev->data->switch_id = base_ethdev->data->switch_id;

Why not let the PMD to set it? 

The PMD knows the specific port is a represntor port and to which switch it belongs. 
Doing it on ethdev layer will block us in the future from having more complex model were, for example, there are multiple switch domain for a set of PF + representors. 

> +
> +	return 0;
> +}
> +
> +#endif /* _RTE_ETHDEV_REPRESENTOR_H_ */
> diff --git a/lib/librte_ether/rte_ethdev_version.map
> b/lib/librte_ether/rte_ethdev_version.map
> index 87f02fb74..48b08bc36 100644
> --- a/lib/librte_ether/rte_ethdev_version.map
> +++ b/lib/librte_ether/rte_ethdev_version.map
> @@ -230,3 +230,11 @@ EXPERIMENTAL {
>  	rte_mtr_stats_update;
> 
>  } DPDK_17.11;
> +
> +EXPERIMENTAL {
> +	global:
> +
> +	rte_eth_dev_create;
> +	rte_eth_dev_destroy;
> +
> +} DPDK_18.05;
> --
> 2.14.3
  
Doherty, Declan March 29, 2018, 9:22 a.m. UTC | #2
On 29/03/2018 7:13 AM, Shahaf Shuler wrote:
> Wednesday, March 28, 2018 4:54 PM, Declan Doherty:
>> Subject: [dpdk-dev][PATCH v6 3/8] ethdev: add generic create/destroy
>> ethdev APIs
>>
>> Add new bus generic ethdev create/destroy APIs which are bus independent
>> and provide hooks for bus specific initialisation.
>>
>> Signed-off-by: Declan Doherty <declan.doherty@intel.com>
>> ---
>>   lib/librte_ether/Makefile                 |  1 +
>>   lib/librte_ether/meson.build              |  1 +
>>   lib/librte_ether/rte_ethdev.c             | 96
>> ++++++++++++++++++++++++++++++-
>>   lib/librte_ether/rte_ethdev_driver.h      | 57 ++++++++++++++++++
>>   lib/librte_ether/rte_ethdev_pci.h         | 12 ++++
>>   lib/librte_ether/rte_ethdev_representor.h | 28 +++++++++
>>   lib/librte_ether/rte_ethdev_version.map   |  8 +++
>>   7 files changed, 202 insertions(+), 1 deletion(-)  create mode 100644
>> lib/librte_ether/rte_ethdev_representor.h
>>
>> diff --git a/lib/librte_ether/Makefile b/lib/librte_ether/Makefile index
>> 3ca5782bb..5698cd47b 100644
>> --- a/lib/librte_ether/Makefile
>> +++ b/lib/librte_ether/Makefile
>> @@ -32,6 +32,7 @@ SYMLINK-y-include += rte_ethdev_driver.h  SYMLINK-y-
>> include += rte_ethdev_core.h  SYMLINK-y-include += rte_ethdev_pci.h
>> SYMLINK-y-include += rte_ethdev_vdev.h
>> +SYMLINK-y-include += rte_ethdev_representor.h
>>   SYMLINK-y-include += rte_eth_ctrl.h
>>   SYMLINK-y-include += rte_dev_info.h
>>   SYMLINK-y-include += rte_flow.h
>> diff --git a/lib/librte_ether/meson.build b/lib/librte_ether/meson.build
>> index 7fed86056..163891556 100644
>> --- a/lib/librte_ether/meson.build
>> +++ b/lib/librte_ether/meson.build
>> @@ -15,6 +15,7 @@ headers = files('rte_ethdev.h',
>>   	'rte_ethdev_core.h',
>>   	'rte_ethdev_pci.h',
>>   	'rte_ethdev_vdev.h',
>> +	'rte_ethdev_representor.h',
>>   	'rte_eth_ctrl.h',
>>   	'rte_dev_info.h',
>>   	'rte_flow.h',
>> diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
>> index f32d18cad..c719f84a3 100644
>> --- a/lib/librte_ether/rte_ethdev.c
>> +++ b/lib/librte_ether/rte_ethdev.c
>> @@ -345,7 +345,8 @@ rte_eth_dev_release_port(struct rte_eth_dev
>> *eth_dev)
>>   	rte_eth_dev_shared_data_prepare();
>>
>>   	rte_spinlock_lock(&rte_eth_dev_shared_data->ownership_lock);
>> -
>> +	eth_dev->device = NULL;
>> +	eth_dev->intr_handle = NULL;
>>   	eth_dev->state = RTE_ETH_DEV_UNUSED;
>>
>>   	memset(eth_dev->data, 0, sizeof(struct rte_eth_dev_data)); @@ -
>> 3403,6 +3404,99 @@ rte_eth_dma_zone_reserve(const struct rte_eth_dev
>> *dev, const char *ring_name,
>>   	return rte_memzone_reserve_aligned(z_name, size, socket_id, 0,
>> align);  }
>>
>> +int __rte_experimental
>> +rte_eth_dev_create(struct rte_device *device, const char *name,
>> +	size_t priv_data_size,
>> +	ethdev_bus_specific_init ethdev_bus_specific_init,
>> +	void *bus_init_params,
>> +	ethdev_init_t ethdev_init, void *init_params) {
>> +	struct rte_eth_dev *ethdev;
>> +	int retval;
>> +
>> +	if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
>> +		ethdev = rte_eth_dev_allocate(name);
>> +		if (!ethdev) {
>> +			retval = -ENODEV;
>> +			goto probe_failed;
>> +		}
>> +
>> +		if (priv_data_size) {
>> +			ethdev->data->dev_private = rte_zmalloc_socket(
>> +				name, priv_data_size,
>> RTE_CACHE_LINE_SIZE,
>> +				device->numa_node);
>> +
>> +			if (!ethdev->data->dev_private) {
>> +				RTE_LOG(ERR, EAL, "failed to allocate private
>> data");
>> +				retval = -ENOMEM;
>> +				goto probe_failed;
>> +			}
>> +		}
>> +	} else {
>> +		ethdev = rte_eth_dev_attach_secondary(name);
>> +		if (!ethdev) {
>> +			RTE_LOG(ERR, EAL, "secondary process attach failed,
>> "
>> +				"ethdev doesn't exist");
>> +			retval = -ENODEV;
>> +			goto probe_failed;
>> +		}
>> +	}
>> +
>> +	ethdev->device = device;
>> +
>> +	if (ethdev_bus_specific_init) {
>> +		retval = ethdev_bus_specific_init(ethdev, bus_init_params);
>> +		if (retval) {
>> +			RTE_LOG(ERR, EAL,
>> +				"ethdev bus specific initialisation failed");
>> +			goto probe_failed;
>> +		}
>> +	}
>> +
>> +	RTE_FUNC_PTR_OR_ERR_RET(*ethdev_init, -EINVAL);
>> +	retval = ethdev_init(ethdev, init_params);
>> +	if (retval) {
>> +		RTE_LOG(ERR, EAL, "ethdev initialisation failed");
>> +		goto probe_failed;
>> +	}
>> +
>> +	return retval;
>> +probe_failed:
>> +	/* free ports private data if primary process */
>> +	if (rte_eal_process_type() == RTE_PROC_PRIMARY)
>> +		rte_free(ethdev->data->dev_private);
>> +
>> +	rte_eth_dev_release_port(ethdev);
>> +
>> +	return retval;
>> +}
>> +
>> +int  __rte_experimental
>> +rte_eth_dev_destroy(struct rte_eth_dev *ethdev,
>> +	ethdev_uninit_t ethdev_uninit)
>> +{
>> +	int ret;
>> +
>> +	ethdev = rte_eth_dev_allocated(ethdev->data->name);
>> +	if (!ethdev)
>> +		return -ENODEV;
>> +
>> +	RTE_FUNC_PTR_OR_ERR_RET(*ethdev_uninit, -EINVAL);
>> +	if (ethdev_uninit) {
>> +		ret = ethdev_uninit(ethdev);
>> +		if (ret)
>> +			return ret;
>> +	}
>> +
>> +	if (rte_eal_process_type() == RTE_PROC_PRIMARY)
>> +		rte_free(ethdev->data->dev_private);
>> +
>> +	ethdev->data->dev_private = NULL;
>> +
>> +	return rte_eth_dev_release_port(ethdev); }
>> +
>> +
>>   int
>>   rte_eth_dev_rx_intr_ctl_q(uint16_t port_id, uint16_t queue_id,
>>   			  int epfd, int op, void *data)
>> diff --git a/lib/librte_ether/rte_ethdev_driver.h
>> b/lib/librte_ether/rte_ethdev_driver.h
>> index 45f08c65e..4896cea93 100644
>> --- a/lib/librte_ether/rte_ethdev_driver.h
>> +++ b/lib/librte_ether/rte_ethdev_driver.h
>> @@ -125,6 +125,63 @@ rte_eth_dma_zone_reserve(const struct
>> rte_eth_dev *eth_dev, const char *name,
>>   			 uint16_t queue_id, size_t size,
>>   			 unsigned align, int socket_id);
>>
>> +
>> +typedef int (*ethdev_init_t)(struct rte_eth_dev *ethdev, void
>> +*init_params); typedef int (*ethdev_bus_specific_init)(struct rte_eth_dev
>> *ethdev,
>> +	void *bus_specific_init_params);
>> +
>> +/**
>> + * @warning
>> + * @b EXPERIMENTAL: this API may change without prior notice.
>> + *
>> + * PMD helper function for the creation of a new ethdev ports.
>> + *
>> + * @param device
>> + *  rte_device handle.
>> + * @param	name
>> + *  port name.
>> + * @param priv_data_size
>> + *  size of private data required for port.
>> + * @param bus_specific_init
>> + *  port bus specific initialisation callback function
>> + * @param bus_init_params
>> + *  port bus specific initialisation parameters
>> + * @param ethdev_init
>> + *  device specific port initialization callback function
>> + * @param init_params
>> + *  port initialisation parameters
>> + *
>> + * @return
>> + *   Negative errno value on error, 0 on success.
>> + */
>> +int __rte_experimental
>> +rte_eth_dev_create(struct rte_device *device, const char *name,
>> +	size_t priv_data_size,
>> +	ethdev_bus_specific_init bus_specific_init, void *bus_init_params,
>> +	ethdev_init_t ethdev_init, void *init_params);
>> +
>> +
>> +typedef int (*ethdev_uninit_t)(struct rte_eth_dev *ethdev);
>> +
>> +/**
>> + * @warning
>> + * @b EXPERIMENTAL: this API may change without prior notice.
>> + *
>> + * PMD helper function for cleaing up the resources of a ethdev port on
>> +it's
>> + * destruction.
>> + *
>> + * @param ethdev
>> + *   ethdev handle of port.
>> + * @param ethdev
>> + *   device specific port un-initialise callback function
>> + *
>> + * @return
>> + *   Negative errno value on error, 0 on success.
>> + */
>> +int __rte_experimental
>> +rte_eth_dev_destroy(struct rte_eth_dev *ethdev,
>> +	ethdev_uninit_t ethdev_uninit);
>> +
>>   #ifdef __cplusplus
>>   }
>>   #endif
>> diff --git a/lib/librte_ether/rte_ethdev_pci.h
>> b/lib/librte_ether/rte_ethdev_pci.h
>> index 897ce5b41..8604a0474 100644
>> --- a/lib/librte_ether/rte_ethdev_pci.h
>> +++ b/lib/librte_ether/rte_ethdev_pci.h
>> @@ -70,6 +70,18 @@ rte_eth_copy_pci_info(struct rte_eth_dev *eth_dev,
>>   	eth_dev->data->numa_node = pci_dev->device.numa_node;  }
>>
>> +static inline int
>> +eth_dev_pci_specific_init(struct rte_eth_dev *eth_dev, void *bus_device)
>> {
>> +	struct rte_pci_device *pci_dev = bus_device;
>> +
>> +	if (!pci_dev)
>> +		return -ENODEV;
>> +
>> +	rte_eth_copy_pci_info(eth_dev, pci_dev);
>> +
>> +	return 0;
>> +}
>> +
>>   /**
>>    * @internal
>>    * Allocates a new ethdev slot for an ethernet device and returns the pointer
>> diff --git a/lib/librte_ether/rte_ethdev_representor.h
>> b/lib/librte_ether/rte_ethdev_representor.h
>> new file mode 100644
>> index 000000000..cbc1f2855
>> --- /dev/null
>> +++ b/lib/librte_ether/rte_ethdev_representor.h
>> @@ -0,0 +1,28 @@
>> +/* SPDX-License-Identifier: BSD-3-Clause
>> + * Copyright(c) 2018 Intel Corporation.
>> + */
>> +
>> +
>> +#ifndef _RTE_ETHDEV_REPRESENTOR_H_
>> +#define _RTE_ETHDEV_REPRESENTOR_H_
>> +
>> +#include <rte_ethdev_driver.h>
>> +
>> +static int
>> +eth_dev_representor_port_init(struct rte_eth_dev *ethdev, void
>> +*init_params) {
>> +	struct rte_eth_dev *base_ethdev = init_params;
>> +
>> +	if (!ethdev || !base_ethdev)
>> +		return -ENODEV;
>> +
>> +	/** representor shares same driver as it's base device */
>> +	ethdev->device->driver = base_ethdev->device->driver;
>> +
>> +	/** representor inherits the switch id of it's base device */
>> +	ethdev->data->switch_id = base_ethdev->data->switch_id;
> 
> Why not let the PMD to set it?
> 
> The PMD knows the specific port is a represntor port and to which switch it belongs.
> Doing it on ethdev layer will block us in the future from having more complex model were, for example, there are multiple switch domain for a set of PF + representors.
> 

This is only a generic helper function for a representor port bus 
specific initialisation, and can be passed as the bus_specific_init 
parameter in the rte_eth_dev_create function, but whether or not to use 
it is complete up to the PMD. It only handles the simple case of a 
single function device with multiple representors on a single switch 
domain. For more complex use cases, like multiple switch domains, the 
PMD can provide it's own implementation of this. I thought it was useful 
to provide as a common function as for the ixgbe, i40e it fulfills there 
requirements, and will probably be sufficient for many other devices too.

>> +
>> +	return 0;
>> +}
>> +
>> +#endif /* _RTE_ETHDEV_REPRESENTOR_H_ */
>> diff --git a/lib/librte_ether/rte_ethdev_version.map
>> b/lib/librte_ether/rte_ethdev_version.map
>> index 87f02fb74..48b08bc36 100644
>> --- a/lib/librte_ether/rte_ethdev_version.map
>> +++ b/lib/librte_ether/rte_ethdev_version.map
>> @@ -230,3 +230,11 @@ EXPERIMENTAL {
>>   	rte_mtr_stats_update;
>>
>>   } DPDK_17.11;
>> +
>> +EXPERIMENTAL {
>> +	global:
>> +
>> +	rte_eth_dev_create;
>> +	rte_eth_dev_destroy;
>> +
>> +} DPDK_18.05;
>> --
>> 2.14.3
>
  

Patch

diff --git a/lib/librte_ether/Makefile b/lib/librte_ether/Makefile
index 3ca5782bb..5698cd47b 100644
--- a/lib/librte_ether/Makefile
+++ b/lib/librte_ether/Makefile
@@ -32,6 +32,7 @@  SYMLINK-y-include += rte_ethdev_driver.h
 SYMLINK-y-include += rte_ethdev_core.h
 SYMLINK-y-include += rte_ethdev_pci.h
 SYMLINK-y-include += rte_ethdev_vdev.h
+SYMLINK-y-include += rte_ethdev_representor.h
 SYMLINK-y-include += rte_eth_ctrl.h
 SYMLINK-y-include += rte_dev_info.h
 SYMLINK-y-include += rte_flow.h
diff --git a/lib/librte_ether/meson.build b/lib/librte_ether/meson.build
index 7fed86056..163891556 100644
--- a/lib/librte_ether/meson.build
+++ b/lib/librte_ether/meson.build
@@ -15,6 +15,7 @@  headers = files('rte_ethdev.h',
 	'rte_ethdev_core.h',
 	'rte_ethdev_pci.h',
 	'rte_ethdev_vdev.h',
+	'rte_ethdev_representor.h',
 	'rte_eth_ctrl.h',
 	'rte_dev_info.h',
 	'rte_flow.h',
diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index f32d18cad..c719f84a3 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -345,7 +345,8 @@  rte_eth_dev_release_port(struct rte_eth_dev *eth_dev)
 	rte_eth_dev_shared_data_prepare();
 
 	rte_spinlock_lock(&rte_eth_dev_shared_data->ownership_lock);
-
+	eth_dev->device = NULL;
+	eth_dev->intr_handle = NULL;
 	eth_dev->state = RTE_ETH_DEV_UNUSED;
 
 	memset(eth_dev->data, 0, sizeof(struct rte_eth_dev_data));
@@ -3403,6 +3404,99 @@  rte_eth_dma_zone_reserve(const struct rte_eth_dev *dev, const char *ring_name,
 	return rte_memzone_reserve_aligned(z_name, size, socket_id, 0, align);
 }
 
+int __rte_experimental
+rte_eth_dev_create(struct rte_device *device, const char *name,
+	size_t priv_data_size,
+	ethdev_bus_specific_init ethdev_bus_specific_init,
+	void *bus_init_params,
+	ethdev_init_t ethdev_init, void *init_params)
+{
+	struct rte_eth_dev *ethdev;
+	int retval;
+
+	if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
+		ethdev = rte_eth_dev_allocate(name);
+		if (!ethdev) {
+			retval = -ENODEV;
+			goto probe_failed;
+		}
+
+		if (priv_data_size) {
+			ethdev->data->dev_private = rte_zmalloc_socket(
+				name, priv_data_size, RTE_CACHE_LINE_SIZE,
+				device->numa_node);
+
+			if (!ethdev->data->dev_private) {
+				RTE_LOG(ERR, EAL, "failed to allocate private data");
+				retval = -ENOMEM;
+				goto probe_failed;
+			}
+		}
+	} else {
+		ethdev = rte_eth_dev_attach_secondary(name);
+		if (!ethdev) {
+			RTE_LOG(ERR, EAL, "secondary process attach failed, "
+				"ethdev doesn't exist");
+			retval = -ENODEV;
+			goto probe_failed;
+		}
+	}
+
+	ethdev->device = device;
+
+	if (ethdev_bus_specific_init) {
+		retval = ethdev_bus_specific_init(ethdev, bus_init_params);
+		if (retval) {
+			RTE_LOG(ERR, EAL,
+				"ethdev bus specific initialisation failed");
+			goto probe_failed;
+		}
+	}
+
+	RTE_FUNC_PTR_OR_ERR_RET(*ethdev_init, -EINVAL);
+	retval = ethdev_init(ethdev, init_params);
+	if (retval) {
+		RTE_LOG(ERR, EAL, "ethdev initialisation failed");
+		goto probe_failed;
+	}
+
+	return retval;
+probe_failed:
+	/* free ports private data if primary process */
+	if (rte_eal_process_type() == RTE_PROC_PRIMARY)
+		rte_free(ethdev->data->dev_private);
+
+	rte_eth_dev_release_port(ethdev);
+
+	return retval;
+}
+
+int  __rte_experimental
+rte_eth_dev_destroy(struct rte_eth_dev *ethdev,
+	ethdev_uninit_t ethdev_uninit)
+{
+	int ret;
+
+	ethdev = rte_eth_dev_allocated(ethdev->data->name);
+	if (!ethdev)
+		return -ENODEV;
+
+	RTE_FUNC_PTR_OR_ERR_RET(*ethdev_uninit, -EINVAL);
+	if (ethdev_uninit) {
+		ret = ethdev_uninit(ethdev);
+		if (ret)
+			return ret;
+	}
+
+	if (rte_eal_process_type() == RTE_PROC_PRIMARY)
+		rte_free(ethdev->data->dev_private);
+
+	ethdev->data->dev_private = NULL;
+
+	return rte_eth_dev_release_port(ethdev);
+}
+
+
 int
 rte_eth_dev_rx_intr_ctl_q(uint16_t port_id, uint16_t queue_id,
 			  int epfd, int op, void *data)
diff --git a/lib/librte_ether/rte_ethdev_driver.h b/lib/librte_ether/rte_ethdev_driver.h
index 45f08c65e..4896cea93 100644
--- a/lib/librte_ether/rte_ethdev_driver.h
+++ b/lib/librte_ether/rte_ethdev_driver.h
@@ -125,6 +125,63 @@  rte_eth_dma_zone_reserve(const struct rte_eth_dev *eth_dev, const char *name,
 			 uint16_t queue_id, size_t size,
 			 unsigned align, int socket_id);
 
+
+typedef int (*ethdev_init_t)(struct rte_eth_dev *ethdev, void *init_params);
+typedef int (*ethdev_bus_specific_init)(struct rte_eth_dev *ethdev,
+	void *bus_specific_init_params);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * PMD helper function for the creation of a new ethdev ports.
+ *
+ * @param device
+ *  rte_device handle.
+ * @param	name
+ *  port name.
+ * @param priv_data_size
+ *  size of private data required for port.
+ * @param bus_specific_init
+ *  port bus specific initialisation callback function
+ * @param bus_init_params
+ *  port bus specific initialisation parameters
+ * @param ethdev_init
+ *  device specific port initialization callback function
+ * @param init_params
+ *  port initialisation parameters
+ *
+ * @return
+ *   Negative errno value on error, 0 on success.
+ */
+int __rte_experimental
+rte_eth_dev_create(struct rte_device *device, const char *name,
+	size_t priv_data_size,
+	ethdev_bus_specific_init bus_specific_init, void *bus_init_params,
+	ethdev_init_t ethdev_init, void *init_params);
+
+
+typedef int (*ethdev_uninit_t)(struct rte_eth_dev *ethdev);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * PMD helper function for cleaing up the resources of a ethdev port on it's
+ * destruction.
+ *
+ * @param ethdev
+ *   ethdev handle of port.
+ * @param ethdev
+ *   device specific port un-initialise callback function
+ *
+ * @return
+ *   Negative errno value on error, 0 on success.
+ */
+int __rte_experimental
+rte_eth_dev_destroy(struct rte_eth_dev *ethdev,
+	ethdev_uninit_t ethdev_uninit);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/librte_ether/rte_ethdev_pci.h b/lib/librte_ether/rte_ethdev_pci.h
index 897ce5b41..8604a0474 100644
--- a/lib/librte_ether/rte_ethdev_pci.h
+++ b/lib/librte_ether/rte_ethdev_pci.h
@@ -70,6 +70,18 @@  rte_eth_copy_pci_info(struct rte_eth_dev *eth_dev,
 	eth_dev->data->numa_node = pci_dev->device.numa_node;
 }
 
+static inline int
+eth_dev_pci_specific_init(struct rte_eth_dev *eth_dev, void *bus_device) {
+	struct rte_pci_device *pci_dev = bus_device;
+
+	if (!pci_dev)
+		return -ENODEV;
+
+	rte_eth_copy_pci_info(eth_dev, pci_dev);
+
+	return 0;
+}
+
 /**
  * @internal
  * Allocates a new ethdev slot for an ethernet device and returns the pointer
diff --git a/lib/librte_ether/rte_ethdev_representor.h b/lib/librte_ether/rte_ethdev_representor.h
new file mode 100644
index 000000000..cbc1f2855
--- /dev/null
+++ b/lib/librte_ether/rte_ethdev_representor.h
@@ -0,0 +1,28 @@ 
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Intel Corporation.
+ */
+
+
+#ifndef _RTE_ETHDEV_REPRESENTOR_H_
+#define _RTE_ETHDEV_REPRESENTOR_H_
+
+#include <rte_ethdev_driver.h>
+
+static int
+eth_dev_representor_port_init(struct rte_eth_dev *ethdev, void *init_params)
+{
+	struct rte_eth_dev *base_ethdev = init_params;
+
+	if (!ethdev || !base_ethdev)
+		return -ENODEV;
+
+	/** representor shares same driver as it's base device */
+	ethdev->device->driver = base_ethdev->device->driver;
+
+	/** representor inherits the switch id of it's base device */
+	ethdev->data->switch_id = base_ethdev->data->switch_id;
+
+	return 0;
+}
+
+#endif /* _RTE_ETHDEV_REPRESENTOR_H_ */
diff --git a/lib/librte_ether/rte_ethdev_version.map b/lib/librte_ether/rte_ethdev_version.map
index 87f02fb74..48b08bc36 100644
--- a/lib/librte_ether/rte_ethdev_version.map
+++ b/lib/librte_ether/rte_ethdev_version.map
@@ -230,3 +230,11 @@  EXPERIMENTAL {
 	rte_mtr_stats_update;
 
 } DPDK_17.11;
+
+EXPERIMENTAL {
+	global:
+
+	rte_eth_dev_create;
+	rte_eth_dev_destroy;
+
+} DPDK_18.05;