> -----Original Message----- > From: Tetsuya Mukawa [mailto:mukawa at igel.co.jp] > Sent: Thursday, February 19, 2015 2:50 AM > To: dev at dpdk.org > Cc: Qiu, Michael; Iremonger, Bernard; thomas.monjalon at 6wind.com; Tetsuya > Mukawa > Subject: [PATCH v9 07/14] eal,ethdev: Add a function and function pointers to > close ether device > > The patch adds function pointer to rte_pci_driver and eth_driver structure. > These function pointers > are used when ports are detached. > Also, the patch adds rte_eth_dev_uninit(). So far, it's not called by > anywhere, but it will be called > when port hotplug function is implemented. > > v9: > - Change parameter of pci_devuninit_t and rte_eth_dev_uninit. > - Remove code that initiaize callback of ethdev from > rte_eth_dev_uninit(). > - Add a function to create a unique device name. > (Thanks to Thomas Monjalon) > v6: > - Fix rte_eth_dev_uninit() to handle a return value of uninit > function of PMD. > v4: > - Add parameter checking. > - Change function names. > > Signed-off-by: Tetsuya Mukawa <mukawa at igel.co.jp> > --- > lib/librte_eal/common/include/rte_pci.h | 6 ++++ > lib/librte_ether/rte_ethdev.c | 62 > +++++++++++++++++++++++++++++++-- > lib/librte_ether/rte_ethdev.h | 24 +++++++++++++ > 3 files changed, 90 insertions(+), 2 deletions(-) > > diff --git a/lib/librte_eal/common/include/rte_pci.h > b/lib/librte_eal/common/include/rte_pci.h > index c609ef3..376f66a 100644 > --- a/lib/librte_eal/common/include/rte_pci.h > +++ b/lib/librte_eal/common/include/rte_pci.h > @@ -189,12 +189,18 @@ struct rte_pci_driver; typedef int > (pci_devinit_t)(struct rte_pci_driver *, > struct rte_pci_device *); > > /** > + * Uninitialisation function for the driver called during hotplugging. > + */ > +typedef int (pci_devuninit_t)(struct rte_pci_device *); > + > +/** > * A structure describing a PCI driver. > */ > struct rte_pci_driver { > TAILQ_ENTRY(rte_pci_driver) next; /**< Next in list. */ > const char *name; /**< Driver name. */ > pci_devinit_t *devinit; /**< Device init. function. */ > + pci_devuninit_t *devuninit; /**< Device uninit function. */ > struct rte_pci_id *id_table; /**< ID table, NULL terminated. > */ > uint32_t drv_flags; /**< Flags contolling handling > of device. */ > }; > diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c > index be5aa18..ef5d226 > 100644 > --- a/lib/librte_ether/rte_ethdev.c > +++ b/lib/librte_ether/rte_ethdev.c > @@ -266,6 +266,24 @@ rte_eth_dev_release_port(struct rte_eth_dev *eth_dev) > return 0; > } > > +static inline int > +rte_eth_dev_create_unique_device_name(char *name, > + struct rte_pci_device *pci_dev) > +{ > + int ret; > + > + if ((name == NULL) || (pci_dev == NULL)) > + return -EINVAL; > + Hi Tetsuya,
It would be safer to pass in the size of the name buffer and use it in the snprintf() call . Regards, Bernard. > + ret = snprintf(name, RTE_ETH_NAME_MAX_LEN, "%d:%d.%d", > + pci_dev->addr.bus, pci_dev->addr.devid, > + pci_dev->addr.function); > + if (ret < 0) > + return ret; > + > + return 0; > +} > + > static int > rte_eth_dev_init(struct rte_pci_driver *pci_drv, > struct rte_pci_device *pci_dev) > @@ -279,8 +297,7 @@ rte_eth_dev_init(struct rte_pci_driver *pci_drv, > eth_drv = (struct eth_driver *)pci_drv; > > /* Create unique Ethernet device name using PCI address */ > - snprintf(ethdev_name, RTE_ETH_NAME_MAX_LEN, "%d:%d.%d", > - pci_dev->addr.bus, pci_dev->addr.devid, > pci_dev->addr.function); > + rte_eth_dev_create_unique_device_name(ethdev_name, pci_dev); > > eth_dev = rte_eth_dev_allocate(ethdev_name); > if (eth_dev == NULL) > @@ -321,6 +338,46 @@ rte_eth_dev_init(struct rte_pci_driver *pci_drv, > return diag; > } > > +static int > +rte_eth_dev_uninit(struct rte_pci_device *pci_dev) { > + const struct eth_driver *eth_drv; > + struct rte_eth_dev *eth_dev; > + char ethdev_name[RTE_ETH_NAME_MAX_LEN]; > + int ret; > + > + if (pci_dev == NULL) > + return -EINVAL; > + > + /* Create unique Ethernet device name using PCI address */ > + rte_eth_dev_create_unique_device_name(ethdev_name, pci_dev); > + > + eth_dev = rte_eth_dev_allocated(ethdev_name); > + if (eth_dev == NULL) > + return -ENODEV; > + > + eth_drv = (const struct eth_driver *)pci_dev->driver; > + > + /* Invoke PMD device uninit function */ > + if (*eth_drv->eth_dev_uninit) { > + ret = (*eth_drv->eth_dev_uninit)(eth_drv, eth_dev); > + if (ret) > + return ret; > + } > + > + /* free ether device */ > + rte_eth_dev_release_port(eth_dev); > + > + if (rte_eal_process_type() == RTE_PROC_PRIMARY) > + rte_free(eth_dev->data->dev_private); > + > + eth_dev->pci_dev = NULL; > + eth_dev->driver = NULL; > + eth_dev->data = NULL; > + > + return 0; > +} > + > /** > * Register an Ethernet [Poll Mode] driver. > * > @@ -339,6 +396,7 @@ void > rte_eth_driver_register(struct eth_driver *eth_drv) { > eth_drv->pci_drv.devinit = rte_eth_dev_init; > + eth_drv->pci_drv.devuninit = rte_eth_dev_uninit; > rte_eal_pci_register(ð_drv->pci_drv); > } > > diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h > index 28ecafd..f403780 > 100644 > --- a/lib/librte_ether/rte_ethdev.h > +++ b/lib/librte_ether/rte_ethdev.h > @@ -1677,6 +1677,27 @@ typedef int (*eth_dev_init_t)(struct eth_driver > *eth_drv, > > /** > * @internal > + * Finalization function of an Ethernet driver invoked for each > +matching > + * Ethernet PCI device detected during the PCI closing phase. > + * > + * @param eth_drv > + * The pointer to the [matching] Ethernet driver structure supplied by > + * the PMD when it registered itself. > + * @param eth_dev > + * The *eth_dev* pointer is the address of the *rte_eth_dev* structure > + * associated with the matching device and which have been [automatically] > + * allocated in the *rte_eth_devices* array. > + * @return > + * - 0: Success, the device is properly finalized by the driver. > + * In particular, the driver MUST free the *dev_ops* pointer > + * of the *eth_dev* structure. > + * - <0: Error code of the device initialization failure. > + */ > +typedef int (*eth_dev_uninit_t)(const struct eth_driver *eth_drv, > + struct rte_eth_dev *eth_dev); > + > +/** > + * @internal > * The structure associated with a PMD Ethernet driver. > * > * Each Ethernet driver acts as a PCI driver and is represented by a generic > @@ -1686,11 +1707,14 @@ > typedef int (*eth_dev_init_t)(struct eth_driver *eth_drv, > * > * - The *eth_dev_init* function invoked for each matching PCI device. > * > + * - The *eth_dev_uninit* function invoked for each matching PCI device. > + * > * - The size of the private data to allocate for each matching device. > */ > struct eth_driver { > struct rte_pci_driver pci_drv; /**< The PMD is also a PCI driver. */ > eth_dev_init_t eth_dev_init; /**< Device init function. */ > + eth_dev_uninit_t eth_dev_uninit; /**< Device uninit function. */ > unsigned int dev_private_size; /**< Size of device private data. */ > }; > > -- > 1.9.1