add top-level SPDX license tag
[dpdk.git] / lib / librte_ethdev / rte_ethdev_pci.h
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2017 Brocade Communications Systems, Inc.
3  *   Author: Jan Blunck <jblunck@infradead.org>
4  *
5  *   Redistribution and use in source and binary forms, with or without
6  *   modification, are permitted provided that the following conditions
7  *   are met:
8  *
9  *     * Redistributions of source code must retain the above copyright
10  *       notice, this list of conditions and the following disclaimer.
11  *     * Redistributions in binary form must reproduce the above copyright
12  *       notice, this list of conditions and the following disclaimer in
13  *       the documentation and/or other materials provided with the
14  *       distribution.
15  *     * Neither the name of the copyright holder nor the names of its
16  *       contributors may be used to endorse or promote products derived
17  *       from this software without specific prior written permission.
18  *
19  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31
32 #ifndef _RTE_ETHDEV_PCI_H_
33 #define _RTE_ETHDEV_PCI_H_
34
35 #include <rte_malloc.h>
36 #include <rte_pci.h>
37 #include <rte_bus_pci.h>
38 #include <rte_config.h>
39 #include <rte_ethdev_driver.h>
40
41 /**
42  * Copy pci device info to the Ethernet device data.
43  * Shared memory (eth_dev->data) only updated by primary process, so it is safe
44  * to call this function from both primary and secondary processes.
45  *
46  * @param eth_dev
47  * The *eth_dev* pointer is the address of the *rte_eth_dev* structure.
48  * @param pci_dev
49  * The *pci_dev* pointer is the address of the *rte_pci_device* structure.
50  */
51 static inline void
52 rte_eth_copy_pci_info(struct rte_eth_dev *eth_dev,
53         struct rte_pci_device *pci_dev)
54 {
55         if ((eth_dev == NULL) || (pci_dev == NULL)) {
56                 RTE_ETHDEV_LOG(ERR, "NULL pointer eth_dev=%p pci_dev=%p",
57                         (void *)eth_dev, (void *)pci_dev);
58                 return;
59         }
60
61         eth_dev->intr_handle = &pci_dev->intr_handle;
62
63         if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
64                 eth_dev->data->dev_flags = 0;
65                 if (pci_dev->driver->drv_flags & RTE_PCI_DRV_INTR_LSC)
66                         eth_dev->data->dev_flags |= RTE_ETH_DEV_INTR_LSC;
67                 if (pci_dev->driver->drv_flags & RTE_PCI_DRV_INTR_RMV)
68                         eth_dev->data->dev_flags |= RTE_ETH_DEV_INTR_RMV;
69
70                 eth_dev->data->kdrv = pci_dev->kdrv;
71                 eth_dev->data->numa_node = pci_dev->device.numa_node;
72         }
73 }
74
75 static inline int
76 eth_dev_pci_specific_init(struct rte_eth_dev *eth_dev, void *bus_device) {
77         struct rte_pci_device *pci_dev = bus_device;
78
79         if (!pci_dev)
80                 return -ENODEV;
81
82         rte_eth_copy_pci_info(eth_dev, pci_dev);
83
84         return 0;
85 }
86
87 /**
88  * @internal
89  * Allocates a new ethdev slot for an ethernet device and returns the pointer
90  * to that slot for the driver to use.
91  *
92  * @param dev
93  *      Pointer to the PCI device
94  *
95  * @param private_data_size
96  *      Size of private data structure
97  *
98  * @return
99  *      A pointer to a rte_eth_dev or NULL if allocation failed.
100  */
101 static inline struct rte_eth_dev *
102 rte_eth_dev_pci_allocate(struct rte_pci_device *dev, size_t private_data_size)
103 {
104         struct rte_eth_dev *eth_dev;
105         const char *name;
106
107         if (!dev)
108                 return NULL;
109
110         name = dev->device.name;
111
112         if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
113                 eth_dev = rte_eth_dev_allocate(name);
114                 if (!eth_dev)
115                         return NULL;
116
117                 if (private_data_size) {
118                         eth_dev->data->dev_private = rte_zmalloc_socket(name,
119                                 private_data_size, RTE_CACHE_LINE_SIZE,
120                                 dev->device.numa_node);
121                         if (!eth_dev->data->dev_private) {
122                                 rte_eth_dev_release_port(eth_dev);
123                                 return NULL;
124                         }
125                 }
126         } else {
127                 eth_dev = rte_eth_dev_attach_secondary(name);
128                 if (!eth_dev)
129                         return NULL;
130         }
131
132         eth_dev->device = &dev->device;
133         rte_eth_copy_pci_info(eth_dev, dev);
134         return eth_dev;
135 }
136
137 static inline void
138 rte_eth_dev_pci_release(struct rte_eth_dev *eth_dev)
139 {
140         eth_dev->device = NULL;
141         eth_dev->intr_handle = NULL;
142
143         /* free ether device */
144         rte_eth_dev_release_port(eth_dev);
145 }
146
147 typedef int (*eth_dev_pci_callback_t)(struct rte_eth_dev *eth_dev);
148
149 /**
150  * @internal
151  * Wrapper for use by pci drivers in a .probe function to attach to a ethdev
152  * interface.
153  */
154 static inline int
155 rte_eth_dev_pci_generic_probe(struct rte_pci_device *pci_dev,
156         size_t private_data_size, eth_dev_pci_callback_t dev_init)
157 {
158         struct rte_eth_dev *eth_dev;
159         int ret;
160
161         eth_dev = rte_eth_dev_pci_allocate(pci_dev, private_data_size);
162         if (!eth_dev)
163                 return -ENOMEM;
164
165         RTE_FUNC_PTR_OR_ERR_RET(*dev_init, -EINVAL);
166         ret = dev_init(eth_dev);
167         if (ret)
168                 rte_eth_dev_pci_release(eth_dev);
169         else
170                 rte_eth_dev_probing_finish(eth_dev);
171
172         return ret;
173 }
174
175 /**
176  * @internal
177  * Wrapper for use by pci drivers in a .remove function to detach a ethdev
178  * interface.
179  */
180 static inline int
181 rte_eth_dev_pci_generic_remove(struct rte_pci_device *pci_dev,
182         eth_dev_pci_callback_t dev_uninit)
183 {
184         struct rte_eth_dev *eth_dev;
185         int ret;
186
187         eth_dev = rte_eth_dev_allocated(pci_dev->device.name);
188         if (!eth_dev)
189                 return 0;
190
191         if (dev_uninit) {
192                 ret = dev_uninit(eth_dev);
193                 if (ret)
194                         return ret;
195         }
196
197         rte_eth_dev_pci_release(eth_dev);
198         return 0;
199 }
200
201 #endif /* _RTE_ETHDEV_PCI_H_ */