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