net/enetc: add PMD with basic operations
[dpdk.git] / drivers / net / enetc / enetc_ethdev.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright 2018 NXP
3  */
4
5 #include <stdbool.h>
6 #include <rte_ethdev_pci.h>
7
8 #include "enetc_logs.h"
9 #include "enetc.h"
10
11 int enetc_logtype_pmd;
12
13 /* Functions Prototypes */
14 static int enetc_dev_configure(struct rte_eth_dev *dev);
15 static int enetc_dev_start(struct rte_eth_dev *dev);
16 static void enetc_dev_stop(struct rte_eth_dev *dev);
17 static void enetc_dev_close(struct rte_eth_dev *dev);
18 static void enetc_dev_infos_get(struct rte_eth_dev *dev,
19                                 struct rte_eth_dev_info *dev_info);
20 static int enetc_link_update(struct rte_eth_dev *dev, int wait_to_complete);
21 static int enetc_hardware_init(struct enetc_eth_hw *hw);
22
23 /*
24  * The set of PCI devices this driver supports
25  */
26 static const struct rte_pci_id pci_id_enetc_map[] = {
27         { RTE_PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, ENETC_DEV_ID) },
28         { RTE_PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, ENETC_DEV_ID_VF) },
29         { .vendor_id = 0, /* sentinel */ },
30 };
31
32 /* Features supported by this driver */
33 static const struct eth_dev_ops enetc_ops = {
34         .dev_configure        = enetc_dev_configure,
35         .dev_start            = enetc_dev_start,
36         .dev_stop             = enetc_dev_stop,
37         .dev_close            = enetc_dev_close,
38         .link_update          = enetc_link_update,
39         .dev_infos_get        = enetc_dev_infos_get,
40 };
41
42 /**
43  * Initialisation of the enetc device
44  *
45  * @param eth_dev
46  *   - Pointer to the structure rte_eth_dev
47  *
48  * @return
49  *   - On success, zero.
50  *   - On failure, negative value.
51  */
52 static int
53 enetc_dev_init(struct rte_eth_dev *eth_dev)
54 {
55         int error = 0;
56         struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
57         struct enetc_eth_hw *hw =
58                 ENETC_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private);
59
60         PMD_INIT_FUNC_TRACE();
61         eth_dev->dev_ops = &enetc_ops;
62         eth_dev->rx_pkt_burst = NULL;
63         eth_dev->tx_pkt_burst = NULL;
64
65         /* Retrieving and storing the HW base address of device */
66         hw->hw.reg = (void *)pci_dev->mem_resource[0].addr;
67         hw->device_id = pci_dev->id.device_id;
68
69         error = enetc_hardware_init(hw);
70         if (error != 0) {
71                 ENETC_PMD_ERR("Hardware initialization failed");
72                 return -1;
73         }
74
75         /* Allocate memory for storing MAC addresses */
76         eth_dev->data->mac_addrs = rte_zmalloc("enetc_eth", ETHER_ADDR_LEN, 0);
77         if (!eth_dev->data->mac_addrs) {
78                 ENETC_PMD_ERR("Failed to allocate %d bytes needed to "
79                               "store MAC addresses",
80                               ETHER_ADDR_LEN * 1);
81                 error = -ENOMEM;
82                 return -1;
83         }
84
85         /* Copy the permanent MAC address */
86         ether_addr_copy((struct ether_addr *)hw->mac.addr,
87                         &eth_dev->data->mac_addrs[0]);
88
89         ENETC_PMD_DEBUG("port_id %d vendorID=0x%x deviceID=0x%x",
90                         eth_dev->data->port_id, pci_dev->id.vendor_id,
91                         pci_dev->id.device_id);
92         return 0;
93 }
94
95 static int
96 enetc_dev_uninit(struct rte_eth_dev *eth_dev)
97 {
98         PMD_INIT_FUNC_TRACE();
99         rte_free(eth_dev->data->mac_addrs);
100
101         return 0;
102 }
103
104 static int
105 enetc_dev_configure(struct rte_eth_dev *dev __rte_unused)
106 {
107         PMD_INIT_FUNC_TRACE();
108         return 0;
109 }
110
111 static int
112 enetc_dev_start(struct rte_eth_dev *dev)
113 {
114         struct enetc_eth_hw *hw =
115                 ENETC_DEV_PRIVATE_TO_HW(dev->data->dev_private);
116         uint32_t val;
117
118         PMD_INIT_FUNC_TRACE();
119         val = ENETC_REG_READ(ENETC_GET_HW_ADDR(hw->hw.port,
120                              ENETC_PM0_CMD_CFG));
121         ENETC_REG_WRITE(ENETC_GET_HW_ADDR(hw->hw.port, ENETC_PM0_CMD_CFG),
122                         val | ENETC_PM0_TX_EN | ENETC_PM0_RX_EN);
123
124         /* Enable port */
125         val = ENETC_REG_READ(ENETC_GET_HW_ADDR(hw->hw.port, ENETC_PMR));
126         ENETC_REG_WRITE(ENETC_GET_HW_ADDR(hw->hw.port, ENETC_PMR),
127                         val | ENETC_PMR_EN);
128
129         return 0;
130 }
131
132 static void
133 enetc_dev_stop(struct rte_eth_dev *dev)
134 {
135         struct enetc_eth_hw *hw =
136                 ENETC_DEV_PRIVATE_TO_HW(dev->data->dev_private);
137         uint32_t val;
138
139         PMD_INIT_FUNC_TRACE();
140         /* Disable port */
141         val = ENETC_REG_READ(ENETC_GET_HW_ADDR(hw->hw.port, ENETC_PMR));
142         ENETC_REG_WRITE(ENETC_GET_HW_ADDR(hw->hw.port, ENETC_PMR),
143                         val & (~ENETC_PMR_EN));
144
145         val = ENETC_REG_READ(ENETC_GET_HW_ADDR(hw->hw.port,
146                              ENETC_PM0_CMD_CFG));
147         ENETC_REG_WRITE(ENETC_GET_HW_ADDR(hw->hw.port, ENETC_PM0_CMD_CFG),
148                         val & (~(ENETC_PM0_TX_EN | ENETC_PM0_RX_EN)));
149 }
150
151 static void
152 enetc_dev_close(struct rte_eth_dev *dev __rte_unused)
153 {
154         PMD_INIT_FUNC_TRACE();
155 }
156
157 /* return 0 means link status changed, -1 means not changed */
158 static int
159 enetc_link_update(struct rte_eth_dev *dev, int wait_to_complete __rte_unused)
160 {
161         struct enetc_eth_hw *hw =
162                 ENETC_DEV_PRIVATE_TO_HW(dev->data->dev_private);
163         struct rte_eth_link link;
164         uint32_t status;
165
166         PMD_INIT_FUNC_TRACE();
167
168         memset(&link, 0, sizeof(link));
169
170         status = ENETC_REG_READ(ENETC_GET_HW_ADDR(hw->hw.port,
171                                 ENETC_PM0_STATUS));
172
173         if (status & ENETC_LINK_MODE)
174                 link.link_duplex = ETH_LINK_FULL_DUPLEX;
175         else
176                 link.link_duplex = ETH_LINK_HALF_DUPLEX;
177
178         if (status & ENETC_LINK_STATUS)
179                 link.link_status = ETH_LINK_UP;
180         else
181                 link.link_status = ETH_LINK_DOWN;
182
183         switch (status & ENETC_LINK_SPEED_MASK) {
184         case ENETC_LINK_SPEED_1G:
185                 link.link_speed = ETH_SPEED_NUM_1G;
186                 break;
187
188         case ENETC_LINK_SPEED_100M:
189                 link.link_speed = ETH_SPEED_NUM_100M;
190                 break;
191
192         default:
193         case ENETC_LINK_SPEED_10M:
194                 link.link_speed = ETH_SPEED_NUM_10M;
195         }
196
197         return rte_eth_linkstatus_set(dev, &link);
198 }
199
200 static int
201 enetc_hardware_init(struct enetc_eth_hw *hw)
202 {
203         uint32_t psipmr = 0;
204
205         PMD_INIT_FUNC_TRACE();
206         /* Calculating and storing the base HW addresses */
207         hw->hw.port = (void *)((size_t)hw->hw.reg + ENETC_PORT_BASE);
208         hw->hw.global = (void *)((size_t)hw->hw.reg + ENETC_GLOBAL_BASE);
209
210         /* Enabling Station Interface */
211         ENETC_REG_WRITE(ENETC_GET_HW_ADDR(hw->hw.reg, ENETC_SIMR),
212                                           ENETC_SIMR_EN);
213
214         /* Setting to accept broadcast packets for each inetrface */
215         psipmr |= ENETC_PSIPMR_SET_UP(0) | ENETC_PSIPMR_SET_MP(0) |
216                   ENETC_PSIPMR_SET_VLAN_MP(0);
217         psipmr |= ENETC_PSIPMR_SET_UP(1) | ENETC_PSIPMR_SET_MP(1) |
218                   ENETC_PSIPMR_SET_VLAN_MP(1);
219         psipmr |= ENETC_PSIPMR_SET_UP(2) | ENETC_PSIPMR_SET_MP(2) |
220                   ENETC_PSIPMR_SET_VLAN_MP(2);
221
222         ENETC_REG_WRITE(ENETC_GET_HW_ADDR(hw->hw.port, ENETC_PSIPMR),
223                         psipmr);
224
225         /* Enabling broadcast address */
226         ENETC_REG_WRITE(ENETC_GET_HW_ADDR(hw->hw.port, ENETC_PSIPMAR0(0)),
227                         0xFFFFFFFF);
228         ENETC_REG_WRITE(ENETC_GET_HW_ADDR(hw->hw.port, ENETC_PSIPMAR1(0)),
229                         0xFFFF << 16);
230
231         return 0;
232 }
233
234 static void
235 enetc_dev_infos_get(struct rte_eth_dev *dev __rte_unused,
236                     struct rte_eth_dev_info *dev_info)
237 {
238         PMD_INIT_FUNC_TRACE();
239         dev_info->max_rx_queues = MAX_RX_RINGS;
240         dev_info->max_tx_queues = MAX_TX_RINGS;
241         dev_info->max_rx_pktlen = 1500;
242 }
243
244 static int
245 enetc_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
246                            struct rte_pci_device *pci_dev)
247 {
248         return rte_eth_dev_pci_generic_probe(pci_dev,
249                                              sizeof(struct enetc_eth_adapter),
250                                              enetc_dev_init);
251 }
252
253 static int
254 enetc_pci_remove(struct rte_pci_device *pci_dev)
255 {
256         return rte_eth_dev_pci_generic_remove(pci_dev, enetc_dev_uninit);
257 }
258
259 static struct rte_pci_driver rte_enetc_pmd = {
260         .id_table = pci_id_enetc_map,
261         .drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_IOVA_AS_VA,
262         .probe = enetc_pci_probe,
263         .remove = enetc_pci_remove,
264 };
265
266 RTE_PMD_REGISTER_PCI(net_enetc, rte_enetc_pmd);
267 RTE_PMD_REGISTER_PCI_TABLE(net_enetc, pci_id_enetc_map);
268 RTE_PMD_REGISTER_KMOD_DEP(net_enetc, "* vfio-pci");
269
270 RTE_INIT(enetc_pmd_init_log)
271 {
272         enetc_logtype_pmd = rte_log_register("pmd.net.enetc");
273         if (enetc_logtype_pmd >= 0)
274                 rte_log_set_level(enetc_logtype_pmd, RTE_LOG_NOTICE);
275 }