2 * SPDX-License-Identifier: BSD-2-Clause
4 * Copyright (c) 2013-2014 Qlogic Corporation
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
32 * Author : David C Somayajulu, Qlogic Corporation, Aliso Viejo, CA 92656.
34 #include <sys/cdefs.h>
38 #include "qls_inline.h"
44 qls_tx_comp(qla_host_t *ha, uint32_t txr_idx, q81_tx_mac_comp_t *tx_comp)
47 uint32_t tx_idx = tx_comp->tid_lo;
49 if (tx_idx >= NUM_TX_DESCRIPTORS) {
50 ha->qla_initiate_recovery = 1;
54 txb = &ha->tx_ring[txr_idx].tx_buf[tx_idx];
57 if_inc_counter(ha->ifp, IFCOUNTER_OPACKETS, 1);
58 bus_dmamap_sync(ha->tx_tag, txb->map,
59 BUS_DMASYNC_POSTWRITE);
60 bus_dmamap_unload(ha->tx_tag, txb->map);
66 ha->tx_ring[txr_idx].txr_done++;
68 if (ha->tx_ring[txr_idx].txr_done == NUM_TX_DESCRIPTORS)
69 ha->tx_ring[txr_idx].txr_done = 0;
73 qls_replenish_rx(qla_host_t *ha, uint32_t r_idx)
78 volatile q81_bq_addr_e_t *sbq_e;
80 rxr = &ha->rx_ring[r_idx];
83 sbq_e = rxr->sbq_vaddr;
86 rxb = &rxr->rx_buf[rxr->sbq_next];
88 if (rxb->m_head == NULL) {
89 if (qls_get_mbuf(ha, rxb, NULL) != 0) {
90 device_printf(ha->pci_dev,
91 "%s: qls_get_mbuf [0,%d,%d] failed\n",
92 __func__, rxr->sbq_next, r_idx);
98 if (rxb->m_head != NULL) {
99 sbq_e[rxr->sbq_next].addr_lo = (uint32_t)rxb->paddr;
100 sbq_e[rxr->sbq_next].addr_hi =
101 (uint32_t)(rxb->paddr >> 32);
104 if (rxr->sbq_next == NUM_RX_DESCRIPTORS)
111 if (rxr->sbq_free == 16) {
113 rxr->sbq_in = rxr->sbq_in & (NUM_RX_DESCRIPTORS - 1);
116 Q81_WR_SBQ_PROD_IDX(r_idx, (rxr->sbq_in));
122 qls_rx_comp(qla_host_t *ha, uint32_t rxr_idx, uint32_t cq_idx, q81_rx_t *cq_e)
126 device_t dev = ha->pci_dev;
127 struct mbuf *mp = NULL;
129 #if defined(INET) || defined(INET6)
130 struct lro_ctrl *lro;
132 struct ether_vlan_header *eh;
134 rxr = &ha->rx_ring[rxr_idx];
136 #if defined(INET) || defined(INET6)
140 rxb = &rxr->rx_buf[rxr->rx_next];
142 if (!(cq_e->flags1 & Q81_RX_FLAGS1_DS)) {
143 device_printf(dev, "%s: DS bit not set \n", __func__);
146 if (rxb->paddr != cq_e->b_paddr) {
148 "%s: (rxb->paddr != cq_e->b_paddr)[%p, %p] \n",
149 __func__, (void *)rxb->paddr, (void *)cq_e->b_paddr);
151 Q81_SET_CQ_INVALID(cq_idx);
153 ha->qla_initiate_recovery = 1;
160 if ((cq_e->flags1 & Q81_RX_FLAGS1_ERR_MASK) == 0) {
165 device_printf(dev, "%s: mp == NULL\n", __func__);
167 mp->m_flags |= M_PKTHDR;
168 mp->m_pkthdr.len = cq_e->length;
169 mp->m_pkthdr.rcvif = ifp;
170 mp->m_len = cq_e->length;
172 eh = mtod(mp, struct ether_vlan_header *);
174 if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) {
175 uint32_t *data = (uint32_t *)eh;
177 mp->m_pkthdr.ether_vtag = ntohs(eh->evl_tag);
178 mp->m_flags |= M_VLANTAG;
180 *(data + 3) = *(data + 2);
181 *(data + 2) = *(data + 1);
184 m_adj(mp, ETHER_VLAN_ENCAP_LEN);
187 if ((cq_e->flags1 & Q81_RX_FLAGS1_RSS_MATCH_MASK)) {
189 mp->m_pkthdr.flowid = cq_e->rss;
190 M_HASHTYPE_SET(mp, M_HASHTYPE_OPAQUE_HASH);
192 if (cq_e->flags0 & (Q81_RX_FLAGS0_TE |
193 Q81_RX_FLAGS0_NU | Q81_RX_FLAGS0_IE)) {
194 mp->m_pkthdr.csum_flags = 0;
196 mp->m_pkthdr.csum_flags = CSUM_IP_CHECKED |
197 CSUM_IP_VALID | CSUM_DATA_VALID |
199 mp->m_pkthdr.csum_data = 0xFFFF;
201 if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
203 #if defined(INET) || defined(INET6)
204 if (lro->lro_cnt && (tcp_lro_rx(lro, mp, 0) == 0)) {
205 /* LRO packet has been successfully queued */
213 device_printf(dev, "%s: err [0%08x]\n", __func__, cq_e->flags1);
219 if (rxr->rx_next == NUM_RX_DESCRIPTORS)
222 if ((rxr->rx_free + rxr->sbq_free) >= 16)
223 qls_replenish_rx(ha, rxr_idx);
229 qls_cq_isr(qla_host_t *ha, uint32_t cq_idx)
231 q81_cq_e_t *cq_e, *cq_b;
232 uint32_t i, cq_comp_idx;
233 int ret = 0, tx_comp_done = 0;
234 #if defined(INET) || defined(INET6)
235 struct lro_ctrl *lro = &ha->rx_ring[cq_idx].lro;
238 cq_b = ha->rx_ring[cq_idx].cq_base_vaddr;
240 cq_comp_idx = *(ha->rx_ring[cq_idx].cqi_vaddr);
242 i = ha->rx_ring[cq_idx].cq_next;
244 while (i != cq_comp_idx) {
247 switch (cq_e->opcode) {
248 case Q81_IOCB_TX_MAC:
249 case Q81_IOCB_TX_TSO:
250 qls_tx_comp(ha, cq_idx, (q81_tx_mac_comp_t *)cq_e);
255 ret = qls_rx_comp(ha, cq_idx, i, (q81_rx_t *)cq_e);
262 device_printf(ha->pci_dev, "%s[%d %d 0x%x]: illegal \n",
263 __func__, i, (*(ha->rx_ring[cq_idx].cqi_vaddr)),
265 qls_dump_buf32(ha, __func__, cq_e,
266 (sizeof (q81_cq_e_t) >> 2));
271 if (i == NUM_CQ_ENTRIES)
278 if (i == cq_comp_idx) {
279 cq_comp_idx = *(ha->rx_ring[cq_idx].cqi_vaddr);
283 taskqueue_enqueue(ha->tx_tq, &ha->tx_task);
288 #if defined(INET) || defined(INET6)
289 tcp_lro_flush_all(lro);
292 ha->rx_ring[cq_idx].cq_next = cq_comp_idx;
295 Q81_WR_CQ_CONS_IDX(cq_idx, (ha->rx_ring[cq_idx].cq_next));
298 taskqueue_enqueue(ha->tx_tq, &ha->tx_task);
304 qls_mbx_isr(qla_host_t *ha)
308 device_t dev = ha->pci_dev;
310 if (qls_mbx_rd_reg(ha, 0, &data) == 0) {
311 if ((data & 0xF000) == 0x4000) {
313 for (i = 1; i < Q81_NUM_MBX_REGISTERS; i++) {
314 if (qls_mbx_rd_reg(ha, i, &data))
319 } else if ((data & 0xF000) == 0x8000) {
323 for (i = 1; i < Q81_NUM_AEN_REGISTERS; i++) {
324 if (qls_mbx_rd_reg(ha, i, &data))
328 device_printf(dev,"%s: AEN "
329 "[0x%08x 0x%08x 0x%08x 0x%08x 0x%08x"
330 " 0x%08x 0x%08x 0x%08x 0x%08x]\n",
332 ha->aen[0], ha->aen[1], ha->aen[2],
333 ha->aen[3], ha->aen[4], ha->aen[5],
334 ha->aen[6], ha->aen[7], ha->aen[8]);
336 switch ((ha->aen[0] & 0xFFFF)) {
346 ha->link_hw_info = ha->aen[1];
350 ha->link_hw_info = 0;
355 WRITE_REG32(ha, Q81_CTL_HOST_CMD_STATUS, Q81_CTL_HCS_CMD_CLR_RTH_INTR);
363 qla_ivec_t *ivec = arg;
370 cq_idx = ivec->cq_idx;
373 status = READ_REG32(ha, Q81_CTL_STATUS);
375 if (status & Q81_CTL_STATUS_FE) {
376 device_printf(dev, "%s fatal error\n", __func__);
380 if ((cq_idx == 0) && (status & Q81_CTL_STATUS_PI)) {
384 status = READ_REG32(ha, Q81_CTL_INTR_STATUS1);
386 if (status & ( 0x1 << cq_idx))
387 qls_cq_isr(ha, cq_idx);
389 Q81_ENABLE_INTR(ha, cq_idx);