xref: /illumos-gate/usr/src/uts/common/io/ena/ena_aenq.c (revision c46e4de3)
1*c46e4de3SAndy Fiddaman /*
2*c46e4de3SAndy Fiddaman  * This file and its contents are supplied under the terms of the
3*c46e4de3SAndy Fiddaman  * Common Development and Distribution License ("CDDL"), version 1.0.
4*c46e4de3SAndy Fiddaman  * You may only use this file in accordance with the terms of version
5*c46e4de3SAndy Fiddaman  * 1.0 of the CDDL.
6*c46e4de3SAndy Fiddaman  *
7*c46e4de3SAndy Fiddaman  * A full copy of the text of the CDDL should have accompanied this
8*c46e4de3SAndy Fiddaman  * source.  A copy of the CDDL is also available via the Internet at
9*c46e4de3SAndy Fiddaman  * http://www.illumos.org/license/CDDL.
10*c46e4de3SAndy Fiddaman  */
11*c46e4de3SAndy Fiddaman 
12*c46e4de3SAndy Fiddaman /*
13*c46e4de3SAndy Fiddaman  * Copyright 2024 Oxide Computer Company
14*c46e4de3SAndy Fiddaman  */
15*c46e4de3SAndy Fiddaman 
16*c46e4de3SAndy Fiddaman #include "ena_hw.h"
17*c46e4de3SAndy Fiddaman #include "ena.h"
18*c46e4de3SAndy Fiddaman 
19*c46e4de3SAndy Fiddaman CTASSERT(sizeof (enahw_aenq_desc_t) == 64);
20*c46e4de3SAndy Fiddaman 
21*c46e4de3SAndy Fiddaman /*
22*c46e4de3SAndy Fiddaman  * We add this here as an extra safety check to make sure that any
23*c46e4de3SAndy Fiddaman  * addition to the AENQ group enum also updates the groups array num
24*c46e4de3SAndy Fiddaman  * value.
25*c46e4de3SAndy Fiddaman  */
26*c46e4de3SAndy Fiddaman CTASSERT(ENAHW_AENQ_GROUPS_ARR_NUM == 8);
27*c46e4de3SAndy Fiddaman 
28*c46e4de3SAndy Fiddaman typedef struct ena_aenq_grpstr {
29*c46e4de3SAndy Fiddaman 	enahw_aenq_groups_t	eag_type;
30*c46e4de3SAndy Fiddaman 	const char		*eag_str;
31*c46e4de3SAndy Fiddaman } ena_aenq_grpstr_t;
32*c46e4de3SAndy Fiddaman 
33*c46e4de3SAndy Fiddaman static ena_aenq_grpstr_t ena_groups_str[ENAHW_AENQ_GROUPS_ARR_NUM] = {
34*c46e4de3SAndy Fiddaman 	{
35*c46e4de3SAndy Fiddaman 		.eag_type = ENAHW_AENQ_GROUP_LINK_CHANGE,
36*c46e4de3SAndy Fiddaman 		.eag_str = "LINK CHANGE"
37*c46e4de3SAndy Fiddaman 	},
38*c46e4de3SAndy Fiddaman 	{
39*c46e4de3SAndy Fiddaman 		.eag_type = ENAHW_AENQ_GROUP_FATAL_ERROR,
40*c46e4de3SAndy Fiddaman 		.eag_str = "FATAL ERROR"
41*c46e4de3SAndy Fiddaman 	},
42*c46e4de3SAndy Fiddaman 	{
43*c46e4de3SAndy Fiddaman 		.eag_type = ENAHW_AENQ_GROUP_WARNING,
44*c46e4de3SAndy Fiddaman 		.eag_str = "WARNING"
45*c46e4de3SAndy Fiddaman 	},
46*c46e4de3SAndy Fiddaman 	{
47*c46e4de3SAndy Fiddaman 		.eag_type = ENAHW_AENQ_GROUP_NOTIFICATION,
48*c46e4de3SAndy Fiddaman 		.eag_str = "NOTIFICATION"
49*c46e4de3SAndy Fiddaman 	},
50*c46e4de3SAndy Fiddaman 	{
51*c46e4de3SAndy Fiddaman 		.eag_type = ENAHW_AENQ_GROUP_KEEP_ALIVE,
52*c46e4de3SAndy Fiddaman 		.eag_str = "KEEP ALIVE"
53*c46e4de3SAndy Fiddaman 	},
54*c46e4de3SAndy Fiddaman 	{
55*c46e4de3SAndy Fiddaman 		.eag_type = ENAHW_AENQ_GROUP_REFRESH_CAPABILITIES,
56*c46e4de3SAndy Fiddaman 		.eag_str = "REFRESH CAPABILITIES"
57*c46e4de3SAndy Fiddaman 	},
58*c46e4de3SAndy Fiddaman 	{
59*c46e4de3SAndy Fiddaman 		.eag_type = ENAHW_AENQ_GROUP_CONF_NOTIFICATIONS,
60*c46e4de3SAndy Fiddaman 		.eag_str = "CONFIG NOTIFICATIONS"
61*c46e4de3SAndy Fiddaman 	},
62*c46e4de3SAndy Fiddaman 	{
63*c46e4de3SAndy Fiddaman 		.eag_type = ENAHW_AENQ_GROUP_DEVICE_REQUEST_RESET,
64*c46e4de3SAndy Fiddaman 		.eag_str = "DEVICE RESET REQUEST"
65*c46e4de3SAndy Fiddaman 	}
66*c46e4de3SAndy Fiddaman };
67*c46e4de3SAndy Fiddaman 
68*c46e4de3SAndy Fiddaman bool
ena_aenq_configure(ena_t * ena)69*c46e4de3SAndy Fiddaman ena_aenq_configure(ena_t *ena)
70*c46e4de3SAndy Fiddaman {
71*c46e4de3SAndy Fiddaman 	enahw_cmd_desc_t cmd;
72*c46e4de3SAndy Fiddaman 	enahw_feat_aenq_t *cmd_feat =
73*c46e4de3SAndy Fiddaman 	    &cmd.ecd_cmd.ecd_set_feat.ecsf_feat.ecsf_aenq;
74*c46e4de3SAndy Fiddaman 	enahw_resp_desc_t resp;
75*c46e4de3SAndy Fiddaman 	enahw_feat_aenq_t *resp_feat = &resp.erd_resp.erd_get_feat.ergf_aenq;
76*c46e4de3SAndy Fiddaman 	enahw_aenq_groups_t to_enable;
77*c46e4de3SAndy Fiddaman 
78*c46e4de3SAndy Fiddaman 	bzero(&resp, sizeof (resp));
79*c46e4de3SAndy Fiddaman 	if (ena_get_feature(ena, &resp, ENAHW_FEAT_AENQ_CONFIG,
80*c46e4de3SAndy Fiddaman 	    ENAHW_FEAT_AENQ_CONFIG_VER) != 0) {
81*c46e4de3SAndy Fiddaman 		return (false);
82*c46e4de3SAndy Fiddaman 	}
83*c46e4de3SAndy Fiddaman 
84*c46e4de3SAndy Fiddaman 	to_enable = BIT(ENAHW_AENQ_GROUP_LINK_CHANGE) |
85*c46e4de3SAndy Fiddaman 	    BIT(ENAHW_AENQ_GROUP_FATAL_ERROR) |
86*c46e4de3SAndy Fiddaman 	    BIT(ENAHW_AENQ_GROUP_WARNING) |
87*c46e4de3SAndy Fiddaman 	    BIT(ENAHW_AENQ_GROUP_NOTIFICATION) |
88*c46e4de3SAndy Fiddaman 	    BIT(ENAHW_AENQ_GROUP_KEEP_ALIVE) |
89*c46e4de3SAndy Fiddaman 	    BIT(ENAHW_AENQ_GROUP_DEVICE_REQUEST_RESET);
90*c46e4de3SAndy Fiddaman 	to_enable &= resp_feat->efa_supported_groups;
91*c46e4de3SAndy Fiddaman 
92*c46e4de3SAndy Fiddaman 	bzero(&cmd, sizeof (cmd));
93*c46e4de3SAndy Fiddaman 	bzero(&resp, sizeof (cmd));
94*c46e4de3SAndy Fiddaman 	cmd_feat->efa_enabled_groups = to_enable;
95*c46e4de3SAndy Fiddaman 
96*c46e4de3SAndy Fiddaman 	if (ena_set_feature(ena, &cmd, &resp, ENAHW_FEAT_AENQ_CONFIG,
97*c46e4de3SAndy Fiddaman 	    ENAHW_FEAT_AENQ_CONFIG_VER) != 0) {
98*c46e4de3SAndy Fiddaman 		return (false);
99*c46e4de3SAndy Fiddaman 	}
100*c46e4de3SAndy Fiddaman 
101*c46e4de3SAndy Fiddaman 	bzero(&resp, sizeof (resp));
102*c46e4de3SAndy Fiddaman 	if (ena_get_feature(ena, &resp, ENAHW_FEAT_AENQ_CONFIG,
103*c46e4de3SAndy Fiddaman 	    ENAHW_FEAT_AENQ_CONFIG_VER) != 0) {
104*c46e4de3SAndy Fiddaman 		return (false);
105*c46e4de3SAndy Fiddaman 	}
106*c46e4de3SAndy Fiddaman 
107*c46e4de3SAndy Fiddaman 	ena->ena_aenq_supported_groups = resp_feat->efa_supported_groups;
108*c46e4de3SAndy Fiddaman 	ena->ena_aenq_enabled_groups = resp_feat->efa_enabled_groups;
109*c46e4de3SAndy Fiddaman 
110*c46e4de3SAndy Fiddaman 	for (uint_t i = 0; i < ENAHW_AENQ_GROUPS_ARR_NUM; i++) {
111*c46e4de3SAndy Fiddaman 		ena_aenq_grpstr_t *grpstr = &ena_groups_str[i];
112*c46e4de3SAndy Fiddaman 		bool supported = BIT(grpstr->eag_type) &
113*c46e4de3SAndy Fiddaman 		    resp_feat->efa_supported_groups;
114*c46e4de3SAndy Fiddaman 		bool enabled = BIT(grpstr->eag_type) &
115*c46e4de3SAndy Fiddaman 		    resp_feat->efa_enabled_groups;
116*c46e4de3SAndy Fiddaman 
117*c46e4de3SAndy Fiddaman 		ena_dbg(ena, "%s supported: %s enabled: %s", grpstr->eag_str,
118*c46e4de3SAndy Fiddaman 		    supported ? "Y" : "N", enabled ? "Y" : "N");
119*c46e4de3SAndy Fiddaman 	}
120*c46e4de3SAndy Fiddaman 
121*c46e4de3SAndy Fiddaman 	return (true);
122*c46e4de3SAndy Fiddaman }
123*c46e4de3SAndy Fiddaman 
124*c46e4de3SAndy Fiddaman void
ena_aenq_work(ena_t * ena)125*c46e4de3SAndy Fiddaman ena_aenq_work(ena_t *ena)
126*c46e4de3SAndy Fiddaman {
127*c46e4de3SAndy Fiddaman 	ena_aenq_t *aenq = &ena->ena_aenq;
128*c46e4de3SAndy Fiddaman 	uint16_t head_mod = aenq->eaenq_head & (aenq->eaenq_num_descs - 1);
129*c46e4de3SAndy Fiddaman 	bool processed = false;
130*c46e4de3SAndy Fiddaman 	enahw_aenq_desc_t *desc = &aenq->eaenq_descs[head_mod];
131*c46e4de3SAndy Fiddaman 
132*c46e4de3SAndy Fiddaman 	ENA_DMA_SYNC(aenq->eaenq_dma, DDI_DMA_SYNC_FORKERNEL);
133*c46e4de3SAndy Fiddaman 
134*c46e4de3SAndy Fiddaman 	while (ENAHW_AENQ_DESC_PHASE(desc) == aenq->eaenq_phase) {
135*c46e4de3SAndy Fiddaman 		ena_aenq_hdlr_t hdlr;
136*c46e4de3SAndy Fiddaman 
137*c46e4de3SAndy Fiddaman 		ASSERT3U(desc->ead_group, <, ENAHW_AENQ_GROUPS_ARR_NUM);
138*c46e4de3SAndy Fiddaman 		processed = true;
139*c46e4de3SAndy Fiddaman 
140*c46e4de3SAndy Fiddaman 		/*
141*c46e4de3SAndy Fiddaman 		 * Keepalives occur once per second, we won't issue a debug
142*c46e4de3SAndy Fiddaman 		 * log message for each of those.
143*c46e4de3SAndy Fiddaman 		 */
144*c46e4de3SAndy Fiddaman 		if (ena_debug &&
145*c46e4de3SAndy Fiddaman 		    desc->ead_group != ENAHW_AENQ_GROUP_KEEP_ALIVE) {
146*c46e4de3SAndy Fiddaman 			uint64_t ts = ((uint64_t)desc->ead_ts_high << 32) |
147*c46e4de3SAndy Fiddaman 			    (uint64_t)desc->ead_ts_low;
148*c46e4de3SAndy Fiddaman 
149*c46e4de3SAndy Fiddaman 			ena_dbg(ena,
150*c46e4de3SAndy Fiddaman 			    "AENQ Group: (0x%x) %s Syndrome: 0x%x ts: %" PRIu64
151*c46e4de3SAndy Fiddaman 			    " us", desc->ead_group,
152*c46e4de3SAndy Fiddaman 			    ena_groups_str[desc->ead_group].eag_str,
153*c46e4de3SAndy Fiddaman 			    desc->ead_syndrome, ts);
154*c46e4de3SAndy Fiddaman 		}
155*c46e4de3SAndy Fiddaman 
156*c46e4de3SAndy Fiddaman 		hdlr = ena->ena_aenq.eaenq_hdlrs[desc->ead_group];
157*c46e4de3SAndy Fiddaman 		hdlr(ena, desc);
158*c46e4de3SAndy Fiddaman 
159*c46e4de3SAndy Fiddaman 		aenq->eaenq_head++;
160*c46e4de3SAndy Fiddaman 		head_mod = aenq->eaenq_head & (aenq->eaenq_num_descs - 1);
161*c46e4de3SAndy Fiddaman 
162*c46e4de3SAndy Fiddaman 		if (head_mod == 0)
163*c46e4de3SAndy Fiddaman 			aenq->eaenq_phase ^= 1;
164*c46e4de3SAndy Fiddaman 
165*c46e4de3SAndy Fiddaman 		desc = &aenq->eaenq_descs[head_mod];
166*c46e4de3SAndy Fiddaman 	}
167*c46e4de3SAndy Fiddaman 
168*c46e4de3SAndy Fiddaman 	if (processed) {
169*c46e4de3SAndy Fiddaman 		ena_hw_bar_write32(ena, ENAHW_REG_AENQ_HEAD_DB,
170*c46e4de3SAndy Fiddaman 		    aenq->eaenq_head);
171*c46e4de3SAndy Fiddaman 	}
172*c46e4de3SAndy Fiddaman }
173*c46e4de3SAndy Fiddaman 
174*c46e4de3SAndy Fiddaman static void
ena_aenq_link_change_hdlr(void * data,enahw_aenq_desc_t * desc)175*c46e4de3SAndy Fiddaman ena_aenq_link_change_hdlr(void *data, enahw_aenq_desc_t *desc)
176*c46e4de3SAndy Fiddaman {
177*c46e4de3SAndy Fiddaman 	ena_t *ena = data;
178*c46e4de3SAndy Fiddaman 	bool is_up = (desc->ead_payload.link_change.flags &
179*c46e4de3SAndy Fiddaman 	    ENAHW_AENQ_LINK_CHANGE_LINK_STATUS_MASK) != 0;
180*c46e4de3SAndy Fiddaman 	link_state_t new_state = is_up ? LINK_STATE_UP : LINK_STATE_DOWN;
181*c46e4de3SAndy Fiddaman 
182*c46e4de3SAndy Fiddaman 	/*
183*c46e4de3SAndy Fiddaman 	 * The interrupts are not enabled until after we register mac,
184*c46e4de3SAndy Fiddaman 	 * so the mac handle should be valid.
185*c46e4de3SAndy Fiddaman 	 */
186*c46e4de3SAndy Fiddaman 	ASSERT3U(ena->ena_attach_seq, >=, ENA_ATTACH_MAC_REGISTER);
187*c46e4de3SAndy Fiddaman 	ena->ena_aenq_stat.eaes_link_change.value.ui64++;
188*c46e4de3SAndy Fiddaman 
189*c46e4de3SAndy Fiddaman 	ena_dbg(ena, "link is %s", is_up ? "UP" : "DOWN");
190*c46e4de3SAndy Fiddaman 
191*c46e4de3SAndy Fiddaman 	mutex_enter(&ena->ena_lock);
192*c46e4de3SAndy Fiddaman 
193*c46e4de3SAndy Fiddaman 	/*
194*c46e4de3SAndy Fiddaman 	 * Notify mac only on an actual change in status.
195*c46e4de3SAndy Fiddaman 	 */
196*c46e4de3SAndy Fiddaman 	if (ena->ena_link_state != new_state) {
197*c46e4de3SAndy Fiddaman 		mac_link_update(ena->ena_mh, new_state);
198*c46e4de3SAndy Fiddaman 		ena->ena_link_state = new_state;
199*c46e4de3SAndy Fiddaman 	}
200*c46e4de3SAndy Fiddaman 
201*c46e4de3SAndy Fiddaman 	mutex_exit(&ena->ena_lock);
202*c46e4de3SAndy Fiddaman }
203*c46e4de3SAndy Fiddaman 
204*c46e4de3SAndy Fiddaman static void
ena_aenq_notification_hdlr(void * data,enahw_aenq_desc_t * desc)205*c46e4de3SAndy Fiddaman ena_aenq_notification_hdlr(void *data, enahw_aenq_desc_t *desc)
206*c46e4de3SAndy Fiddaman {
207*c46e4de3SAndy Fiddaman 	ena_t *ena = data;
208*c46e4de3SAndy Fiddaman 
209*c46e4de3SAndy Fiddaman 	if (desc->ead_syndrome == ENAHW_AENQ_SYNDROME_UPDATE_HINTS) {
210*c46e4de3SAndy Fiddaman 		enahw_device_hints_t *hints =
211*c46e4de3SAndy Fiddaman 		    (enahw_device_hints_t *)desc->ead_payload.raw;
212*c46e4de3SAndy Fiddaman 
213*c46e4de3SAndy Fiddaman 		ena_update_hints(ena, hints);
214*c46e4de3SAndy Fiddaman 	} else {
215*c46e4de3SAndy Fiddaman 		ena_err(ena, "Invalid aenq notification syndrome 0x%x",
216*c46e4de3SAndy Fiddaman 		    desc->ead_syndrome);
217*c46e4de3SAndy Fiddaman 	}
218*c46e4de3SAndy Fiddaman 
219*c46e4de3SAndy Fiddaman 	ena->ena_aenq_stat.eaes_notification.value.ui64++;
220*c46e4de3SAndy Fiddaman }
221*c46e4de3SAndy Fiddaman 
222*c46e4de3SAndy Fiddaman static void
ena_aenq_keep_alive_hdlr(void * data,enahw_aenq_desc_t * desc)223*c46e4de3SAndy Fiddaman ena_aenq_keep_alive_hdlr(void *data, enahw_aenq_desc_t *desc)
224*c46e4de3SAndy Fiddaman {
225*c46e4de3SAndy Fiddaman 	ena_t *ena = data;
226*c46e4de3SAndy Fiddaman 	uint64_t rx_drops, tx_drops, rx_overruns;
227*c46e4de3SAndy Fiddaman 	ena_basic_stat_t *ebs = ena->ena_device_basic_kstat->ks_data;
228*c46e4de3SAndy Fiddaman 	uint64_t now = (uint64_t)gethrtime();
229*c46e4de3SAndy Fiddaman 
230*c46e4de3SAndy Fiddaman 	(void) atomic_swap_64(&ena->ena_watchdog_last_keepalive, now);
231*c46e4de3SAndy Fiddaman 
232*c46e4de3SAndy Fiddaman 	rx_drops =
233*c46e4de3SAndy Fiddaman 	    ((uint64_t)desc->ead_payload.keep_alive.rx_drops_high << 32) |
234*c46e4de3SAndy Fiddaman 	    desc->ead_payload.keep_alive.rx_drops_low;
235*c46e4de3SAndy Fiddaman 	tx_drops =
236*c46e4de3SAndy Fiddaman 	    ((uint64_t)desc->ead_payload.keep_alive.tx_drops_high << 32) |
237*c46e4de3SAndy Fiddaman 	    desc->ead_payload.keep_alive.tx_drops_low;
238*c46e4de3SAndy Fiddaman 	rx_overruns =
239*c46e4de3SAndy Fiddaman 	    ((uint64_t)desc->ead_payload.keep_alive.rx_overruns_high << 32) |
240*c46e4de3SAndy Fiddaman 	    desc->ead_payload.keep_alive.rx_overruns_low;
241*c46e4de3SAndy Fiddaman 
242*c46e4de3SAndy Fiddaman 	mutex_enter(&ena->ena_device_basic_stat_lock);
243*c46e4de3SAndy Fiddaman 	ebs->ebs_rx_drops.value.ui64 = rx_drops;
244*c46e4de3SAndy Fiddaman 	ebs->ebs_tx_drops.value.ui64 = tx_drops;
245*c46e4de3SAndy Fiddaman 	ebs->ebs_rx_overruns.value.ui64 = rx_overruns;
246*c46e4de3SAndy Fiddaman 	mutex_exit(&ena->ena_device_basic_stat_lock);
247*c46e4de3SAndy Fiddaman 
248*c46e4de3SAndy Fiddaman 	ena->ena_aenq_stat.eaes_keep_alive.value.ui64++;
249*c46e4de3SAndy Fiddaman }
250*c46e4de3SAndy Fiddaman 
251*c46e4de3SAndy Fiddaman static void
ena_aenq_request_reset_hdlr(void * data,enahw_aenq_desc_t * desc)252*c46e4de3SAndy Fiddaman ena_aenq_request_reset_hdlr(void *data, enahw_aenq_desc_t *desc)
253*c46e4de3SAndy Fiddaman {
254*c46e4de3SAndy Fiddaman 	ena_t *ena = data;
255*c46e4de3SAndy Fiddaman 
256*c46e4de3SAndy Fiddaman 	ena->ena_reset_reason = ENAHW_RESET_DEVICE_REQUEST;
257*c46e4de3SAndy Fiddaman 	atomic_or_32(&ena->ena_state, ENA_STATE_ERROR);
258*c46e4de3SAndy Fiddaman 
259*c46e4de3SAndy Fiddaman 	ena->ena_aenq_stat.eaes_request_reset.value.ui64++;
260*c46e4de3SAndy Fiddaman }
261*c46e4de3SAndy Fiddaman 
262*c46e4de3SAndy Fiddaman static void
ena_aenq_fatal_error_hdlr(void * data,enahw_aenq_desc_t * desc)263*c46e4de3SAndy Fiddaman ena_aenq_fatal_error_hdlr(void *data, enahw_aenq_desc_t *desc)
264*c46e4de3SAndy Fiddaman {
265*c46e4de3SAndy Fiddaman 	ena_t *ena = data;
266*c46e4de3SAndy Fiddaman 
267*c46e4de3SAndy Fiddaman 	/*
268*c46e4de3SAndy Fiddaman 	 * The other open source drivers register this event but don't do
269*c46e4de3SAndy Fiddaman 	 * anything when it triggers. We do the same for now. If this indicates
270*c46e4de3SAndy Fiddaman 	 * that the fatal error bit has been set in the status register, the
271*c46e4de3SAndy Fiddaman 	 * watchdog will pick that up directly and issue a reset.
272*c46e4de3SAndy Fiddaman 	 */
273*c46e4de3SAndy Fiddaman 	ena->ena_aenq_stat.eaes_fatal_error.value.ui64++;
274*c46e4de3SAndy Fiddaman }
275*c46e4de3SAndy Fiddaman 
276*c46e4de3SAndy Fiddaman static void
ena_aenq_warning_hdlr(void * data,enahw_aenq_desc_t * desc)277*c46e4de3SAndy Fiddaman ena_aenq_warning_hdlr(void *data, enahw_aenq_desc_t *desc)
278*c46e4de3SAndy Fiddaman {
279*c46e4de3SAndy Fiddaman 	ena_t *ena = data;
280*c46e4de3SAndy Fiddaman 
281*c46e4de3SAndy Fiddaman 	/*
282*c46e4de3SAndy Fiddaman 	 * The other open source drivers register this event but don't do
283*c46e4de3SAndy Fiddaman 	 * anything when it triggers. We do the same for now.
284*c46e4de3SAndy Fiddaman 	 */
285*c46e4de3SAndy Fiddaman 	ena->ena_aenq_stat.eaes_warning.value.ui64++;
286*c46e4de3SAndy Fiddaman }
287*c46e4de3SAndy Fiddaman 
288*c46e4de3SAndy Fiddaman static void
ena_aenq_default_hdlr(void * data,enahw_aenq_desc_t * desc)289*c46e4de3SAndy Fiddaman ena_aenq_default_hdlr(void *data, enahw_aenq_desc_t *desc)
290*c46e4de3SAndy Fiddaman {
291*c46e4de3SAndy Fiddaman 	ena_t *ena = data;
292*c46e4de3SAndy Fiddaman 
293*c46e4de3SAndy Fiddaman 	ena->ena_aenq_stat.eaes_default.value.ui64++;
294*c46e4de3SAndy Fiddaman 	/*
295*c46e4de3SAndy Fiddaman 	 * We don't enable any of the groups that we don't support, so this
296*c46e4de3SAndy Fiddaman 	 * should not happen.
297*c46e4de3SAndy Fiddaman 	 */
298*c46e4de3SAndy Fiddaman 	ena_dbg(ena, "unimplemented handler for aenq group: %s",
299*c46e4de3SAndy Fiddaman 	    ena_groups_str[desc->ead_group].eag_str);
300*c46e4de3SAndy Fiddaman }
301*c46e4de3SAndy Fiddaman 
302*c46e4de3SAndy Fiddaman static void
ena_aenq_set_hdlrs(ena_aenq_t * aenq)303*c46e4de3SAndy Fiddaman ena_aenq_set_hdlrs(ena_aenq_t *aenq)
304*c46e4de3SAndy Fiddaman {
305*c46e4de3SAndy Fiddaman 	aenq->eaenq_hdlrs[ENAHW_AENQ_GROUP_LINK_CHANGE] =
306*c46e4de3SAndy Fiddaman 	    ena_aenq_link_change_hdlr;
307*c46e4de3SAndy Fiddaman 	aenq->eaenq_hdlrs[ENAHW_AENQ_GROUP_NOTIFICATION] =
308*c46e4de3SAndy Fiddaman 	    ena_aenq_notification_hdlr;
309*c46e4de3SAndy Fiddaman 	aenq->eaenq_hdlrs[ENAHW_AENQ_GROUP_KEEP_ALIVE] =
310*c46e4de3SAndy Fiddaman 	    ena_aenq_keep_alive_hdlr;
311*c46e4de3SAndy Fiddaman 	aenq->eaenq_hdlrs[ENAHW_AENQ_GROUP_DEVICE_REQUEST_RESET] =
312*c46e4de3SAndy Fiddaman 	    ena_aenq_request_reset_hdlr;
313*c46e4de3SAndy Fiddaman 	aenq->eaenq_hdlrs[ENAHW_AENQ_GROUP_FATAL_ERROR] =
314*c46e4de3SAndy Fiddaman 	    ena_aenq_fatal_error_hdlr;
315*c46e4de3SAndy Fiddaman 	aenq->eaenq_hdlrs[ENAHW_AENQ_GROUP_WARNING] =
316*c46e4de3SAndy Fiddaman 	    ena_aenq_warning_hdlr;
317*c46e4de3SAndy Fiddaman 
318*c46e4de3SAndy Fiddaman 	/* The following events are not handled */
319*c46e4de3SAndy Fiddaman 	aenq->eaenq_hdlrs[ENAHW_AENQ_GROUP_REFRESH_CAPABILITIES] =
320*c46e4de3SAndy Fiddaman 	    ena_aenq_default_hdlr;
321*c46e4de3SAndy Fiddaman 	aenq->eaenq_hdlrs[ENAHW_AENQ_GROUP_CONF_NOTIFICATIONS] =
322*c46e4de3SAndy Fiddaman 	    ena_aenq_default_hdlr;
323*c46e4de3SAndy Fiddaman }
324*c46e4de3SAndy Fiddaman 
325*c46e4de3SAndy Fiddaman bool
ena_aenq_init(ena_t * ena)326*c46e4de3SAndy Fiddaman ena_aenq_init(ena_t *ena)
327*c46e4de3SAndy Fiddaman {
328*c46e4de3SAndy Fiddaman 	ena_aenq_t *aenq = &ena->ena_aenq;
329*c46e4de3SAndy Fiddaman 	uint32_t addr_low, addr_high, wval;
330*c46e4de3SAndy Fiddaman 
331*c46e4de3SAndy Fiddaman 	if (aenq->eaenq_descs == NULL) {
332*c46e4de3SAndy Fiddaman 		size_t size;
333*c46e4de3SAndy Fiddaman 
334*c46e4de3SAndy Fiddaman 		aenq->eaenq_num_descs = ENA_AENQ_NUM_DESCS;
335*c46e4de3SAndy Fiddaman 		size = aenq->eaenq_num_descs * sizeof (*aenq->eaenq_descs);
336*c46e4de3SAndy Fiddaman 
337*c46e4de3SAndy Fiddaman 		ena_dma_conf_t conf = {
338*c46e4de3SAndy Fiddaman 			.edc_size = size,
339*c46e4de3SAndy Fiddaman 			.edc_align = ENAHW_AENQ_DESC_BUF_ALIGNMENT,
340*c46e4de3SAndy Fiddaman 			.edc_sgl = 1,
341*c46e4de3SAndy Fiddaman 			.edc_endian = DDI_NEVERSWAP_ACC,
342*c46e4de3SAndy Fiddaman 			.edc_stream = false,
343*c46e4de3SAndy Fiddaman 		};
344*c46e4de3SAndy Fiddaman 
345*c46e4de3SAndy Fiddaman 		if (!ena_dma_alloc(ena, &aenq->eaenq_dma, &conf, size)) {
346*c46e4de3SAndy Fiddaman 			ena_err(ena, "failed to allocate DMA for AENQ");
347*c46e4de3SAndy Fiddaman 			return (false);
348*c46e4de3SAndy Fiddaman 		}
349*c46e4de3SAndy Fiddaman 
350*c46e4de3SAndy Fiddaman 		ENA_DMA_VERIFY_ADDR(ena,
351*c46e4de3SAndy Fiddaman 		    aenq->eaenq_dma.edb_cookie->dmac_laddress);
352*c46e4de3SAndy Fiddaman 		aenq->eaenq_descs = (void *)aenq->eaenq_dma.edb_va;
353*c46e4de3SAndy Fiddaman 		ena_aenq_set_hdlrs(aenq);
354*c46e4de3SAndy Fiddaman 	} else {
355*c46e4de3SAndy Fiddaman 		ena_dma_bzero(&aenq->eaenq_dma);
356*c46e4de3SAndy Fiddaman 	}
357*c46e4de3SAndy Fiddaman 
358*c46e4de3SAndy Fiddaman 	aenq->eaenq_head = aenq->eaenq_num_descs;
359*c46e4de3SAndy Fiddaman 	aenq->eaenq_phase = 1;
360*c46e4de3SAndy Fiddaman 
361*c46e4de3SAndy Fiddaman 	addr_low = (uint32_t)(aenq->eaenq_dma.edb_cookie->dmac_laddress);
362*c46e4de3SAndy Fiddaman 	addr_high = (uint32_t)(aenq->eaenq_dma.edb_cookie->dmac_laddress >> 32);
363*c46e4de3SAndy Fiddaman 	ena_hw_bar_write32(ena, ENAHW_REG_AENQ_BASE_LO, addr_low);
364*c46e4de3SAndy Fiddaman 	ena_hw_bar_write32(ena, ENAHW_REG_AENQ_BASE_HI, addr_high);
365*c46e4de3SAndy Fiddaman 	ENA_DMA_SYNC(aenq->eaenq_dma, DDI_DMA_SYNC_FORDEV);
366*c46e4de3SAndy Fiddaman 	wval = ENAHW_AENQ_CAPS_DEPTH(aenq->eaenq_num_descs) |
367*c46e4de3SAndy Fiddaman 	    ENAHW_AENQ_CAPS_ENTRY_SIZE(sizeof (*aenq->eaenq_descs));
368*c46e4de3SAndy Fiddaman 	ena_hw_bar_write32(ena, ENAHW_REG_AENQ_CAPS, wval);
369*c46e4de3SAndy Fiddaman 
370*c46e4de3SAndy Fiddaman 	return (true);
371*c46e4de3SAndy Fiddaman }
372*c46e4de3SAndy Fiddaman 
373*c46e4de3SAndy Fiddaman void
ena_aenq_enable(ena_t * ena)374*c46e4de3SAndy Fiddaman ena_aenq_enable(ena_t *ena)
375*c46e4de3SAndy Fiddaman {
376*c46e4de3SAndy Fiddaman 	/*
377*c46e4de3SAndy Fiddaman 	 * We set this to zero here so that the watchdog will ignore it until
378*c46e4de3SAndy Fiddaman 	 * the first keepalive event is received. Devices that do not support
379*c46e4de3SAndy Fiddaman 	 * sending keepalives will result in this value remaining at 0.
380*c46e4de3SAndy Fiddaman 	 */
381*c46e4de3SAndy Fiddaman 	ena->ena_watchdog_last_keepalive = 0;
382*c46e4de3SAndy Fiddaman 	ena_hw_bar_write32(ena, ENAHW_REG_AENQ_HEAD_DB,
383*c46e4de3SAndy Fiddaman 	    ena->ena_aenq.eaenq_head);
384*c46e4de3SAndy Fiddaman }
385*c46e4de3SAndy Fiddaman 
386*c46e4de3SAndy Fiddaman void
ena_aenq_free(ena_t * ena)387*c46e4de3SAndy Fiddaman ena_aenq_free(ena_t *ena)
388*c46e4de3SAndy Fiddaman {
389*c46e4de3SAndy Fiddaman 	ena_dma_free(&ena->ena_aenq.eaenq_dma);
390*c46e4de3SAndy Fiddaman }
391