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