xref: /illumos-gate/usr/src/uts/common/io/hxge/hpi_txdma.c (revision 2d6eb4a5)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <hpi_txdma.h>
27 #include <hxge_impl.h>
28 
29 #define	TXDMA_WAIT_LOOP		10000
30 #define	TXDMA_WAIT_MSEC		5
31 
32 static hpi_status_t hpi_txdma_control_reset_wait(hpi_handle_t handle,
33     uint8_t channel);
34 
35 hpi_status_t
hpi_txdma_log_page_handle_set(hpi_handle_t handle,uint8_t channel,tdc_page_handle_t * hdl_p)36 hpi_txdma_log_page_handle_set(hpi_handle_t handle, uint8_t channel,
37     tdc_page_handle_t *hdl_p)
38 {
39 	int status = HPI_SUCCESS;
40 
41 	if (!TXDMA_CHANNEL_VALID(channel)) {
42 		HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
43 		    " hpi_txdma_log_page_handle_set"
44 		    " Invalid Input: channel <0x%x>", channel));
45 		return (HPI_FAILURE | HPI_TXDMA_CHANNEL_INVALID(channel));
46 	}
47 
48 	TXDMA_REG_WRITE64(handle, TDC_PAGE_HANDLE, channel, hdl_p->value);
49 
50 	return (status);
51 }
52 
53 hpi_status_t
hpi_txdma_channel_reset(hpi_handle_t handle,uint8_t channel)54 hpi_txdma_channel_reset(hpi_handle_t handle, uint8_t channel)
55 {
56 	HPI_DEBUG_MSG((handle.function, HPI_TDC_CTL,
57 	    " hpi_txdma_channel_reset" " RESETTING", channel));
58 	return (hpi_txdma_channel_control(handle, TXDMA_RESET, channel));
59 }
60 
61 hpi_status_t
hpi_txdma_channel_init_enable(hpi_handle_t handle,uint8_t channel)62 hpi_txdma_channel_init_enable(hpi_handle_t handle, uint8_t channel)
63 {
64 	return (hpi_txdma_channel_control(handle, TXDMA_INIT_START, channel));
65 }
66 
67 hpi_status_t
hpi_txdma_channel_enable(hpi_handle_t handle,uint8_t channel)68 hpi_txdma_channel_enable(hpi_handle_t handle, uint8_t channel)
69 {
70 	return (hpi_txdma_channel_control(handle, TXDMA_START, channel));
71 }
72 
73 hpi_status_t
hpi_txdma_channel_disable(hpi_handle_t handle,uint8_t channel)74 hpi_txdma_channel_disable(hpi_handle_t handle, uint8_t channel)
75 {
76 	return (hpi_txdma_channel_control(handle, TXDMA_STOP, channel));
77 }
78 
79 hpi_status_t
hpi_txdma_channel_mbox_enable(hpi_handle_t handle,uint8_t channel)80 hpi_txdma_channel_mbox_enable(hpi_handle_t handle, uint8_t channel)
81 {
82 	return (hpi_txdma_channel_control(handle, TXDMA_MBOX_ENABLE, channel));
83 }
84 
85 hpi_status_t
hpi_txdma_channel_control(hpi_handle_t handle,txdma_cs_cntl_t control,uint8_t channel)86 hpi_txdma_channel_control(hpi_handle_t handle, txdma_cs_cntl_t control,
87     uint8_t channel)
88 {
89 	int		status = HPI_SUCCESS;
90 	tdc_stat_t	cs;
91 	tdc_tdr_cfg_t	cfg;
92 
93 	if (!TXDMA_CHANNEL_VALID(channel)) {
94 		HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
95 		    " hpi_txdma_channel_control"
96 		    " Invalid Input: channel <0x%x>", channel));
97 		return (HPI_FAILURE | HPI_TXDMA_CHANNEL_INVALID(channel));
98 	}
99 
100 	switch (control) {
101 	case TXDMA_INIT_RESET:
102 		cfg.value = 0;
103 		TXDMA_REG_READ64(handle, TDC_TDR_CFG, channel, &cfg.value);
104 		cfg.bits.reset = 1;
105 		TXDMA_REG_WRITE64(handle, TDC_TDR_CFG, channel, cfg.value);
106 		return (hpi_txdma_control_reset_wait(handle, channel));
107 
108 	case TXDMA_INIT_START:
109 		cfg.value = 0;
110 		TXDMA_REG_READ64(handle, TDC_TDR_CFG, channel, &cfg.value);
111 		cfg.bits.enable = 1;
112 		TXDMA_REG_WRITE64(handle, TDC_TDR_CFG, channel, cfg.value);
113 		break;
114 
115 	case TXDMA_RESET:
116 		/*
117 		 * Sets reset bit only (Hardware will reset all the RW bits but
118 		 * leave the RO bits alone.
119 		 */
120 		cfg.value = 0;
121 		cfg.bits.reset = 1;
122 		TXDMA_REG_WRITE64(handle, TDC_TDR_CFG, channel, cfg.value);
123 		return (hpi_txdma_control_reset_wait(handle, channel));
124 
125 	case TXDMA_START:
126 		/* Enable the DMA channel */
127 		TXDMA_REG_READ64(handle, TDC_TDR_CFG, channel, &cfg.value);
128 		cfg.bits.enable = 1;
129 		TXDMA_REG_WRITE64(handle, TDC_TDR_CFG, channel, cfg.value);
130 		break;
131 
132 	case TXDMA_STOP:
133 		/* Disable the DMA channel */
134 		TXDMA_REG_READ64(handle, TDC_TDR_CFG, channel, &cfg.value);
135 		cfg.bits.enable = 0;
136 		TXDMA_REG_WRITE64(handle, TDC_TDR_CFG, channel, cfg.value);
137 		status = hpi_txdma_control_stop_wait(handle, channel);
138 		if (status) {
139 			HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
140 			    "Cannot stop channel %d (TXC hung!)", channel));
141 		}
142 		break;
143 
144 	case TXDMA_MBOX_ENABLE:
145 		/*
146 		 * Write 1 to MB bit to enable mailbox update (cleared to 0 by
147 		 * hardware after update).
148 		 */
149 		TXDMA_REG_READ64(handle, TDC_STAT, channel, &cs.value);
150 		cs.bits.mb = 1;
151 		TXDMA_REG_WRITE64(handle, TDC_STAT, channel, cs.value);
152 		break;
153 
154 	default:
155 		status = (HPI_FAILURE | HPI_TXDMA_OPCODE_INVALID(channel));
156 		HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
157 		    " hpi_txdma_channel_control"
158 		    " Invalid Input: control <0x%x>", control));
159 	}
160 
161 	return (status);
162 }
163 
164 hpi_status_t
hpi_txdma_control_status(hpi_handle_t handle,io_op_t op_mode,uint8_t channel,tdc_stat_t * cs_p)165 hpi_txdma_control_status(hpi_handle_t handle, io_op_t op_mode, uint8_t channel,
166     tdc_stat_t *cs_p)
167 {
168 	int		status = HPI_SUCCESS;
169 	tdc_stat_t	txcs;
170 
171 	if (!TXDMA_CHANNEL_VALID(channel)) {
172 		HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
173 		    " hpi_txdma_control_status"
174 		    " Invalid Input: channel <0x%x>", channel));
175 		return (HPI_FAILURE | HPI_TXDMA_CHANNEL_INVALID(channel));
176 	}
177 	switch (op_mode) {
178 	case OP_GET:
179 		TXDMA_REG_READ64(handle, TDC_STAT, channel, &cs_p->value);
180 		break;
181 
182 	case OP_SET:
183 		TXDMA_REG_WRITE64(handle, TDC_STAT, channel, cs_p->value);
184 		break;
185 
186 	case OP_UPDATE:
187 		TXDMA_REG_READ64(handle, TDC_STAT, channel, &txcs.value);
188 		TXDMA_REG_WRITE64(handle, TDC_STAT, channel,
189 		    cs_p->value | txcs.value);
190 		break;
191 
192 	default:
193 		HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
194 		    " hpi_txdma_control_status"
195 		    " Invalid Input: control <0x%x>", op_mode));
196 		return (HPI_FAILURE | HPI_TXDMA_OPCODE_INVALID(channel));
197 	}
198 
199 	return (status);
200 }
201 
202 hpi_status_t
hpi_txdma_event_mask(hpi_handle_t handle,io_op_t op_mode,uint8_t channel,tdc_int_mask_t * mask_p)203 hpi_txdma_event_mask(hpi_handle_t handle, io_op_t op_mode, uint8_t channel,
204     tdc_int_mask_t *mask_p)
205 {
206 	int		status = HPI_SUCCESS;
207 	tdc_int_mask_t	mask;
208 
209 	if (!TXDMA_CHANNEL_VALID(channel)) {
210 		HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
211 		    " hpi_txdma_event_mask Invalid Input: channel <0x%x>",
212 		    channel));
213 		return (HPI_FAILURE | HPI_TXDMA_CHANNEL_INVALID(channel));
214 	}
215 	switch (op_mode) {
216 	case OP_GET:
217 		TXDMA_REG_READ64(handle, TDC_INT_MASK, channel, &mask_p->value);
218 		break;
219 
220 	case OP_SET:
221 		TXDMA_REG_WRITE64(handle, TDC_INT_MASK, channel, mask_p->value);
222 		break;
223 
224 	case OP_UPDATE:
225 		TXDMA_REG_READ64(handle, TDC_INT_MASK, channel, &mask.value);
226 		TXDMA_REG_WRITE64(handle, TDC_INT_MASK, channel,
227 		    mask_p->value | mask.value);
228 		break;
229 
230 	default:
231 		HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
232 		    " hpi_txdma_event_mask Invalid Input: eventmask <0x%x>",
233 		    op_mode));
234 		return (HPI_FAILURE | HPI_TXDMA_OPCODE_INVALID(channel));
235 	}
236 
237 	return (status);
238 }
239 
240 hpi_status_t
hpi_txdma_ring_config(hpi_handle_t handle,io_op_t op_mode,uint8_t channel,uint64_t * reg_data)241 hpi_txdma_ring_config(hpi_handle_t handle, io_op_t op_mode,
242     uint8_t channel, uint64_t *reg_data)
243 {
244 	int status = HPI_SUCCESS;
245 
246 	if (!TXDMA_CHANNEL_VALID(channel)) {
247 		HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
248 		    " hpi_txdma_ring_config"
249 		    " Invalid Input: channel <0x%x>", channel));
250 		return (HPI_FAILURE | HPI_TXDMA_CHANNEL_INVALID(channel));
251 	}
252 	switch (op_mode) {
253 	case OP_GET:
254 		TXDMA_REG_READ64(handle, TDC_TDR_CFG, channel, reg_data);
255 		break;
256 
257 	case OP_SET:
258 		TXDMA_REG_WRITE64(handle, TDC_TDR_CFG, channel, *reg_data);
259 		break;
260 
261 	default:
262 		HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
263 		    " hpi_txdma_ring_config"
264 		    " Invalid Input: ring_config <0x%x>", op_mode));
265 		return (HPI_FAILURE | HPI_TXDMA_OPCODE_INVALID(channel));
266 	}
267 
268 	return (status);
269 }
270 
271 hpi_status_t
hpi_txdma_mbox_config(hpi_handle_t handle,io_op_t op_mode,uint8_t channel,uint64_t * mbox_addr)272 hpi_txdma_mbox_config(hpi_handle_t handle, io_op_t op_mode,
273     uint8_t channel, uint64_t *mbox_addr)
274 {
275 	int		status = HPI_SUCCESS;
276 	tdc_mbh_t	mh;
277 	tdc_mbl_t	ml;
278 
279 	if (!TXDMA_CHANNEL_VALID(channel)) {
280 		HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
281 		    " hpi_txdma_mbox_config Invalid Input: channel <0x%x>",
282 		    channel));
283 		return (HPI_FAILURE | HPI_TXDMA_CHANNEL_INVALID(channel));
284 	}
285 
286 	mh.value = ml.value = 0;
287 
288 	switch (op_mode) {
289 	case OP_GET:
290 		TXDMA_REG_READ64(handle, TDC_MBH, channel, &mh.value);
291 		TXDMA_REG_READ64(handle, TDC_MBL, channel, &ml.value);
292 		*mbox_addr = ml.value;
293 		*mbox_addr |= (mh.value << TDC_MBH_ADDR_SHIFT);
294 
295 		break;
296 
297 	case OP_SET:
298 		ml.bits.mbaddr = ((*mbox_addr & TDC_MBL_MASK) >> TDC_MBL_SHIFT);
299 		TXDMA_REG_WRITE64(handle, TDC_MBL, channel, ml.value);
300 		mh.bits.mbaddr = ((*mbox_addr >> TDC_MBH_ADDR_SHIFT) &
301 		    TDC_MBH_MASK);
302 		TXDMA_REG_WRITE64(handle, TDC_MBH, channel, mh.value);
303 		break;
304 
305 	default:
306 		HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
307 		    " hpi_txdma_mbox_config Invalid Input: mbox <0x%x>",
308 		    op_mode));
309 		return (HPI_FAILURE | HPI_TXDMA_OPCODE_INVALID(channel));
310 	}
311 
312 	return (status);
313 }
314 
315 /*
316  * This function is called to set up a transmit descriptor entry.
317  */
318 hpi_status_t
hpi_txdma_desc_gather_set(hpi_handle_t handle,p_tx_desc_t desc_p,uint8_t gather_index,boolean_t mark,uint8_t ngathers,uint64_t dma_ioaddr,uint32_t transfer_len)319 hpi_txdma_desc_gather_set(hpi_handle_t handle, p_tx_desc_t desc_p,
320     uint8_t gather_index, boolean_t mark, uint8_t ngathers,
321     uint64_t dma_ioaddr, uint32_t transfer_len)
322 {
323 	int status;
324 
325 	status = HPI_TXDMA_GATHER_INDEX(gather_index);
326 	if (status) {
327 		HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
328 		    " hpi_txdma_desc_gather_set"
329 		    " Invalid Input: gather_index <0x%x>", gather_index));
330 		return (status);
331 	}
332 	if (transfer_len > TX_MAX_TRANSFER_LENGTH) {
333 		HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
334 		    " hpi_txdma_desc_gather_set"
335 		    " Invalid Input: tr_len <0x%x>", transfer_len));
336 		return (HPI_FAILURE | HPI_TXDMA_XFER_LEN_INVALID);
337 	}
338 	if (gather_index == 0) {
339 		desc_p->bits.sop = 1;
340 		desc_p->bits.mark = mark;
341 		desc_p->bits.num_ptr = ngathers;
342 		HPI_DEBUG_MSG((handle.function, HPI_TDC_CTL,
343 		    "hpi_txdma_gather_set: SOP len %d (%d)",
344 		    desc_p->bits.tr_len, transfer_len));
345 	}
346 	desc_p->bits.tr_len = transfer_len;
347 	desc_p->bits.sad = dma_ioaddr >> 32;
348 	desc_p->bits.sad_l = dma_ioaddr & 0xffffffff;
349 
350 	HPI_DEBUG_MSG((handle.function, HPI_TDC_CTL,
351 	    "hpi_txdma_gather_set: xfer len %d to set (%d)",
352 	    desc_p->bits.tr_len, transfer_len));
353 
354 	HXGE_MEM_PIO_WRITE64(handle, desc_p->value);
355 
356 	return (status);
357 }
358 
359 hpi_status_t
hpi_txdma_desc_set_zero(hpi_handle_t handle,uint16_t entries)360 hpi_txdma_desc_set_zero(hpi_handle_t handle, uint16_t entries)
361 {
362 	uint32_t	offset;
363 	int		i;
364 
365 	/*
366 	 * Assume no wrapped around.
367 	 */
368 	offset = 0;
369 	for (i = 0; i < entries; i++) {
370 		HXGE_REG_WR64(handle, offset, 0);
371 		offset += (i * (sizeof (tx_desc_t)));
372 	}
373 
374 	return (HPI_SUCCESS);
375 }
376 
377 /*
378  * This function is called to get the transmit ring head index.
379  */
380 hpi_status_t
hpi_txdma_ring_head_get(hpi_handle_t handle,uint8_t channel,tdc_tdr_head_t * hdl_p)381 hpi_txdma_ring_head_get(hpi_handle_t handle, uint8_t channel,
382     tdc_tdr_head_t *hdl_p)
383 {
384 	int status = HPI_SUCCESS;
385 
386 	if (!TXDMA_CHANNEL_VALID(channel)) {
387 		HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
388 		    " hpi_txdma_ring_head_get"
389 		    " Invalid Input: channel <0x%x>", channel));
390 		return (HPI_FAILURE | HPI_TXDMA_CHANNEL_INVALID(channel));
391 	}
392 	TXDMA_REG_READ64(handle, TDC_TDR_HEAD, channel, &hdl_p->value);
393 
394 	return (status);
395 }
396 
397 /*
398  * Dumps the contents of transmit descriptors.
399  */
400 /*ARGSUSED*/
401 void
hpi_txdma_dump_desc_one(hpi_handle_t handle,p_tx_desc_t desc_p,int desc_index)402 hpi_txdma_dump_desc_one(hpi_handle_t handle, p_tx_desc_t desc_p, int desc_index)
403 {
404 	tx_desc_t desc, *desp;
405 
406 #ifdef HXGE_DEBUG
407 	uint64_t sad;
408 	int xfer_len;
409 #endif
410 
411 	HPI_DEBUG_MSG((handle.function, HPI_TDC_CTL,
412 	    "\n==> hpi_txdma_dump_desc_one: dump "
413 	    " desc_p $%p descriptor entry %d\n", desc_p, desc_index));
414 	desc.value = 0;
415 	desp = ((desc_p != NULL) ? desc_p : (p_tx_desc_t)&desc);
416 	HXGE_MEM_PIO_READ64(handle, &desp->value);
417 #ifdef HXGE_DEBUG
418 	sad = desp->bits.sad;
419 	sad = (sad << 32) | desp->bits.sad_l;
420 	xfer_len = desp->bits.tr_len;
421 #endif
422 	HPI_DEBUG_MSG((handle.function, HPI_TDC_CTL, "\n\t: value 0x%llx\n"
423 	    "\t\tsad $%p\ttr_len %d len %d\tnptrs %d\tmark %d sop %d\n",
424 	    desp->value, sad, desp->bits.tr_len, xfer_len,
425 	    desp->bits.num_ptr, desp->bits.mark, desp->bits.sop));
426 
427 	HPI_DEBUG_MSG((handle.function, HPI_TDC_CTL,
428 	    "\n<== hpi_txdma_dump_desc_one: Done \n"));
429 }
430 
431 /*
432  * Static functions start here.
433  */
434 static hpi_status_t
hpi_txdma_control_reset_wait(hpi_handle_t handle,uint8_t channel)435 hpi_txdma_control_reset_wait(hpi_handle_t handle, uint8_t channel)
436 {
437 	tdc_tdr_cfg_t txcs;
438 	int loop = 0;
439 
440 	txcs.value = 0;
441 	do {
442 		HXGE_DELAY(TXDMA_WAIT_MSEC);
443 		TXDMA_REG_READ64(handle, TDC_TDR_CFG, channel, &txcs.value);
444 
445 		/*
446 		 * Reset completes when this bit is set to 1 by hw
447 		 */
448 		if (txcs.bits.qst) {
449 			return (HPI_SUCCESS);
450 		}
451 		loop++;
452 	} while (loop < TXDMA_WAIT_LOOP);
453 
454 	if (loop == TXDMA_WAIT_LOOP) {
455 		HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
456 		    "hpi_txdma_control_reset_wait: RST bit not "
457 		    "cleared to 0 txcs.bits 0x%llx", txcs.value));
458 		return (HPI_FAILURE | HPI_TXDMA_RESET_FAILED);
459 	}
460 	return (HPI_SUCCESS);
461 }
462 
463 hpi_status_t
hpi_txdma_control_stop_wait(hpi_handle_t handle,uint8_t channel)464 hpi_txdma_control_stop_wait(hpi_handle_t handle, uint8_t channel)
465 {
466 	tdc_tdr_cfg_t	txcs;
467 	int		loop = 0;
468 
469 	do {
470 		txcs.value = 0;
471 		HXGE_DELAY(TXDMA_WAIT_MSEC);
472 		TXDMA_REG_READ64(handle, TDC_TDR_CFG, channel, &txcs.value);
473 		if (txcs.bits.qst) {
474 			return (HPI_SUCCESS);
475 		}
476 		loop++;
477 	} while (loop < TXDMA_WAIT_LOOP);
478 
479 	if (loop == TXDMA_WAIT_LOOP) {
480 		HPI_ERROR_MSG((handle.function, HPI_ERR_CTL,
481 		    "hpi_txdma_control_stop_wait: SNG_STATE not "
482 		    "set to 1 txcs.bits 0x%llx", txcs.value));
483 		return (HPI_FAILURE | HPI_TXDMA_STOP_FAILED);
484 	}
485 	return (HPI_SUCCESS);
486 }
487