xref: /illumos-gate/usr/src/uts/common/io/ena/ena_hw.c (revision c46e4de3)
1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright 2024 Oxide Computer Company
14  */
15 
16 #include "ena_hw.h"
17 #include "ena.h"
18 
19 uint32_t
ena_hw_bar_read32(const ena_t * ena,const uint16_t offset)20 ena_hw_bar_read32(const ena_t *ena, const uint16_t offset)
21 {
22 	caddr_t addr = ena->ena_reg_base + offset;
23 	return (ena_hw_abs_read32(ena, (uint32_t *)addr));
24 }
25 
26 uint32_t
ena_hw_abs_read32(const ena_t * ena,uint32_t * addr)27 ena_hw_abs_read32(const ena_t *ena, uint32_t *addr)
28 {
29 	VERIFY3U(addr, >=, ena->ena_reg_base);
30 	VERIFY3U(addr, <, ena->ena_reg_base + (ena->ena_reg_size - 4));
31 
32 	return (ddi_get32(ena->ena_reg_hdl, addr));
33 }
34 
35 void
ena_hw_bar_write32(const ena_t * ena,const uint16_t offset,const uint32_t val)36 ena_hw_bar_write32(const ena_t *ena, const uint16_t offset, const uint32_t val)
37 {
38 	caddr_t addr = ena->ena_reg_base + offset;
39 	ena_hw_abs_write32(ena, (uint32_t *)addr, val);
40 }
41 
42 void
ena_hw_abs_write32(const ena_t * ena,uint32_t * addr,const uint32_t val)43 ena_hw_abs_write32(const ena_t *ena, uint32_t *addr, const uint32_t val)
44 {
45 	VERIFY3P(ena, !=, NULL);
46 	VERIFY3P(addr, !=, NULL);
47 	VERIFY3U(addr, >=, ena->ena_reg_base);
48 	VERIFY3U(addr, <, ena->ena_reg_base + (ena->ena_reg_size - 4));
49 
50 	ddi_put32(ena->ena_reg_hdl, addr, val);
51 }
52 
53 int
enahw_resp_status_to_errno(ena_t * ena,enahw_resp_status_t status)54 enahw_resp_status_to_errno(ena_t *ena, enahw_resp_status_t status)
55 {
56 	int ret = 0;
57 
58 	switch (status) {
59 	case ENAHW_RESP_SUCCESS:
60 		break;
61 
62 	case ENAHW_RESP_RESOURCE_ALLOCATION_FAILURE:
63 		ret = ENOMEM;
64 		break;
65 
66 	case ENAHW_RESP_UNSUPPORTED_OPCODE:
67 		ret = ENOTSUP;
68 		break;
69 
70 	case ENAHW_RESP_BAD_OPCODE:
71 	case ENAHW_RESP_MALFORMED_REQUEST:
72 	case ENAHW_RESP_ILLEGAL_PARAMETER:
73 		ret = EINVAL;
74 		break;
75 
76 	case ENAHW_RESP_RESOURCE_BUSY:
77 		ret = EAGAIN;
78 		break;
79 
80 	case ENAHW_RESP_UNKNOWN_ERROR:
81 	default:
82 		/*
83 		 * If the device presents us with an "unknown error"
84 		 * code, or the status code is undefined, then we log
85 		 * an error and convert it to EIO.
86 		 */
87 		ena_err(ena, "unexpected status code: %d", status);
88 		ret = EIO;
89 		break;
90 	}
91 
92 	return (ret);
93 }
94 
95 const char *
enahw_reset_reason(enahw_reset_reason_t reason)96 enahw_reset_reason(enahw_reset_reason_t reason)
97 {
98 	switch (reason) {
99 	case ENAHW_RESET_NORMAL:
100 		return ("normal");
101 	case ENAHW_RESET_KEEP_ALIVE_TO:
102 		return ("keep-alive timeout");
103 	case ENAHW_RESET_ADMIN_TO:
104 		return ("admin timeout");
105 	case ENAHW_RESET_MISS_TX_CMPL:
106 		return ("missed TX completion");
107 	case ENAHW_RESET_INV_RX_REQ_ID:
108 		return ("invalid RX request ID");
109 	case ENAHW_RESET_INV_TX_REQ_ID:
110 		return ("invalid TX request ID");
111 	case ENAHW_RESET_TOO_MANY_RX_DESCS:
112 		return ("too many RX descs");
113 	case ENAHW_RESET_INIT_ERR:
114 		return ("initialization error");
115 	case ENAHW_RESET_DRIVER_INVALID_STATE:
116 		return ("invalid driver state");
117 	case ENAHW_RESET_OS_TRIGGER:
118 		return ("OS trigger");
119 	case ENAHW_RESET_OS_NETDEV_WD:
120 		return ("netdev watchdog");
121 	case ENAHW_RESET_SHUTDOWN:
122 		return ("shutdown");
123 	case ENAHW_RESET_USER_TRIGGER:
124 		return ("user trigger");
125 	case ENAHW_RESET_GENERIC:
126 		return ("generic");
127 	case ENAHW_RESET_MISS_INTERRUPT:
128 		return ("missed interrupt");
129 	case ENAHW_RESET_SUSPECTED_POLL_STARVATION:
130 		return ("suspected poll starvation");
131 	case ENAHW_RESET_RX_DESCRIPTOR_MALFORMED:
132 		return ("malformed RX descriptor");
133 	case ENAHW_RESET_TX_DESCRIPTOR_MALFORMED:
134 		return ("malformed TX descriptor");
135 	case ENAHW_RESET_MISSING_ADMIN_INTERRUPT:
136 		return ("missing admin interrupt");
137 	case ENAHW_RESET_DEVICE_REQUEST:
138 		return ("device request");
139 	default:
140 		return ("unknown");
141 	}
142 }
143 
144 #ifdef DEBUG
145 static const ena_reg_t reg_cache_template[ENAHW_NUM_REGS] = {
146 	{
147 		.er_name = "Version",
148 		.er_offset = ENAHW_REG_VERSION
149 	},
150 	{
151 		.er_name = "Controller Version",
152 		.er_offset = ENAHW_REG_CONTROLLER_VERSION
153 	},
154 	{
155 		.er_name = "Caps",
156 		.er_offset = ENAHW_REG_CAPS
157 	},
158 	{
159 		.er_name = "Extended Caps",
160 		.er_offset = ENAHW_REG_CAPS_EXT
161 	},
162 	{
163 		.er_name = "Admin SQ Base Low",
164 		.er_offset = ENAHW_REG_ASQ_BASE_LO
165 	},
166 	{
167 		.er_name = "Admin SQ Base High",
168 		.er_offset = ENAHW_REG_ASQ_BASE_HI
169 	},
170 	{
171 		.er_name = "Admin SQ Caps",
172 		.er_offset = ENAHW_REG_ASQ_CAPS
173 	},
174 	{
175 		.er_name = "Gap 0x1C",
176 		.er_offset = ENAHW_REG_GAP_1C
177 	},
178 	{
179 		.er_name = "Admin CQ Base Low",
180 		.er_offset = ENAHW_REG_ACQ_BASE_LO
181 	},
182 	{
183 		.er_name = "Admin CQ Base High",
184 		.er_offset = ENAHW_REG_ACQ_BASE_HI
185 	},
186 	{
187 		.er_name = "Admin CQ Caps",
188 		.er_offset = ENAHW_REG_ACQ_CAPS
189 	},
190 	{
191 		.er_name = "Admin SQ Doorbell",
192 		.er_offset = ENAHW_REG_ASQ_DB
193 	},
194 	{
195 		.er_name = "Admin CQ Tail",
196 		.er_offset = ENAHW_REG_ACQ_TAIL
197 	},
198 	{
199 		.er_name = "Admin Event Notification Queue Caps",
200 		.er_offset = ENAHW_REG_AENQ_CAPS
201 	},
202 	{
203 		.er_name = "Admin Event Notification Queue Base Low",
204 		.er_offset = ENAHW_REG_AENQ_BASE_LO
205 	},
206 	{
207 		.er_name = "Admin Event Notification Queue Base High",
208 		.er_offset = ENAHW_REG_AENQ_BASE_HI
209 	},
210 	{
211 		.er_name = "Admin Event Notification Queue Head Doorbell",
212 		.er_offset = ENAHW_REG_AENQ_HEAD_DB
213 	},
214 	{
215 		.er_name = "Admin Event Notification Queue Tail",
216 		.er_offset = ENAHW_REG_AENQ_TAIL
217 	},
218 	{
219 		.er_name = "Gap 0x48",
220 		.er_offset = ENAHW_REG_GAP_48
221 	},
222 	{
223 		.er_name = "Interrupt Mask (disable interrupts)",
224 		.er_offset = ENAHW_REG_INTERRUPT_MASK
225 	},
226 	{
227 		.er_name = "Gap 0x50",
228 		.er_offset = ENAHW_REG_GAP_50
229 	},
230 	{
231 		.er_name = "Device Control",
232 		.er_offset = ENAHW_REG_DEV_CTL
233 	},
234 	{
235 		.er_name = "Device Status",
236 		.er_offset = ENAHW_REG_DEV_STS
237 	},
238 	{
239 		.er_name = "MMIO Register Read",
240 		.er_offset = ENAHW_REG_MMIO_REG_READ
241 	},
242 	{
243 		.er_name = "MMIO Response Address Low",
244 		.er_offset = ENAHW_REG_MMIO_RESP_LO
245 	},
246 	{
247 		.er_name = "MMIO Response Address High",
248 		.er_offset = ENAHW_REG_MMIO_RESP_HI
249 	},
250 	{
251 		.er_name = "RSS Indirection Entry Update",
252 		.er_offset = ENAHW_REG_RSS_IND_ENTRY_UPDATE
253 	},
254 };
255 
256 void
ena_update_regcache(ena_t * ena)257 ena_update_regcache(ena_t *ena)
258 {
259 	for (uint_t i = 0; i < ENAHW_NUM_REGS; i++) {
260 		ena_reg_t *r = &ena->ena_reg[i];
261 
262 		r->er_value = ena_hw_bar_read32(ena, r->er_offset);
263 	}
264 }
265 
266 void
ena_init_regcache(ena_t * ena)267 ena_init_regcache(ena_t *ena)
268 {
269 	bcopy(reg_cache_template, ena->ena_reg, sizeof (ena->ena_reg));
270 	ena_update_regcache(ena);
271 }
272 #endif /* DEBUG */
273