ena: Amazon Elastic Network Adapter (ENA) native driver
[vpp.git] / src / plugins / dev_ena / reg.c
1 /* SPDX-License-Identifier: Apache-2.0
2  * Copyright(c) 2023 Cisco Systems, Inc.
3  */
4
5 #include <vlib/vlib.h>
6 #include <vnet/dev/dev.h>
7
8 #include <dev_ena/ena.h>
9 #include <dev_ena/ena_inlines.h>
10
11 VLIB_REGISTER_LOG_CLASS (ena_log, static) = {
12   .class_name = "ena",
13   .subclass_name = "reg",
14 };
15
16 static vnet_dev_rv_t
17 ena_err (vnet_dev_t *dev, vnet_dev_rv_t rv, char *fmt, ...)
18 {
19   va_list va;
20   u8 *s;
21
22   va_start (va, fmt);
23   s = va_format (0, fmt, &va);
24   va_end (va);
25   log_err (dev, "%v", s);
26   vec_free (s);
27   return rv;
28 }
29
30 static u8 *
31 format_ena_reg_name (u8 *s, va_list *args)
32 {
33   int offset = va_arg (*args, int);
34
35   char *reg_names[] = {
36 #define _(o, r, rn, m) [(o) >> 2] = #rn,
37     foreach_ena_reg
38 #undef _
39   };
40
41   offset >>= 2;
42
43   if (offset < 0 || offset >= ARRAY_LEN (reg_names) || reg_names[offset] == 0)
44     return format (s, "(unknown)");
45   return format (s, "%s", reg_names[offset]);
46 }
47
48 void
49 ena_reg_write (vnet_dev_t *dev, ena_reg_t reg, void *v)
50 {
51   ena_device_t *ed = vnet_dev_get_data (dev);
52   u32 *p = (u32 *) ((u8 *) ed->reg_bar + reg);
53   u32 val = *(u32 *) v;
54   log_debug (dev, "%s: reg %U (0x%02x) value 0x%08x", __func__,
55              format_ena_reg_name, reg, reg, val);
56   __atomic_store_n (p, val, __ATOMIC_RELEASE);
57 }
58
59 void
60 ena_reg_set_dma_addr (vlib_main_t *vm, vnet_dev_t *dev, u32 rlo, u32 rhi,
61                       void *p)
62 {
63   uword pa = vnet_dev_get_dma_addr (vm, dev, p);
64   u32 reg = (u32) pa;
65   ena_reg_write (dev, rlo, &reg);
66   reg = pa >> 32;
67   ena_reg_write (dev, rhi, &reg);
68 }
69
70 void
71 ena_reg_read (vnet_dev_t *dev, ena_reg_t reg, const void *v)
72 {
73   ena_device_t *ed = vnet_dev_get_data (dev);
74   vlib_main_t *vm = vlib_get_main ();
75   u32 rv;
76   f64 dt = 0, t0;
77
78   if (ed->readless == 0)
79     {
80       rv =
81         __atomic_load_n ((u32 *) ((u8 *) ed->reg_bar + reg), __ATOMIC_SEQ_CST);
82     }
83   else
84     {
85       u32 *p = (u32 *) ((u8 *) ed->reg_bar + ENA_REG_MMIO_REG_READ);
86
87       ena_reg_mmio_reg_read_t rr = { .reg_off = reg, .req_id = 1 };
88       ed->mmio_resp->req_id = 0;
89       ed->mmio_resp->reg_val = ~0;
90
91       __atomic_store_n (p, rr.as_u32, __ATOMIC_RELEASE);
92
93       t0 = vlib_time_now (vm);
94       while (ed->mmio_resp->req_id == 0 && dt < 0.2)
95         {
96           CLIB_PAUSE ();
97           dt = vlib_time_now (vm) - t0;
98         }
99
100       rv = ed->mmio_resp->reg_val;
101     }
102
103   log_debug (dev, "%s: reg %U (0x%02x) value 0x%08x dt %.3fs", __func__,
104              format_ena_reg_name, reg, reg, rv, dt);
105   *(u32 *) v = rv;
106 }
107
108 vnet_dev_rv_t
109 ena_reg_reset (vlib_main_t *vm, vnet_dev_t *dev, ena_reset_reason_t reason)
110 {
111   ena_device_t *ed = vnet_dev_get_data (dev);
112   ena_reg_version_t ver;
113   ena_reg_controller_version_t ctrl_ver;
114   ena_reg_caps_t caps = {};
115   ena_reg_dev_sts_t dev_sts = {};
116   ena_reg_dev_ctl_t reset_start = { .dev_reset = 1, .reset_reason = reason };
117
118   if (ed->readless)
119     ena_reg_set_dma_addr (vm, dev, ENA_REG_MMIO_RESP_LO, ENA_REG_MMIO_RESP_HI,
120                           ed->mmio_resp);
121
122   ena_reg_read (dev, ENA_REG_DEV_STS, &dev_sts);
123   ena_reg_read (dev, ENA_REG_CAPS, &caps);
124
125   if (caps.as_u32 == ~0 && dev_sts.as_u32 == ~0)
126     return ena_err (dev, VNET_DEV_ERR_BUS, "failed to read regs");
127
128   if (dev_sts.ready == 0)
129     return VNET_DEV_ERR_NOT_READY;
130
131   log_debug (dev, "reg_reset: reset timeout is %u", caps.reset_timeout);
132
133   ena_reg_write (dev, ENA_REG_DEV_CTL, &reset_start);
134
135   if (ed->readless)
136     ena_reg_set_dma_addr (vm, dev, ENA_REG_MMIO_RESP_LO, ENA_REG_MMIO_RESP_HI,
137                           ed->mmio_resp);
138
139   while (1)
140     {
141       int i = 0;
142       ena_reg_read (dev, ENA_REG_DEV_STS, &dev_sts);
143       if (dev_sts.reset_in_progress)
144         break;
145       if (i++ == 20)
146         return ena_err (dev, VNET_DEV_ERR_BUS, "failed to initiate reset");
147       vlib_process_suspend (vm, 0.001);
148     }
149
150   ena_reg_write (dev, ENA_REG_DEV_CTL, &(ena_reg_dev_ctl_t){});
151
152   return 0;
153   while (1)
154     {
155       int i = 0;
156       ena_reg_read (dev, ENA_REG_DEV_STS, &dev_sts);
157       if (dev_sts.reset_in_progress == 0)
158         break;
159       if (i++ == 20)
160         return ena_err (dev, VNET_DEV_ERR_BUS, "failed to complete reset");
161       vlib_process_suspend (vm, 0.001);
162     }
163
164   ena_reg_read (dev, ENA_REG_VERSION, &ver);
165   ena_reg_read (dev, ENA_REG_CONTROLLER_VERSION, &ctrl_ver);
166
167   log_info (dev, "version %u.%u controller_version %u.%u.%u impl_id %u\n",
168             ver.major, ver.minor, ctrl_ver.major, ctrl_ver.minor,
169             ctrl_ver.subminor, ctrl_ver.impl_id);
170
171   return 0;
172 }