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/*
23 * Copyright 2010 Emulex.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27/*
28 * Source file containing the implementation of the Transmit
29 * Path
30 */
31
32#include <oce_impl.h>
33
34static void oce_free_wqed(struct oce_wq *wq,  oce_wqe_desc_t *wqed);
35static int oce_map_wqe(struct oce_wq *wq, oce_wqe_desc_t *wqed,
36    mblk_t *mp, uint32_t pkt_len);
37static int oce_bcopy_wqe(struct oce_wq *wq, oce_wqe_desc_t *wqed, mblk_t *mp,
38    uint32_t pkt_len);
39static void oce_wqb_dtor(struct oce_wq *wq, oce_wq_bdesc_t *wqbd);
40static int oce_wqb_ctor(oce_wq_bdesc_t *wqbd, struct oce_wq *wq,
41    size_t size, int flags);
42static inline oce_wq_bdesc_t *oce_wqb_alloc(struct oce_wq *wq);
43static void oce_wqb_free(struct oce_wq *wq, oce_wq_bdesc_t *wqbd);
44
45static void oce_wqmd_free(struct oce_wq *wq, oce_wq_mdesc_t *wqmd);
46static void oce_wqm_free(struct oce_wq *wq, oce_wq_mdesc_t *wqmd);
47static oce_wq_mdesc_t *oce_wqm_alloc(struct oce_wq *wq);
48static int oce_wqm_ctor(oce_wq_mdesc_t *wqmd, struct oce_wq *wq);
49static void oce_wqm_dtor(struct oce_wq *wq, oce_wq_mdesc_t *wqmd);
50static void oce_fill_ring_descs(struct oce_wq *wq, oce_wqe_desc_t *wqed);
51static void oce_remove_vtag(mblk_t *mp);
52static void oce_insert_vtag(mblk_t  *mp, uint16_t vlan_tag);
53static inline int oce_process_tx_compl(struct oce_wq *wq, boolean_t rearm);
54
55
56static ddi_dma_attr_t tx_map_dma_attr = {
57	DMA_ATTR_V0,		/* version number */
58	0x0000000000000000ull,	/* low address */
59	0xFFFFFFFFFFFFFFFFull,	/* high address */
60	0x0000000000010000ull,	/* dma counter max */
61	OCE_TXMAP_ALIGN,	/* alignment */
62	0x7FF,			/* burst sizes */
63	0x00000001,		/* minimum transfer size */
64	0x00000000FFFFFFFFull,	/* maximum transfer size */
65	0xFFFFFFFFFFFFFFFFull,	/* maximum segment size */
66	OCE_MAX_TXDMA_COOKIES,	/* scatter/gather list length */
67	0x00000001,		/* granularity */
68	DDI_DMA_FLAGERR		/* dma_attr_flags */
69};
70
71
72ddi_dma_attr_t oce_tx_dma_buf_attr = {
73	DMA_ATTR_V0,		/* version number */
74	0x0000000000000000ull,	/* low address */
75	0xFFFFFFFFFFFFFFFFull,	/* high address */
76	0x00000000FFFFFFFFull,	/* dma counter max */
77	OCE_DMA_ALIGNMENT,	/* alignment */
78	0x000007FF,		/* burst sizes */
79	0x00000001,		/* minimum transfer size */
80	0x00000000FFFFFFFFull,	/* maximum transfer size */
81	0xFFFFFFFFFFFFFFFFull,	/* maximum segment size */
82	1,			/* scatter/gather list length */
83	0x00000001,		/* granularity */
84	DDI_DMA_FLAGERR		/* dma_attr_flags */
85};
86
87/*
88 * WQ map handle destructor
89 *
90 * wq - Pointer to WQ structure
91 * wqmd - pointer to WQE mapping handle descriptor
92 *
93 * return none
94 */
95
96static void
97oce_wqm_dtor(struct oce_wq *wq, oce_wq_mdesc_t *wqmd)
98{
99	_NOTE(ARGUNUSED(wq));
100	/* Free the DMA handle */
101	if (wqmd->dma_handle != NULL)
102		(void) ddi_dma_free_handle(&(wqmd->dma_handle));
103	wqmd->dma_handle = NULL;
104} /* oce_wqm_dtor */
105
106/*
107 * WQ map handles contructor
108 *
109 * wqmd - pointer to WQE mapping handle descriptor
110 * wq - Pointer to WQ structure
111 *
112 * return DDI_SUCCESS=>success, DDI_FAILURE=>error
113 */
114static int
115oce_wqm_ctor(oce_wq_mdesc_t *wqmd, struct oce_wq *wq)
116{
117	struct oce_dev *dev;
118	int ret;
119
120	dev = wq->parent;
121	/* Allocate DMA handle */
122	ret = ddi_dma_alloc_handle(dev->dip, &tx_map_dma_attr,
123	    DDI_DMA_DONTWAIT, NULL, &wqmd->dma_handle);
124
125	return (ret);
126} /* oce_wqm_ctor */
127
128/*
129 * function to create WQ mapping handles cache
130 *
131 * wq - pointer to WQ structure
132 *
133 * return DDI_SUCCESS=>success, DDI_FAILURE=>error
134 */
135int
136oce_wqm_cache_create(struct oce_wq *wq)
137{
138	struct oce_dev *dev = wq->parent;
139	int size;
140	int cnt;
141	int ret;
142
143	size = wq->cfg.nhdl * sizeof (oce_wq_mdesc_t);
144	wq->wq_mdesc_array = kmem_zalloc(size, KM_NOSLEEP);
145	if (wq->wq_mdesc_array == NULL) {
146		return (DDI_FAILURE);
147	}
148
149	/* Create the free buffer list */
150	OCE_LIST_CREATE(&wq->wq_mdesc_list, DDI_INTR_PRI(dev->intr_pri));
151
152	for (cnt = 0; cnt < wq->cfg.nhdl; cnt++) {
153		ret = oce_wqm_ctor(&wq->wq_mdesc_array[cnt], wq);
154		if (ret != DDI_SUCCESS) {
155			goto wqm_fail;
156		}
157		OCE_LIST_INSERT_TAIL(&wq->wq_mdesc_list,
158		    &wq->wq_mdesc_array[cnt]);
159	}
160	return (DDI_SUCCESS);
161
162wqm_fail:
163	oce_wqm_cache_destroy(wq);
164	return (DDI_FAILURE);
165}
166
167/*
168 * function to destroy WQ mapping handles cache
169 *
170 * wq - pointer to WQ structure
171 *
172 * return none
173 */
174void
175oce_wqm_cache_destroy(struct oce_wq *wq)
176{
177	oce_wq_mdesc_t *wqmd;
178
179	while ((wqmd = OCE_LIST_REM_HEAD(&wq->wq_mdesc_list)) != NULL) {
180		oce_wqm_dtor(wq, wqmd);
181	}
182
183	kmem_free(wq->wq_mdesc_array,
184	    wq->cfg.nhdl * sizeof (oce_wq_mdesc_t));
185
186	OCE_LIST_DESTROY(&wq->wq_mdesc_list);
187}
188
189/*
190 * function to create  WQ buffer cache
191 *
192 * wq - pointer to WQ structure
193 * buf_size - size of the buffer
194 *
195 * return DDI_SUCCESS=>success, DDI_FAILURE=>error
196 */
197int
198oce_wqb_cache_create(struct oce_wq *wq, size_t buf_size)
199{
200	struct oce_dev *dev = wq->parent;
201	int size;
202	int cnt;
203	int ret;
204
205	size = wq->cfg.nbufs * sizeof (oce_wq_bdesc_t);
206	wq->wq_bdesc_array = kmem_zalloc(size, KM_NOSLEEP);
207	if (wq->wq_bdesc_array == NULL) {
208		return (DDI_FAILURE);
209	}
210
211	/* Create the free buffer list */
212	OCE_LIST_CREATE(&wq->wq_buf_list, DDI_INTR_PRI(dev->intr_pri));
213
214	for (cnt = 0; cnt <  wq->cfg.nbufs; cnt++) {
215		ret = oce_wqb_ctor(&wq->wq_bdesc_array[cnt],
216		    wq, buf_size, DDI_DMA_STREAMING);
217		if (ret != DDI_SUCCESS) {
218			goto wqb_fail;
219		}
220		OCE_LIST_INSERT_TAIL(&wq->wq_buf_list,
221		    &wq->wq_bdesc_array[cnt]);
222	}
223	return (DDI_SUCCESS);
224
225wqb_fail:
226	oce_wqb_cache_destroy(wq);
227	return (DDI_FAILURE);
228}
229
230/*
231 * function to destroy WQ buffer cache
232 *
233 * wq - pointer to WQ structure
234 *
235 * return none
236 */
237void
238oce_wqb_cache_destroy(struct oce_wq *wq)
239{
240	oce_wq_bdesc_t *wqbd;
241	while ((wqbd = OCE_LIST_REM_HEAD(&wq->wq_buf_list)) != NULL) {
242		oce_wqb_dtor(wq, wqbd);
243	}
244	kmem_free(wq->wq_bdesc_array,
245	    wq->cfg.nbufs * sizeof (oce_wq_bdesc_t));
246	OCE_LIST_DESTROY(&wq->wq_buf_list);
247}
248
249/*
250 * WQ buffer constructor
251 *
252 * wqbd - pointer to WQ buffer descriptor
253 * wq - pointer to WQ structure
254 * size - size of the buffer
255 * flags - KM_SLEEP or KM_NOSLEEP
256 *
257 * return DDI_SUCCESS=>success, DDI_FAILURE=>error
258 */
259static int
260oce_wqb_ctor(oce_wq_bdesc_t *wqbd, struct oce_wq *wq, size_t size, int flags)
261{
262	struct oce_dev *dev;
263	dev = wq->parent;
264
265	wqbd->wqb = oce_alloc_dma_buffer(dev, size, &oce_tx_dma_buf_attr,
266	    flags);
267	if (wqbd->wqb == NULL) {
268		return (DDI_FAILURE);
269	}
270	wqbd->frag_addr.dw.addr_lo = ADDR_LO(wqbd->wqb->addr);
271	wqbd->frag_addr.dw.addr_hi = ADDR_HI(wqbd->wqb->addr);
272	return (DDI_SUCCESS);
273}
274
275/*
276 * WQ buffer destructor
277 *
278 * wq - pointer to WQ structure
279 * wqbd - pointer to WQ buffer descriptor
280 *
281 * return none
282 */
283static void
284oce_wqb_dtor(struct oce_wq *wq, oce_wq_bdesc_t *wqbd)
285{
286	oce_free_dma_buffer(wq->parent, wqbd->wqb);
287}
288
289/*
290 * function to alloc   WQE buffer descriptor
291 *
292 * wq - pointer to WQ structure
293 *
294 * return pointer to WQE buffer descriptor
295 */
296static inline oce_wq_bdesc_t *
297oce_wqb_alloc(struct oce_wq *wq)
298{
299	return (OCE_LIST_REM_HEAD(&wq->wq_buf_list));
300}
301
302/*
303 * function to free   WQE buffer descriptor
304 *
305 * wq - pointer to WQ structure
306 * wqbd - pointer to WQ buffer descriptor
307 *
308 * return none
309 */
310static inline void
311oce_wqb_free(struct oce_wq *wq, oce_wq_bdesc_t *wqbd)
312{
313	OCE_LIST_INSERT_TAIL(&wq->wq_buf_list, wqbd);
314} /* oce_wqb_free */
315
316/*
317 * function to allocate   WQE mapping descriptor
318 *
319 * wq - pointer to WQ structure
320 *
321 * return pointer to WQE mapping descriptor
322 */
323static inline oce_wq_mdesc_t *
324oce_wqm_alloc(struct oce_wq *wq)
325{
326	return (OCE_LIST_REM_HEAD(&wq->wq_mdesc_list));
327} /* oce_wqm_alloc */
328
329/*
330 * function to insert	WQE mapping descriptor to the list
331 *
332 * wq - pointer to WQ structure
333 * wqmd - Pointer to WQ mapping descriptor
334 *
335 * return none
336 */
337static inline void
338oce_wqm_free(struct oce_wq *wq, oce_wq_mdesc_t *wqmd)
339{
340	OCE_LIST_INSERT_TAIL(&wq->wq_mdesc_list, wqmd);
341}
342
343/*
344 * function to free  WQE mapping descriptor
345 *
346 * wq - pointer to WQ structure
347 * wqmd - Pointer to WQ mapping descriptor
348 *
349 * return none
350 */
351static void
352oce_wqmd_free(struct oce_wq *wq, oce_wq_mdesc_t *wqmd)
353{
354	if (wqmd == NULL) {
355		return;
356	}
357	(void) ddi_dma_unbind_handle(wqmd->dma_handle);
358	oce_wqm_free(wq, wqmd);
359}
360
361/*
362 * WQED kmem_cache constructor
363 *
364 * buf - pointer to WQE descriptor
365 *
366 * return DDI_SUCCESS
367 */
368int
369oce_wqe_desc_ctor(void *buf, void *arg, int kmflags)
370{
371	_NOTE(ARGUNUSED(buf));
372	_NOTE(ARGUNUSED(arg));
373	_NOTE(ARGUNUSED(kmflags));
374
375	return (DDI_SUCCESS);
376}
377
378/*
379 * WQED kmem_cache destructor
380 *
381 * buf - pointer to WQE descriptor
382 *
383 * return none
384 */
385void
386oce_wqe_desc_dtor(void *buf, void *arg)
387{
388	_NOTE(ARGUNUSED(buf));
389	_NOTE(ARGUNUSED(arg));
390}
391
392/*
393 * function to choose a WQ given a mblk depending on priority, flowID etc.
394 *
395 * dev - software handle to device
396 * mp - the mblk to send
397 *
398 * return pointer to the WQ selected
399 */
400static uint8_t oce_tx_hash_policy = 0x4;
401struct oce_wq *
402oce_get_wq(struct oce_dev *dev, mblk_t *mp)
403{
404	struct oce_wq *wq;
405	int qidx = 0;
406	if (dev->nwqs > 1) {
407		qidx = mac_pkt_hash(DL_ETHER, mp, oce_tx_hash_policy, B_TRUE);
408		qidx = qidx % dev->nwqs;
409
410	} else {
411		qidx = 0;
412	}
413	wq = dev->wq[qidx];
414	/* for the time being hardcode */
415	return (wq);
416} /* oce_get_wq */
417
418/*
419 * function to populate the single WQE
420 *
421 * wq - pointer to wq
422 * wqed - pointer to WQ entry  descriptor
423 *
424 * return none
425 */
426#pragma inline(oce_fill_ring_descs)
427static void
428oce_fill_ring_descs(struct oce_wq *wq, oce_wqe_desc_t *wqed)
429{
430
431	struct oce_nic_frag_wqe *wqe;
432	int i;
433	/* Copy the precreate WQE descs to the ring desc */
434	for (i = 0; i < wqed->wqe_cnt; i++) {
435		wqe = RING_GET_PRODUCER_ITEM_VA(wq->ring,
436		    struct oce_nic_frag_wqe);
437
438		bcopy(&wqed->frag[i], wqe, NIC_WQE_SIZE);
439		RING_PUT(wq->ring, 1);
440	}
441} /* oce_fill_ring_descs */
442
443/*
444 * function to copy the packet to preallocated Tx buffer
445 *
446 * wq - pointer to WQ
447 * wqed - Pointer to WQE descriptor
448 * mp - Pointer to packet chain
449 * pktlen - Size of the packet
450 *
451 * return 0=>success, error code otherwise
452 */
453static int
454oce_bcopy_wqe(struct oce_wq *wq, oce_wqe_desc_t *wqed, mblk_t *mp,
455    uint32_t pkt_len)
456{
457	oce_wq_bdesc_t *wqbd;
458	caddr_t buf_va;
459	struct oce_dev *dev = wq->parent;
460	int len = 0;
461
462	wqbd = oce_wqb_alloc(wq);
463	if (wqbd == NULL) {
464		atomic_inc_32(&dev->tx_noxmtbuf);
465		oce_log(dev, CE_WARN, MOD_TX, "%s",
466		    "wqb pool empty");
467		return (ENOMEM);
468	}
469
470	/* create a fragment wqe for the packet */
471	wqed->frag[wqed->frag_idx].u0.s.frag_pa_hi = wqbd->frag_addr.dw.addr_hi;
472	wqed->frag[wqed->frag_idx].u0.s.frag_pa_lo = wqbd->frag_addr.dw.addr_lo;
473	buf_va = DBUF_VA(wqbd->wqb);
474
475	/* copy pkt into buffer */
476	for (len = 0; mp != NULL && len < pkt_len; mp = mp->b_cont) {
477		bcopy(mp->b_rptr, buf_va, MBLKL(mp));
478		buf_va += MBLKL(mp);
479		len += MBLKL(mp);
480	}
481
482	(void) ddi_dma_sync(DBUF_DHDL(wqbd->wqb), 0, pkt_len,
483	    DDI_DMA_SYNC_FORDEV);
484
485	if (oce_fm_check_dma_handle(dev, DBUF_DHDL(wqbd->wqb))) {
486		ddi_fm_service_impact(dev->dip, DDI_SERVICE_DEGRADED);
487		/* Free the buffer */
488		oce_wqb_free(wq, wqbd);
489		return (EIO);
490	}
491	wqed->frag[wqed->frag_idx].u0.s.frag_len   =  pkt_len;
492	wqed->hdesc[wqed->nhdl].hdl = (void *)(wqbd);
493	wqed->hdesc[wqed->nhdl].type = COPY_WQE;
494	wqed->frag_cnt++;
495	wqed->frag_idx++;
496	wqed->nhdl++;
497	return (0);
498} /* oce_bcopy_wqe */
499
500/*
501 * function to copy the packet or dma map on the fly depending on size
502 *
503 * wq - pointer to WQ
504 * wqed - Pointer to WQE descriptor
505 * mp - Pointer to packet chain
506 *
507 * return DDI_SUCCESS=>success, DDI_FAILURE=>error
508 */
509static  int
510oce_map_wqe(struct oce_wq *wq, oce_wqe_desc_t *wqed, mblk_t *mp,
511    uint32_t pkt_len)
512{
513	ddi_dma_cookie_t cookie;
514	oce_wq_mdesc_t *wqmd;
515	uint32_t ncookies;
516	int ret;
517	struct oce_dev *dev = wq->parent;
518
519	wqmd = oce_wqm_alloc(wq);
520	if (wqmd == NULL) {
521		oce_log(dev, CE_WARN, MOD_TX, "%s",
522		    "wqm pool empty");
523		return (ENOMEM);
524	}
525
526	ret = ddi_dma_addr_bind_handle(wqmd->dma_handle,
527	    (struct as *)0, (caddr_t)mp->b_rptr,
528	    pkt_len, DDI_DMA_WRITE | DDI_DMA_STREAMING,
529	    DDI_DMA_DONTWAIT, NULL, &cookie, &ncookies);
530	if (ret != DDI_DMA_MAPPED) {
531		oce_log(dev, CE_WARN, MOD_TX, "MAP FAILED %d",
532		    ret);
533		/* free the last one */
534		oce_wqm_free(wq, wqmd);
535		return (ENOMEM);
536	}
537	do {
538		wqed->frag[wqed->frag_idx].u0.s.frag_pa_hi =
539		    ADDR_HI(cookie.dmac_laddress);
540		wqed->frag[wqed->frag_idx].u0.s.frag_pa_lo =
541		    ADDR_LO(cookie.dmac_laddress);
542		wqed->frag[wqed->frag_idx].u0.s.frag_len =
543		    (uint32_t)cookie.dmac_size;
544		wqed->frag_cnt++;
545		wqed->frag_idx++;
546		if (--ncookies > 0)
547			ddi_dma_nextcookie(wqmd->dma_handle,
548			    &cookie);
549			else break;
550	} while (ncookies > 0);
551
552	wqed->hdesc[wqed->nhdl].hdl = (void *)wqmd;
553	wqed->hdesc[wqed->nhdl].type = MAPPED_WQE;
554	wqed->nhdl++;
555	return (0);
556} /* oce_map_wqe */
557
558static inline int
559oce_process_tx_compl(struct oce_wq *wq, boolean_t rearm)
560{
561	struct oce_nic_tx_cqe *cqe;
562	uint16_t num_cqe = 0;
563	struct oce_cq *cq;
564	oce_wqe_desc_t *wqed;
565	int wqe_freed = 0;
566	struct oce_dev *dev;
567
568	cq  = wq->cq;
569	dev = wq->parent;
570	(void) ddi_dma_sync(cq->ring->dbuf->dma_handle, 0, 0,
571	    DDI_DMA_SYNC_FORKERNEL);
572
573	mutex_enter(&wq->txc_lock);
574	cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring, struct oce_nic_tx_cqe);
575	while (WQ_CQE_VALID(cqe)) {
576
577		DW_SWAP(u32ptr(cqe), sizeof (struct oce_nic_tx_cqe));
578
579		/* update stats */
580		if (cqe->u0.s.status != 0) {
581			atomic_inc_32(&dev->tx_errors);
582		}
583
584		/* complete the WQEs */
585		wqed = OCE_LIST_REM_HEAD(&wq->wqe_desc_list);
586
587		wqe_freed = wqed->wqe_cnt;
588		oce_free_wqed(wq, wqed);
589		RING_GET(wq->ring, wqe_freed);
590		atomic_add_32(&wq->wq_free, wqe_freed);
591		/* clear the valid bit and progress cqe */
592		WQ_CQE_INVALIDATE(cqe);
593		RING_GET(cq->ring, 1);
594		cqe = RING_GET_CONSUMER_ITEM_VA(cq->ring,
595		    struct oce_nic_tx_cqe);
596		num_cqe++;
597	} /* for all valid CQE */
598	mutex_exit(&wq->txc_lock);
599	if (num_cqe)
600		oce_arm_cq(wq->parent, cq->cq_id, num_cqe, rearm);
601	return (num_cqe);
602} /* oce_process_tx_completion */
603
604/*
605 * function to drain a TxCQ and process its CQEs
606 *
607 * dev - software handle to the device
608 * cq - pointer to the cq to drain
609 *
610 * return the number of CQEs processed
611 */
612uint16_t
613oce_drain_wq_cq(void *arg)
614{
615	uint16_t num_cqe = 0;
616	struct oce_dev *dev;
617	struct oce_wq *wq;
618
619	wq = (struct oce_wq *)arg;
620	dev = wq->parent;
621
622	/* do while we do not reach a cqe that is not valid */
623	num_cqe = oce_process_tx_compl(wq, B_FALSE);
624
625	/* check if we need to restart Tx */
626	if (wq->resched && num_cqe) {
627		wq->resched = B_FALSE;
628		mac_tx_update(dev->mac_handle);
629	}
630
631	return (num_cqe);
632} /* oce_process_wq_cqe */
633
634/*
635 * function to insert vtag to packet
636 *
637 * mp - mblk pointer
638 * vlan_tag - tag to be inserted
639 *
640 * return none
641 */
642static inline void
643oce_insert_vtag(mblk_t *mp, uint16_t vlan_tag)
644{
645	struct ether_vlan_header  *evh;
646	(void) memmove(mp->b_rptr - VLAN_TAGSZ,
647	    mp->b_rptr, 2 * ETHERADDRL);
648	mp->b_rptr -= VLAN_TAGSZ;
649	evh = (struct ether_vlan_header *)(void *)mp->b_rptr;
650	evh->ether_tpid = htons(VLAN_TPID);
651	evh->ether_tci = htons(vlan_tag);
652}
653
654/*
655 * function to strip  vtag from packet
656 *
657 * mp - mblk pointer
658 *
659 * return none
660 */
661
662static inline void
663oce_remove_vtag(mblk_t *mp)
664{
665	(void) memmove(mp->b_rptr + VLAN_TAGSZ, mp->b_rptr,
666	    ETHERADDRL * 2);
667	mp->b_rptr += VLAN_TAGSZ;
668}
669
670/*
671 * function to xmit  Single packet over the wire
672 *
673 * wq - pointer to WQ
674 * mp - Pointer to packet chain
675 *
676 * return pointer to the packet
677 */
678mblk_t *
679oce_send_packet(struct oce_wq *wq, mblk_t *mp)
680{
681
682	struct oce_nic_hdr_wqe *wqeh;
683	struct oce_dev *dev;
684	struct ether_header *eh;
685	struct ether_vlan_header *evh;
686	int32_t num_wqes;
687	uint16_t etype;
688	uint32_t ip_offset;
689	uint32_t csum_flags = 0;
690	boolean_t use_copy = B_FALSE;
691	boolean_t tagged   = B_FALSE;
692	uint16_t  vlan_tag;
693	uint32_t  reg_value = 0;
694	oce_wqe_desc_t *wqed = NULL;
695	mblk_t *nmp = NULL;
696	mblk_t *tmp = NULL;
697	uint32_t pkt_len = 0;
698	int num_mblks = 0;
699	int ret = 0;
700	uint32_t mss = 0;
701	uint32_t flags = 0;
702	int len = 0;
703
704	/* retrieve the adap priv struct ptr */
705	dev = wq->parent;
706
707	/* check if we have enough free slots */
708	if (wq->wq_free < dev->tx_reclaim_threshold) {
709		(void) oce_process_tx_compl(wq, B_FALSE);
710	}
711	if (wq->wq_free < OCE_MAX_TX_HDL) {
712		return (mp);
713	}
714
715	/* check if we should copy */
716	for (tmp = mp; tmp != NULL; tmp = tmp->b_cont) {
717		pkt_len += MBLKL(tmp);
718		num_mblks++;
719	}
720
721	if (pkt_len == 0 || num_mblks == 0) {
722		freemsg(mp);
723		return (NULL);
724	}
725
726	/* retrieve LSO information */
727	mac_lso_get(mp, &mss, &flags);
728
729	/* get the offload flags */
730	mac_hcksum_get(mp, NULL, NULL, NULL, NULL, &csum_flags);
731
732	/* restrict the mapped segment to wat we support */
733	if (num_mblks  > OCE_MAX_TX_HDL) {
734		nmp = msgpullup(mp, -1);
735		if (nmp == NULL) {
736			atomic_inc_32(&wq->pkt_drops);
737			freemsg(mp);
738			return (NULL);
739		}
740		/* Reset it to new collapsed mp */
741		freemsg(mp);
742		mp = nmp;
743	}
744
745	/* Get the packet descriptor for Tx */
746	wqed = kmem_cache_alloc(wq->wqed_cache, KM_NOSLEEP);
747	if (wqed == NULL) {
748		atomic_inc_32(&wq->pkt_drops);
749		freemsg(mp);
750		return (NULL);
751	}
752	eh = (struct ether_header *)(void *)mp->b_rptr;
753	if (ntohs(eh->ether_type) == VLAN_TPID) {
754		evh = (struct ether_vlan_header *)(void *)mp->b_rptr;
755		tagged = B_TRUE;
756		etype = ntohs(evh->ether_type);
757		ip_offset = sizeof (struct ether_vlan_header);
758		pkt_len -= VLAN_TAGSZ;
759		vlan_tag = ntohs(evh->ether_tci);
760		oce_remove_vtag(mp);
761	} else {
762		etype = ntohs(eh->ether_type);
763		ip_offset = sizeof (struct ether_header);
764	}
765
766	/* Save the WQ pointer */
767	wqed->wq = wq;
768	wqed->frag_idx = 1; /* index zero is always header */
769	wqed->frag_cnt = 0;
770	wqed->nhdl = 0;
771	wqed->mp = NULL;
772	OCE_LIST_LINK_INIT(&wqed->link);
773
774	/* If entire packet is less than the copy limit  just do copy */
775	if (pkt_len < dev->tx_bcopy_limit) {
776		use_copy = B_TRUE;
777		ret = oce_bcopy_wqe(wq, wqed, mp, pkt_len);
778	} else {
779		/* copy or dma map the individual fragments */
780		for (nmp = mp; nmp != NULL; nmp = nmp->b_cont) {
781			len = MBLKL(nmp);
782			if (len == 0) {
783				continue;
784			}
785			if (len < dev->tx_bcopy_limit) {
786				ret = oce_bcopy_wqe(wq, wqed, nmp, len);
787			} else {
788				ret = oce_map_wqe(wq, wqed, nmp, len);
789			}
790			if (ret != 0)
791				break;
792		}
793	}
794
795	/*
796	 * Any failure other than insufficient Q entries
797	 * drop the packet
798	 */
799	if (ret != 0) {
800		oce_free_wqed(wq, wqed);
801		atomic_inc_32(&wq->pkt_drops);
802		freemsg(mp);
803		return (NULL);
804	}
805
806	wqeh = (struct oce_nic_hdr_wqe *)&wqed->frag[0];
807	bzero(wqeh, sizeof (struct oce_nic_hdr_wqe));
808
809	/* fill rest of wqe header fields based on packet */
810	if (flags & HW_LSO) {
811		wqeh->u0.s.lso = B_TRUE;
812		wqeh->u0.s.lso_mss = mss;
813	}
814	if (csum_flags & HCK_FULLCKSUM) {
815		uint8_t *proto;
816		if (etype == ETHERTYPE_IP) {
817			proto = (uint8_t *)(void *)
818			    (mp->b_rptr + ip_offset);
819			if (proto[9] == 6)
820				/* IPPROTO_TCP */
821				wqeh->u0.s.tcpcs = B_TRUE;
822			else if (proto[9] == 17)
823				/* IPPROTO_UDP */
824				wqeh->u0.s.udpcs = B_TRUE;
825		}
826	}
827
828	if (csum_flags & HCK_IPV4_HDRCKSUM)
829		wqeh->u0.s.ipcs = B_TRUE;
830	if (tagged) {
831		wqeh->u0.s.vlan = B_TRUE;
832		wqeh->u0.s.vlan_tag = vlan_tag;
833	}
834
835	wqeh->u0.s.complete = B_TRUE;
836	wqeh->u0.s.event = B_TRUE;
837	wqeh->u0.s.crc = B_TRUE;
838	wqeh->u0.s.total_length = pkt_len;
839
840	num_wqes = wqed->frag_cnt + 1;
841
842	/* h/w expects even no. of WQEs */
843	if (num_wqes & 0x1) {
844		bzero(&wqed->frag[num_wqes], sizeof (struct oce_nic_frag_wqe));
845		num_wqes++;
846	}
847	wqed->wqe_cnt = (uint16_t)num_wqes;
848	wqeh->u0.s.num_wqe = num_wqes;
849	DW_SWAP(u32ptr(&wqed->frag[0]), (wqed->wqe_cnt * NIC_WQE_SIZE));
850
851	mutex_enter(&wq->tx_lock);
852	if (num_wqes > wq->wq_free) {
853		atomic_inc_32(&wq->tx_deferd);
854		mutex_exit(&wq->tx_lock);
855		goto wqe_fail;
856	}
857	atomic_add_32(&wq->wq_free, -num_wqes);
858
859	/* fill the wq for adapter */
860	oce_fill_ring_descs(wq, wqed);
861
862	/* Add the packet desc to list to be retrieved during cmpl */
863	OCE_LIST_INSERT_TAIL(&wq->wqe_desc_list,  wqed);
864	(void) ddi_dma_sync(wq->ring->dbuf->dma_handle, 0, 0,
865	    DDI_DMA_SYNC_FORDEV);
866
867	/* ring tx doorbell */
868	reg_value = (num_wqes << 16) | wq->wq_id;
869	/* Ring the door bell  */
870	OCE_DB_WRITE32(dev, PD_TXULP_DB, reg_value);
871	mutex_exit(&wq->tx_lock);
872	if (oce_fm_check_acc_handle(dev, dev->db_handle) != DDI_FM_OK) {
873		ddi_fm_service_impact(dev->dip, DDI_SERVICE_DEGRADED);
874	}
875
876	/* free mp if copied or packet chain collapsed */
877	if (use_copy == B_TRUE) {
878		freemsg(mp);
879	} else
880		wqed->mp = mp;
881	return (NULL);
882
883wqe_fail:
884
885	if (tagged) {
886		oce_insert_vtag(mp, vlan_tag);
887	}
888	oce_free_wqed(wq, wqed);
889	return (mp);
890} /* oce_send_packet */
891
892/*
893 * function to free the WQE descriptor
894 *
895 * wq - pointer to WQ
896 * wqed - Pointer to WQE descriptor
897 *
898 * return none
899 */
900#pragma inline(oce_free_wqed)
901static void
902oce_free_wqed(struct oce_wq *wq, oce_wqe_desc_t *wqed)
903{
904	int i = 0;
905	if (wqed == NULL) {
906		return;
907	}
908
909	for (i = 0; i < wqed->nhdl; i++) {
910		if (wqed->hdesc[i].type == COPY_WQE) {
911		oce_wqb_free(wq, wqed->hdesc[i].hdl);
912		} else 	if (wqed->hdesc[i].type == MAPPED_WQE) {
913			oce_wqmd_free(wq, wqed->hdesc[i].hdl);
914		}
915	}
916	if (wqed->mp)
917		freemsg(wqed->mp);
918	kmem_cache_free(wq->wqed_cache, wqed);
919} /* oce_free_wqed */
920
921/*
922 * function to start the WQ
923 *
924 * wq - pointer to WQ
925 *
926 * return DDI_SUCCESS
927 */
928
929int
930oce_start_wq(struct oce_wq *wq)
931{
932	_NOTE(ARGUNUSED(wq));
933	return (DDI_SUCCESS);
934} /* oce_start_wq */
935
936/*
937 * function to stop  the WQ
938 *
939 * wq - pointer to WQ
940 *
941 * return none
942 */
943void
944oce_clean_wq(struct oce_wq *wq)
945{
946	oce_wqe_desc_t *wqed;
947	int ti;
948
949	/* Wait for already posted Tx to complete */
950
951	for (ti = 0; ti < DEFAULT_DRAIN_TIME; ti++) {
952		(void) oce_process_tx_compl(wq, B_FALSE);
953		OCE_MSDELAY(1);
954	}
955
956	/* Free the remaining descriptors */
957	while ((wqed = OCE_LIST_REM_HEAD(&wq->wqe_desc_list)) != NULL) {
958		atomic_add_32(&wq->wq_free, wqed->wqe_cnt);
959		oce_free_wqed(wq, wqed);
960	}
961	oce_drain_eq(wq->cq->eq);
962} /* oce_stop_wq */
963
964/*
965 * function to set the tx mapping handle fma attr
966 *
967 * fm_caps - capability flags
968 *
969 * return none
970 */
971
972void
973oce_set_tx_map_dma_fma_flags(int fm_caps)
974{
975	if (fm_caps == DDI_FM_NOT_CAPABLE) {
976		return;
977	}
978
979	if (DDI_FM_DMA_ERR_CAP(fm_caps)) {
980		tx_map_dma_attr.dma_attr_flags |= DDI_DMA_FLAGERR;
981	} else {
982		tx_map_dma_attr.dma_attr_flags &= ~DDI_DMA_FLAGERR;
983	}
984} /* oce_set_tx_map_dma_fma_flags */
985