xref: /illumos-gate/usr/src/uts/common/io/ena/ena_hw.c (revision c46e4de3)
16f443ebcSRyan Zezeski /*
26f443ebcSRyan Zezeski  * This file and its contents are supplied under the terms of the
36f443ebcSRyan Zezeski  * Common Development and Distribution License ("CDDL"), version 1.0.
46f443ebcSRyan Zezeski  * You may only use this file in accordance with the terms of version
56f443ebcSRyan Zezeski  * 1.0 of the CDDL.
66f443ebcSRyan Zezeski  *
76f443ebcSRyan Zezeski  * A full copy of the text of the CDDL should have accompanied this
86f443ebcSRyan Zezeski  * source.  A copy of the CDDL is also available via the Internet at
96f443ebcSRyan Zezeski  * http://www.illumos.org/license/CDDL.
106f443ebcSRyan Zezeski  */
116f443ebcSRyan Zezeski 
126f443ebcSRyan Zezeski /*
13*c46e4de3SAndy Fiddaman  * Copyright 2024 Oxide Computer Company
146f443ebcSRyan Zezeski  */
156f443ebcSRyan Zezeski 
166f443ebcSRyan Zezeski #include "ena_hw.h"
176f443ebcSRyan Zezeski #include "ena.h"
186f443ebcSRyan Zezeski 
196f443ebcSRyan Zezeski uint32_t
ena_hw_bar_read32(const ena_t * ena,const uint16_t offset)206f443ebcSRyan Zezeski ena_hw_bar_read32(const ena_t *ena, const uint16_t offset)
216f443ebcSRyan Zezeski {
226f443ebcSRyan Zezeski 	caddr_t addr = ena->ena_reg_base + offset;
236f443ebcSRyan Zezeski 	return (ena_hw_abs_read32(ena, (uint32_t *)addr));
246f443ebcSRyan Zezeski }
256f443ebcSRyan Zezeski 
266f443ebcSRyan Zezeski uint32_t
ena_hw_abs_read32(const ena_t * ena,uint32_t * addr)276f443ebcSRyan Zezeski ena_hw_abs_read32(const ena_t *ena, uint32_t *addr)
286f443ebcSRyan Zezeski {
296f443ebcSRyan Zezeski 	VERIFY3U(addr, >=, ena->ena_reg_base);
306f443ebcSRyan Zezeski 	VERIFY3U(addr, <, ena->ena_reg_base + (ena->ena_reg_size - 4));
316f443ebcSRyan Zezeski 
326f443ebcSRyan Zezeski 	return (ddi_get32(ena->ena_reg_hdl, addr));
336f443ebcSRyan Zezeski }
346f443ebcSRyan Zezeski 
356f443ebcSRyan Zezeski void
ena_hw_bar_write32(const ena_t * ena,const uint16_t offset,const uint32_t val)366f443ebcSRyan Zezeski ena_hw_bar_write32(const ena_t *ena, const uint16_t offset, const uint32_t val)
376f443ebcSRyan Zezeski {
386f443ebcSRyan Zezeski 	caddr_t addr = ena->ena_reg_base + offset;
396f443ebcSRyan Zezeski 	ena_hw_abs_write32(ena, (uint32_t *)addr, val);
406f443ebcSRyan Zezeski }
416f443ebcSRyan Zezeski 
426f443ebcSRyan Zezeski void
ena_hw_abs_write32(const ena_t * ena,uint32_t * addr,const uint32_t val)436f443ebcSRyan Zezeski ena_hw_abs_write32(const ena_t *ena, uint32_t *addr, const uint32_t val)
446f443ebcSRyan Zezeski {
456f443ebcSRyan Zezeski 	VERIFY3P(ena, !=, NULL);
466f443ebcSRyan Zezeski 	VERIFY3P(addr, !=, NULL);
476f443ebcSRyan Zezeski 	VERIFY3U(addr, >=, ena->ena_reg_base);
486f443ebcSRyan Zezeski 	VERIFY3U(addr, <, ena->ena_reg_base + (ena->ena_reg_size - 4));
496f443ebcSRyan Zezeski 
506f443ebcSRyan Zezeski 	ddi_put32(ena->ena_reg_hdl, addr, val);
516f443ebcSRyan Zezeski }
526f443ebcSRyan Zezeski 
536f443ebcSRyan Zezeski int
enahw_resp_status_to_errno(ena_t * ena,enahw_resp_status_t status)546f443ebcSRyan Zezeski enahw_resp_status_to_errno(ena_t *ena, enahw_resp_status_t status)
556f443ebcSRyan Zezeski {
566f443ebcSRyan Zezeski 	int ret = 0;
576f443ebcSRyan Zezeski 
586f443ebcSRyan Zezeski 	switch (status) {
596f443ebcSRyan Zezeski 	case ENAHW_RESP_SUCCESS:
606f443ebcSRyan Zezeski 		break;
616f443ebcSRyan Zezeski 
626f443ebcSRyan Zezeski 	case ENAHW_RESP_RESOURCE_ALLOCATION_FAILURE:
636f443ebcSRyan Zezeski 		ret = ENOMEM;
646f443ebcSRyan Zezeski 		break;
656f443ebcSRyan Zezeski 
666f443ebcSRyan Zezeski 	case ENAHW_RESP_UNSUPPORTED_OPCODE:
676f443ebcSRyan Zezeski 		ret = ENOTSUP;
686f443ebcSRyan Zezeski 		break;
696f443ebcSRyan Zezeski 
706f443ebcSRyan Zezeski 	case ENAHW_RESP_BAD_OPCODE:
716f443ebcSRyan Zezeski 	case ENAHW_RESP_MALFORMED_REQUEST:
726f443ebcSRyan Zezeski 	case ENAHW_RESP_ILLEGAL_PARAMETER:
736f443ebcSRyan Zezeski 		ret = EINVAL;
746f443ebcSRyan Zezeski 		break;
756f443ebcSRyan Zezeski 
766f443ebcSRyan Zezeski 	case ENAHW_RESP_RESOURCE_BUSY:
776f443ebcSRyan Zezeski 		ret = EAGAIN;
786f443ebcSRyan Zezeski 		break;
796f443ebcSRyan Zezeski 
806f443ebcSRyan Zezeski 	case ENAHW_RESP_UNKNOWN_ERROR:
816f443ebcSRyan Zezeski 	default:
826f443ebcSRyan Zezeski 		/*
83*c46e4de3SAndy Fiddaman 		 * If the device presents us with an "unknown error"
846f443ebcSRyan Zezeski 		 * code, or the status code is undefined, then we log
856f443ebcSRyan Zezeski 		 * an error and convert it to EIO.
866f443ebcSRyan Zezeski 		 */
876f443ebcSRyan Zezeski 		ena_err(ena, "unexpected status code: %d", status);
886f443ebcSRyan Zezeski 		ret = EIO;
896f443ebcSRyan Zezeski 		break;
906f443ebcSRyan Zezeski 	}
916f443ebcSRyan Zezeski 
926f443ebcSRyan Zezeski 	return (ret);
936f443ebcSRyan Zezeski }
94*c46e4de3SAndy Fiddaman 
95*c46e4de3SAndy Fiddaman const char *
enahw_reset_reason(enahw_reset_reason_t reason)96*c46e4de3SAndy Fiddaman enahw_reset_reason(enahw_reset_reason_t reason)
97*c46e4de3SAndy Fiddaman {
98*c46e4de3SAndy Fiddaman 	switch (reason) {
99*c46e4de3SAndy Fiddaman 	case ENAHW_RESET_NORMAL:
100*c46e4de3SAndy Fiddaman 		return ("normal");
101*c46e4de3SAndy Fiddaman 	case ENAHW_RESET_KEEP_ALIVE_TO:
102*c46e4de3SAndy Fiddaman 		return ("keep-alive timeout");
103*c46e4de3SAndy Fiddaman 	case ENAHW_RESET_ADMIN_TO:
104*c46e4de3SAndy Fiddaman 		return ("admin timeout");
105*c46e4de3SAndy Fiddaman 	case ENAHW_RESET_MISS_TX_CMPL:
106*c46e4de3SAndy Fiddaman 		return ("missed TX completion");
107*c46e4de3SAndy Fiddaman 	case ENAHW_RESET_INV_RX_REQ_ID:
108*c46e4de3SAndy Fiddaman 		return ("invalid RX request ID");
109*c46e4de3SAndy Fiddaman 	case ENAHW_RESET_INV_TX_REQ_ID:
110*c46e4de3SAndy Fiddaman 		return ("invalid TX request ID");
111*c46e4de3SAndy Fiddaman 	case ENAHW_RESET_TOO_MANY_RX_DESCS:
112*c46e4de3SAndy Fiddaman 		return ("too many RX descs");
113*c46e4de3SAndy Fiddaman 	case ENAHW_RESET_INIT_ERR:
114*c46e4de3SAndy Fiddaman 		return ("initialization error");
115*c46e4de3SAndy Fiddaman 	case ENAHW_RESET_DRIVER_INVALID_STATE:
116*c46e4de3SAndy Fiddaman 		return ("invalid driver state");
117*c46e4de3SAndy Fiddaman 	case ENAHW_RESET_OS_TRIGGER:
118*c46e4de3SAndy Fiddaman 		return ("OS trigger");
119*c46e4de3SAndy Fiddaman 	case ENAHW_RESET_OS_NETDEV_WD:
120*c46e4de3SAndy Fiddaman 		return ("netdev watchdog");
121*c46e4de3SAndy Fiddaman 	case ENAHW_RESET_SHUTDOWN:
122*c46e4de3SAndy Fiddaman 		return ("shutdown");
123*c46e4de3SAndy Fiddaman 	case ENAHW_RESET_USER_TRIGGER:
124*c46e4de3SAndy Fiddaman 		return ("user trigger");
125*c46e4de3SAndy Fiddaman 	case ENAHW_RESET_GENERIC:
126*c46e4de3SAndy Fiddaman 		return ("generic");
127*c46e4de3SAndy Fiddaman 	case ENAHW_RESET_MISS_INTERRUPT:
128*c46e4de3SAndy Fiddaman 		return ("missed interrupt");
129*c46e4de3SAndy Fiddaman 	case ENAHW_RESET_SUSPECTED_POLL_STARVATION:
130*c46e4de3SAndy Fiddaman 		return ("suspected poll starvation");
131*c46e4de3SAndy Fiddaman 	case ENAHW_RESET_RX_DESCRIPTOR_MALFORMED:
132*c46e4de3SAndy Fiddaman 		return ("malformed RX descriptor");
133*c46e4de3SAndy Fiddaman 	case ENAHW_RESET_TX_DESCRIPTOR_MALFORMED:
134*c46e4de3SAndy Fiddaman 		return ("malformed TX descriptor");
135*c46e4de3SAndy Fiddaman 	case ENAHW_RESET_MISSING_ADMIN_INTERRUPT:
136*c46e4de3SAndy Fiddaman 		return ("missing admin interrupt");
137*c46e4de3SAndy Fiddaman 	case ENAHW_RESET_DEVICE_REQUEST:
138*c46e4de3SAndy Fiddaman 		return ("device request");
139*c46e4de3SAndy Fiddaman 	default:
140*c46e4de3SAndy Fiddaman 		return ("unknown");
141*c46e4de3SAndy Fiddaman 	}
142*c46e4de3SAndy Fiddaman }
143*c46e4de3SAndy Fiddaman 
144*c46e4de3SAndy Fiddaman #ifdef DEBUG
145*c46e4de3SAndy Fiddaman static const ena_reg_t reg_cache_template[ENAHW_NUM_REGS] = {
146*c46e4de3SAndy Fiddaman 	{
147*c46e4de3SAndy Fiddaman 		.er_name = "Version",
148*c46e4de3SAndy Fiddaman 		.er_offset = ENAHW_REG_VERSION
149*c46e4de3SAndy Fiddaman 	},
150*c46e4de3SAndy Fiddaman 	{
151*c46e4de3SAndy Fiddaman 		.er_name = "Controller Version",
152*c46e4de3SAndy Fiddaman 		.er_offset = ENAHW_REG_CONTROLLER_VERSION
153*c46e4de3SAndy Fiddaman 	},
154*c46e4de3SAndy Fiddaman 	{
155*c46e4de3SAndy Fiddaman 		.er_name = "Caps",
156*c46e4de3SAndy Fiddaman 		.er_offset = ENAHW_REG_CAPS
157*c46e4de3SAndy Fiddaman 	},
158*c46e4de3SAndy Fiddaman 	{
159*c46e4de3SAndy Fiddaman 		.er_name = "Extended Caps",
160*c46e4de3SAndy Fiddaman 		.er_offset = ENAHW_REG_CAPS_EXT
161*c46e4de3SAndy Fiddaman 	},
162*c46e4de3SAndy Fiddaman 	{
163*c46e4de3SAndy Fiddaman 		.er_name = "Admin SQ Base Low",
164*c46e4de3SAndy Fiddaman 		.er_offset = ENAHW_REG_ASQ_BASE_LO
165*c46e4de3SAndy Fiddaman 	},
166*c46e4de3SAndy Fiddaman 	{
167*c46e4de3SAndy Fiddaman 		.er_name = "Admin SQ Base High",
168*c46e4de3SAndy Fiddaman 		.er_offset = ENAHW_REG_ASQ_BASE_HI
169*c46e4de3SAndy Fiddaman 	},
170*c46e4de3SAndy Fiddaman 	{
171*c46e4de3SAndy Fiddaman 		.er_name = "Admin SQ Caps",
172*c46e4de3SAndy Fiddaman 		.er_offset = ENAHW_REG_ASQ_CAPS
173*c46e4de3SAndy Fiddaman 	},
174*c46e4de3SAndy Fiddaman 	{
175*c46e4de3SAndy Fiddaman 		.er_name = "Gap 0x1C",
176*c46e4de3SAndy Fiddaman 		.er_offset = ENAHW_REG_GAP_1C
177*c46e4de3SAndy Fiddaman 	},
178*c46e4de3SAndy Fiddaman 	{
179*c46e4de3SAndy Fiddaman 		.er_name = "Admin CQ Base Low",
180*c46e4de3SAndy Fiddaman 		.er_offset = ENAHW_REG_ACQ_BASE_LO
181*c46e4de3SAndy Fiddaman 	},
182*c46e4de3SAndy Fiddaman 	{
183*c46e4de3SAndy Fiddaman 		.er_name = "Admin CQ Base High",
184*c46e4de3SAndy Fiddaman 		.er_offset = ENAHW_REG_ACQ_BASE_HI
185*c46e4de3SAndy Fiddaman 	},
186*c46e4de3SAndy Fiddaman 	{
187*c46e4de3SAndy Fiddaman 		.er_name = "Admin CQ Caps",
188*c46e4de3SAndy Fiddaman 		.er_offset = ENAHW_REG_ACQ_CAPS
189*c46e4de3SAndy Fiddaman 	},
190*c46e4de3SAndy Fiddaman 	{
191*c46e4de3SAndy Fiddaman 		.er_name = "Admin SQ Doorbell",
192*c46e4de3SAndy Fiddaman 		.er_offset = ENAHW_REG_ASQ_DB
193*c46e4de3SAndy Fiddaman 	},
194*c46e4de3SAndy Fiddaman 	{
195*c46e4de3SAndy Fiddaman 		.er_name = "Admin CQ Tail",
196*c46e4de3SAndy Fiddaman 		.er_offset = ENAHW_REG_ACQ_TAIL
197*c46e4de3SAndy Fiddaman 	},
198*c46e4de3SAndy Fiddaman 	{
199*c46e4de3SAndy Fiddaman 		.er_name = "Admin Event Notification Queue Caps",
200*c46e4de3SAndy Fiddaman 		.er_offset = ENAHW_REG_AENQ_CAPS
201*c46e4de3SAndy Fiddaman 	},
202*c46e4de3SAndy Fiddaman 	{
203*c46e4de3SAndy Fiddaman 		.er_name = "Admin Event Notification Queue Base Low",
204*c46e4de3SAndy Fiddaman 		.er_offset = ENAHW_REG_AENQ_BASE_LO
205*c46e4de3SAndy Fiddaman 	},
206*c46e4de3SAndy Fiddaman 	{
207*c46e4de3SAndy Fiddaman 		.er_name = "Admin Event Notification Queue Base High",
208*c46e4de3SAndy Fiddaman 		.er_offset = ENAHW_REG_AENQ_BASE_HI
209*c46e4de3SAndy Fiddaman 	},
210*c46e4de3SAndy Fiddaman 	{
211*c46e4de3SAndy Fiddaman 		.er_name = "Admin Event Notification Queue Head Doorbell",
212*c46e4de3SAndy Fiddaman 		.er_offset = ENAHW_REG_AENQ_HEAD_DB
213*c46e4de3SAndy Fiddaman 	},
214*c46e4de3SAndy Fiddaman 	{
215*c46e4de3SAndy Fiddaman 		.er_name = "Admin Event Notification Queue Tail",
216*c46e4de3SAndy Fiddaman 		.er_offset = ENAHW_REG_AENQ_TAIL
217*c46e4de3SAndy Fiddaman 	},
218*c46e4de3SAndy Fiddaman 	{
219*c46e4de3SAndy Fiddaman 		.er_name = "Gap 0x48",
220*c46e4de3SAndy Fiddaman 		.er_offset = ENAHW_REG_GAP_48
221*c46e4de3SAndy Fiddaman 	},
222*c46e4de3SAndy Fiddaman 	{
223*c46e4de3SAndy Fiddaman 		.er_name = "Interrupt Mask (disable interrupts)",
224*c46e4de3SAndy Fiddaman 		.er_offset = ENAHW_REG_INTERRUPT_MASK
225*c46e4de3SAndy Fiddaman 	},
226*c46e4de3SAndy Fiddaman 	{
227*c46e4de3SAndy Fiddaman 		.er_name = "Gap 0x50",
228*c46e4de3SAndy Fiddaman 		.er_offset = ENAHW_REG_GAP_50
229*c46e4de3SAndy Fiddaman 	},
230*c46e4de3SAndy Fiddaman 	{
231*c46e4de3SAndy Fiddaman 		.er_name = "Device Control",
232*c46e4de3SAndy Fiddaman 		.er_offset = ENAHW_REG_DEV_CTL
233*c46e4de3SAndy Fiddaman 	},
234*c46e4de3SAndy Fiddaman 	{
235*c46e4de3SAndy Fiddaman 		.er_name = "Device Status",
236*c46e4de3SAndy Fiddaman 		.er_offset = ENAHW_REG_DEV_STS
237*c46e4de3SAndy Fiddaman 	},
238*c46e4de3SAndy Fiddaman 	{
239*c46e4de3SAndy Fiddaman 		.er_name = "MMIO Register Read",
240*c46e4de3SAndy Fiddaman 		.er_offset = ENAHW_REG_MMIO_REG_READ
241*c46e4de3SAndy Fiddaman 	},
242*c46e4de3SAndy Fiddaman 	{
243*c46e4de3SAndy Fiddaman 		.er_name = "MMIO Response Address Low",
244*c46e4de3SAndy Fiddaman 		.er_offset = ENAHW_REG_MMIO_RESP_LO
245*c46e4de3SAndy Fiddaman 	},
246*c46e4de3SAndy Fiddaman 	{
247*c46e4de3SAndy Fiddaman 		.er_name = "MMIO Response Address High",
248*c46e4de3SAndy Fiddaman 		.er_offset = ENAHW_REG_MMIO_RESP_HI
249*c46e4de3SAndy Fiddaman 	},
250*c46e4de3SAndy Fiddaman 	{
251*c46e4de3SAndy Fiddaman 		.er_name = "RSS Indirection Entry Update",
252*c46e4de3SAndy Fiddaman 		.er_offset = ENAHW_REG_RSS_IND_ENTRY_UPDATE
253*c46e4de3SAndy Fiddaman 	},
254*c46e4de3SAndy Fiddaman };
255*c46e4de3SAndy Fiddaman 
256*c46e4de3SAndy Fiddaman void
ena_update_regcache(ena_t * ena)257*c46e4de3SAndy Fiddaman ena_update_regcache(ena_t *ena)
258*c46e4de3SAndy Fiddaman {
259*c46e4de3SAndy Fiddaman 	for (uint_t i = 0; i < ENAHW_NUM_REGS; i++) {
260*c46e4de3SAndy Fiddaman 		ena_reg_t *r = &ena->ena_reg[i];
261*c46e4de3SAndy Fiddaman 
262*c46e4de3SAndy Fiddaman 		r->er_value = ena_hw_bar_read32(ena, r->er_offset);
263*c46e4de3SAndy Fiddaman 	}
264*c46e4de3SAndy Fiddaman }
265*c46e4de3SAndy Fiddaman 
266*c46e4de3SAndy Fiddaman void
ena_init_regcache(ena_t * ena)267*c46e4de3SAndy Fiddaman ena_init_regcache(ena_t *ena)
268*c46e4de3SAndy Fiddaman {
269*c46e4de3SAndy Fiddaman 	bcopy(reg_cache_template, ena->ena_reg, sizeof (ena->ena_reg));
270*c46e4de3SAndy Fiddaman 	ena_update_regcache(ena);
271*c46e4de3SAndy Fiddaman }
272*c46e4de3SAndy Fiddaman #endif /* DEBUG */
273