xref: /dpdk/lib/ethdev/ethdev_pci.h (revision 719834a6849e1daf4a70ff7742bbcc3ae7e25607)
199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
299a2dd95SBruce Richardson  * Copyright(c) 2017 Brocade Communications Systems, Inc.
399a2dd95SBruce Richardson  *   Author: Jan Blunck <jblunck@infradead.org>
499a2dd95SBruce Richardson  */
599a2dd95SBruce Richardson 
699a2dd95SBruce Richardson #ifndef _RTE_ETHDEV_PCI_H_
799a2dd95SBruce Richardson #define _RTE_ETHDEV_PCI_H_
899a2dd95SBruce Richardson 
999a2dd95SBruce Richardson #include <rte_malloc.h>
1099a2dd95SBruce Richardson #include <rte_pci.h>
111f37cb2bSDavid Marchand #include <bus_pci_driver.h>
1299a2dd95SBruce Richardson #include <rte_config.h>
1399a2dd95SBruce Richardson #include <ethdev_driver.h>
1499a2dd95SBruce Richardson 
15*719834a6SMattias Rönnblom #ifdef __cplusplus
16*719834a6SMattias Rönnblom extern "C" {
17*719834a6SMattias Rönnblom #endif
18*719834a6SMattias Rönnblom 
1999a2dd95SBruce Richardson /**
2099a2dd95SBruce Richardson  * Copy pci device info to the Ethernet device data.
2199a2dd95SBruce Richardson  * Shared memory (eth_dev->data) only updated by primary process, so it is safe
2299a2dd95SBruce Richardson  * to call this function from both primary and secondary processes.
2399a2dd95SBruce Richardson  *
2499a2dd95SBruce Richardson  * @param eth_dev
2599a2dd95SBruce Richardson  * The *eth_dev* pointer is the address of the *rte_eth_dev* structure.
2699a2dd95SBruce Richardson  * @param pci_dev
2799a2dd95SBruce Richardson  * The *pci_dev* pointer is the address of the *rte_pci_device* structure.
2899a2dd95SBruce Richardson  */
2999a2dd95SBruce Richardson static inline void
3099a2dd95SBruce Richardson rte_eth_copy_pci_info(struct rte_eth_dev *eth_dev,
3199a2dd95SBruce Richardson 	struct rte_pci_device *pci_dev)
3299a2dd95SBruce Richardson {
3399a2dd95SBruce Richardson 	if ((eth_dev == NULL) || (pci_dev == NULL)) {
340e21c7c0SDavid Marchand 		RTE_ETHDEV_LOG_LINE(ERR, "NULL pointer eth_dev=%p pci_dev=%p",
3599a2dd95SBruce Richardson 			(void *)eth_dev, (void *)pci_dev);
3699a2dd95SBruce Richardson 		return;
3799a2dd95SBruce Richardson 	}
3899a2dd95SBruce Richardson 
39d61138d4SHarman Kalra 	eth_dev->intr_handle = pci_dev->intr_handle;
4099a2dd95SBruce Richardson 
4199a2dd95SBruce Richardson 	if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
4299a2dd95SBruce Richardson 		eth_dev->data->dev_flags = 0;
4399a2dd95SBruce Richardson 		if (pci_dev->driver->drv_flags & RTE_PCI_DRV_INTR_LSC)
4499a2dd95SBruce Richardson 			eth_dev->data->dev_flags |= RTE_ETH_DEV_INTR_LSC;
4599a2dd95SBruce Richardson 		if (pci_dev->driver->drv_flags & RTE_PCI_DRV_INTR_RMV)
4699a2dd95SBruce Richardson 			eth_dev->data->dev_flags |= RTE_ETH_DEV_INTR_RMV;
4799a2dd95SBruce Richardson 
4899a2dd95SBruce Richardson 		eth_dev->data->numa_node = pci_dev->device.numa_node;
4999a2dd95SBruce Richardson 	}
5099a2dd95SBruce Richardson }
5199a2dd95SBruce Richardson 
5299a2dd95SBruce Richardson static inline int
535ed2a2d4SBruce Richardson eth_dev_pci_specific_init(struct rte_eth_dev *eth_dev, void *bus_device)
545ed2a2d4SBruce Richardson {
555ed2a2d4SBruce Richardson 	struct rte_pci_device *pci_dev = (struct rte_pci_device *)bus_device;
5699a2dd95SBruce Richardson 
5799a2dd95SBruce Richardson 	if (!pci_dev)
5899a2dd95SBruce Richardson 		return -ENODEV;
5999a2dd95SBruce Richardson 
6099a2dd95SBruce Richardson 	rte_eth_copy_pci_info(eth_dev, pci_dev);
6199a2dd95SBruce Richardson 
6299a2dd95SBruce Richardson 	return 0;
6399a2dd95SBruce Richardson }
6499a2dd95SBruce Richardson 
6599a2dd95SBruce Richardson /**
6699a2dd95SBruce Richardson  * @internal
670d9f56a8SAndrew Rybchenko  * Allocates a new ethdev slot for an Ethernet device and returns the pointer
6899a2dd95SBruce Richardson  * to that slot for the driver to use.
6999a2dd95SBruce Richardson  *
7099a2dd95SBruce Richardson  * @param dev
7199a2dd95SBruce Richardson  *	Pointer to the PCI device
7299a2dd95SBruce Richardson  *
7399a2dd95SBruce Richardson  * @param private_data_size
7499a2dd95SBruce Richardson  *	Size of private data structure
7599a2dd95SBruce Richardson  *
7699a2dd95SBruce Richardson  * @return
7799a2dd95SBruce Richardson  *	A pointer to a rte_eth_dev or NULL if allocation failed.
7899a2dd95SBruce Richardson  */
7999a2dd95SBruce Richardson static inline struct rte_eth_dev *
8099a2dd95SBruce Richardson rte_eth_dev_pci_allocate(struct rte_pci_device *dev, size_t private_data_size)
8199a2dd95SBruce Richardson {
8299a2dd95SBruce Richardson 	struct rte_eth_dev *eth_dev;
8399a2dd95SBruce Richardson 	const char *name;
8499a2dd95SBruce Richardson 
8599a2dd95SBruce Richardson 	if (!dev)
8699a2dd95SBruce Richardson 		return NULL;
8799a2dd95SBruce Richardson 
8899a2dd95SBruce Richardson 	name = dev->device.name;
8999a2dd95SBruce Richardson 
9099a2dd95SBruce Richardson 	if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
9199a2dd95SBruce Richardson 		eth_dev = rte_eth_dev_allocate(name);
9299a2dd95SBruce Richardson 		if (!eth_dev)
9399a2dd95SBruce Richardson 			return NULL;
9499a2dd95SBruce Richardson 
9599a2dd95SBruce Richardson 		if (private_data_size) {
96ed34d87dSBruce Richardson 			/* Try and alloc the private-data structure on socket local to the device */
9799a2dd95SBruce Richardson 			eth_dev->data->dev_private = rte_zmalloc_socket(name,
9899a2dd95SBruce Richardson 				private_data_size, RTE_CACHE_LINE_SIZE,
9999a2dd95SBruce Richardson 				dev->device.numa_node);
100ed34d87dSBruce Richardson 
101ed34d87dSBruce Richardson 			/* if cannot allocate memory on the socket local to the device
102ed34d87dSBruce Richardson 			 * use rte_malloc to allocate memory on some other socket, if available.
103ed34d87dSBruce Richardson 			 */
104ed34d87dSBruce Richardson 			if (eth_dev->data->dev_private == NULL) {
105ed34d87dSBruce Richardson 				eth_dev->data->dev_private = rte_zmalloc(name,
106ed34d87dSBruce Richardson 						private_data_size, RTE_CACHE_LINE_SIZE);
107ed34d87dSBruce Richardson 
108ed34d87dSBruce Richardson 				if (eth_dev->data->dev_private == NULL) {
10999a2dd95SBruce Richardson 					rte_eth_dev_release_port(eth_dev);
11099a2dd95SBruce Richardson 					return NULL;
11199a2dd95SBruce Richardson 				}
112ed34d87dSBruce Richardson 				/* got memory, but not local, so issue warning */
113ed34d87dSBruce Richardson 				RTE_ETHDEV_LOG_LINE(WARNING,
114ed34d87dSBruce Richardson 						"Private data for ethdev '%s' not allocated on local NUMA node %d",
115ed34d87dSBruce Richardson 						dev->device.name, dev->device.numa_node);
116ed34d87dSBruce Richardson 			}
11799a2dd95SBruce Richardson 		}
11899a2dd95SBruce Richardson 	} else {
11999a2dd95SBruce Richardson 		eth_dev = rte_eth_dev_attach_secondary(name);
12099a2dd95SBruce Richardson 		if (!eth_dev)
12199a2dd95SBruce Richardson 			return NULL;
12299a2dd95SBruce Richardson 	}
12399a2dd95SBruce Richardson 
12499a2dd95SBruce Richardson 	eth_dev->device = &dev->device;
12599a2dd95SBruce Richardson 	rte_eth_copy_pci_info(eth_dev, dev);
12699a2dd95SBruce Richardson 	return eth_dev;
12799a2dd95SBruce Richardson }
12899a2dd95SBruce Richardson 
12999a2dd95SBruce Richardson typedef int (*eth_dev_pci_callback_t)(struct rte_eth_dev *eth_dev);
13099a2dd95SBruce Richardson 
13199a2dd95SBruce Richardson /**
13299a2dd95SBruce Richardson  * @internal
13399a2dd95SBruce Richardson  * Wrapper for use by pci drivers in a .probe function to attach to a ethdev
13499a2dd95SBruce Richardson  * interface.
13599a2dd95SBruce Richardson  */
13699a2dd95SBruce Richardson static inline int
13799a2dd95SBruce Richardson rte_eth_dev_pci_generic_probe(struct rte_pci_device *pci_dev,
13899a2dd95SBruce Richardson 	size_t private_data_size, eth_dev_pci_callback_t dev_init)
13999a2dd95SBruce Richardson {
14099a2dd95SBruce Richardson 	struct rte_eth_dev *eth_dev;
14199a2dd95SBruce Richardson 	int ret;
14299a2dd95SBruce Richardson 
1431f00a6a0SKaiyu Zhang 	if (*dev_init == NULL)
1441f00a6a0SKaiyu Zhang 		return -EINVAL;
1451f00a6a0SKaiyu Zhang 
14699a2dd95SBruce Richardson 	eth_dev = rte_eth_dev_pci_allocate(pci_dev, private_data_size);
14799a2dd95SBruce Richardson 	if (!eth_dev)
14899a2dd95SBruce Richardson 		return -ENOMEM;
14999a2dd95SBruce Richardson 
15099a2dd95SBruce Richardson 	ret = dev_init(eth_dev);
15199a2dd95SBruce Richardson 	if (ret)
15299a2dd95SBruce Richardson 		rte_eth_dev_release_port(eth_dev);
15399a2dd95SBruce Richardson 	else
15499a2dd95SBruce Richardson 		rte_eth_dev_probing_finish(eth_dev);
15599a2dd95SBruce Richardson 
15699a2dd95SBruce Richardson 	return ret;
15799a2dd95SBruce Richardson }
15899a2dd95SBruce Richardson 
15999a2dd95SBruce Richardson /**
16099a2dd95SBruce Richardson  * @internal
16199a2dd95SBruce Richardson  * Wrapper for use by pci drivers in a .remove function to detach a ethdev
16299a2dd95SBruce Richardson  * interface.
16399a2dd95SBruce Richardson  */
16499a2dd95SBruce Richardson static inline int
16599a2dd95SBruce Richardson rte_eth_dev_pci_generic_remove(struct rte_pci_device *pci_dev,
16699a2dd95SBruce Richardson 	eth_dev_pci_callback_t dev_uninit)
16799a2dd95SBruce Richardson {
16899a2dd95SBruce Richardson 	struct rte_eth_dev *eth_dev;
16999a2dd95SBruce Richardson 	int ret;
17099a2dd95SBruce Richardson 
17199a2dd95SBruce Richardson 	eth_dev = rte_eth_dev_allocated(pci_dev->device.name);
17299a2dd95SBruce Richardson 	if (!eth_dev)
17399a2dd95SBruce Richardson 		return 0;
17499a2dd95SBruce Richardson 
17517faaed8SHuisong Li 	/*
17617faaed8SHuisong Li 	 * In secondary process, a released eth device can be found by its name
17717faaed8SHuisong Li 	 * in shared memory.
17817faaed8SHuisong Li 	 * If the state of the eth device is RTE_ETH_DEV_UNUSED, it means the
17917faaed8SHuisong Li 	 * eth device has been released.
18017faaed8SHuisong Li 	 */
18117faaed8SHuisong Li 	if (rte_eal_process_type() == RTE_PROC_SECONDARY &&
18217faaed8SHuisong Li 	    eth_dev->state == RTE_ETH_DEV_UNUSED)
18317faaed8SHuisong Li 		return 0;
18417faaed8SHuisong Li 
18599a2dd95SBruce Richardson 	if (dev_uninit) {
18699a2dd95SBruce Richardson 		ret = dev_uninit(eth_dev);
18799a2dd95SBruce Richardson 		if (ret)
18899a2dd95SBruce Richardson 			return ret;
18999a2dd95SBruce Richardson 	}
19099a2dd95SBruce Richardson 
19199a2dd95SBruce Richardson 	rte_eth_dev_release_port(eth_dev);
19299a2dd95SBruce Richardson 	return 0;
19399a2dd95SBruce Richardson }
19499a2dd95SBruce Richardson 
195dbf9fc1dSBrian Dooley #ifdef __cplusplus
196dbf9fc1dSBrian Dooley }
197dbf9fc1dSBrian Dooley #endif
198dbf9fc1dSBrian Dooley 
19999a2dd95SBruce Richardson #endif /* _RTE_ETHDEV_PCI_H_ */
200