xref: /freebsd/sys/dev/qlxgb/qla_hw.c (revision 685dc743dc3b5645e34836464128e1c0558b404b)
1718cf2ccSPedro F. Giffuni /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3718cf2ccSPedro F. Giffuni  *
4088fc971SDavid C Somayajulu  * Copyright (c) 2011-2012 Qlogic Corporation
50bc7cf6fSBjoern A. Zeeb  * All rights reserved.
60bc7cf6fSBjoern A. Zeeb  *
70bc7cf6fSBjoern A. Zeeb  *  Redistribution and use in source and binary forms, with or without
80bc7cf6fSBjoern A. Zeeb  *  modification, are permitted provided that the following conditions
90bc7cf6fSBjoern A. Zeeb  *  are met:
100bc7cf6fSBjoern A. Zeeb  *
110bc7cf6fSBjoern A. Zeeb  *  1. Redistributions of source code must retain the above copyright
120bc7cf6fSBjoern A. Zeeb  *     notice, this list of conditions and the following disclaimer.
130bc7cf6fSBjoern A. Zeeb  *  2. Redistributions in binary form must reproduce the above copyright
140bc7cf6fSBjoern A. Zeeb  *     notice, this list of conditions and the following disclaimer in the
150bc7cf6fSBjoern A. Zeeb  *     documentation and/or other materials provided with the distribution.
160bc7cf6fSBjoern A. Zeeb  *
170bc7cf6fSBjoern A. Zeeb  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
180bc7cf6fSBjoern A. Zeeb  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
190bc7cf6fSBjoern A. Zeeb  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
200bc7cf6fSBjoern A. Zeeb  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
210bc7cf6fSBjoern A. Zeeb  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
220bc7cf6fSBjoern A. Zeeb  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
230bc7cf6fSBjoern A. Zeeb  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
240bc7cf6fSBjoern A. Zeeb  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
250bc7cf6fSBjoern A. Zeeb  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
260bc7cf6fSBjoern A. Zeeb  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
270bc7cf6fSBjoern A. Zeeb  *  POSSIBILITY OF SUCH DAMAGE.
280bc7cf6fSBjoern A. Zeeb  */
290bc7cf6fSBjoern A. Zeeb 
300bc7cf6fSBjoern A. Zeeb /*
310bc7cf6fSBjoern A. Zeeb  * File: qla_hw.c
320bc7cf6fSBjoern A. Zeeb  * Author : David C Somayajulu, Qlogic Corporation, Aliso Viejo, CA 92656.
33453130d9SPedro F. Giffuni  * Content: Contains Hardware dependent functions
340bc7cf6fSBjoern A. Zeeb  */
350bc7cf6fSBjoern A. Zeeb 
360bc7cf6fSBjoern A. Zeeb #include <sys/cdefs.h>
370bc7cf6fSBjoern A. Zeeb #include "qla_os.h"
380bc7cf6fSBjoern A. Zeeb #include "qla_reg.h"
390bc7cf6fSBjoern A. Zeeb #include "qla_hw.h"
400bc7cf6fSBjoern A. Zeeb #include "qla_def.h"
410bc7cf6fSBjoern A. Zeeb #include "qla_inline.h"
420bc7cf6fSBjoern A. Zeeb #include "qla_ver.h"
430bc7cf6fSBjoern A. Zeeb #include "qla_glbl.h"
440bc7cf6fSBjoern A. Zeeb #include "qla_dbg.h"
450bc7cf6fSBjoern A. Zeeb 
460bc7cf6fSBjoern A. Zeeb static uint32_t sysctl_num_rds_rings = 2;
470bc7cf6fSBjoern A. Zeeb static uint32_t sysctl_num_sds_rings = 4;
480bc7cf6fSBjoern A. Zeeb 
490bc7cf6fSBjoern A. Zeeb /*
500bc7cf6fSBjoern A. Zeeb  * Static Functions
510bc7cf6fSBjoern A. Zeeb  */
520bc7cf6fSBjoern A. Zeeb 
530bc7cf6fSBjoern A. Zeeb static void qla_init_cntxt_regions(qla_host_t *ha);
540bc7cf6fSBjoern A. Zeeb static int qla_issue_cmd(qla_host_t *ha, qla_cdrp_t *cdrp);
550bc7cf6fSBjoern A. Zeeb static int qla_fw_cmd(qla_host_t *ha, void *fw_cmd, uint32_t size);
560bc7cf6fSBjoern A. Zeeb static int qla_config_mac_addr(qla_host_t *ha, uint8_t *mac_addr,
570bc7cf6fSBjoern A. Zeeb 		uint16_t cntxt_id, uint32_t add_multi);
580bc7cf6fSBjoern A. Zeeb static void qla_del_rcv_cntxt(qla_host_t *ha);
590bc7cf6fSBjoern A. Zeeb static int qla_init_rcv_cntxt(qla_host_t *ha);
600bc7cf6fSBjoern A. Zeeb static void qla_del_xmt_cntxt(qla_host_t *ha);
610bc7cf6fSBjoern A. Zeeb static int qla_init_xmt_cntxt(qla_host_t *ha);
620bc7cf6fSBjoern A. Zeeb static int qla_get_max_rds(qla_host_t *ha);
630bc7cf6fSBjoern A. Zeeb static int qla_get_max_sds(qla_host_t *ha);
640bc7cf6fSBjoern A. Zeeb static int qla_get_max_rules(qla_host_t *ha);
650bc7cf6fSBjoern A. Zeeb static int qla_get_max_rcv_cntxts(qla_host_t *ha);
660bc7cf6fSBjoern A. Zeeb static int qla_get_max_tx_cntxts(qla_host_t *ha);
670bc7cf6fSBjoern A. Zeeb static int qla_get_max_mtu(qla_host_t *ha);
680bc7cf6fSBjoern A. Zeeb static int qla_get_max_lro(qla_host_t *ha);
690bc7cf6fSBjoern A. Zeeb static int qla_get_flow_control(qla_host_t *ha);
700bc7cf6fSBjoern A. Zeeb static void qla_hw_tx_done_locked(qla_host_t *ha);
710bc7cf6fSBjoern A. Zeeb 
720bc7cf6fSBjoern A. Zeeb int
qla_get_msix_count(qla_host_t * ha)730bc7cf6fSBjoern A. Zeeb qla_get_msix_count(qla_host_t *ha)
740bc7cf6fSBjoern A. Zeeb {
750bc7cf6fSBjoern A. Zeeb 	return (sysctl_num_sds_rings);
760bc7cf6fSBjoern A. Zeeb }
770bc7cf6fSBjoern A. Zeeb 
780bc7cf6fSBjoern A. Zeeb /*
790bc7cf6fSBjoern A. Zeeb  * Name: qla_hw_add_sysctls
800bc7cf6fSBjoern A. Zeeb  * Function: Add P3Plus specific sysctls
810bc7cf6fSBjoern A. Zeeb  */
820bc7cf6fSBjoern A. Zeeb void
qla_hw_add_sysctls(qla_host_t * ha)830bc7cf6fSBjoern A. Zeeb qla_hw_add_sysctls(qla_host_t *ha)
840bc7cf6fSBjoern A. Zeeb {
850bc7cf6fSBjoern A. Zeeb         device_t	dev;
860bc7cf6fSBjoern A. Zeeb 
870bc7cf6fSBjoern A. Zeeb         dev = ha->pci_dev;
880bc7cf6fSBjoern A. Zeeb 
890bc7cf6fSBjoern A. Zeeb         SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
900bc7cf6fSBjoern A. Zeeb                 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
910bc7cf6fSBjoern A. Zeeb                 OID_AUTO, "num_rds_rings", CTLFLAG_RD, &sysctl_num_rds_rings,
920bc7cf6fSBjoern A. Zeeb 		sysctl_num_rds_rings, "Number of Rcv Descriptor Rings");
930bc7cf6fSBjoern A. Zeeb 
940bc7cf6fSBjoern A. Zeeb         SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
950bc7cf6fSBjoern A. Zeeb                 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
960bc7cf6fSBjoern A. Zeeb                 OID_AUTO, "num_sds_rings", CTLFLAG_RD, &sysctl_num_sds_rings,
970bc7cf6fSBjoern A. Zeeb 		sysctl_num_sds_rings, "Number of Status Descriptor Rings");
980bc7cf6fSBjoern A. Zeeb }
990bc7cf6fSBjoern A. Zeeb 
1000bc7cf6fSBjoern A. Zeeb /*
1010bc7cf6fSBjoern A. Zeeb  * Name: qla_free_dma
1020bc7cf6fSBjoern A. Zeeb  * Function: Frees the DMA'able memory allocated in qla_alloc_dma()
1030bc7cf6fSBjoern A. Zeeb  */
1040bc7cf6fSBjoern A. Zeeb void
qla_free_dma(qla_host_t * ha)1050bc7cf6fSBjoern A. Zeeb qla_free_dma(qla_host_t *ha)
1060bc7cf6fSBjoern A. Zeeb {
1070bc7cf6fSBjoern A. Zeeb 	uint32_t i;
1080bc7cf6fSBjoern A. Zeeb 
1090bc7cf6fSBjoern A. Zeeb         if (ha->hw.dma_buf.flags.context) {
1100bc7cf6fSBjoern A. Zeeb 		qla_free_dmabuf(ha, &ha->hw.dma_buf.context);
1110bc7cf6fSBjoern A. Zeeb         	ha->hw.dma_buf.flags.context = 0;
1120bc7cf6fSBjoern A. Zeeb 	}
1130bc7cf6fSBjoern A. Zeeb 
1140bc7cf6fSBjoern A. Zeeb         if (ha->hw.dma_buf.flags.sds_ring) {
1150bc7cf6fSBjoern A. Zeeb 		for (i = 0; i < ha->hw.num_sds_rings; i++)
1160bc7cf6fSBjoern A. Zeeb 			qla_free_dmabuf(ha, &ha->hw.dma_buf.sds_ring[i]);
1170bc7cf6fSBjoern A. Zeeb         	ha->hw.dma_buf.flags.sds_ring = 0;
1180bc7cf6fSBjoern A. Zeeb 	}
1190bc7cf6fSBjoern A. Zeeb 
1200bc7cf6fSBjoern A. Zeeb         if (ha->hw.dma_buf.flags.rds_ring) {
1210bc7cf6fSBjoern A. Zeeb 		for (i = 0; i < ha->hw.num_rds_rings; i++)
1220bc7cf6fSBjoern A. Zeeb 			qla_free_dmabuf(ha, &ha->hw.dma_buf.rds_ring[i]);
1230bc7cf6fSBjoern A. Zeeb         	ha->hw.dma_buf.flags.rds_ring = 0;
1240bc7cf6fSBjoern A. Zeeb 	}
1250bc7cf6fSBjoern A. Zeeb 
1260bc7cf6fSBjoern A. Zeeb         if (ha->hw.dma_buf.flags.tx_ring) {
1270bc7cf6fSBjoern A. Zeeb 		qla_free_dmabuf(ha, &ha->hw.dma_buf.tx_ring);
1280bc7cf6fSBjoern A. Zeeb         	ha->hw.dma_buf.flags.tx_ring = 0;
1290bc7cf6fSBjoern A. Zeeb 	}
1300bc7cf6fSBjoern A. Zeeb }
1310bc7cf6fSBjoern A. Zeeb 
1320bc7cf6fSBjoern A. Zeeb /*
1330bc7cf6fSBjoern A. Zeeb  * Name: qla_alloc_dma
1340bc7cf6fSBjoern A. Zeeb  * Function: Allocates DMA'able memory for Tx/Rx Rings, Tx/Rx Contexts.
1350bc7cf6fSBjoern A. Zeeb  */
1360bc7cf6fSBjoern A. Zeeb int
qla_alloc_dma(qla_host_t * ha)1370bc7cf6fSBjoern A. Zeeb qla_alloc_dma(qla_host_t *ha)
1380bc7cf6fSBjoern A. Zeeb {
1390bc7cf6fSBjoern A. Zeeb         device_t                dev;
1400bc7cf6fSBjoern A. Zeeb 	uint32_t		i, j, size;
1410bc7cf6fSBjoern A. Zeeb 
1420bc7cf6fSBjoern A. Zeeb         dev = ha->pci_dev;
1430bc7cf6fSBjoern A. Zeeb 
1440bc7cf6fSBjoern A. Zeeb         QL_DPRINT2((dev, "%s: enter\n", __func__));
1450bc7cf6fSBjoern A. Zeeb 
1460bc7cf6fSBjoern A. Zeeb 	ha->hw.num_rds_rings = (uint16_t)sysctl_num_rds_rings;
1470bc7cf6fSBjoern A. Zeeb 	ha->hw.num_sds_rings = (uint16_t)sysctl_num_sds_rings;
1480bc7cf6fSBjoern A. Zeeb 
1490bc7cf6fSBjoern A. Zeeb 	/*
1500bc7cf6fSBjoern A. Zeeb 	 * Allocate Transmit Ring
1510bc7cf6fSBjoern A. Zeeb 	 */
1520bc7cf6fSBjoern A. Zeeb 
1530bc7cf6fSBjoern A. Zeeb 	ha->hw.dma_buf.tx_ring.alignment = 8;
1540bc7cf6fSBjoern A. Zeeb 	ha->hw.dma_buf.tx_ring.size =
1550bc7cf6fSBjoern A. Zeeb 		(sizeof(q80_tx_cmd_t)) * NUM_TX_DESCRIPTORS;
1560bc7cf6fSBjoern A. Zeeb 
1570bc7cf6fSBjoern A. Zeeb         if (qla_alloc_dmabuf(ha, &ha->hw.dma_buf.tx_ring)) {
1580bc7cf6fSBjoern A. Zeeb                 device_printf(dev, "%s: tx ring alloc failed\n", __func__);
1590bc7cf6fSBjoern A. Zeeb                 goto qla_alloc_dma_exit;
1600bc7cf6fSBjoern A. Zeeb         }
1610bc7cf6fSBjoern A. Zeeb         ha->hw.dma_buf.flags.tx_ring = 1;
1620bc7cf6fSBjoern A. Zeeb 
1630bc7cf6fSBjoern A. Zeeb 	QL_DPRINT2((dev, "%s: tx_ring phys %p virt %p\n",
1640bc7cf6fSBjoern A. Zeeb 		__func__, (void *)(ha->hw.dma_buf.tx_ring.dma_addr),
1650bc7cf6fSBjoern A. Zeeb 		ha->hw.dma_buf.tx_ring.dma_b));
1660bc7cf6fSBjoern A. Zeeb 	/*
1670bc7cf6fSBjoern A. Zeeb 	 * Allocate Receive Descriptor Rings
1680bc7cf6fSBjoern A. Zeeb 	 */
1690bc7cf6fSBjoern A. Zeeb 
1700bc7cf6fSBjoern A. Zeeb 	for (i = 0; i < ha->hw.num_rds_rings; i++) {
1710bc7cf6fSBjoern A. Zeeb 		ha->hw.dma_buf.rds_ring[i].alignment = 8;
1720bc7cf6fSBjoern A. Zeeb 
1730bc7cf6fSBjoern A. Zeeb 		if (i == RDS_RING_INDEX_NORMAL) {
1740bc7cf6fSBjoern A. Zeeb 			ha->hw.dma_buf.rds_ring[i].size =
1750bc7cf6fSBjoern A. Zeeb 				(sizeof(q80_recv_desc_t)) * NUM_RX_DESCRIPTORS;
1760bc7cf6fSBjoern A. Zeeb 		} else if (i == RDS_RING_INDEX_JUMBO) {
1770bc7cf6fSBjoern A. Zeeb 			ha->hw.dma_buf.rds_ring[i].size =
1780bc7cf6fSBjoern A. Zeeb 				(sizeof(q80_recv_desc_t)) *
1790bc7cf6fSBjoern A. Zeeb 					NUM_RX_JUMBO_DESCRIPTORS;
1800bc7cf6fSBjoern A. Zeeb 		} else
1810bc7cf6fSBjoern A. Zeeb 			break;
1820bc7cf6fSBjoern A. Zeeb 
1830bc7cf6fSBjoern A. Zeeb 		if (qla_alloc_dmabuf(ha, &ha->hw.dma_buf.rds_ring[i])) {
1840bc7cf6fSBjoern A. Zeeb 			QL_DPRINT4((dev, "%s: rds ring alloc failed\n",
1850bc7cf6fSBjoern A. Zeeb 				__func__));
1860bc7cf6fSBjoern A. Zeeb 
1870bc7cf6fSBjoern A. Zeeb 			for (j = 0; j < i; j++)
1880bc7cf6fSBjoern A. Zeeb 				qla_free_dmabuf(ha,
1890bc7cf6fSBjoern A. Zeeb 					&ha->hw.dma_buf.rds_ring[j]);
1900bc7cf6fSBjoern A. Zeeb 
1910bc7cf6fSBjoern A. Zeeb 			goto qla_alloc_dma_exit;
1920bc7cf6fSBjoern A. Zeeb 		}
1930bc7cf6fSBjoern A. Zeeb 		QL_DPRINT4((dev, "%s: rx_ring[%d] phys %p virt %p\n",
1940bc7cf6fSBjoern A. Zeeb 			__func__, i,
1950bc7cf6fSBjoern A. Zeeb 			(void *)(ha->hw.dma_buf.rds_ring[i].dma_addr),
1960bc7cf6fSBjoern A. Zeeb 			ha->hw.dma_buf.rds_ring[i].dma_b));
1970bc7cf6fSBjoern A. Zeeb 	}
1980bc7cf6fSBjoern A. Zeeb 	ha->hw.dma_buf.flags.rds_ring = 1;
1990bc7cf6fSBjoern A. Zeeb 
2000bc7cf6fSBjoern A. Zeeb 	/*
2010bc7cf6fSBjoern A. Zeeb 	 * Allocate Status Descriptor Rings
2020bc7cf6fSBjoern A. Zeeb 	 */
2030bc7cf6fSBjoern A. Zeeb 
2040bc7cf6fSBjoern A. Zeeb 	for (i = 0; i < ha->hw.num_sds_rings; i++) {
2050bc7cf6fSBjoern A. Zeeb 		ha->hw.dma_buf.sds_ring[i].alignment = 8;
2060bc7cf6fSBjoern A. Zeeb 		ha->hw.dma_buf.sds_ring[i].size =
2070bc7cf6fSBjoern A. Zeeb 			(sizeof(q80_stat_desc_t)) * NUM_STATUS_DESCRIPTORS;
2080bc7cf6fSBjoern A. Zeeb 
2090bc7cf6fSBjoern A. Zeeb 		if (qla_alloc_dmabuf(ha, &ha->hw.dma_buf.sds_ring[i])) {
2100bc7cf6fSBjoern A. Zeeb 			device_printf(dev, "%s: sds ring alloc failed\n",
2110bc7cf6fSBjoern A. Zeeb 				__func__);
2120bc7cf6fSBjoern A. Zeeb 
2130bc7cf6fSBjoern A. Zeeb 			for (j = 0; j < i; j++)
2140bc7cf6fSBjoern A. Zeeb 				qla_free_dmabuf(ha,
2150bc7cf6fSBjoern A. Zeeb 					&ha->hw.dma_buf.sds_ring[j]);
2160bc7cf6fSBjoern A. Zeeb 
2170bc7cf6fSBjoern A. Zeeb 			goto qla_alloc_dma_exit;
2180bc7cf6fSBjoern A. Zeeb 		}
2190bc7cf6fSBjoern A. Zeeb 		QL_DPRINT4((dev, "%s: sds_ring[%d] phys %p virt %p\n",
2200bc7cf6fSBjoern A. Zeeb 			__func__, i,
2210bc7cf6fSBjoern A. Zeeb 			(void *)(ha->hw.dma_buf.sds_ring[i].dma_addr),
2220bc7cf6fSBjoern A. Zeeb 			ha->hw.dma_buf.sds_ring[i].dma_b));
2230bc7cf6fSBjoern A. Zeeb 	}
2240bc7cf6fSBjoern A. Zeeb 	ha->hw.dma_buf.flags.sds_ring = 1;
2250bc7cf6fSBjoern A. Zeeb 
2260bc7cf6fSBjoern A. Zeeb 	/*
2270bc7cf6fSBjoern A. Zeeb 	 * Allocate Context Area
2280bc7cf6fSBjoern A. Zeeb 	 */
2290bc7cf6fSBjoern A. Zeeb 	size = QL_ALIGN((sizeof (q80_tx_cntxt_req_t)), QL_BUFFER_ALIGN);
2300bc7cf6fSBjoern A. Zeeb 
2310bc7cf6fSBjoern A. Zeeb 	size += QL_ALIGN((sizeof (q80_tx_cntxt_rsp_t)), QL_BUFFER_ALIGN);
2320bc7cf6fSBjoern A. Zeeb 
2330bc7cf6fSBjoern A. Zeeb 	size += QL_ALIGN((sizeof (q80_rcv_cntxt_req_t)), QL_BUFFER_ALIGN);
2340bc7cf6fSBjoern A. Zeeb 
2350bc7cf6fSBjoern A. Zeeb 	size += QL_ALIGN((sizeof (q80_rcv_cntxt_rsp_t)), QL_BUFFER_ALIGN);
2360bc7cf6fSBjoern A. Zeeb 
2370bc7cf6fSBjoern A. Zeeb 	size += sizeof (uint32_t); /* for tx consumer index */
2380bc7cf6fSBjoern A. Zeeb 
2390bc7cf6fSBjoern A. Zeeb 	size = QL_ALIGN(size, PAGE_SIZE);
2400bc7cf6fSBjoern A. Zeeb 
2410bc7cf6fSBjoern A. Zeeb 	ha->hw.dma_buf.context.alignment = 8;
2420bc7cf6fSBjoern A. Zeeb 	ha->hw.dma_buf.context.size = size;
2430bc7cf6fSBjoern A. Zeeb 
2440bc7cf6fSBjoern A. Zeeb         if (qla_alloc_dmabuf(ha, &ha->hw.dma_buf.context)) {
2450bc7cf6fSBjoern A. Zeeb                 device_printf(dev, "%s: context alloc failed\n", __func__);
2460bc7cf6fSBjoern A. Zeeb                 goto qla_alloc_dma_exit;
2470bc7cf6fSBjoern A. Zeeb         }
2480bc7cf6fSBjoern A. Zeeb         ha->hw.dma_buf.flags.context = 1;
2490bc7cf6fSBjoern A. Zeeb 	QL_DPRINT2((dev, "%s: context phys %p virt %p\n",
2500bc7cf6fSBjoern A. Zeeb 		__func__, (void *)(ha->hw.dma_buf.context.dma_addr),
2510bc7cf6fSBjoern A. Zeeb 		ha->hw.dma_buf.context.dma_b));
2520bc7cf6fSBjoern A. Zeeb 
2530bc7cf6fSBjoern A. Zeeb 	qla_init_cntxt_regions(ha);
2540bc7cf6fSBjoern A. Zeeb 
2550bc7cf6fSBjoern A. Zeeb 	return 0;
2560bc7cf6fSBjoern A. Zeeb 
2570bc7cf6fSBjoern A. Zeeb qla_alloc_dma_exit:
2580bc7cf6fSBjoern A. Zeeb 	qla_free_dma(ha);
2590bc7cf6fSBjoern A. Zeeb 	return -1;
2600bc7cf6fSBjoern A. Zeeb }
2610bc7cf6fSBjoern A. Zeeb 
2620bc7cf6fSBjoern A. Zeeb /*
2630bc7cf6fSBjoern A. Zeeb  * Name: qla_init_cntxt_regions
2640bc7cf6fSBjoern A. Zeeb  * Function: Initializes Tx/Rx Contexts.
2650bc7cf6fSBjoern A. Zeeb  */
2660bc7cf6fSBjoern A. Zeeb static void
qla_init_cntxt_regions(qla_host_t * ha)2670bc7cf6fSBjoern A. Zeeb qla_init_cntxt_regions(qla_host_t *ha)
2680bc7cf6fSBjoern A. Zeeb {
2690bc7cf6fSBjoern A. Zeeb 	qla_hw_t		*hw;
2700bc7cf6fSBjoern A. Zeeb 	q80_tx_cntxt_req_t	*tx_cntxt_req;
2710bc7cf6fSBjoern A. Zeeb 	q80_rcv_cntxt_req_t	*rx_cntxt_req;
2720bc7cf6fSBjoern A. Zeeb 	bus_addr_t		phys_addr;
2730bc7cf6fSBjoern A. Zeeb 	uint32_t		i;
2740bc7cf6fSBjoern A. Zeeb 	uint32_t		size;
2750bc7cf6fSBjoern A. Zeeb 
2760bc7cf6fSBjoern A. Zeeb 	hw = &ha->hw;
2770bc7cf6fSBjoern A. Zeeb 
2780bc7cf6fSBjoern A. Zeeb 	hw->tx_ring_base = hw->dma_buf.tx_ring.dma_b;
2790bc7cf6fSBjoern A. Zeeb 
2800bc7cf6fSBjoern A. Zeeb 	for (i = 0; i < ha->hw.num_sds_rings; i++)
2810bc7cf6fSBjoern A. Zeeb 		hw->sds[i].sds_ring_base =
2820bc7cf6fSBjoern A. Zeeb 			(q80_stat_desc_t *)hw->dma_buf.sds_ring[i].dma_b;
2830bc7cf6fSBjoern A. Zeeb 
2840bc7cf6fSBjoern A. Zeeb 	phys_addr = hw->dma_buf.context.dma_addr;
2850bc7cf6fSBjoern A. Zeeb 
2860bc7cf6fSBjoern A. Zeeb 	memset((void *)hw->dma_buf.context.dma_b, 0,
2870bc7cf6fSBjoern A. Zeeb 		ha->hw.dma_buf.context.size);
2880bc7cf6fSBjoern A. Zeeb 
2890bc7cf6fSBjoern A. Zeeb 	hw->tx_cntxt_req	=
2900bc7cf6fSBjoern A. Zeeb 		(q80_tx_cntxt_req_t *)hw->dma_buf.context.dma_b;
2910bc7cf6fSBjoern A. Zeeb 	hw->tx_cntxt_req_paddr	= phys_addr;
2920bc7cf6fSBjoern A. Zeeb 
2930bc7cf6fSBjoern A. Zeeb 	size = QL_ALIGN((sizeof (q80_tx_cntxt_req_t)), QL_BUFFER_ALIGN);
2940bc7cf6fSBjoern A. Zeeb 
2950bc7cf6fSBjoern A. Zeeb 	hw->tx_cntxt_rsp	=
2960bc7cf6fSBjoern A. Zeeb 		(q80_tx_cntxt_rsp_t *)((uint8_t *)hw->tx_cntxt_req + size);
2970bc7cf6fSBjoern A. Zeeb 	hw->tx_cntxt_rsp_paddr	= hw->tx_cntxt_req_paddr + size;
2980bc7cf6fSBjoern A. Zeeb 
2990bc7cf6fSBjoern A. Zeeb 	size = QL_ALIGN((sizeof (q80_tx_cntxt_rsp_t)), QL_BUFFER_ALIGN);
3000bc7cf6fSBjoern A. Zeeb 
3010bc7cf6fSBjoern A. Zeeb 	hw->rx_cntxt_req =
3020bc7cf6fSBjoern A. Zeeb 		(q80_rcv_cntxt_req_t *)((uint8_t *)hw->tx_cntxt_rsp + size);
3030bc7cf6fSBjoern A. Zeeb 	hw->rx_cntxt_req_paddr = hw->tx_cntxt_rsp_paddr + size;
3040bc7cf6fSBjoern A. Zeeb 
3050bc7cf6fSBjoern A. Zeeb 	size = QL_ALIGN((sizeof (q80_rcv_cntxt_req_t)), QL_BUFFER_ALIGN);
3060bc7cf6fSBjoern A. Zeeb 
3070bc7cf6fSBjoern A. Zeeb 	hw->rx_cntxt_rsp =
3080bc7cf6fSBjoern A. Zeeb 		(q80_rcv_cntxt_rsp_t *)((uint8_t *)hw->rx_cntxt_req + size);
3090bc7cf6fSBjoern A. Zeeb 	hw->rx_cntxt_rsp_paddr = hw->rx_cntxt_req_paddr + size;
3100bc7cf6fSBjoern A. Zeeb 
3110bc7cf6fSBjoern A. Zeeb 	size = QL_ALIGN((sizeof (q80_rcv_cntxt_rsp_t)), QL_BUFFER_ALIGN);
3120bc7cf6fSBjoern A. Zeeb 
3130bc7cf6fSBjoern A. Zeeb 	hw->tx_cons = (uint32_t *)((uint8_t *)hw->rx_cntxt_rsp + size);
3140bc7cf6fSBjoern A. Zeeb 	hw->tx_cons_paddr = hw->rx_cntxt_rsp_paddr + size;
3150bc7cf6fSBjoern A. Zeeb 
3160bc7cf6fSBjoern A. Zeeb 	/*
3170bc7cf6fSBjoern A. Zeeb 	 * Initialize the Transmit Context Request so that we don't need to
3180bc7cf6fSBjoern A. Zeeb 	 * do it every time we need to create a context
3190bc7cf6fSBjoern A. Zeeb 	 */
3200bc7cf6fSBjoern A. Zeeb 	tx_cntxt_req = hw->tx_cntxt_req;
3210bc7cf6fSBjoern A. Zeeb 
3220bc7cf6fSBjoern A. Zeeb 	tx_cntxt_req->rsp_dma_addr = qla_host_to_le64(hw->tx_cntxt_rsp_paddr);
3230bc7cf6fSBjoern A. Zeeb 
3240bc7cf6fSBjoern A. Zeeb 	tx_cntxt_req->cmd_cons_dma_addr = qla_host_to_le64(hw->tx_cons_paddr);
3250bc7cf6fSBjoern A. Zeeb 
3260bc7cf6fSBjoern A. Zeeb 	tx_cntxt_req->caps[0] = qla_host_to_le32((CNTXT_CAP0_BASEFW |
3270bc7cf6fSBjoern A. Zeeb 					CNTXT_CAP0_LEGACY_MN | CNTXT_CAP0_LSO));
3280bc7cf6fSBjoern A. Zeeb 
3290bc7cf6fSBjoern A. Zeeb 	tx_cntxt_req->intr_mode = qla_host_to_le32(CNTXT_INTR_MODE_SHARED);
3300bc7cf6fSBjoern A. Zeeb 
3310bc7cf6fSBjoern A. Zeeb 	tx_cntxt_req->phys_addr =
3320bc7cf6fSBjoern A. Zeeb 		qla_host_to_le64(hw->dma_buf.tx_ring.dma_addr);
3330bc7cf6fSBjoern A. Zeeb 
3340bc7cf6fSBjoern A. Zeeb 	tx_cntxt_req->num_entries = qla_host_to_le32(NUM_TX_DESCRIPTORS);
3350bc7cf6fSBjoern A. Zeeb 
3360bc7cf6fSBjoern A. Zeeb 	/*
3370bc7cf6fSBjoern A. Zeeb 	 * Initialize the Receive Context Request
3380bc7cf6fSBjoern A. Zeeb 	 */
3390bc7cf6fSBjoern A. Zeeb 
3400bc7cf6fSBjoern A. Zeeb 	rx_cntxt_req = hw->rx_cntxt_req;
3410bc7cf6fSBjoern A. Zeeb 
3420bc7cf6fSBjoern A. Zeeb 	rx_cntxt_req->rx_req.rsp_dma_addr =
3430bc7cf6fSBjoern A. Zeeb 		qla_host_to_le64(hw->rx_cntxt_rsp_paddr);
3440bc7cf6fSBjoern A. Zeeb 
3450bc7cf6fSBjoern A. Zeeb 	rx_cntxt_req->rx_req.caps[0] = qla_host_to_le32(CNTXT_CAP0_BASEFW |
3460bc7cf6fSBjoern A. Zeeb 						CNTXT_CAP0_LEGACY_MN |
3470bc7cf6fSBjoern A. Zeeb 						CNTXT_CAP0_JUMBO |
3480bc7cf6fSBjoern A. Zeeb 						CNTXT_CAP0_LRO|
3490bc7cf6fSBjoern A. Zeeb 						CNTXT_CAP0_HW_LRO);
3500bc7cf6fSBjoern A. Zeeb 
3510bc7cf6fSBjoern A. Zeeb 	rx_cntxt_req->rx_req.intr_mode =
3520bc7cf6fSBjoern A. Zeeb 		qla_host_to_le32(CNTXT_INTR_MODE_SHARED);
3530bc7cf6fSBjoern A. Zeeb 
3540bc7cf6fSBjoern A. Zeeb 	rx_cntxt_req->rx_req.rds_intr_mode =
3550bc7cf6fSBjoern A. Zeeb 		qla_host_to_le32(CNTXT_INTR_MODE_UNIQUE);
3560bc7cf6fSBjoern A. Zeeb 
3570bc7cf6fSBjoern A. Zeeb 	rx_cntxt_req->rx_req.rds_ring_offset = 0;
3580bc7cf6fSBjoern A. Zeeb 	rx_cntxt_req->rx_req.sds_ring_offset = qla_host_to_le32(
3590bc7cf6fSBjoern A. Zeeb 		(hw->num_rds_rings * sizeof(q80_rq_rds_ring_t)));
3600bc7cf6fSBjoern A. Zeeb 	rx_cntxt_req->rx_req.num_rds_rings =
3610bc7cf6fSBjoern A. Zeeb 		qla_host_to_le16(hw->num_rds_rings);
3620bc7cf6fSBjoern A. Zeeb 	rx_cntxt_req->rx_req.num_sds_rings =
3630bc7cf6fSBjoern A. Zeeb 		qla_host_to_le16(hw->num_sds_rings);
3640bc7cf6fSBjoern A. Zeeb 
3650bc7cf6fSBjoern A. Zeeb 	for (i = 0; i < hw->num_rds_rings; i++) {
3660bc7cf6fSBjoern A. Zeeb 		rx_cntxt_req->rds_req[i].phys_addr =
3670bc7cf6fSBjoern A. Zeeb 			qla_host_to_le64(hw->dma_buf.rds_ring[i].dma_addr);
3680bc7cf6fSBjoern A. Zeeb 
3690bc7cf6fSBjoern A. Zeeb 		if (i == RDS_RING_INDEX_NORMAL) {
3700bc7cf6fSBjoern A. Zeeb 			rx_cntxt_req->rds_req[i].buf_size =
3710bc7cf6fSBjoern A. Zeeb 				qla_host_to_le64(MCLBYTES);
3720bc7cf6fSBjoern A. Zeeb 			rx_cntxt_req->rds_req[i].size =
3730bc7cf6fSBjoern A. Zeeb 				qla_host_to_le32(NUM_RX_DESCRIPTORS);
3740bc7cf6fSBjoern A. Zeeb 		} else {
3750bc7cf6fSBjoern A. Zeeb 			rx_cntxt_req->rds_req[i].buf_size =
3760bc7cf6fSBjoern A. Zeeb 				qla_host_to_le64(MJUM9BYTES);
3770bc7cf6fSBjoern A. Zeeb 			rx_cntxt_req->rds_req[i].size =
3780bc7cf6fSBjoern A. Zeeb 				qla_host_to_le32(NUM_RX_JUMBO_DESCRIPTORS);
3790bc7cf6fSBjoern A. Zeeb 		}
3800bc7cf6fSBjoern A. Zeeb 	}
3810bc7cf6fSBjoern A. Zeeb 
3820bc7cf6fSBjoern A. Zeeb 	for (i = 0; i < hw->num_sds_rings; i++) {
3830bc7cf6fSBjoern A. Zeeb 		rx_cntxt_req->sds_req[i].phys_addr =
3840bc7cf6fSBjoern A. Zeeb 			qla_host_to_le64(hw->dma_buf.sds_ring[i].dma_addr);
3850bc7cf6fSBjoern A. Zeeb 		rx_cntxt_req->sds_req[i].size =
3860bc7cf6fSBjoern A. Zeeb 			qla_host_to_le32(NUM_STATUS_DESCRIPTORS);
3870bc7cf6fSBjoern A. Zeeb 		rx_cntxt_req->sds_req[i].msi_index = qla_host_to_le16(i);
3880bc7cf6fSBjoern A. Zeeb 	}
3890bc7cf6fSBjoern A. Zeeb 
3900bc7cf6fSBjoern A. Zeeb 	QL_DPRINT2((ha->pci_dev, "%s: tx_cntxt_req = %p paddr %p\n",
3910bc7cf6fSBjoern A. Zeeb 		__func__, hw->tx_cntxt_req, (void *)hw->tx_cntxt_req_paddr));
3920bc7cf6fSBjoern A. Zeeb 	QL_DPRINT2((ha->pci_dev, "%s: tx_cntxt_rsp = %p paddr %p\n",
3930bc7cf6fSBjoern A. Zeeb 		__func__, hw->tx_cntxt_rsp, (void *)hw->tx_cntxt_rsp_paddr));
3940bc7cf6fSBjoern A. Zeeb 	QL_DPRINT2((ha->pci_dev, "%s: rx_cntxt_req = %p paddr %p\n",
3950bc7cf6fSBjoern A. Zeeb 		__func__, hw->rx_cntxt_req, (void *)hw->rx_cntxt_req_paddr));
3960bc7cf6fSBjoern A. Zeeb 	QL_DPRINT2((ha->pci_dev, "%s: rx_cntxt_rsp = %p paddr %p\n",
3970bc7cf6fSBjoern A. Zeeb 		__func__, hw->rx_cntxt_rsp, (void *)hw->rx_cntxt_rsp_paddr));
3980bc7cf6fSBjoern A. Zeeb 	QL_DPRINT2((ha->pci_dev, "%s: tx_cons      = %p paddr %p\n",
3990bc7cf6fSBjoern A. Zeeb 		__func__, hw->tx_cons, (void *)hw->tx_cons_paddr));
4000bc7cf6fSBjoern A. Zeeb }
4010bc7cf6fSBjoern A. Zeeb 
4020bc7cf6fSBjoern A. Zeeb /*
4030bc7cf6fSBjoern A. Zeeb  * Name: qla_issue_cmd
4040bc7cf6fSBjoern A. Zeeb  * Function: Issues commands on the CDRP interface and returns responses.
4050bc7cf6fSBjoern A. Zeeb  */
4060bc7cf6fSBjoern A. Zeeb static int
qla_issue_cmd(qla_host_t * ha,qla_cdrp_t * cdrp)4070bc7cf6fSBjoern A. Zeeb qla_issue_cmd(qla_host_t *ha, qla_cdrp_t *cdrp)
4080bc7cf6fSBjoern A. Zeeb {
4090bc7cf6fSBjoern A. Zeeb 	int	ret = 0;
4100bc7cf6fSBjoern A. Zeeb 	uint32_t signature;
4110bc7cf6fSBjoern A. Zeeb 	uint32_t count = 400; /* 4 seconds or 400 10ms intervals */
4120bc7cf6fSBjoern A. Zeeb 	uint32_t data;
4130bc7cf6fSBjoern A. Zeeb 	device_t dev;
4140bc7cf6fSBjoern A. Zeeb 
4150bc7cf6fSBjoern A. Zeeb 	dev = ha->pci_dev;
4160bc7cf6fSBjoern A. Zeeb 
4170bc7cf6fSBjoern A. Zeeb 	signature = 0xcafe0000 | 0x0100 | ha->pci_func;
4180bc7cf6fSBjoern A. Zeeb 
4190bc7cf6fSBjoern A. Zeeb 	ret = qla_sem_lock(ha, Q8_SEM5_LOCK, 0, (uint32_t)ha->pci_func);
4200bc7cf6fSBjoern A. Zeeb 
4210bc7cf6fSBjoern A. Zeeb 	if (ret) {
4220bc7cf6fSBjoern A. Zeeb 		device_printf(dev, "%s: SEM5_LOCK lock failed\n", __func__);
4230bc7cf6fSBjoern A. Zeeb 		return (ret);
4240bc7cf6fSBjoern A. Zeeb 	}
4250bc7cf6fSBjoern A. Zeeb 
4260bc7cf6fSBjoern A. Zeeb 	WRITE_OFFSET32(ha, Q8_NX_CDRP_SIGNATURE, signature);
4270bc7cf6fSBjoern A. Zeeb 
4280bc7cf6fSBjoern A. Zeeb 	WRITE_OFFSET32(ha, Q8_NX_CDRP_ARG1, (cdrp->cmd_arg1));
4290bc7cf6fSBjoern A. Zeeb 	WRITE_OFFSET32(ha, Q8_NX_CDRP_ARG2, (cdrp->cmd_arg2));
4300bc7cf6fSBjoern A. Zeeb 	WRITE_OFFSET32(ha, Q8_NX_CDRP_ARG3, (cdrp->cmd_arg3));
4310bc7cf6fSBjoern A. Zeeb 
4320bc7cf6fSBjoern A. Zeeb 	WRITE_OFFSET32(ha, Q8_NX_CDRP_CMD_RSP, cdrp->cmd);
4330bc7cf6fSBjoern A. Zeeb 
4340bc7cf6fSBjoern A. Zeeb 	while (count) {
4350bc7cf6fSBjoern A. Zeeb 		qla_mdelay(__func__, 10);
4360bc7cf6fSBjoern A. Zeeb 
4370bc7cf6fSBjoern A. Zeeb 		data = READ_REG32(ha, Q8_NX_CDRP_CMD_RSP);
4380bc7cf6fSBjoern A. Zeeb 
4390bc7cf6fSBjoern A. Zeeb 		if ((!(data & 0x80000000)))
4400bc7cf6fSBjoern A. Zeeb 			break;
4410bc7cf6fSBjoern A. Zeeb 		count--;
4420bc7cf6fSBjoern A. Zeeb 	}
4430bc7cf6fSBjoern A. Zeeb 	if ((!count) || (data != 1))
4440bc7cf6fSBjoern A. Zeeb 		ret = -1;
4450bc7cf6fSBjoern A. Zeeb 
4460bc7cf6fSBjoern A. Zeeb 	cdrp->rsp = READ_REG32(ha, Q8_NX_CDRP_CMD_RSP);
4470bc7cf6fSBjoern A. Zeeb 	cdrp->rsp_arg1 = READ_REG32(ha, Q8_NX_CDRP_ARG1);
4480bc7cf6fSBjoern A. Zeeb 	cdrp->rsp_arg2 = READ_REG32(ha, Q8_NX_CDRP_ARG2);
4490bc7cf6fSBjoern A. Zeeb 	cdrp->rsp_arg3 = READ_REG32(ha, Q8_NX_CDRP_ARG3);
4500bc7cf6fSBjoern A. Zeeb 
4510bc7cf6fSBjoern A. Zeeb 	qla_sem_unlock(ha, Q8_SEM5_UNLOCK);
4520bc7cf6fSBjoern A. Zeeb 
4530bc7cf6fSBjoern A. Zeeb 	if (ret) {
4540bc7cf6fSBjoern A. Zeeb 		device_printf(dev, "%s: "
4550bc7cf6fSBjoern A. Zeeb 			"cmd[0x%08x] = 0x%08x\n"
4560bc7cf6fSBjoern A. Zeeb 			"\tsig[0x%08x] = 0x%08x\n"
4570bc7cf6fSBjoern A. Zeeb 			"\targ1[0x%08x] = 0x%08x\n"
4580bc7cf6fSBjoern A. Zeeb 			"\targ2[0x%08x] = 0x%08x\n"
4590bc7cf6fSBjoern A. Zeeb 			"\targ3[0x%08x] = 0x%08x\n",
4600bc7cf6fSBjoern A. Zeeb 			__func__, Q8_NX_CDRP_CMD_RSP, cdrp->cmd,
4610bc7cf6fSBjoern A. Zeeb 			Q8_NX_CDRP_SIGNATURE, signature,
4620bc7cf6fSBjoern A. Zeeb 			Q8_NX_CDRP_ARG1, cdrp->cmd_arg1,
4630bc7cf6fSBjoern A. Zeeb 			Q8_NX_CDRP_ARG2, cdrp->cmd_arg2,
4640bc7cf6fSBjoern A. Zeeb 			Q8_NX_CDRP_ARG3, cdrp->cmd_arg3);
4650bc7cf6fSBjoern A. Zeeb 
4660bc7cf6fSBjoern A. Zeeb 		device_printf(dev, "%s: exit (ret = 0x%x)\n"
4670bc7cf6fSBjoern A. Zeeb 			"\t\t rsp = 0x%08x\n"
4680bc7cf6fSBjoern A. Zeeb 			"\t\t arg1 = 0x%08x\n"
4690bc7cf6fSBjoern A. Zeeb 			"\t\t arg2 = 0x%08x\n"
4700bc7cf6fSBjoern A. Zeeb 			"\t\t arg3 = 0x%08x\n",
4710bc7cf6fSBjoern A. Zeeb 			__func__, ret, cdrp->rsp,
4720bc7cf6fSBjoern A. Zeeb 			cdrp->rsp_arg1, cdrp->rsp_arg2, cdrp->rsp_arg3);
4730bc7cf6fSBjoern A. Zeeb 	}
4740bc7cf6fSBjoern A. Zeeb 
4750bc7cf6fSBjoern A. Zeeb 	return (ret);
4760bc7cf6fSBjoern A. Zeeb }
4770bc7cf6fSBjoern A. Zeeb 
4780bc7cf6fSBjoern A. Zeeb #define QLA_TX_MIN_FREE	2
4790bc7cf6fSBjoern A. Zeeb 
4800bc7cf6fSBjoern A. Zeeb /*
4810bc7cf6fSBjoern A. Zeeb  * Name: qla_fw_cmd
4820bc7cf6fSBjoern A. Zeeb  * Function: Issues firmware control commands on the Tx Ring.
4830bc7cf6fSBjoern A. Zeeb  */
4840bc7cf6fSBjoern A. Zeeb static int
qla_fw_cmd(qla_host_t * ha,void * fw_cmd,uint32_t size)4850bc7cf6fSBjoern A. Zeeb qla_fw_cmd(qla_host_t *ha, void *fw_cmd, uint32_t size)
4860bc7cf6fSBjoern A. Zeeb {
4870bc7cf6fSBjoern A. Zeeb 	device_t dev;
4880bc7cf6fSBjoern A. Zeeb         q80_tx_cmd_t *tx_cmd;
4890bc7cf6fSBjoern A. Zeeb         qla_hw_t *hw = &ha->hw;
4900bc7cf6fSBjoern A. Zeeb 	int count = 100;
4910bc7cf6fSBjoern A. Zeeb 
4920bc7cf6fSBjoern A. Zeeb 	dev = ha->pci_dev;
4930bc7cf6fSBjoern A. Zeeb 
4940bc7cf6fSBjoern A. Zeeb 	QLA_TX_LOCK(ha);
4950bc7cf6fSBjoern A. Zeeb 
4960bc7cf6fSBjoern A. Zeeb         if (hw->txr_free <= QLA_TX_MIN_FREE) {
4970bc7cf6fSBjoern A. Zeeb 		while (count--) {
4980bc7cf6fSBjoern A. Zeeb 			qla_hw_tx_done_locked(ha);
4990bc7cf6fSBjoern A. Zeeb 			if (hw->txr_free > QLA_TX_MIN_FREE)
5000bc7cf6fSBjoern A. Zeeb 				break;
5010bc7cf6fSBjoern A. Zeeb 
5020bc7cf6fSBjoern A. Zeeb 			QLA_TX_UNLOCK(ha);
5030bc7cf6fSBjoern A. Zeeb 			qla_mdelay(__func__, 10);
5040bc7cf6fSBjoern A. Zeeb 			QLA_TX_LOCK(ha);
5050bc7cf6fSBjoern A. Zeeb 		}
5060bc7cf6fSBjoern A. Zeeb         	if (hw->txr_free <= QLA_TX_MIN_FREE) {
5070bc7cf6fSBjoern A. Zeeb 			QLA_TX_UNLOCK(ha);
5080bc7cf6fSBjoern A. Zeeb 			device_printf(dev, "%s: xmit queue full\n", __func__);
5090bc7cf6fSBjoern A. Zeeb                 	return (-1);
5100bc7cf6fSBjoern A. Zeeb 		}
5110bc7cf6fSBjoern A. Zeeb         }
5120bc7cf6fSBjoern A. Zeeb         tx_cmd = &hw->tx_ring_base[hw->txr_next];
5130bc7cf6fSBjoern A. Zeeb 
5140bc7cf6fSBjoern A. Zeeb         bzero((void *)tx_cmd, sizeof(q80_tx_cmd_t));
5150bc7cf6fSBjoern A. Zeeb 
5160bc7cf6fSBjoern A. Zeeb 	bcopy(fw_cmd, tx_cmd, size);
5170bc7cf6fSBjoern A. Zeeb 
5180bc7cf6fSBjoern A. Zeeb 	hw->txr_next = (hw->txr_next + 1) & (NUM_TX_DESCRIPTORS - 1);
5190bc7cf6fSBjoern A. Zeeb 	hw->txr_free--;
5200bc7cf6fSBjoern A. Zeeb 
5210bc7cf6fSBjoern A. Zeeb 	QL_UPDATE_TX_PRODUCER_INDEX(ha, hw->txr_next);
5220bc7cf6fSBjoern A. Zeeb 
5230bc7cf6fSBjoern A. Zeeb 	QLA_TX_UNLOCK(ha);
5240bc7cf6fSBjoern A. Zeeb 
5250bc7cf6fSBjoern A. Zeeb 	return (0);
5260bc7cf6fSBjoern A. Zeeb }
5270bc7cf6fSBjoern A. Zeeb 
5280bc7cf6fSBjoern A. Zeeb /*
5290bc7cf6fSBjoern A. Zeeb  * Name: qla_config_rss
5300bc7cf6fSBjoern A. Zeeb  * Function: Configure RSS for the context/interface.
5310bc7cf6fSBjoern A. Zeeb  */
5320bc7cf6fSBjoern A. Zeeb const uint64_t rss_key[] = { 0xbeac01fa6a42b73bULL, 0x8030f20c77cb2da3ULL,
5330bc7cf6fSBjoern A. Zeeb 			0xae7b30b4d0ca2bcbULL, 0x43a38fb04167253dULL,
5340bc7cf6fSBjoern A. Zeeb 			0x255b0ec26d5a56daULL };
5350bc7cf6fSBjoern A. Zeeb 
5360bc7cf6fSBjoern A. Zeeb static int
qla_config_rss(qla_host_t * ha,uint16_t cntxt_id)5370bc7cf6fSBjoern A. Zeeb qla_config_rss(qla_host_t *ha, uint16_t cntxt_id)
5380bc7cf6fSBjoern A. Zeeb {
5390bc7cf6fSBjoern A. Zeeb 	qla_fw_cds_config_rss_t rss_config;
5400bc7cf6fSBjoern A. Zeeb 	int ret, i;
5410bc7cf6fSBjoern A. Zeeb 
5420bc7cf6fSBjoern A. Zeeb 	bzero(&rss_config, sizeof(qla_fw_cds_config_rss_t));
5430bc7cf6fSBjoern A. Zeeb 
5440bc7cf6fSBjoern A. Zeeb 	rss_config.hdr.cmd = Q8_FWCD_CNTRL_REQ;
5450bc7cf6fSBjoern A. Zeeb 	rss_config.hdr.opcode = Q8_FWCD_OPCODE_CONFIG_RSS;
5460bc7cf6fSBjoern A. Zeeb 	rss_config.hdr.cntxt_id = cntxt_id;
5470bc7cf6fSBjoern A. Zeeb 
5480bc7cf6fSBjoern A. Zeeb 	rss_config.hash_type = (Q8_FWCD_RSS_HASH_TYPE_IPV4_TCP_IP |
5490bc7cf6fSBjoern A. Zeeb 					Q8_FWCD_RSS_HASH_TYPE_IPV6_TCP_IP);
5500bc7cf6fSBjoern A. Zeeb 	rss_config.flags = Q8_FWCD_RSS_FLAGS_ENABLE_RSS;
5510bc7cf6fSBjoern A. Zeeb 
5520bc7cf6fSBjoern A. Zeeb 	rss_config.ind_tbl_mask = 0x7;
5530bc7cf6fSBjoern A. Zeeb 
5540bc7cf6fSBjoern A. Zeeb 	for (i = 0; i < 5; i++)
5550bc7cf6fSBjoern A. Zeeb 		rss_config.rss_key[i] = rss_key[i];
5560bc7cf6fSBjoern A. Zeeb 
5570bc7cf6fSBjoern A. Zeeb 	ret = qla_fw_cmd(ha, &rss_config, sizeof(qla_fw_cds_config_rss_t));
5580bc7cf6fSBjoern A. Zeeb 
5590bc7cf6fSBjoern A. Zeeb 	return ret;
5600bc7cf6fSBjoern A. Zeeb }
5610bc7cf6fSBjoern A. Zeeb 
5620bc7cf6fSBjoern A. Zeeb /*
5630bc7cf6fSBjoern A. Zeeb  * Name: qla_config_intr_coalesce
5640bc7cf6fSBjoern A. Zeeb  * Function: Configure Interrupt Coalescing.
5650bc7cf6fSBjoern A. Zeeb  */
5660bc7cf6fSBjoern A. Zeeb static int
qla_config_intr_coalesce(qla_host_t * ha,uint16_t cntxt_id,int tenable)5670bc7cf6fSBjoern A. Zeeb qla_config_intr_coalesce(qla_host_t *ha, uint16_t cntxt_id, int tenable)
5680bc7cf6fSBjoern A. Zeeb {
5690bc7cf6fSBjoern A. Zeeb 	qla_fw_cds_config_intr_coalesc_t intr_coalesce;
5700bc7cf6fSBjoern A. Zeeb 	int ret;
5710bc7cf6fSBjoern A. Zeeb 
5720bc7cf6fSBjoern A. Zeeb 	bzero(&intr_coalesce, sizeof(qla_fw_cds_config_intr_coalesc_t));
5730bc7cf6fSBjoern A. Zeeb 
5740bc7cf6fSBjoern A. Zeeb 	intr_coalesce.hdr.cmd = Q8_FWCD_CNTRL_REQ;
5750bc7cf6fSBjoern A. Zeeb 	intr_coalesce.hdr.opcode = Q8_FWCD_OPCODE_CONFIG_INTR_COALESCING;
5760bc7cf6fSBjoern A. Zeeb 	intr_coalesce.hdr.cntxt_id = cntxt_id;
5770bc7cf6fSBjoern A. Zeeb 
5780bc7cf6fSBjoern A. Zeeb 	intr_coalesce.flags = 0x04;
5790bc7cf6fSBjoern A. Zeeb 	intr_coalesce.max_rcv_pkts = 256;
5800bc7cf6fSBjoern A. Zeeb 	intr_coalesce.max_rcv_usecs = 3;
5810bc7cf6fSBjoern A. Zeeb 	intr_coalesce.max_snd_pkts = 64;
5820bc7cf6fSBjoern A. Zeeb 	intr_coalesce.max_snd_usecs = 4;
5830bc7cf6fSBjoern A. Zeeb 
5840bc7cf6fSBjoern A. Zeeb 	if (tenable) {
5850bc7cf6fSBjoern A. Zeeb 		intr_coalesce.usecs_to = 1000; /* 1 millisecond */
5860bc7cf6fSBjoern A. Zeeb 		intr_coalesce.timer_type = Q8_FWCMD_INTR_COALESC_TIMER_PERIODIC;
5870bc7cf6fSBjoern A. Zeeb 		intr_coalesce.sds_ring_bitmask =
5880bc7cf6fSBjoern A. Zeeb 			Q8_FWCMD_INTR_COALESC_SDS_RING_0;
5890bc7cf6fSBjoern A. Zeeb 	}
5900bc7cf6fSBjoern A. Zeeb 
5910bc7cf6fSBjoern A. Zeeb 	ret = qla_fw_cmd(ha, &intr_coalesce,
5920bc7cf6fSBjoern A. Zeeb 			sizeof(qla_fw_cds_config_intr_coalesc_t));
5930bc7cf6fSBjoern A. Zeeb 
5940bc7cf6fSBjoern A. Zeeb 	return ret;
5950bc7cf6fSBjoern A. Zeeb }
5960bc7cf6fSBjoern A. Zeeb 
5970bc7cf6fSBjoern A. Zeeb /*
5980bc7cf6fSBjoern A. Zeeb  * Name: qla_config_mac_addr
5990bc7cf6fSBjoern A. Zeeb  * Function: binds a MAC address to the context/interface.
6000bc7cf6fSBjoern A. Zeeb  *	Can be unicast, multicast or broadcast.
6010bc7cf6fSBjoern A. Zeeb  */
6020bc7cf6fSBjoern A. Zeeb static int
qla_config_mac_addr(qla_host_t * ha,uint8_t * mac_addr,uint16_t cntxt_id,uint32_t add_multi)6030bc7cf6fSBjoern A. Zeeb qla_config_mac_addr(qla_host_t *ha, uint8_t *mac_addr, uint16_t cntxt_id,
6040bc7cf6fSBjoern A. Zeeb 	uint32_t add_multi)
6050bc7cf6fSBjoern A. Zeeb {
6060bc7cf6fSBjoern A. Zeeb 	qla_fw_cds_config_mac_addr_t mac_config;
6070bc7cf6fSBjoern A. Zeeb 	int ret;
6080bc7cf6fSBjoern A. Zeeb 
6090bc7cf6fSBjoern A. Zeeb //	device_printf(ha->pci_dev,
6100bc7cf6fSBjoern A. Zeeb //		"%s: mac_addr %02x:%02x:%02x:%02x:%02x:%02x\n", __func__,
6110bc7cf6fSBjoern A. Zeeb //		mac_addr[0], mac_addr[1], mac_addr[2],
6120bc7cf6fSBjoern A. Zeeb //		mac_addr[3], mac_addr[4], mac_addr[5]);
6130bc7cf6fSBjoern A. Zeeb 
6140bc7cf6fSBjoern A. Zeeb 	bzero(&mac_config, sizeof(qla_fw_cds_config_mac_addr_t));
6150bc7cf6fSBjoern A. Zeeb 
6160bc7cf6fSBjoern A. Zeeb 	mac_config.hdr.cmd = Q8_FWCD_CNTRL_REQ;
6170bc7cf6fSBjoern A. Zeeb 	mac_config.hdr.opcode = Q8_FWCD_OPCODE_CONFIG_MAC_ADDR;
6180bc7cf6fSBjoern A. Zeeb 	mac_config.hdr.cntxt_id = cntxt_id;
6190bc7cf6fSBjoern A. Zeeb 
6200bc7cf6fSBjoern A. Zeeb 	if (add_multi)
6210bc7cf6fSBjoern A. Zeeb 		mac_config.cmd = Q8_FWCD_ADD_MAC_ADDR;
6220bc7cf6fSBjoern A. Zeeb 	else
6230bc7cf6fSBjoern A. Zeeb 		mac_config.cmd = Q8_FWCD_DEL_MAC_ADDR;
6240bc7cf6fSBjoern A. Zeeb 	bcopy(mac_addr, mac_config.mac_addr,6);
6250bc7cf6fSBjoern A. Zeeb 
6260bc7cf6fSBjoern A. Zeeb 	ret = qla_fw_cmd(ha, &mac_config, sizeof(qla_fw_cds_config_mac_addr_t));
6270bc7cf6fSBjoern A. Zeeb 
6280bc7cf6fSBjoern A. Zeeb 	return ret;
6290bc7cf6fSBjoern A. Zeeb }
6300bc7cf6fSBjoern A. Zeeb 
6310bc7cf6fSBjoern A. Zeeb /*
6320bc7cf6fSBjoern A. Zeeb  * Name: qla_set_mac_rcv_mode
633453130d9SPedro F. Giffuni  * Function: Enable/Disable AllMulticast and Promiscuous Modes.
6340bc7cf6fSBjoern A. Zeeb  */
6350bc7cf6fSBjoern A. Zeeb static int
qla_set_mac_rcv_mode(qla_host_t * ha,uint16_t cntxt_id,uint32_t mode)6360bc7cf6fSBjoern A. Zeeb qla_set_mac_rcv_mode(qla_host_t *ha, uint16_t cntxt_id, uint32_t mode)
6370bc7cf6fSBjoern A. Zeeb {
6380bc7cf6fSBjoern A. Zeeb 	qla_set_mac_rcv_mode_t rcv_mode;
6390bc7cf6fSBjoern A. Zeeb 	int ret;
6400bc7cf6fSBjoern A. Zeeb 
6410bc7cf6fSBjoern A. Zeeb 	bzero(&rcv_mode, sizeof(qla_set_mac_rcv_mode_t));
6420bc7cf6fSBjoern A. Zeeb 
6430bc7cf6fSBjoern A. Zeeb 	rcv_mode.hdr.cmd = Q8_FWCD_CNTRL_REQ;
6440bc7cf6fSBjoern A. Zeeb 	rcv_mode.hdr.opcode = Q8_FWCD_OPCODE_CONFIG_MAC_RCV_MODE;
6450bc7cf6fSBjoern A. Zeeb 	rcv_mode.hdr.cntxt_id = cntxt_id;
6460bc7cf6fSBjoern A. Zeeb 
6470bc7cf6fSBjoern A. Zeeb 	rcv_mode.mode = mode;
6480bc7cf6fSBjoern A. Zeeb 
6490bc7cf6fSBjoern A. Zeeb 	ret = qla_fw_cmd(ha, &rcv_mode, sizeof(qla_set_mac_rcv_mode_t));
6500bc7cf6fSBjoern A. Zeeb 
6510bc7cf6fSBjoern A. Zeeb 	return ret;
6520bc7cf6fSBjoern A. Zeeb }
6530bc7cf6fSBjoern A. Zeeb 
6540bc7cf6fSBjoern A. Zeeb void
qla_set_promisc(qla_host_t * ha)6550bc7cf6fSBjoern A. Zeeb qla_set_promisc(qla_host_t *ha)
6560bc7cf6fSBjoern A. Zeeb {
6570bc7cf6fSBjoern A. Zeeb 	(void)qla_set_mac_rcv_mode(ha,
6580bc7cf6fSBjoern A. Zeeb 		(ha->hw.rx_cntxt_rsp)->rx_rsp.cntxt_id,
6590bc7cf6fSBjoern A. Zeeb 		Q8_MAC_RCV_ENABLE_PROMISCUOUS);
6600bc7cf6fSBjoern A. Zeeb }
6610bc7cf6fSBjoern A. Zeeb 
6620bc7cf6fSBjoern A. Zeeb void
qla_set_allmulti(qla_host_t * ha)6630bc7cf6fSBjoern A. Zeeb qla_set_allmulti(qla_host_t *ha)
6640bc7cf6fSBjoern A. Zeeb {
6650bc7cf6fSBjoern A. Zeeb 	(void)qla_set_mac_rcv_mode(ha,
6660bc7cf6fSBjoern A. Zeeb 		(ha->hw.rx_cntxt_rsp)->rx_rsp.cntxt_id,
6670bc7cf6fSBjoern A. Zeeb 		Q8_MAC_RCV_ENABLE_ALLMULTI);
6680bc7cf6fSBjoern A. Zeeb }
6690bc7cf6fSBjoern A. Zeeb 
6700bc7cf6fSBjoern A. Zeeb void
qla_reset_promisc_allmulti(qla_host_t * ha)6710bc7cf6fSBjoern A. Zeeb qla_reset_promisc_allmulti(qla_host_t *ha)
6720bc7cf6fSBjoern A. Zeeb {
6730bc7cf6fSBjoern A. Zeeb 	(void)qla_set_mac_rcv_mode(ha,
6740bc7cf6fSBjoern A. Zeeb 		(ha->hw.rx_cntxt_rsp)->rx_rsp.cntxt_id,
6750bc7cf6fSBjoern A. Zeeb 		Q8_MAC_RCV_RESET_PROMISC_ALLMULTI);
6760bc7cf6fSBjoern A. Zeeb }
6770bc7cf6fSBjoern A. Zeeb 
6780bc7cf6fSBjoern A. Zeeb /*
6790bc7cf6fSBjoern A. Zeeb  * Name: qla_config_ipv4_addr
6800bc7cf6fSBjoern A. Zeeb  * Function: Configures the Destination IP Addr for LRO.
6810bc7cf6fSBjoern A. Zeeb  */
6820bc7cf6fSBjoern A. Zeeb void
qla_config_ipv4_addr(qla_host_t * ha,uint32_t ipv4_addr)6830bc7cf6fSBjoern A. Zeeb qla_config_ipv4_addr(qla_host_t *ha, uint32_t ipv4_addr)
6840bc7cf6fSBjoern A. Zeeb {
6850bc7cf6fSBjoern A. Zeeb 	qla_config_ipv4_t ip_conf;
6860bc7cf6fSBjoern A. Zeeb 
6870bc7cf6fSBjoern A. Zeeb 	bzero(&ip_conf, sizeof(qla_config_ipv4_t));
6880bc7cf6fSBjoern A. Zeeb 
6890bc7cf6fSBjoern A. Zeeb 	ip_conf.hdr.cmd = Q8_FWCD_CNTRL_REQ;
6900bc7cf6fSBjoern A. Zeeb 	ip_conf.hdr.opcode = Q8_FWCD_OPCODE_CONFIG_IPADDR;
6910bc7cf6fSBjoern A. Zeeb 	ip_conf.hdr.cntxt_id = (ha->hw.rx_cntxt_rsp)->rx_rsp.cntxt_id;
6920bc7cf6fSBjoern A. Zeeb 
6930bc7cf6fSBjoern A. Zeeb 	ip_conf.cmd = (uint64_t)Q8_CONFIG_CMD_IP_ENABLE;
6940bc7cf6fSBjoern A. Zeeb 	ip_conf.ipv4_addr = (uint64_t)ipv4_addr;
6950bc7cf6fSBjoern A. Zeeb 
6960bc7cf6fSBjoern A. Zeeb 	(void)qla_fw_cmd(ha, &ip_conf, sizeof(qla_config_ipv4_t));
6970bc7cf6fSBjoern A. Zeeb 
6980bc7cf6fSBjoern A. Zeeb 	return;
6990bc7cf6fSBjoern A. Zeeb }
7000bc7cf6fSBjoern A. Zeeb 
7010bc7cf6fSBjoern A. Zeeb /*
7020bc7cf6fSBjoern A. Zeeb  * Name: qla_tx_tso
7030bc7cf6fSBjoern A. Zeeb  * Function: Checks if the packet to be transmitted is a candidate for
7040bc7cf6fSBjoern A. Zeeb  *	Large TCP Segment Offload. If yes, the appropriate fields in the Tx
7050bc7cf6fSBjoern A. Zeeb  *	Ring Structure are plugged in.
7060bc7cf6fSBjoern A. Zeeb  */
7070bc7cf6fSBjoern A. Zeeb static int
qla_tx_tso(qla_host_t * ha,struct mbuf * mp,q80_tx_cmd_t * tx_cmd,uint8_t * hdr)708088fc971SDavid C Somayajulu qla_tx_tso(qla_host_t *ha, struct mbuf *mp, q80_tx_cmd_t *tx_cmd, uint8_t *hdr)
7090bc7cf6fSBjoern A. Zeeb {
7100bc7cf6fSBjoern A. Zeeb 	struct ether_vlan_header *eh;
7110bc7cf6fSBjoern A. Zeeb 	struct ip *ip = NULL;
7120bc7cf6fSBjoern A. Zeeb 	struct tcphdr *th = NULL;
713088fc971SDavid C Somayajulu 	uint32_t ehdrlen,  hdrlen = 0, ip_hlen, tcp_hlen, tcp_opt_off;
7140bc7cf6fSBjoern A. Zeeb 	uint16_t etype, opcode, offload = 1;
715088fc971SDavid C Somayajulu 	uint8_t *tcp_opt;
7160bc7cf6fSBjoern A. Zeeb 	device_t dev;
7170bc7cf6fSBjoern A. Zeeb 
7180bc7cf6fSBjoern A. Zeeb 	dev = ha->pci_dev;
7190bc7cf6fSBjoern A. Zeeb 
7200bc7cf6fSBjoern A. Zeeb 	eh = mtod(mp, struct ether_vlan_header *);
7210bc7cf6fSBjoern A. Zeeb 
7220bc7cf6fSBjoern A. Zeeb 	if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) {
7230bc7cf6fSBjoern A. Zeeb 		ehdrlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
7240bc7cf6fSBjoern A. Zeeb 		etype = ntohs(eh->evl_proto);
7250bc7cf6fSBjoern A. Zeeb 	} else {
7260bc7cf6fSBjoern A. Zeeb 		ehdrlen = ETHER_HDR_LEN;
7270bc7cf6fSBjoern A. Zeeb 		etype = ntohs(eh->evl_encap_proto);
7280bc7cf6fSBjoern A. Zeeb 	}
7290bc7cf6fSBjoern A. Zeeb 
7300bc7cf6fSBjoern A. Zeeb 	switch (etype) {
7310bc7cf6fSBjoern A. Zeeb 		case ETHERTYPE_IP:
732088fc971SDavid C Somayajulu 
733088fc971SDavid C Somayajulu 			tcp_opt_off = ehdrlen + sizeof(struct ip) +
734088fc971SDavid C Somayajulu 					sizeof(struct tcphdr);
735088fc971SDavid C Somayajulu 
736088fc971SDavid C Somayajulu 			if (mp->m_len < tcp_opt_off) {
737088fc971SDavid C Somayajulu 				m_copydata(mp, 0, tcp_opt_off, hdr);
738088fc971SDavid C Somayajulu 				ip = (struct ip *)hdr;
739088fc971SDavid C Somayajulu 			} else {
7400bc7cf6fSBjoern A. Zeeb 				ip = (struct ip *)(mp->m_data + ehdrlen);
741088fc971SDavid C Somayajulu 			}
742088fc971SDavid C Somayajulu 
7430bc7cf6fSBjoern A. Zeeb 			ip_hlen = ip->ip_hl << 2;
7440bc7cf6fSBjoern A. Zeeb 			opcode = Q8_TX_CMD_OP_XMT_TCP_LSO;
7450bc7cf6fSBjoern A. Zeeb 
746088fc971SDavid C Somayajulu 			if ((ip->ip_p != IPPROTO_TCP) ||
747088fc971SDavid C Somayajulu 				(ip_hlen != sizeof (struct ip))) {
7480bc7cf6fSBjoern A. Zeeb 				offload = 0;
749088fc971SDavid C Somayajulu 			} else {
7500bc7cf6fSBjoern A. Zeeb 				th = (struct tcphdr *)((caddr_t)ip + ip_hlen);
751088fc971SDavid C Somayajulu 			}
7520bc7cf6fSBjoern A. Zeeb 		break;
7530bc7cf6fSBjoern A. Zeeb 
7540bc7cf6fSBjoern A. Zeeb 		default:
7550bc7cf6fSBjoern A. Zeeb 			QL_DPRINT8((dev, "%s: type!=ip\n", __func__));
7560bc7cf6fSBjoern A. Zeeb 			offload = 0;
7570bc7cf6fSBjoern A. Zeeb 		break;
7580bc7cf6fSBjoern A. Zeeb 	}
7590bc7cf6fSBjoern A. Zeeb 
7600bc7cf6fSBjoern A. Zeeb 	if (!offload)
7610bc7cf6fSBjoern A. Zeeb 		return (-1);
7620bc7cf6fSBjoern A. Zeeb 
7630bc7cf6fSBjoern A. Zeeb 	tcp_hlen = th->th_off << 2;
7640bc7cf6fSBjoern A. Zeeb 
7650bc7cf6fSBjoern A. Zeeb 	hdrlen = ehdrlen + ip_hlen + tcp_hlen;
7660bc7cf6fSBjoern A. Zeeb 
7670bc7cf6fSBjoern A. Zeeb 	if (mp->m_len < hdrlen) {
768088fc971SDavid C Somayajulu 		if (mp->m_len < tcp_opt_off) {
769088fc971SDavid C Somayajulu 			if (tcp_hlen > sizeof(struct tcphdr)) {
770088fc971SDavid C Somayajulu 				m_copydata(mp, tcp_opt_off,
771088fc971SDavid C Somayajulu 					(tcp_hlen - sizeof(struct tcphdr)),
772088fc971SDavid C Somayajulu 					&hdr[tcp_opt_off]);
773088fc971SDavid C Somayajulu 			}
774088fc971SDavid C Somayajulu 		} else {
775088fc971SDavid C Somayajulu 			m_copydata(mp, 0, hdrlen, hdr);
776088fc971SDavid C Somayajulu 		}
777088fc971SDavid C Somayajulu 	}
778088fc971SDavid C Somayajulu 
779088fc971SDavid C Somayajulu 	if ((mp->m_pkthdr.csum_flags & CSUM_TSO) == 0) {
780088fc971SDavid C Somayajulu 		/* If TCP options are preset only time stamp option is supported */
781088fc971SDavid C Somayajulu 		if ((tcp_hlen - sizeof(struct tcphdr)) != 10)
782088fc971SDavid C Somayajulu 			return -1;
783088fc971SDavid C Somayajulu 		else {
784088fc971SDavid C Somayajulu 			if (mp->m_len < hdrlen) {
785088fc971SDavid C Somayajulu 				tcp_opt = &hdr[tcp_opt_off];
786088fc971SDavid C Somayajulu 			} else {
787088fc971SDavid C Somayajulu 				tcp_opt = (uint8_t *)(mp->m_data + tcp_opt_off);
788088fc971SDavid C Somayajulu 			}
789088fc971SDavid C Somayajulu 
790088fc971SDavid C Somayajulu 			if ((*tcp_opt != 0x01) || (*(tcp_opt + 1) != 0x01) ||
791e0f6860dSPedro F. Giffuni 				(*(tcp_opt + 2) != 0x08) ||
792e0f6860dSPedro F. Giffuni 				(*(tcp_opt + 3) != 10)) {
793088fc971SDavid C Somayajulu 				return -1;
794088fc971SDavid C Somayajulu 			}
795088fc971SDavid C Somayajulu 		}
796088fc971SDavid C Somayajulu 
797088fc971SDavid C Somayajulu 		tx_cmd->mss = ha->max_frame_size - ETHER_CRC_LEN - hdrlen;
798088fc971SDavid C Somayajulu 	} else {
799088fc971SDavid C Somayajulu 		tx_cmd->mss = mp->m_pkthdr.tso_segsz;
8000bc7cf6fSBjoern A. Zeeb 	}
8010bc7cf6fSBjoern A. Zeeb 
8020bc7cf6fSBjoern A. Zeeb 	tx_cmd->flags_opcode = opcode ;
8030bc7cf6fSBjoern A. Zeeb 	tx_cmd->tcp_hdr_off = ip_hlen + ehdrlen;
8040bc7cf6fSBjoern A. Zeeb 	tx_cmd->ip_hdr_off = ehdrlen;
8050bc7cf6fSBjoern A. Zeeb 	tx_cmd->mss = mp->m_pkthdr.tso_segsz;
8060bc7cf6fSBjoern A. Zeeb 	tx_cmd->total_hdr_len = hdrlen;
8070bc7cf6fSBjoern A. Zeeb 
8080bc7cf6fSBjoern A. Zeeb 	/* Check for Multicast least significant bit of MSB == 1 */
8090bc7cf6fSBjoern A. Zeeb 	if (eh->evl_dhost[0] & 0x01) {
8100bc7cf6fSBjoern A. Zeeb 		tx_cmd->flags_opcode = Q8_TX_CMD_FLAGS_MULTICAST;
8110bc7cf6fSBjoern A. Zeeb 	}
8120bc7cf6fSBjoern A. Zeeb 
813088fc971SDavid C Somayajulu 	if (mp->m_len < hdrlen) {
814088fc971SDavid C Somayajulu 		return (1);
815088fc971SDavid C Somayajulu 	}
816088fc971SDavid C Somayajulu 
8170bc7cf6fSBjoern A. Zeeb 	return (0);
8180bc7cf6fSBjoern A. Zeeb }
8190bc7cf6fSBjoern A. Zeeb 
8200bc7cf6fSBjoern A. Zeeb /*
8210bc7cf6fSBjoern A. Zeeb  * Name: qla_tx_chksum
8220bc7cf6fSBjoern A. Zeeb  * Function: Checks if the packet to be transmitted is a candidate for
8230bc7cf6fSBjoern A. Zeeb  *	TCP/UDP Checksum offload. If yes, the appropriate fields in the Tx
8240bc7cf6fSBjoern A. Zeeb  *	Ring Structure are plugged in.
8250bc7cf6fSBjoern A. Zeeb  */
8260bc7cf6fSBjoern A. Zeeb static int
qla_tx_chksum(qla_host_t * ha,struct mbuf * mp,q80_tx_cmd_t * tx_cmd)8270bc7cf6fSBjoern A. Zeeb qla_tx_chksum(qla_host_t *ha, struct mbuf *mp, q80_tx_cmd_t *tx_cmd)
8280bc7cf6fSBjoern A. Zeeb {
8290bc7cf6fSBjoern A. Zeeb 	struct ether_vlan_header *eh;
8300bc7cf6fSBjoern A. Zeeb 	struct ip *ip;
8310bc7cf6fSBjoern A. Zeeb 	struct ip6_hdr *ip6;
8320bc7cf6fSBjoern A. Zeeb 	uint32_t ehdrlen, ip_hlen;
8330bc7cf6fSBjoern A. Zeeb 	uint16_t etype, opcode, offload = 1;
8340bc7cf6fSBjoern A. Zeeb 	device_t dev;
8350bc7cf6fSBjoern A. Zeeb 
8360bc7cf6fSBjoern A. Zeeb 	dev = ha->pci_dev;
8370bc7cf6fSBjoern A. Zeeb 
8380bc7cf6fSBjoern A. Zeeb 	if ((mp->m_pkthdr.csum_flags & (CSUM_TCP|CSUM_UDP)) == 0)
8390bc7cf6fSBjoern A. Zeeb 		return (-1);
8400bc7cf6fSBjoern A. Zeeb 
8410bc7cf6fSBjoern A. Zeeb 	eh = mtod(mp, struct ether_vlan_header *);
8420bc7cf6fSBjoern A. Zeeb 
8430bc7cf6fSBjoern A. Zeeb 	if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) {
8440bc7cf6fSBjoern A. Zeeb 		ehdrlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
8450bc7cf6fSBjoern A. Zeeb 		etype = ntohs(eh->evl_proto);
8460bc7cf6fSBjoern A. Zeeb 	} else {
8470bc7cf6fSBjoern A. Zeeb 		ehdrlen = ETHER_HDR_LEN;
8480bc7cf6fSBjoern A. Zeeb 		etype = ntohs(eh->evl_encap_proto);
8490bc7cf6fSBjoern A. Zeeb 	}
8500bc7cf6fSBjoern A. Zeeb 
8510bc7cf6fSBjoern A. Zeeb 
8520bc7cf6fSBjoern A. Zeeb 	switch (etype) {
8530bc7cf6fSBjoern A. Zeeb 		case ETHERTYPE_IP:
8540bc7cf6fSBjoern A. Zeeb 			ip = (struct ip *)(mp->m_data + ehdrlen);
8550bc7cf6fSBjoern A. Zeeb 
856088fc971SDavid C Somayajulu 			ip_hlen = sizeof (struct ip);
8570bc7cf6fSBjoern A. Zeeb 
8580bc7cf6fSBjoern A. Zeeb 			if (mp->m_len < (ehdrlen + ip_hlen)) {
8590bc7cf6fSBjoern A. Zeeb 				device_printf(dev, "%s: ipv4 mlen\n", __func__);
8600bc7cf6fSBjoern A. Zeeb 				offload = 0;
8610bc7cf6fSBjoern A. Zeeb 				break;
8620bc7cf6fSBjoern A. Zeeb 			}
8630bc7cf6fSBjoern A. Zeeb 
8640bc7cf6fSBjoern A. Zeeb 			if (ip->ip_p == IPPROTO_TCP)
8650bc7cf6fSBjoern A. Zeeb 				opcode = Q8_TX_CMD_OP_XMT_TCP_CHKSUM;
8660bc7cf6fSBjoern A. Zeeb 			else if (ip->ip_p == IPPROTO_UDP)
8670bc7cf6fSBjoern A. Zeeb 				opcode = Q8_TX_CMD_OP_XMT_UDP_CHKSUM;
8680bc7cf6fSBjoern A. Zeeb 			else {
8690bc7cf6fSBjoern A. Zeeb 				device_printf(dev, "%s: ipv4\n", __func__);
8700bc7cf6fSBjoern A. Zeeb 				offload = 0;
8710bc7cf6fSBjoern A. Zeeb 			}
8720bc7cf6fSBjoern A. Zeeb 		break;
8730bc7cf6fSBjoern A. Zeeb 
8740bc7cf6fSBjoern A. Zeeb 		case ETHERTYPE_IPV6:
8750bc7cf6fSBjoern A. Zeeb 			ip6 = (struct ip6_hdr *)(mp->m_data + ehdrlen);
8760bc7cf6fSBjoern A. Zeeb 
8770bc7cf6fSBjoern A. Zeeb 			ip_hlen = sizeof(struct ip6_hdr);
8780bc7cf6fSBjoern A. Zeeb 
8790bc7cf6fSBjoern A. Zeeb 			if (mp->m_len < (ehdrlen + ip_hlen)) {
8800bc7cf6fSBjoern A. Zeeb 				device_printf(dev, "%s: ipv6 mlen\n", __func__);
8810bc7cf6fSBjoern A. Zeeb 				offload = 0;
8820bc7cf6fSBjoern A. Zeeb 				break;
8830bc7cf6fSBjoern A. Zeeb 			}
8840bc7cf6fSBjoern A. Zeeb 
8850bc7cf6fSBjoern A. Zeeb 			if (ip6->ip6_nxt == IPPROTO_TCP)
8860bc7cf6fSBjoern A. Zeeb 				opcode = Q8_TX_CMD_OP_XMT_TCP_CHKSUM_IPV6;
8870bc7cf6fSBjoern A. Zeeb 			else if (ip6->ip6_nxt == IPPROTO_UDP)
8880bc7cf6fSBjoern A. Zeeb 				opcode = Q8_TX_CMD_OP_XMT_UDP_CHKSUM_IPV6;
8890bc7cf6fSBjoern A. Zeeb 			else {
8900bc7cf6fSBjoern A. Zeeb 				device_printf(dev, "%s: ipv6\n", __func__);
8910bc7cf6fSBjoern A. Zeeb 				offload = 0;
8920bc7cf6fSBjoern A. Zeeb 			}
8930bc7cf6fSBjoern A. Zeeb 		break;
8940bc7cf6fSBjoern A. Zeeb 
8950bc7cf6fSBjoern A. Zeeb 		default:
8960bc7cf6fSBjoern A. Zeeb 			offload = 0;
8970bc7cf6fSBjoern A. Zeeb 		break;
8980bc7cf6fSBjoern A. Zeeb 	}
8990bc7cf6fSBjoern A. Zeeb 	if (!offload)
9000bc7cf6fSBjoern A. Zeeb 		return (-1);
9010bc7cf6fSBjoern A. Zeeb 
9020bc7cf6fSBjoern A. Zeeb 	tx_cmd->flags_opcode = opcode;
9030bc7cf6fSBjoern A. Zeeb 
9040bc7cf6fSBjoern A. Zeeb 	tx_cmd->tcp_hdr_off = ip_hlen + ehdrlen;
9050bc7cf6fSBjoern A. Zeeb 
9060bc7cf6fSBjoern A. Zeeb 	return (0);
9070bc7cf6fSBjoern A. Zeeb }
9080bc7cf6fSBjoern A. Zeeb 
9090bc7cf6fSBjoern A. Zeeb /*
9100bc7cf6fSBjoern A. Zeeb  * Name: qla_hw_send
9110bc7cf6fSBjoern A. Zeeb  * Function: Transmits a packet. It first checks if the packet is a
9120bc7cf6fSBjoern A. Zeeb  *	candidate for Large TCP Segment Offload and then for UDP/TCP checksum
9130bc7cf6fSBjoern A. Zeeb  *	offload. If either of these creteria are not met, it is transmitted
9140bc7cf6fSBjoern A. Zeeb  *	as a regular ethernet frame.
9150bc7cf6fSBjoern A. Zeeb  */
9160bc7cf6fSBjoern A. Zeeb int
qla_hw_send(qla_host_t * ha,bus_dma_segment_t * segs,int nsegs,uint32_t * tx_idx,struct mbuf * mp)9170bc7cf6fSBjoern A. Zeeb qla_hw_send(qla_host_t *ha, bus_dma_segment_t *segs, int nsegs,
9180bc7cf6fSBjoern A. Zeeb 	uint32_t *tx_idx,  struct mbuf *mp)
9190bc7cf6fSBjoern A. Zeeb {
9200bc7cf6fSBjoern A. Zeeb 	struct ether_vlan_header *eh;
9210bc7cf6fSBjoern A. Zeeb 	qla_hw_t *hw = &ha->hw;
9220bc7cf6fSBjoern A. Zeeb 	q80_tx_cmd_t *tx_cmd, tso_cmd;
9230bc7cf6fSBjoern A. Zeeb 	bus_dma_segment_t *c_seg;
9240bc7cf6fSBjoern A. Zeeb 	uint32_t num_tx_cmds, hdr_len = 0;
9250bc7cf6fSBjoern A. Zeeb 	uint32_t total_length = 0, bytes, tx_cmd_count = 0;
9260bc7cf6fSBjoern A. Zeeb 	device_t dev;
927088fc971SDavid C Somayajulu 	int i, ret;
928088fc971SDavid C Somayajulu 	uint8_t *src = NULL, *dst = NULL;
9290bc7cf6fSBjoern A. Zeeb 
9300bc7cf6fSBjoern A. Zeeb 	dev = ha->pci_dev;
9310bc7cf6fSBjoern A. Zeeb 
9320bc7cf6fSBjoern A. Zeeb 	/*
9330bc7cf6fSBjoern A. Zeeb 	 * Always make sure there is atleast one empty slot in the tx_ring
9340bc7cf6fSBjoern A. Zeeb 	 * tx_ring is considered full when there only one entry available
9350bc7cf6fSBjoern A. Zeeb 	 */
9360bc7cf6fSBjoern A. Zeeb         num_tx_cmds = (nsegs + (Q8_TX_CMD_MAX_SEGMENTS - 1)) >> 2;
9370bc7cf6fSBjoern A. Zeeb 
9380bc7cf6fSBjoern A. Zeeb 	total_length = mp->m_pkthdr.len;
9390bc7cf6fSBjoern A. Zeeb 	if (total_length > QLA_MAX_TSO_FRAME_SIZE) {
9400bc7cf6fSBjoern A. Zeeb 		device_printf(dev, "%s: total length exceeds maxlen(%d)\n",
9410bc7cf6fSBjoern A. Zeeb 			__func__, total_length);
9420bc7cf6fSBjoern A. Zeeb 		return (-1);
9430bc7cf6fSBjoern A. Zeeb 	}
944088fc971SDavid C Somayajulu 	eh = mtod(mp, struct ether_vlan_header *);
945088fc971SDavid C Somayajulu 
946088fc971SDavid C Somayajulu 	if ((mp->m_pkthdr.len > ha->max_frame_size)||(nsegs > Q8_TX_MAX_SEGMENTS)) {
9470bc7cf6fSBjoern A. Zeeb 		bzero((void *)&tso_cmd, sizeof(q80_tx_cmd_t));
9480bc7cf6fSBjoern A. Zeeb 
949088fc971SDavid C Somayajulu 		src = ha->hw.frame_hdr;
950088fc971SDavid C Somayajulu 		ret = qla_tx_tso(ha, mp, &tso_cmd, src);
951088fc971SDavid C Somayajulu 
952088fc971SDavid C Somayajulu 		if (!(ret & ~1)) {
9530bc7cf6fSBjoern A. Zeeb 			/* find the additional tx_cmd descriptors required */
9540bc7cf6fSBjoern A. Zeeb 
9550bc7cf6fSBjoern A. Zeeb 			hdr_len = tso_cmd.total_hdr_len;
9560bc7cf6fSBjoern A. Zeeb 
9570bc7cf6fSBjoern A. Zeeb 			bytes = sizeof(q80_tx_cmd_t) - Q8_TX_CMD_TSO_ALIGN;
9580bc7cf6fSBjoern A. Zeeb 			bytes = QL_MIN(bytes, hdr_len);
9590bc7cf6fSBjoern A. Zeeb 
9600bc7cf6fSBjoern A. Zeeb 			num_tx_cmds++;
9610bc7cf6fSBjoern A. Zeeb 			hdr_len -= bytes;
9620bc7cf6fSBjoern A. Zeeb 
9630bc7cf6fSBjoern A. Zeeb 			while (hdr_len) {
9640bc7cf6fSBjoern A. Zeeb 				bytes = QL_MIN((sizeof(q80_tx_cmd_t)), hdr_len);
9650bc7cf6fSBjoern A. Zeeb 				hdr_len -= bytes;
9660bc7cf6fSBjoern A. Zeeb 				num_tx_cmds++;
9670bc7cf6fSBjoern A. Zeeb 			}
9680bc7cf6fSBjoern A. Zeeb 			hdr_len = tso_cmd.total_hdr_len;
969088fc971SDavid C Somayajulu 
970088fc971SDavid C Somayajulu 			if (ret == 0)
971088fc971SDavid C Somayajulu 				src = (uint8_t *)eh;
972088fc971SDavid C Somayajulu 		}
9730bc7cf6fSBjoern A. Zeeb 	}
9740bc7cf6fSBjoern A. Zeeb 
9750bc7cf6fSBjoern A. Zeeb 	if (hw->txr_free <= (num_tx_cmds + QLA_TX_MIN_FREE)) {
9760bc7cf6fSBjoern A. Zeeb 		qla_hw_tx_done_locked(ha);
9770bc7cf6fSBjoern A. Zeeb 		if (hw->txr_free <= (num_tx_cmds + QLA_TX_MIN_FREE)) {
9780bc7cf6fSBjoern A. Zeeb         		QL_DPRINT8((dev, "%s: (hw->txr_free <= "
9790bc7cf6fSBjoern A. Zeeb 				"(num_tx_cmds + QLA_TX_MIN_FREE))\n",
9800bc7cf6fSBjoern A. Zeeb 				__func__));
9810bc7cf6fSBjoern A. Zeeb 			return (-1);
9820bc7cf6fSBjoern A. Zeeb 		}
9830bc7cf6fSBjoern A. Zeeb 	}
9840bc7cf6fSBjoern A. Zeeb 
9850bc7cf6fSBjoern A. Zeeb 	*tx_idx = hw->txr_next;
9860bc7cf6fSBjoern A. Zeeb 
9870bc7cf6fSBjoern A. Zeeb         tx_cmd = &hw->tx_ring_base[hw->txr_next];
9880bc7cf6fSBjoern A. Zeeb 
9890bc7cf6fSBjoern A. Zeeb 	if (hdr_len == 0) {
9900bc7cf6fSBjoern A. Zeeb 		if ((nsegs > Q8_TX_MAX_SEGMENTS) ||
9910bc7cf6fSBjoern A. Zeeb 			(mp->m_pkthdr.len > ha->max_frame_size)){
9920bc7cf6fSBjoern A. Zeeb         		device_printf(dev,
9931b4381afSAndre Oppermann 				"%s: (nsegs[%d, %d, 0x%b] > Q8_TX_MAX_SEGMENTS)\n",
9940bc7cf6fSBjoern A. Zeeb 				__func__, nsegs, mp->m_pkthdr.len,
9951b4381afSAndre Oppermann 				(int)mp->m_pkthdr.csum_flags, CSUM_BITS);
9960bc7cf6fSBjoern A. Zeeb 			qla_dump_buf8(ha, "qla_hw_send: wrong pkt",
9970bc7cf6fSBjoern A. Zeeb 				mtod(mp, char *), mp->m_len);
9980bc7cf6fSBjoern A. Zeeb 			return (EINVAL);
9990bc7cf6fSBjoern A. Zeeb 		}
10000bc7cf6fSBjoern A. Zeeb 		bzero((void *)tx_cmd, sizeof(q80_tx_cmd_t));
10010bc7cf6fSBjoern A. Zeeb 		if (qla_tx_chksum(ha, mp, tx_cmd) != 0)
10020bc7cf6fSBjoern A. Zeeb         		tx_cmd->flags_opcode = Q8_TX_CMD_OP_XMT_ETHER;
10030bc7cf6fSBjoern A. Zeeb 	} else {
10040bc7cf6fSBjoern A. Zeeb 		bcopy(&tso_cmd, tx_cmd, sizeof(q80_tx_cmd_t));
10050bc7cf6fSBjoern A. Zeeb 	}
10060bc7cf6fSBjoern A. Zeeb 
10070bc7cf6fSBjoern A. Zeeb 	if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN))
10080bc7cf6fSBjoern A. Zeeb         	tx_cmd->flags_opcode |= Q8_TX_CMD_FLAGS_VLAN_TAGGED;
10090bc7cf6fSBjoern A. Zeeb 	else if (mp->m_flags & M_VLANTAG) {
10100bc7cf6fSBjoern A. Zeeb         	tx_cmd->flags_opcode |= (Q8_TX_CMD_FLAGS_VLAN_TAGGED |
10110bc7cf6fSBjoern A. Zeeb 						Q8_TX_CMD_FLAGS_HW_VLAN_ID);
10120bc7cf6fSBjoern A. Zeeb 		tx_cmd->vlan_tci = mp->m_pkthdr.ether_vtag;
10130bc7cf6fSBjoern A. Zeeb 	}
10140bc7cf6fSBjoern A. Zeeb 
10150bc7cf6fSBjoern A. Zeeb         tx_cmd->n_bufs = (uint8_t)nsegs;
10160bc7cf6fSBjoern A. Zeeb         tx_cmd->data_len_lo = (uint8_t)(total_length & 0xFF);
10170bc7cf6fSBjoern A. Zeeb         tx_cmd->data_len_hi = qla_host_to_le16(((uint16_t)(total_length >> 8)));
10180bc7cf6fSBjoern A. Zeeb 	tx_cmd->port_cntxtid = Q8_TX_CMD_PORT_CNXTID(ha->pci_func);
10190bc7cf6fSBjoern A. Zeeb 
10200bc7cf6fSBjoern A. Zeeb 	c_seg = segs;
10210bc7cf6fSBjoern A. Zeeb 
10220bc7cf6fSBjoern A. Zeeb 	while (1) {
10230bc7cf6fSBjoern A. Zeeb 		for (i = 0; ((i < Q8_TX_CMD_MAX_SEGMENTS) && nsegs); i++) {
10240bc7cf6fSBjoern A. Zeeb 			switch (i) {
10250bc7cf6fSBjoern A. Zeeb 			case 0:
10260bc7cf6fSBjoern A. Zeeb 				tx_cmd->buf1_addr = c_seg->ds_addr;
10270bc7cf6fSBjoern A. Zeeb 				tx_cmd->buf1_len = c_seg->ds_len;
10280bc7cf6fSBjoern A. Zeeb 				break;
10290bc7cf6fSBjoern A. Zeeb 
10300bc7cf6fSBjoern A. Zeeb 			case 1:
10310bc7cf6fSBjoern A. Zeeb 				tx_cmd->buf2_addr = c_seg->ds_addr;
10320bc7cf6fSBjoern A. Zeeb 				tx_cmd->buf2_len = c_seg->ds_len;
10330bc7cf6fSBjoern A. Zeeb 				break;
10340bc7cf6fSBjoern A. Zeeb 
10350bc7cf6fSBjoern A. Zeeb 			case 2:
10360bc7cf6fSBjoern A. Zeeb 				tx_cmd->buf3_addr = c_seg->ds_addr;
10370bc7cf6fSBjoern A. Zeeb 				tx_cmd->buf3_len = c_seg->ds_len;
10380bc7cf6fSBjoern A. Zeeb 				break;
10390bc7cf6fSBjoern A. Zeeb 
10400bc7cf6fSBjoern A. Zeeb 			case 3:
10410bc7cf6fSBjoern A. Zeeb 				tx_cmd->buf4_addr = c_seg->ds_addr;
10420bc7cf6fSBjoern A. Zeeb 				tx_cmd->buf4_len = c_seg->ds_len;
10430bc7cf6fSBjoern A. Zeeb 				break;
10440bc7cf6fSBjoern A. Zeeb 			}
10450bc7cf6fSBjoern A. Zeeb 
10460bc7cf6fSBjoern A. Zeeb 			c_seg++;
10470bc7cf6fSBjoern A. Zeeb 			nsegs--;
10480bc7cf6fSBjoern A. Zeeb 		}
10490bc7cf6fSBjoern A. Zeeb 
10500bc7cf6fSBjoern A. Zeeb 		hw->txr_next = (hw->txr_next + 1) & (NUM_TX_DESCRIPTORS - 1);
10510bc7cf6fSBjoern A. Zeeb 		tx_cmd_count++;
10520bc7cf6fSBjoern A. Zeeb 
10530bc7cf6fSBjoern A. Zeeb 		if (!nsegs)
10540bc7cf6fSBjoern A. Zeeb 			break;
10550bc7cf6fSBjoern A. Zeeb 
10560bc7cf6fSBjoern A. Zeeb         	tx_cmd = &hw->tx_ring_base[hw->txr_next];
10570bc7cf6fSBjoern A. Zeeb 		bzero((void *)tx_cmd, sizeof(q80_tx_cmd_t));
10580bc7cf6fSBjoern A. Zeeb 	}
10590bc7cf6fSBjoern A. Zeeb 
10600bc7cf6fSBjoern A. Zeeb 	if (hdr_len) {
10610bc7cf6fSBjoern A. Zeeb 		/* TSO : Copy the header in the following tx cmd descriptors */
10620bc7cf6fSBjoern A. Zeeb 
10630bc7cf6fSBjoern A. Zeeb 		tx_cmd = &hw->tx_ring_base[hw->txr_next];
10640bc7cf6fSBjoern A. Zeeb 		bzero((void *)tx_cmd, sizeof(q80_tx_cmd_t));
10650bc7cf6fSBjoern A. Zeeb 
10660bc7cf6fSBjoern A. Zeeb 		bytes = sizeof(q80_tx_cmd_t) - Q8_TX_CMD_TSO_ALIGN;
10670bc7cf6fSBjoern A. Zeeb 		bytes = QL_MIN(bytes, hdr_len);
10680bc7cf6fSBjoern A. Zeeb 
10690bc7cf6fSBjoern A. Zeeb 		dst = (uint8_t *)tx_cmd + Q8_TX_CMD_TSO_ALIGN;
10700bc7cf6fSBjoern A. Zeeb 
10710bc7cf6fSBjoern A. Zeeb 		if (mp->m_flags & M_VLANTAG) {
10720bc7cf6fSBjoern A. Zeeb 			/* first copy the src/dst MAC addresses */
10730bc7cf6fSBjoern A. Zeeb 			bcopy(src, dst, (ETHER_ADDR_LEN * 2));
10740bc7cf6fSBjoern A. Zeeb 			dst += (ETHER_ADDR_LEN * 2);
10750bc7cf6fSBjoern A. Zeeb 			src += (ETHER_ADDR_LEN * 2);
10760bc7cf6fSBjoern A. Zeeb 
10770bc7cf6fSBjoern A. Zeeb 			hdr_len -= (ETHER_ADDR_LEN * 2);
10780bc7cf6fSBjoern A. Zeeb 
10790bc7cf6fSBjoern A. Zeeb 			*((uint16_t *)dst) = htons(ETHERTYPE_VLAN);
10800bc7cf6fSBjoern A. Zeeb 			dst += 2;
10810bc7cf6fSBjoern A. Zeeb 			*((uint16_t *)dst) = mp->m_pkthdr.ether_vtag;
10820bc7cf6fSBjoern A. Zeeb 			dst += 2;
10830bc7cf6fSBjoern A. Zeeb 
10840bc7cf6fSBjoern A. Zeeb 			bytes -= ((ETHER_ADDR_LEN * 2) + 4);
10850bc7cf6fSBjoern A. Zeeb 
10860bc7cf6fSBjoern A. Zeeb 			bcopy(src, dst, bytes);
10870bc7cf6fSBjoern A. Zeeb 			src += bytes;
10880bc7cf6fSBjoern A. Zeeb 			hdr_len -= bytes;
10890bc7cf6fSBjoern A. Zeeb 		} else {
10900bc7cf6fSBjoern A. Zeeb 			bcopy(src, dst, bytes);
10910bc7cf6fSBjoern A. Zeeb 			src += bytes;
10920bc7cf6fSBjoern A. Zeeb 			hdr_len -= bytes;
10930bc7cf6fSBjoern A. Zeeb 		}
10940bc7cf6fSBjoern A. Zeeb 
10950bc7cf6fSBjoern A. Zeeb 		hw->txr_next = (hw->txr_next + 1) & (NUM_TX_DESCRIPTORS - 1);
10960bc7cf6fSBjoern A. Zeeb 		tx_cmd_count++;
10970bc7cf6fSBjoern A. Zeeb 
10980bc7cf6fSBjoern A. Zeeb 		while (hdr_len) {
10990bc7cf6fSBjoern A. Zeeb 			tx_cmd = &hw->tx_ring_base[hw->txr_next];
11000bc7cf6fSBjoern A. Zeeb 			bzero((void *)tx_cmd, sizeof(q80_tx_cmd_t));
11010bc7cf6fSBjoern A. Zeeb 
11020bc7cf6fSBjoern A. Zeeb 			bytes = QL_MIN((sizeof(q80_tx_cmd_t)), hdr_len);
11030bc7cf6fSBjoern A. Zeeb 
11040bc7cf6fSBjoern A. Zeeb 			bcopy(src, tx_cmd, bytes);
11050bc7cf6fSBjoern A. Zeeb 			src += bytes;
11060bc7cf6fSBjoern A. Zeeb 			hdr_len -= bytes;
11070bc7cf6fSBjoern A. Zeeb 			hw->txr_next =
11080bc7cf6fSBjoern A. Zeeb 				(hw->txr_next + 1) & (NUM_TX_DESCRIPTORS - 1);
11090bc7cf6fSBjoern A. Zeeb 			tx_cmd_count++;
11100bc7cf6fSBjoern A. Zeeb 		}
11110bc7cf6fSBjoern A. Zeeb 	}
11120bc7cf6fSBjoern A. Zeeb 
11130bc7cf6fSBjoern A. Zeeb 	hw->txr_free = hw->txr_free - tx_cmd_count;
11140bc7cf6fSBjoern A. Zeeb 
11150bc7cf6fSBjoern A. Zeeb 	QL_UPDATE_TX_PRODUCER_INDEX(ha, hw->txr_next);
11160bc7cf6fSBjoern A. Zeeb        	QL_DPRINT8((dev, "%s: return\n", __func__));
11170bc7cf6fSBjoern A. Zeeb 	return (0);
11180bc7cf6fSBjoern A. Zeeb }
11190bc7cf6fSBjoern A. Zeeb 
11200bc7cf6fSBjoern A. Zeeb /*
11210bc7cf6fSBjoern A. Zeeb  * Name: qla_del_hw_if
11220bc7cf6fSBjoern A. Zeeb  * Function: Destroys the hardware specific entities corresponding to an
11230bc7cf6fSBjoern A. Zeeb  *	Ethernet Interface
11240bc7cf6fSBjoern A. Zeeb  */
11250bc7cf6fSBjoern A. Zeeb void
qla_del_hw_if(qla_host_t * ha)11260bc7cf6fSBjoern A. Zeeb qla_del_hw_if(qla_host_t *ha)
11270bc7cf6fSBjoern A. Zeeb {
11280bc7cf6fSBjoern A. Zeeb 	int	i;
11290bc7cf6fSBjoern A. Zeeb 
11300bc7cf6fSBjoern A. Zeeb 	for (i = 0; i < ha->hw.num_sds_rings; i++)
11310bc7cf6fSBjoern A. Zeeb 		QL_DISABLE_INTERRUPTS(ha, i);
11320bc7cf6fSBjoern A. Zeeb 
11330bc7cf6fSBjoern A. Zeeb 	qla_del_rcv_cntxt(ha);
11340bc7cf6fSBjoern A. Zeeb 	qla_del_xmt_cntxt(ha);
11350bc7cf6fSBjoern A. Zeeb 
11360bc7cf6fSBjoern A. Zeeb 	ha->hw.flags.lro = 0;
11370bc7cf6fSBjoern A. Zeeb }
11380bc7cf6fSBjoern A. Zeeb 
11390bc7cf6fSBjoern A. Zeeb /*
11400bc7cf6fSBjoern A. Zeeb  * Name: qla_init_hw_if
11410bc7cf6fSBjoern A. Zeeb  * Function: Creates the hardware specific entities corresponding to an
11420bc7cf6fSBjoern A. Zeeb  *	Ethernet Interface - Transmit and Receive Contexts. Sets the MAC Address
11430bc7cf6fSBjoern A. Zeeb  *	corresponding to the interface. Enables LRO if allowed.
11440bc7cf6fSBjoern A. Zeeb  */
11450bc7cf6fSBjoern A. Zeeb int
qla_init_hw_if(qla_host_t * ha)11460bc7cf6fSBjoern A. Zeeb qla_init_hw_if(qla_host_t *ha)
11470bc7cf6fSBjoern A. Zeeb {
11480bc7cf6fSBjoern A. Zeeb 	int		i;
11490bc7cf6fSBjoern A. Zeeb 	uint8_t		bcast_mac[6];
11500bc7cf6fSBjoern A. Zeeb 
11510bc7cf6fSBjoern A. Zeeb 	qla_get_hw_caps(ha);
11520bc7cf6fSBjoern A. Zeeb 
11530bc7cf6fSBjoern A. Zeeb 	for (i = 0; i < ha->hw.num_sds_rings; i++) {
11540bc7cf6fSBjoern A. Zeeb 		bzero(ha->hw.dma_buf.sds_ring[i].dma_b,
11550bc7cf6fSBjoern A. Zeeb 			ha->hw.dma_buf.sds_ring[i].size);
11560bc7cf6fSBjoern A. Zeeb 	}
11570bc7cf6fSBjoern A. Zeeb 	/*
11580bc7cf6fSBjoern A. Zeeb 	 * Create Receive Context
11590bc7cf6fSBjoern A. Zeeb 	 */
11600bc7cf6fSBjoern A. Zeeb 	if (qla_init_rcv_cntxt(ha)) {
11610bc7cf6fSBjoern A. Zeeb 		return (-1);
11620bc7cf6fSBjoern A. Zeeb 	}
11630bc7cf6fSBjoern A. Zeeb 
11640bc7cf6fSBjoern A. Zeeb 	ha->hw.rx_next = NUM_RX_DESCRIPTORS - 2;
11650bc7cf6fSBjoern A. Zeeb 	ha->hw.rxj_next = NUM_RX_JUMBO_DESCRIPTORS - 2;
11660bc7cf6fSBjoern A. Zeeb 	ha->hw.rx_in = ha->hw.rxj_in = 0;
11670bc7cf6fSBjoern A. Zeeb 
11680bc7cf6fSBjoern A. Zeeb 	/* Update the RDS Producer Indices */
11690bc7cf6fSBjoern A. Zeeb 	QL_UPDATE_RDS_PRODUCER_INDEX(ha, 0, ha->hw.rx_next);
11700bc7cf6fSBjoern A. Zeeb 	QL_UPDATE_RDS_PRODUCER_INDEX(ha, 1, ha->hw.rxj_next);
11710bc7cf6fSBjoern A. Zeeb 
11720bc7cf6fSBjoern A. Zeeb 	/*
11730bc7cf6fSBjoern A. Zeeb 	 * Create Transmit Context
11740bc7cf6fSBjoern A. Zeeb 	 */
11750bc7cf6fSBjoern A. Zeeb 	if (qla_init_xmt_cntxt(ha)) {
11760bc7cf6fSBjoern A. Zeeb 		qla_del_rcv_cntxt(ha);
11770bc7cf6fSBjoern A. Zeeb 		return (-1);
11780bc7cf6fSBjoern A. Zeeb 	}
11790bc7cf6fSBjoern A. Zeeb 
11800bc7cf6fSBjoern A. Zeeb 	qla_config_mac_addr(ha, ha->hw.mac_addr,
11810bc7cf6fSBjoern A. Zeeb 		(ha->hw.rx_cntxt_rsp)->rx_rsp.cntxt_id, 1);
11820bc7cf6fSBjoern A. Zeeb 
11830bc7cf6fSBjoern A. Zeeb 	bcast_mac[0] = 0xFF; bcast_mac[1] = 0xFF; bcast_mac[2] = 0xFF;
11840bc7cf6fSBjoern A. Zeeb 	bcast_mac[3] = 0xFF; bcast_mac[4] = 0xFF; bcast_mac[5] = 0xFF;
11850bc7cf6fSBjoern A. Zeeb 	qla_config_mac_addr(ha, bcast_mac,
11860bc7cf6fSBjoern A. Zeeb 		(ha->hw.rx_cntxt_rsp)->rx_rsp.cntxt_id, 1);
11870bc7cf6fSBjoern A. Zeeb 
11880bc7cf6fSBjoern A. Zeeb 	qla_config_rss(ha, (ha->hw.rx_cntxt_rsp)->rx_rsp.cntxt_id);
11890bc7cf6fSBjoern A. Zeeb 
11900bc7cf6fSBjoern A. Zeeb 	qla_config_intr_coalesce(ha, (ha->hw.rx_cntxt_rsp)->rx_rsp.cntxt_id, 0);
11910bc7cf6fSBjoern A. Zeeb 
11920bc7cf6fSBjoern A. Zeeb 	for (i = 0; i < ha->hw.num_sds_rings; i++)
11930bc7cf6fSBjoern A. Zeeb 		QL_ENABLE_INTERRUPTS(ha, i);
11940bc7cf6fSBjoern A. Zeeb 
11950bc7cf6fSBjoern A. Zeeb 	return (0);
11960bc7cf6fSBjoern A. Zeeb }
11970bc7cf6fSBjoern A. Zeeb 
11980bc7cf6fSBjoern A. Zeeb /*
11990bc7cf6fSBjoern A. Zeeb  * Name: qla_init_rcv_cntxt
12000bc7cf6fSBjoern A. Zeeb  * Function: Creates the Receive Context.
12010bc7cf6fSBjoern A. Zeeb  */
12020bc7cf6fSBjoern A. Zeeb static int
qla_init_rcv_cntxt(qla_host_t * ha)12030bc7cf6fSBjoern A. Zeeb qla_init_rcv_cntxt(qla_host_t *ha)
12040bc7cf6fSBjoern A. Zeeb {
12050bc7cf6fSBjoern A. Zeeb 	device_t		dev;
12060bc7cf6fSBjoern A. Zeeb 	qla_cdrp_t		cdrp;
12070bc7cf6fSBjoern A. Zeeb 	q80_rcv_cntxt_rsp_t	*rsp;
12080bc7cf6fSBjoern A. Zeeb 	q80_stat_desc_t		*sdesc;
12090bc7cf6fSBjoern A. Zeeb 	bus_addr_t		phys_addr;
12100bc7cf6fSBjoern A. Zeeb 	int			i, j;
12110bc7cf6fSBjoern A. Zeeb         qla_hw_t		*hw = &ha->hw;
12120bc7cf6fSBjoern A. Zeeb 
12130bc7cf6fSBjoern A. Zeeb 	dev = ha->pci_dev;
12140bc7cf6fSBjoern A. Zeeb 
12150bc7cf6fSBjoern A. Zeeb 	/*
12160bc7cf6fSBjoern A. Zeeb 	 * Create Receive Context
12170bc7cf6fSBjoern A. Zeeb 	 */
12180bc7cf6fSBjoern A. Zeeb 
12190bc7cf6fSBjoern A. Zeeb 	for (i = 0; i < hw->num_sds_rings; i++) {
12200bc7cf6fSBjoern A. Zeeb 		sdesc = (q80_stat_desc_t *)&hw->sds[i].sds_ring_base[0];
12210bc7cf6fSBjoern A. Zeeb 		for (j = 0; j < NUM_STATUS_DESCRIPTORS; j++) {
12220bc7cf6fSBjoern A. Zeeb 			sdesc->data[0] =
12230bc7cf6fSBjoern A. Zeeb 				Q8_STAT_DESC_SET_OWNER(Q8_STAT_DESC_OWNER_FW);
12240bc7cf6fSBjoern A. Zeeb 		}
12250bc7cf6fSBjoern A. Zeeb 	}
12260bc7cf6fSBjoern A. Zeeb 
12270bc7cf6fSBjoern A. Zeeb 	phys_addr = ha->hw.rx_cntxt_req_paddr;
12280bc7cf6fSBjoern A. Zeeb 
12290bc7cf6fSBjoern A. Zeeb 	bzero(&cdrp, sizeof(qla_cdrp_t));
12300bc7cf6fSBjoern A. Zeeb 
12310bc7cf6fSBjoern A. Zeeb 	cdrp.cmd = Q8_CMD_CREATE_RX_CNTXT;
12320bc7cf6fSBjoern A. Zeeb 	cdrp.cmd_arg1 = (uint32_t)(phys_addr >> 32);
12330bc7cf6fSBjoern A. Zeeb 	cdrp.cmd_arg2 = (uint32_t)(phys_addr);
12340bc7cf6fSBjoern A. Zeeb 	cdrp.cmd_arg3 = (uint32_t)(sizeof (q80_rcv_cntxt_req_t));
12350bc7cf6fSBjoern A. Zeeb 
12360bc7cf6fSBjoern A. Zeeb 	if (qla_issue_cmd(ha, &cdrp)) {
12370bc7cf6fSBjoern A. Zeeb 		device_printf(dev, "%s: Q8_CMD_CREATE_RX_CNTXT failed\n",
12380bc7cf6fSBjoern A. Zeeb 			__func__);
12390bc7cf6fSBjoern A. Zeeb 		return (-1);
12400bc7cf6fSBjoern A. Zeeb 	} else {
12410bc7cf6fSBjoern A. Zeeb 		rsp = ha->hw.rx_cntxt_rsp;
12420bc7cf6fSBjoern A. Zeeb 
12430bc7cf6fSBjoern A. Zeeb 		QL_DPRINT2((dev, "%s: rcv cntxt successful"
12440bc7cf6fSBjoern A. Zeeb 			" rds_ring_offset = 0x%08x"
12450bc7cf6fSBjoern A. Zeeb 			" sds_ring_offset = 0x%08x"
12460bc7cf6fSBjoern A. Zeeb 			" cntxt_state = 0x%08x"
12470bc7cf6fSBjoern A. Zeeb 			" funcs_per_port = 0x%08x"
12480bc7cf6fSBjoern A. Zeeb 			" num_rds_rings = 0x%04x"
12490bc7cf6fSBjoern A. Zeeb 			" num_sds_rings = 0x%04x"
12500bc7cf6fSBjoern A. Zeeb 			" cntxt_id = 0x%04x"
12510bc7cf6fSBjoern A. Zeeb 			" phys_port = 0x%02x"
12520bc7cf6fSBjoern A. Zeeb 			" virt_port = 0x%02x\n",
12530bc7cf6fSBjoern A. Zeeb 			__func__,
12540bc7cf6fSBjoern A. Zeeb 			rsp->rx_rsp.rds_ring_offset,
12550bc7cf6fSBjoern A. Zeeb 			rsp->rx_rsp.sds_ring_offset,
12560bc7cf6fSBjoern A. Zeeb 			rsp->rx_rsp.cntxt_state,
12570bc7cf6fSBjoern A. Zeeb 			rsp->rx_rsp.funcs_per_port,
12580bc7cf6fSBjoern A. Zeeb 			rsp->rx_rsp.num_rds_rings,
12590bc7cf6fSBjoern A. Zeeb 			rsp->rx_rsp.num_sds_rings,
12600bc7cf6fSBjoern A. Zeeb 			rsp->rx_rsp.cntxt_id,
12610bc7cf6fSBjoern A. Zeeb 			rsp->rx_rsp.phys_port,
12620bc7cf6fSBjoern A. Zeeb 			rsp->rx_rsp.virt_port));
12630bc7cf6fSBjoern A. Zeeb 
12640bc7cf6fSBjoern A. Zeeb 		for (i = 0; i < ha->hw.num_rds_rings; i++) {
12650bc7cf6fSBjoern A. Zeeb 			QL_DPRINT2((dev,
12660bc7cf6fSBjoern A. Zeeb 				"%s: rcv cntxt rds[%i].producer_reg = 0x%08x\n",
12670bc7cf6fSBjoern A. Zeeb 				__func__, i, rsp->rds_rsp[i].producer_reg));
12680bc7cf6fSBjoern A. Zeeb 		}
12690bc7cf6fSBjoern A. Zeeb 		for (i = 0; i < ha->hw.num_sds_rings; i++) {
12700bc7cf6fSBjoern A. Zeeb 			QL_DPRINT2((dev,
12710bc7cf6fSBjoern A. Zeeb 				"%s: rcv cntxt sds[%i].consumer_reg = 0x%08x"
12720bc7cf6fSBjoern A. Zeeb 				" sds[%i].intr_mask_reg = 0x%08x\n",
12730bc7cf6fSBjoern A. Zeeb 				__func__, i, rsp->sds_rsp[i].consumer_reg,
12740bc7cf6fSBjoern A. Zeeb 				i, rsp->sds_rsp[i].intr_mask_reg));
12750bc7cf6fSBjoern A. Zeeb 		}
12760bc7cf6fSBjoern A. Zeeb 	}
12770bc7cf6fSBjoern A. Zeeb 	ha->hw.flags.init_rx_cnxt = 1;
12780bc7cf6fSBjoern A. Zeeb 	return (0);
12790bc7cf6fSBjoern A. Zeeb }
12800bc7cf6fSBjoern A. Zeeb 
12810bc7cf6fSBjoern A. Zeeb /*
12820bc7cf6fSBjoern A. Zeeb  * Name: qla_del_rcv_cntxt
12830bc7cf6fSBjoern A. Zeeb  * Function: Destroys the Receive Context.
12840bc7cf6fSBjoern A. Zeeb  */
12850bc7cf6fSBjoern A. Zeeb void
qla_del_rcv_cntxt(qla_host_t * ha)12860bc7cf6fSBjoern A. Zeeb qla_del_rcv_cntxt(qla_host_t *ha)
12870bc7cf6fSBjoern A. Zeeb {
12880bc7cf6fSBjoern A. Zeeb 	qla_cdrp_t	cdrp;
12890bc7cf6fSBjoern A. Zeeb 	device_t	dev = ha->pci_dev;
12900bc7cf6fSBjoern A. Zeeb 
12910bc7cf6fSBjoern A. Zeeb 	if (!ha->hw.flags.init_rx_cnxt)
12920bc7cf6fSBjoern A. Zeeb 		return;
12930bc7cf6fSBjoern A. Zeeb 
12940bc7cf6fSBjoern A. Zeeb 	bzero(&cdrp, sizeof(qla_cdrp_t));
12950bc7cf6fSBjoern A. Zeeb 
12960bc7cf6fSBjoern A. Zeeb 	cdrp.cmd = Q8_CMD_DESTROY_RX_CNTXT;
12970bc7cf6fSBjoern A. Zeeb 	cdrp.cmd_arg1 = (uint32_t) (ha->hw.rx_cntxt_rsp)->rx_rsp.cntxt_id;
12980bc7cf6fSBjoern A. Zeeb 
12990bc7cf6fSBjoern A. Zeeb 	if (qla_issue_cmd(ha, &cdrp)) {
13000bc7cf6fSBjoern A. Zeeb 		device_printf(dev, "%s: Q8_CMD_DESTROY_RX_CNTXT failed\n",
13010bc7cf6fSBjoern A. Zeeb 			__func__);
13020bc7cf6fSBjoern A. Zeeb 	}
13030bc7cf6fSBjoern A. Zeeb 	ha->hw.flags.init_rx_cnxt = 0;
13040bc7cf6fSBjoern A. Zeeb }
13050bc7cf6fSBjoern A. Zeeb 
13060bc7cf6fSBjoern A. Zeeb /*
13070bc7cf6fSBjoern A. Zeeb  * Name: qla_init_xmt_cntxt
13080bc7cf6fSBjoern A. Zeeb  * Function: Creates the Transmit Context.
13090bc7cf6fSBjoern A. Zeeb  */
13100bc7cf6fSBjoern A. Zeeb static int
qla_init_xmt_cntxt(qla_host_t * ha)13110bc7cf6fSBjoern A. Zeeb qla_init_xmt_cntxt(qla_host_t *ha)
13120bc7cf6fSBjoern A. Zeeb {
13130bc7cf6fSBjoern A. Zeeb 	bus_addr_t		phys_addr;
13140bc7cf6fSBjoern A. Zeeb 	device_t		dev;
13150bc7cf6fSBjoern A. Zeeb 	q80_tx_cntxt_rsp_t	*tx_rsp;
13160bc7cf6fSBjoern A. Zeeb 	qla_cdrp_t		cdrp;
13170bc7cf6fSBjoern A. Zeeb         qla_hw_t		*hw = &ha->hw;
13180bc7cf6fSBjoern A. Zeeb 
13190bc7cf6fSBjoern A. Zeeb 	dev = ha->pci_dev;
13200bc7cf6fSBjoern A. Zeeb 
13210bc7cf6fSBjoern A. Zeeb 	/*
13220bc7cf6fSBjoern A. Zeeb 	 * Create Transmit Context
13230bc7cf6fSBjoern A. Zeeb 	 */
13240bc7cf6fSBjoern A. Zeeb 	phys_addr = ha->hw.tx_cntxt_req_paddr;
13250bc7cf6fSBjoern A. Zeeb 	tx_rsp = ha->hw.tx_cntxt_rsp;
13260bc7cf6fSBjoern A. Zeeb 
13270bc7cf6fSBjoern A. Zeeb 	hw->txr_comp = hw->txr_next = 0;
13280bc7cf6fSBjoern A. Zeeb 	*(hw->tx_cons) = 0;
13290bc7cf6fSBjoern A. Zeeb 
13300bc7cf6fSBjoern A. Zeeb 	bzero(&cdrp, sizeof(qla_cdrp_t));
13310bc7cf6fSBjoern A. Zeeb 
13320bc7cf6fSBjoern A. Zeeb 	cdrp.cmd = Q8_CMD_CREATE_TX_CNTXT;
13330bc7cf6fSBjoern A. Zeeb 	cdrp.cmd_arg1 = (uint32_t)(phys_addr >> 32);
13340bc7cf6fSBjoern A. Zeeb 	cdrp.cmd_arg2 = (uint32_t)(phys_addr);
13350bc7cf6fSBjoern A. Zeeb 	cdrp.cmd_arg3 = (uint32_t)(sizeof (q80_tx_cntxt_req_t));
13360bc7cf6fSBjoern A. Zeeb 
13370bc7cf6fSBjoern A. Zeeb 	if (qla_issue_cmd(ha, &cdrp)) {
13380bc7cf6fSBjoern A. Zeeb 		device_printf(dev, "%s: Q8_CMD_CREATE_TX_CNTXT failed\n",
13390bc7cf6fSBjoern A. Zeeb 			__func__);
13400bc7cf6fSBjoern A. Zeeb 		return (-1);
13410bc7cf6fSBjoern A. Zeeb 	} else {
13420bc7cf6fSBjoern A. Zeeb 		ha->hw.tx_prod_reg = tx_rsp->producer_reg;
13430bc7cf6fSBjoern A. Zeeb 
13440bc7cf6fSBjoern A. Zeeb 		QL_DPRINT2((dev, "%s: tx cntxt successful"
13450bc7cf6fSBjoern A. Zeeb 			" cntxt_state = 0x%08x "
13460bc7cf6fSBjoern A. Zeeb 			" cntxt_id = 0x%04x "
13470bc7cf6fSBjoern A. Zeeb 			" phys_port_id = 0x%02x "
13480bc7cf6fSBjoern A. Zeeb 			" virt_port_id = 0x%02x "
13490bc7cf6fSBjoern A. Zeeb 			" producer_reg = 0x%08x "
13500bc7cf6fSBjoern A. Zeeb 			" intr_mask_reg = 0x%08x\n",
13510bc7cf6fSBjoern A. Zeeb 			__func__, tx_rsp->cntxt_state, tx_rsp->cntxt_id,
13520bc7cf6fSBjoern A. Zeeb 			tx_rsp->phys_port_id, tx_rsp->virt_port_id,
13530bc7cf6fSBjoern A. Zeeb 			tx_rsp->producer_reg, tx_rsp->intr_mask_reg));
13540bc7cf6fSBjoern A. Zeeb 	}
13550bc7cf6fSBjoern A. Zeeb 	ha->hw.txr_free = NUM_TX_DESCRIPTORS;
13560bc7cf6fSBjoern A. Zeeb 
13570bc7cf6fSBjoern A. Zeeb 	ha->hw.flags.init_tx_cnxt = 1;
13580bc7cf6fSBjoern A. Zeeb 	return (0);
13590bc7cf6fSBjoern A. Zeeb }
13600bc7cf6fSBjoern A. Zeeb 
13610bc7cf6fSBjoern A. Zeeb /*
13620bc7cf6fSBjoern A. Zeeb  * Name: qla_del_xmt_cntxt
13630bc7cf6fSBjoern A. Zeeb  * Function: Destroys the Transmit Context.
13640bc7cf6fSBjoern A. Zeeb  */
13650bc7cf6fSBjoern A. Zeeb static void
qla_del_xmt_cntxt(qla_host_t * ha)13660bc7cf6fSBjoern A. Zeeb qla_del_xmt_cntxt(qla_host_t *ha)
13670bc7cf6fSBjoern A. Zeeb {
13680bc7cf6fSBjoern A. Zeeb 	qla_cdrp_t	cdrp;
13690bc7cf6fSBjoern A. Zeeb 	device_t	dev = ha->pci_dev;
13700bc7cf6fSBjoern A. Zeeb 
13710bc7cf6fSBjoern A. Zeeb 	if (!ha->hw.flags.init_tx_cnxt)
13720bc7cf6fSBjoern A. Zeeb 		return;
13730bc7cf6fSBjoern A. Zeeb 
13740bc7cf6fSBjoern A. Zeeb 	bzero(&cdrp, sizeof(qla_cdrp_t));
13750bc7cf6fSBjoern A. Zeeb 
13760bc7cf6fSBjoern A. Zeeb 	cdrp.cmd = Q8_CMD_DESTROY_TX_CNTXT;
13770bc7cf6fSBjoern A. Zeeb 	cdrp.cmd_arg1 = (uint32_t) (ha->hw.tx_cntxt_rsp)->cntxt_id;
13780bc7cf6fSBjoern A. Zeeb 
13790bc7cf6fSBjoern A. Zeeb 	if (qla_issue_cmd(ha, &cdrp)) {
13800bc7cf6fSBjoern A. Zeeb 		device_printf(dev, "%s: Q8_CMD_DESTROY_TX_CNTXT failed\n",
13810bc7cf6fSBjoern A. Zeeb 			__func__);
13820bc7cf6fSBjoern A. Zeeb 	}
13830bc7cf6fSBjoern A. Zeeb 	ha->hw.flags.init_tx_cnxt = 0;
13840bc7cf6fSBjoern A. Zeeb }
13850bc7cf6fSBjoern A. Zeeb 
13860bc7cf6fSBjoern A. Zeeb /*
13870bc7cf6fSBjoern A. Zeeb  * Name: qla_get_max_rds
13880bc7cf6fSBjoern A. Zeeb  * Function: Returns the maximum number of Receive Descriptor Rings per context.
13890bc7cf6fSBjoern A. Zeeb  */
13900bc7cf6fSBjoern A. Zeeb static int
qla_get_max_rds(qla_host_t * ha)13910bc7cf6fSBjoern A. Zeeb qla_get_max_rds(qla_host_t *ha)
13920bc7cf6fSBjoern A. Zeeb {
13930bc7cf6fSBjoern A. Zeeb 	qla_cdrp_t	cdrp;
13940bc7cf6fSBjoern A. Zeeb 	device_t	dev;
13950bc7cf6fSBjoern A. Zeeb 
13960bc7cf6fSBjoern A. Zeeb 	dev = ha->pci_dev;
13970bc7cf6fSBjoern A. Zeeb 
13980bc7cf6fSBjoern A. Zeeb 	bzero(&cdrp, sizeof(qla_cdrp_t));
13990bc7cf6fSBjoern A. Zeeb 
14000bc7cf6fSBjoern A. Zeeb 	cdrp.cmd = Q8_CMD_RD_MAX_RDS_PER_CNTXT;
14010bc7cf6fSBjoern A. Zeeb 
14020bc7cf6fSBjoern A. Zeeb 	if (qla_issue_cmd(ha, &cdrp)) {
14030bc7cf6fSBjoern A. Zeeb 		device_printf(dev, "%s: Q8_CMD_RD_MAX_RDS_PER_CNTXT failed\n",
14040bc7cf6fSBjoern A. Zeeb 			__func__);
14050bc7cf6fSBjoern A. Zeeb 		return (-1);
14060bc7cf6fSBjoern A. Zeeb 	} else {
14070bc7cf6fSBjoern A. Zeeb 		ha->hw.max_rds_per_cntxt = cdrp.rsp_arg1;
14080bc7cf6fSBjoern A. Zeeb 		QL_DPRINT2((dev, "%s: max_rds_per_context 0x%08x\n",
14090bc7cf6fSBjoern A. Zeeb 			__func__, ha->hw.max_rds_per_cntxt));
14100bc7cf6fSBjoern A. Zeeb 	}
14110bc7cf6fSBjoern A. Zeeb 	return 0;
14120bc7cf6fSBjoern A. Zeeb }
14130bc7cf6fSBjoern A. Zeeb 
14140bc7cf6fSBjoern A. Zeeb /*
14150bc7cf6fSBjoern A. Zeeb  * Name: qla_get_max_sds
14160bc7cf6fSBjoern A. Zeeb  * Function: Returns the maximum number of Status Descriptor Rings per context.
14170bc7cf6fSBjoern A. Zeeb  */
14180bc7cf6fSBjoern A. Zeeb static int
qla_get_max_sds(qla_host_t * ha)14190bc7cf6fSBjoern A. Zeeb qla_get_max_sds(qla_host_t *ha)
14200bc7cf6fSBjoern A. Zeeb {
14210bc7cf6fSBjoern A. Zeeb 	qla_cdrp_t	cdrp;
14220bc7cf6fSBjoern A. Zeeb 	device_t	dev;
14230bc7cf6fSBjoern A. Zeeb 
14240bc7cf6fSBjoern A. Zeeb 	dev = ha->pci_dev;
14250bc7cf6fSBjoern A. Zeeb 
14260bc7cf6fSBjoern A. Zeeb 	bzero(&cdrp, sizeof(qla_cdrp_t));
14270bc7cf6fSBjoern A. Zeeb 
14280bc7cf6fSBjoern A. Zeeb 	cdrp.cmd = Q8_CMD_RD_MAX_SDS_PER_CNTXT;
14290bc7cf6fSBjoern A. Zeeb 
14300bc7cf6fSBjoern A. Zeeb 	if (qla_issue_cmd(ha, &cdrp)) {
14310bc7cf6fSBjoern A. Zeeb 		device_printf(dev, "%s: Q8_CMD_RD_MAX_RDS_PER_CNTXT failed\n",
14320bc7cf6fSBjoern A. Zeeb 			__func__);
14330bc7cf6fSBjoern A. Zeeb 		return (-1);
14340bc7cf6fSBjoern A. Zeeb 	} else {
14350bc7cf6fSBjoern A. Zeeb 		ha->hw.max_sds_per_cntxt = cdrp.rsp_arg1;
14360bc7cf6fSBjoern A. Zeeb 		QL_DPRINT2((dev, "%s: max_sds_per_context 0x%08x\n",
14370bc7cf6fSBjoern A. Zeeb 			__func__, ha->hw.max_sds_per_cntxt));
14380bc7cf6fSBjoern A. Zeeb 	}
14390bc7cf6fSBjoern A. Zeeb 	return 0;
14400bc7cf6fSBjoern A. Zeeb }
14410bc7cf6fSBjoern A. Zeeb 
14420bc7cf6fSBjoern A. Zeeb /*
14430bc7cf6fSBjoern A. Zeeb  * Name: qla_get_max_rules
14440bc7cf6fSBjoern A. Zeeb  * Function: Returns the maximum number of Rules per context.
14450bc7cf6fSBjoern A. Zeeb  */
14460bc7cf6fSBjoern A. Zeeb static int
qla_get_max_rules(qla_host_t * ha)14470bc7cf6fSBjoern A. Zeeb qla_get_max_rules(qla_host_t *ha)
14480bc7cf6fSBjoern A. Zeeb {
14490bc7cf6fSBjoern A. Zeeb 	qla_cdrp_t	cdrp;
14500bc7cf6fSBjoern A. Zeeb 	device_t	dev;
14510bc7cf6fSBjoern A. Zeeb 
14520bc7cf6fSBjoern A. Zeeb 	dev = ha->pci_dev;
14530bc7cf6fSBjoern A. Zeeb 
14540bc7cf6fSBjoern A. Zeeb 	bzero(&cdrp, sizeof(qla_cdrp_t));
14550bc7cf6fSBjoern A. Zeeb 
14560bc7cf6fSBjoern A. Zeeb 	cdrp.cmd = Q8_CMD_RD_MAX_RULES_PER_CNTXT;
14570bc7cf6fSBjoern A. Zeeb 
14580bc7cf6fSBjoern A. Zeeb 	if (qla_issue_cmd(ha, &cdrp)) {
14590bc7cf6fSBjoern A. Zeeb 		device_printf(dev, "%s: Q8_CMD_RD_MAX_RULES_PER_CNTXT failed\n",
14600bc7cf6fSBjoern A. Zeeb 			__func__);
14610bc7cf6fSBjoern A. Zeeb 		return (-1);
14620bc7cf6fSBjoern A. Zeeb 	} else {
14630bc7cf6fSBjoern A. Zeeb 		ha->hw.max_rules_per_cntxt = cdrp.rsp_arg1;
14640bc7cf6fSBjoern A. Zeeb 		QL_DPRINT2((dev, "%s: max_rules_per_cntxt 0x%08x\n",
14650bc7cf6fSBjoern A. Zeeb 			__func__, ha->hw.max_rules_per_cntxt));
14660bc7cf6fSBjoern A. Zeeb 	}
14670bc7cf6fSBjoern A. Zeeb 	return 0;
14680bc7cf6fSBjoern A. Zeeb }
14690bc7cf6fSBjoern A. Zeeb 
14700bc7cf6fSBjoern A. Zeeb /*
14710bc7cf6fSBjoern A. Zeeb  * Name: qla_get_max_rcv_cntxts
14720bc7cf6fSBjoern A. Zeeb  * Function: Returns the maximum number of Receive Contexts supported.
14730bc7cf6fSBjoern A. Zeeb  */
14740bc7cf6fSBjoern A. Zeeb static int
qla_get_max_rcv_cntxts(qla_host_t * ha)14750bc7cf6fSBjoern A. Zeeb qla_get_max_rcv_cntxts(qla_host_t *ha)
14760bc7cf6fSBjoern A. Zeeb {
14770bc7cf6fSBjoern A. Zeeb 	qla_cdrp_t	cdrp;
14780bc7cf6fSBjoern A. Zeeb 	device_t	dev;
14790bc7cf6fSBjoern A. Zeeb 
14800bc7cf6fSBjoern A. Zeeb 	dev = ha->pci_dev;
14810bc7cf6fSBjoern A. Zeeb 
14820bc7cf6fSBjoern A. Zeeb 	bzero(&cdrp, sizeof(qla_cdrp_t));
14830bc7cf6fSBjoern A. Zeeb 
14840bc7cf6fSBjoern A. Zeeb 	cdrp.cmd = Q8_CMD_RD_MAX_RX_CNTXT;
14850bc7cf6fSBjoern A. Zeeb 
14860bc7cf6fSBjoern A. Zeeb 	if (qla_issue_cmd(ha, &cdrp)) {
14870bc7cf6fSBjoern A. Zeeb 		device_printf(dev, "%s: Q8_CMD_RD_MAX_RX_CNTXT failed\n",
14880bc7cf6fSBjoern A. Zeeb 			__func__);
14890bc7cf6fSBjoern A. Zeeb 		return (-1);
14900bc7cf6fSBjoern A. Zeeb 	} else {
14910bc7cf6fSBjoern A. Zeeb 		ha->hw.max_rcv_cntxts = cdrp.rsp_arg1;
14920bc7cf6fSBjoern A. Zeeb 		QL_DPRINT2((dev, "%s: max_rcv_cntxts 0x%08x\n",
14930bc7cf6fSBjoern A. Zeeb 			__func__, ha->hw.max_rcv_cntxts));
14940bc7cf6fSBjoern A. Zeeb 	}
14950bc7cf6fSBjoern A. Zeeb 	return 0;
14960bc7cf6fSBjoern A. Zeeb }
14970bc7cf6fSBjoern A. Zeeb 
14980bc7cf6fSBjoern A. Zeeb /*
14990bc7cf6fSBjoern A. Zeeb  * Name: qla_get_max_tx_cntxts
15000bc7cf6fSBjoern A. Zeeb  * Function: Returns the maximum number of Transmit Contexts supported.
15010bc7cf6fSBjoern A. Zeeb  */
15020bc7cf6fSBjoern A. Zeeb static int
qla_get_max_tx_cntxts(qla_host_t * ha)15030bc7cf6fSBjoern A. Zeeb qla_get_max_tx_cntxts(qla_host_t *ha)
15040bc7cf6fSBjoern A. Zeeb {
15050bc7cf6fSBjoern A. Zeeb 	qla_cdrp_t	cdrp;
15060bc7cf6fSBjoern A. Zeeb 	device_t	dev;
15070bc7cf6fSBjoern A. Zeeb 
15080bc7cf6fSBjoern A. Zeeb 	dev = ha->pci_dev;
15090bc7cf6fSBjoern A. Zeeb 
15100bc7cf6fSBjoern A. Zeeb 	bzero(&cdrp, sizeof(qla_cdrp_t));
15110bc7cf6fSBjoern A. Zeeb 
15120bc7cf6fSBjoern A. Zeeb 	cdrp.cmd = Q8_CMD_RD_MAX_TX_CNTXT;
15130bc7cf6fSBjoern A. Zeeb 
15140bc7cf6fSBjoern A. Zeeb 	if (qla_issue_cmd(ha, &cdrp)) {
15150bc7cf6fSBjoern A. Zeeb 		device_printf(dev, "%s: Q8_CMD_RD_MAX_TX_CNTXT failed\n",
15160bc7cf6fSBjoern A. Zeeb 			__func__);
15170bc7cf6fSBjoern A. Zeeb 		return (-1);
15180bc7cf6fSBjoern A. Zeeb 	} else {
15190bc7cf6fSBjoern A. Zeeb 		ha->hw.max_xmt_cntxts = cdrp.rsp_arg1;
15200bc7cf6fSBjoern A. Zeeb 		QL_DPRINT2((dev, "%s: max_xmt_cntxts 0x%08x\n",
15210bc7cf6fSBjoern A. Zeeb 			__func__, ha->hw.max_xmt_cntxts));
15220bc7cf6fSBjoern A. Zeeb 	}
15230bc7cf6fSBjoern A. Zeeb 	return 0;
15240bc7cf6fSBjoern A. Zeeb }
15250bc7cf6fSBjoern A. Zeeb 
15260bc7cf6fSBjoern A. Zeeb /*
15270bc7cf6fSBjoern A. Zeeb  * Name: qla_get_max_mtu
15280bc7cf6fSBjoern A. Zeeb  * Function: Returns the MTU supported for a context.
15290bc7cf6fSBjoern A. Zeeb  */
15300bc7cf6fSBjoern A. Zeeb static int
qla_get_max_mtu(qla_host_t * ha)15310bc7cf6fSBjoern A. Zeeb qla_get_max_mtu(qla_host_t *ha)
15320bc7cf6fSBjoern A. Zeeb {
15330bc7cf6fSBjoern A. Zeeb 	qla_cdrp_t	cdrp;
15340bc7cf6fSBjoern A. Zeeb 	device_t	dev;
15350bc7cf6fSBjoern A. Zeeb 
15360bc7cf6fSBjoern A. Zeeb 	dev = ha->pci_dev;
15370bc7cf6fSBjoern A. Zeeb 
15380bc7cf6fSBjoern A. Zeeb 	bzero(&cdrp, sizeof(qla_cdrp_t));
15390bc7cf6fSBjoern A. Zeeb 
15400bc7cf6fSBjoern A. Zeeb 	cdrp.cmd = Q8_CMD_RD_MAX_MTU;
15410bc7cf6fSBjoern A. Zeeb 
15420bc7cf6fSBjoern A. Zeeb 	if (qla_issue_cmd(ha, &cdrp)) {
15430bc7cf6fSBjoern A. Zeeb 		device_printf(dev, "%s: Q8_CMD_RD_MAX_MTU failed\n", __func__);
15440bc7cf6fSBjoern A. Zeeb 		return (-1);
15450bc7cf6fSBjoern A. Zeeb 	} else {
15460bc7cf6fSBjoern A. Zeeb 		ha->hw.max_mtu = cdrp.rsp_arg1;
15470bc7cf6fSBjoern A. Zeeb 		QL_DPRINT2((dev, "%s: max_mtu 0x%08x\n", __func__,
15480bc7cf6fSBjoern A. Zeeb 			ha->hw.max_mtu));
15490bc7cf6fSBjoern A. Zeeb 	}
15500bc7cf6fSBjoern A. Zeeb 	return 0;
15510bc7cf6fSBjoern A. Zeeb }
15520bc7cf6fSBjoern A. Zeeb 
15530bc7cf6fSBjoern A. Zeeb /*
15540bc7cf6fSBjoern A. Zeeb  * Name: qla_set_max_mtu
15550bc7cf6fSBjoern A. Zeeb  * Function:
15560bc7cf6fSBjoern A. Zeeb  *	Sets the maximum transfer unit size for the specified rcv context.
15570bc7cf6fSBjoern A. Zeeb  */
15580bc7cf6fSBjoern A. Zeeb int
qla_set_max_mtu(qla_host_t * ha,uint32_t mtu,uint16_t cntxt_id)15590bc7cf6fSBjoern A. Zeeb qla_set_max_mtu(qla_host_t *ha, uint32_t mtu, uint16_t cntxt_id)
15600bc7cf6fSBjoern A. Zeeb {
15610bc7cf6fSBjoern A. Zeeb 	qla_cdrp_t	cdrp;
15620bc7cf6fSBjoern A. Zeeb 	device_t	dev;
15630bc7cf6fSBjoern A. Zeeb 
15640bc7cf6fSBjoern A. Zeeb 	dev = ha->pci_dev;
15650bc7cf6fSBjoern A. Zeeb 
15660bc7cf6fSBjoern A. Zeeb 	bzero(&cdrp, sizeof(qla_cdrp_t));
15670bc7cf6fSBjoern A. Zeeb 
15680bc7cf6fSBjoern A. Zeeb 	cdrp.cmd = Q8_CMD_SET_MTU;
15690bc7cf6fSBjoern A. Zeeb 	cdrp.cmd_arg1 = (uint32_t)cntxt_id;
15700bc7cf6fSBjoern A. Zeeb 	cdrp.cmd_arg2 = mtu;
15710bc7cf6fSBjoern A. Zeeb 
15720bc7cf6fSBjoern A. Zeeb 	if (qla_issue_cmd(ha, &cdrp)) {
15730bc7cf6fSBjoern A. Zeeb 		device_printf(dev, "%s: Q8_CMD_RD_MAX_MTU failed\n", __func__);
15740bc7cf6fSBjoern A. Zeeb 		return (-1);
15750bc7cf6fSBjoern A. Zeeb 	} else {
15760bc7cf6fSBjoern A. Zeeb 		ha->hw.max_mtu = cdrp.rsp_arg1;
15770bc7cf6fSBjoern A. Zeeb 	}
15780bc7cf6fSBjoern A. Zeeb 	return 0;
15790bc7cf6fSBjoern A. Zeeb }
15800bc7cf6fSBjoern A. Zeeb 
15810bc7cf6fSBjoern A. Zeeb /*
15820bc7cf6fSBjoern A. Zeeb  * Name: qla_get_max_lro
15830bc7cf6fSBjoern A. Zeeb  * Function: Returns the maximum number of TCP Connection which can be supported
15840bc7cf6fSBjoern A. Zeeb  *	with LRO.
15850bc7cf6fSBjoern A. Zeeb  */
15860bc7cf6fSBjoern A. Zeeb static int
qla_get_max_lro(qla_host_t * ha)15870bc7cf6fSBjoern A. Zeeb qla_get_max_lro(qla_host_t *ha)
15880bc7cf6fSBjoern A. Zeeb {
15890bc7cf6fSBjoern A. Zeeb 	qla_cdrp_t	cdrp;
15900bc7cf6fSBjoern A. Zeeb 	device_t	dev;
15910bc7cf6fSBjoern A. Zeeb 
15920bc7cf6fSBjoern A. Zeeb 	dev = ha->pci_dev;
15930bc7cf6fSBjoern A. Zeeb 
15940bc7cf6fSBjoern A. Zeeb 	bzero(&cdrp, sizeof(qla_cdrp_t));
15950bc7cf6fSBjoern A. Zeeb 
15960bc7cf6fSBjoern A. Zeeb 	cdrp.cmd = Q8_CMD_RD_MAX_LRO;
15970bc7cf6fSBjoern A. Zeeb 
15980bc7cf6fSBjoern A. Zeeb 	if (qla_issue_cmd(ha, &cdrp)) {
15990bc7cf6fSBjoern A. Zeeb 		device_printf(dev, "%s: Q8_CMD_RD_MAX_LRO failed\n", __func__);
16000bc7cf6fSBjoern A. Zeeb 		return (-1);
16010bc7cf6fSBjoern A. Zeeb 	} else {
16020bc7cf6fSBjoern A. Zeeb 		ha->hw.max_lro = cdrp.rsp_arg1;
16030bc7cf6fSBjoern A. Zeeb 		QL_DPRINT2((dev, "%s: max_lro 0x%08x\n", __func__,
16040bc7cf6fSBjoern A. Zeeb 			ha->hw.max_lro));
16050bc7cf6fSBjoern A. Zeeb 	}
16060bc7cf6fSBjoern A. Zeeb 	return 0;
16070bc7cf6fSBjoern A. Zeeb }
16080bc7cf6fSBjoern A. Zeeb 
16090bc7cf6fSBjoern A. Zeeb /*
16100bc7cf6fSBjoern A. Zeeb  * Name: qla_get_flow_control
16110bc7cf6fSBjoern A. Zeeb  * Function: Returns the Receive/Transmit Flow Control (PAUSE) settings for
16120bc7cf6fSBjoern A. Zeeb  *	PCI function.
16130bc7cf6fSBjoern A. Zeeb  */
16140bc7cf6fSBjoern A. Zeeb static int
qla_get_flow_control(qla_host_t * ha)16150bc7cf6fSBjoern A. Zeeb qla_get_flow_control(qla_host_t *ha)
16160bc7cf6fSBjoern A. Zeeb {
16170bc7cf6fSBjoern A. Zeeb 	qla_cdrp_t	cdrp;
16180bc7cf6fSBjoern A. Zeeb 	device_t	dev;
16190bc7cf6fSBjoern A. Zeeb 
16200bc7cf6fSBjoern A. Zeeb 	dev = ha->pci_dev;
16210bc7cf6fSBjoern A. Zeeb 
16220bc7cf6fSBjoern A. Zeeb 	bzero(&cdrp, sizeof(qla_cdrp_t));
16230bc7cf6fSBjoern A. Zeeb 
16240bc7cf6fSBjoern A. Zeeb 	cdrp.cmd = Q8_CMD_GET_FLOW_CNTRL;
16250bc7cf6fSBjoern A. Zeeb 
16260bc7cf6fSBjoern A. Zeeb 	if (qla_issue_cmd(ha, &cdrp)) {
16270bc7cf6fSBjoern A. Zeeb 		device_printf(dev, "%s: Q8_CMD_GET_FLOW_CNTRL failed\n",
16280bc7cf6fSBjoern A. Zeeb 			__func__);
16290bc7cf6fSBjoern A. Zeeb 		return (-1);
16300bc7cf6fSBjoern A. Zeeb 	} else {
16310bc7cf6fSBjoern A. Zeeb 		QL_DPRINT2((dev, "%s: flow control 0x%08x\n", __func__,
16320bc7cf6fSBjoern A. Zeeb 			cdrp.rsp_arg1));
16330bc7cf6fSBjoern A. Zeeb 	}
16340bc7cf6fSBjoern A. Zeeb 	return 0;
16350bc7cf6fSBjoern A. Zeeb }
16360bc7cf6fSBjoern A. Zeeb 
16370bc7cf6fSBjoern A. Zeeb /*
16380bc7cf6fSBjoern A. Zeeb  * Name: qla_get_flow_control
16390bc7cf6fSBjoern A. Zeeb  * Function: Retrieves hardware capabilities
16400bc7cf6fSBjoern A. Zeeb  */
16410bc7cf6fSBjoern A. Zeeb void
qla_get_hw_caps(qla_host_t * ha)16420bc7cf6fSBjoern A. Zeeb qla_get_hw_caps(qla_host_t *ha)
16430bc7cf6fSBjoern A. Zeeb {
16440bc7cf6fSBjoern A. Zeeb 	//qla_read_mac_addr(ha);
16450bc7cf6fSBjoern A. Zeeb 	qla_get_max_rds(ha);
16460bc7cf6fSBjoern A. Zeeb 	qla_get_max_sds(ha);
16470bc7cf6fSBjoern A. Zeeb 	qla_get_max_rules(ha);
16480bc7cf6fSBjoern A. Zeeb 	qla_get_max_rcv_cntxts(ha);
16490bc7cf6fSBjoern A. Zeeb 	qla_get_max_tx_cntxts(ha);
16500bc7cf6fSBjoern A. Zeeb 	qla_get_max_mtu(ha);
16510bc7cf6fSBjoern A. Zeeb 	qla_get_max_lro(ha);
16520bc7cf6fSBjoern A. Zeeb 	qla_get_flow_control(ha);
16530bc7cf6fSBjoern A. Zeeb 	return;
16540bc7cf6fSBjoern A. Zeeb }
16550bc7cf6fSBjoern A. Zeeb 
16560bc7cf6fSBjoern A. Zeeb /*
16570bc7cf6fSBjoern A. Zeeb  * Name: qla_hw_set_multi
16580bc7cf6fSBjoern A. Zeeb  * Function: Sets the Multicast Addresses provided the host O.S into the
16590bc7cf6fSBjoern A. Zeeb  *	hardware (for the given interface)
16600bc7cf6fSBjoern A. Zeeb  */
16610bc7cf6fSBjoern A. Zeeb void
qla_hw_set_multi(qla_host_t * ha,uint8_t * mta,uint32_t mcnt,uint32_t add_multi)16620bc7cf6fSBjoern A. Zeeb qla_hw_set_multi(qla_host_t *ha, uint8_t *mta, uint32_t mcnt,
16630bc7cf6fSBjoern A. Zeeb 	uint32_t add_multi)
16640bc7cf6fSBjoern A. Zeeb {
16650bc7cf6fSBjoern A. Zeeb 	q80_rcv_cntxt_rsp_t	*rsp;
16660bc7cf6fSBjoern A. Zeeb 	int i;
16670bc7cf6fSBjoern A. Zeeb 
16680bc7cf6fSBjoern A. Zeeb 	rsp = ha->hw.rx_cntxt_rsp;
16690bc7cf6fSBjoern A. Zeeb 	for (i = 0; i < mcnt; i++) {
16700bc7cf6fSBjoern A. Zeeb 		qla_config_mac_addr(ha, mta, rsp->rx_rsp.cntxt_id, add_multi);
16710bc7cf6fSBjoern A. Zeeb 		mta += Q8_MAC_ADDR_LEN;
16720bc7cf6fSBjoern A. Zeeb 	}
16730bc7cf6fSBjoern A. Zeeb 	return;
16740bc7cf6fSBjoern A. Zeeb }
16750bc7cf6fSBjoern A. Zeeb 
16760bc7cf6fSBjoern A. Zeeb /*
16770bc7cf6fSBjoern A. Zeeb  * Name: qla_hw_tx_done_locked
16780bc7cf6fSBjoern A. Zeeb  * Function: Handle Transmit Completions
16790bc7cf6fSBjoern A. Zeeb  */
16800bc7cf6fSBjoern A. Zeeb static void
qla_hw_tx_done_locked(qla_host_t * ha)16810bc7cf6fSBjoern A. Zeeb qla_hw_tx_done_locked(qla_host_t *ha)
16820bc7cf6fSBjoern A. Zeeb {
16830bc7cf6fSBjoern A. Zeeb 	qla_tx_buf_t *txb;
16840bc7cf6fSBjoern A. Zeeb         qla_hw_t *hw = &ha->hw;
16850bc7cf6fSBjoern A. Zeeb 	uint32_t comp_idx, comp_count = 0;
16860bc7cf6fSBjoern A. Zeeb 
16870bc7cf6fSBjoern A. Zeeb 	/* retrieve index of last entry in tx ring completed */
16880bc7cf6fSBjoern A. Zeeb 	comp_idx = qla_le32_to_host(*(hw->tx_cons));
16890bc7cf6fSBjoern A. Zeeb 
16900bc7cf6fSBjoern A. Zeeb 	while (comp_idx != hw->txr_comp) {
16910bc7cf6fSBjoern A. Zeeb 		txb = &ha->tx_buf[hw->txr_comp];
16920bc7cf6fSBjoern A. Zeeb 
16930bc7cf6fSBjoern A. Zeeb 		hw->txr_comp++;
16940bc7cf6fSBjoern A. Zeeb 		if (hw->txr_comp == NUM_TX_DESCRIPTORS)
16950bc7cf6fSBjoern A. Zeeb 			hw->txr_comp = 0;
16960bc7cf6fSBjoern A. Zeeb 
16970bc7cf6fSBjoern A. Zeeb 		comp_count++;
16980bc7cf6fSBjoern A. Zeeb 
16990bc7cf6fSBjoern A. Zeeb 		if (txb->m_head) {
17000bc7cf6fSBjoern A. Zeeb 			bus_dmamap_sync(ha->tx_tag, txb->map,
17010bc7cf6fSBjoern A. Zeeb 				BUS_DMASYNC_POSTWRITE);
17020bc7cf6fSBjoern A. Zeeb 			bus_dmamap_unload(ha->tx_tag, txb->map);
17030bc7cf6fSBjoern A. Zeeb 			bus_dmamap_destroy(ha->tx_tag, txb->map);
17040bc7cf6fSBjoern A. Zeeb 			m_freem(txb->m_head);
17050bc7cf6fSBjoern A. Zeeb 
17060bc7cf6fSBjoern A. Zeeb 			txb->map = (bus_dmamap_t)0;
17070bc7cf6fSBjoern A. Zeeb 			txb->m_head = NULL;
17080bc7cf6fSBjoern A. Zeeb 		}
17090bc7cf6fSBjoern A. Zeeb 	}
17100bc7cf6fSBjoern A. Zeeb 
17110bc7cf6fSBjoern A. Zeeb 	hw->txr_free += comp_count;
17120bc7cf6fSBjoern A. Zeeb 
17130bc7cf6fSBjoern A. Zeeb        	QL_DPRINT8((ha->pci_dev, "%s: return [c,f, p, pn][%d, %d, %d, %d]\n", __func__,
17140bc7cf6fSBjoern A. Zeeb 		hw->txr_comp, hw->txr_free, hw->txr_next, READ_REG32(ha, (ha->hw.tx_prod_reg + 0x1b2000))));
17150bc7cf6fSBjoern A. Zeeb 
17160bc7cf6fSBjoern A. Zeeb 	return;
17170bc7cf6fSBjoern A. Zeeb }
17180bc7cf6fSBjoern A. Zeeb 
17190bc7cf6fSBjoern A. Zeeb /*
17200bc7cf6fSBjoern A. Zeeb  * Name: qla_hw_tx_done
17210bc7cf6fSBjoern A. Zeeb  * Function: Handle Transmit Completions
17220bc7cf6fSBjoern A. Zeeb  */
17230bc7cf6fSBjoern A. Zeeb void
qla_hw_tx_done(qla_host_t * ha)17240bc7cf6fSBjoern A. Zeeb qla_hw_tx_done(qla_host_t *ha)
17250bc7cf6fSBjoern A. Zeeb {
17260bc7cf6fSBjoern A. Zeeb 	if (!mtx_trylock(&ha->tx_lock)) {
17270bc7cf6fSBjoern A. Zeeb        		QL_DPRINT8((ha->pci_dev,
17280bc7cf6fSBjoern A. Zeeb 			"%s: !mtx_trylock(&ha->tx_lock)\n", __func__));
17290bc7cf6fSBjoern A. Zeeb 		return;
17300bc7cf6fSBjoern A. Zeeb 	}
17310bc7cf6fSBjoern A. Zeeb 	qla_hw_tx_done_locked(ha);
17320bc7cf6fSBjoern A. Zeeb 
17330bc7cf6fSBjoern A. Zeeb 	if (ha->hw.txr_free > free_pkt_thres)
17345b587352SJustin Hibbits 		if_setdrvflagbits(ha->ifp, 0, IFF_DRV_OACTIVE);
17350bc7cf6fSBjoern A. Zeeb 
17360bc7cf6fSBjoern A. Zeeb 	mtx_unlock(&ha->tx_lock);
17370bc7cf6fSBjoern A. Zeeb 	return;
17380bc7cf6fSBjoern A. Zeeb }
17390bc7cf6fSBjoern A. Zeeb 
17400bc7cf6fSBjoern A. Zeeb void
qla_update_link_state(qla_host_t * ha)17410bc7cf6fSBjoern A. Zeeb qla_update_link_state(qla_host_t *ha)
17420bc7cf6fSBjoern A. Zeeb {
17430bc7cf6fSBjoern A. Zeeb 	uint32_t link_state;
1744088fc971SDavid C Somayajulu 	uint32_t prev_link_state;
17450bc7cf6fSBjoern A. Zeeb 
17465b587352SJustin Hibbits 	if (!(if_getdrvflags(ha->ifp) & IFF_DRV_RUNNING)) {
17470bc7cf6fSBjoern A. Zeeb 		ha->hw.flags.link_up = 0;
17480bc7cf6fSBjoern A. Zeeb 		return;
17490bc7cf6fSBjoern A. Zeeb 	}
17500bc7cf6fSBjoern A. Zeeb 	link_state = READ_REG32(ha, Q8_LINK_STATE);
17510bc7cf6fSBjoern A. Zeeb 
1752088fc971SDavid C Somayajulu 	prev_link_state =  ha->hw.flags.link_up;
1753088fc971SDavid C Somayajulu 
17540bc7cf6fSBjoern A. Zeeb 	if (ha->pci_func == 0)
17550bc7cf6fSBjoern A. Zeeb 		ha->hw.flags.link_up = (((link_state & 0xF) == 1)? 1 : 0);
17560bc7cf6fSBjoern A. Zeeb 	else
17570bc7cf6fSBjoern A. Zeeb 		ha->hw.flags.link_up = ((((link_state >> 4)& 0xF) == 1)? 1 : 0);
1758088fc971SDavid C Somayajulu 
1759088fc971SDavid C Somayajulu 	if (prev_link_state !=  ha->hw.flags.link_up) {
1760088fc971SDavid C Somayajulu 		if (ha->hw.flags.link_up) {
1761088fc971SDavid C Somayajulu 			if_link_state_change(ha->ifp, LINK_STATE_UP);
1762088fc971SDavid C Somayajulu 		} else {
1763088fc971SDavid C Somayajulu 			if_link_state_change(ha->ifp, LINK_STATE_DOWN);
1764088fc971SDavid C Somayajulu 		}
1765088fc971SDavid C Somayajulu 	}
17660bc7cf6fSBjoern A. Zeeb }
17670bc7cf6fSBjoern A. Zeeb 
17680bc7cf6fSBjoern A. Zeeb int
qla_config_lro(qla_host_t * ha)17690bc7cf6fSBjoern A. Zeeb qla_config_lro(qla_host_t *ha)
17700bc7cf6fSBjoern A. Zeeb {
1771618aa8cdSJohn Baldwin #if defined(INET) || defined(INET6)
17720bc7cf6fSBjoern A. Zeeb 	int i;
17730bc7cf6fSBjoern A. Zeeb         qla_hw_t *hw = &ha->hw;
17740bc7cf6fSBjoern A. Zeeb 	struct lro_ctrl *lro;
17750bc7cf6fSBjoern A. Zeeb 
17760bc7cf6fSBjoern A. Zeeb 	for (i = 0; i < hw->num_sds_rings; i++) {
17770bc7cf6fSBjoern A. Zeeb 		lro = &hw->sds[i].lro;
17780bc7cf6fSBjoern A. Zeeb 		if (tcp_lro_init(lro)) {
17790bc7cf6fSBjoern A. Zeeb 			device_printf(ha->pci_dev, "%s: tcp_lro_init failed\n",
17800bc7cf6fSBjoern A. Zeeb 				__func__);
17810bc7cf6fSBjoern A. Zeeb 			return (-1);
17820bc7cf6fSBjoern A. Zeeb 		}
17830bc7cf6fSBjoern A. Zeeb 		lro->ifp = ha->ifp;
17840bc7cf6fSBjoern A. Zeeb 	}
17850bc7cf6fSBjoern A. Zeeb 	ha->flags.lro_init = 1;
17860bc7cf6fSBjoern A. Zeeb 
17870bc7cf6fSBjoern A. Zeeb 	QL_DPRINT2((ha->pci_dev, "%s: LRO initialized\n", __func__));
1788618aa8cdSJohn Baldwin #endif
17890bc7cf6fSBjoern A. Zeeb 	return (0);
17900bc7cf6fSBjoern A. Zeeb }
17910bc7cf6fSBjoern A. Zeeb 
17920bc7cf6fSBjoern A. Zeeb void
qla_free_lro(qla_host_t * ha)17930bc7cf6fSBjoern A. Zeeb qla_free_lro(qla_host_t *ha)
17940bc7cf6fSBjoern A. Zeeb {
1795618aa8cdSJohn Baldwin #if defined(INET) || defined(INET6)
17960bc7cf6fSBjoern A. Zeeb 	int i;
17970bc7cf6fSBjoern A. Zeeb         qla_hw_t *hw = &ha->hw;
17980bc7cf6fSBjoern A. Zeeb 	struct lro_ctrl *lro;
17990bc7cf6fSBjoern A. Zeeb 
18000bc7cf6fSBjoern A. Zeeb 	if (!ha->flags.lro_init)
18010bc7cf6fSBjoern A. Zeeb 		return;
18020bc7cf6fSBjoern A. Zeeb 
18030bc7cf6fSBjoern A. Zeeb 	for (i = 0; i < hw->num_sds_rings; i++) {
18040bc7cf6fSBjoern A. Zeeb 		lro = &hw->sds[i].lro;
18050bc7cf6fSBjoern A. Zeeb 		tcp_lro_free(lro);
18060bc7cf6fSBjoern A. Zeeb 	}
18070bc7cf6fSBjoern A. Zeeb 	ha->flags.lro_init = 0;
1808618aa8cdSJohn Baldwin #endif
18090bc7cf6fSBjoern A. Zeeb }
18100bc7cf6fSBjoern A. Zeeb 
18110bc7cf6fSBjoern A. Zeeb void
qla_hw_stop_rcv(qla_host_t * ha)18120bc7cf6fSBjoern A. Zeeb qla_hw_stop_rcv(qla_host_t *ha)
18130bc7cf6fSBjoern A. Zeeb {
18140bc7cf6fSBjoern A. Zeeb 	int i, done, count = 100;
18150bc7cf6fSBjoern A. Zeeb 
18160bc7cf6fSBjoern A. Zeeb 	while (count--) {
18170bc7cf6fSBjoern A. Zeeb 		done = 1;
18180bc7cf6fSBjoern A. Zeeb 		for (i = 0; i < ha->hw.num_sds_rings; i++) {
18190bc7cf6fSBjoern A. Zeeb 			if (ha->hw.sds[i].rcv_active)
18200bc7cf6fSBjoern A. Zeeb 				done = 0;
18210bc7cf6fSBjoern A. Zeeb 		}
18220bc7cf6fSBjoern A. Zeeb 		if (done)
18230bc7cf6fSBjoern A. Zeeb 			break;
18240bc7cf6fSBjoern A. Zeeb 		else
18250bc7cf6fSBjoern A. Zeeb 			qla_mdelay(__func__, 10);
18260bc7cf6fSBjoern A. Zeeb 	}
18270bc7cf6fSBjoern A. Zeeb }
1828