diff --git a/sys/dev/qlxge/qls_isr.c b/sys/dev/qlxge/qls_isr.c index f8fc84680997..9778fecc4218 100644 --- a/sys/dev/qlxge/qls_isr.c +++ b/sys/dev/qlxge/qls_isr.c @@ -1,396 +1,394 @@ /*- - * SPDX-License-Identifier: BSD-2-Clause - * * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2013-2014 Qlogic Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * File: qls_isr.c * Author : David C Somayajulu, Qlogic Corporation, Aliso Viejo, CA 92656. */ #include __FBSDID("$FreeBSD$"); #include "qls_os.h" #include "qls_hw.h" #include "qls_def.h" #include "qls_inline.h" #include "qls_ver.h" #include "qls_glbl.h" #include "qls_dbg.h" static void qls_tx_comp(qla_host_t *ha, uint32_t txr_idx, q81_tx_mac_comp_t *tx_comp) { qla_tx_buf_t *txb; uint32_t tx_idx = tx_comp->tid_lo; if (tx_idx >= NUM_TX_DESCRIPTORS) { ha->qla_initiate_recovery = 1; return; } txb = &ha->tx_ring[txr_idx].tx_buf[tx_idx]; if (txb->m_head) { if_inc_counter(ha->ifp, IFCOUNTER_OPACKETS, 1); bus_dmamap_sync(ha->tx_tag, txb->map, BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(ha->tx_tag, txb->map); m_freem(txb->m_head); txb->m_head = NULL; } ha->tx_ring[txr_idx].txr_done++; if (ha->tx_ring[txr_idx].txr_done == NUM_TX_DESCRIPTORS) ha->tx_ring[txr_idx].txr_done = 0; } static void qls_replenish_rx(qla_host_t *ha, uint32_t r_idx) { qla_rx_buf_t *rxb; qla_rx_ring_t *rxr; int count; volatile q81_bq_addr_e_t *sbq_e; rxr = &ha->rx_ring[r_idx]; count = rxr->rx_free; sbq_e = rxr->sbq_vaddr; while (count--) { rxb = &rxr->rx_buf[rxr->sbq_next]; if (rxb->m_head == NULL) { if (qls_get_mbuf(ha, rxb, NULL) != 0) { device_printf(ha->pci_dev, "%s: qls_get_mbuf [0,%d,%d] failed\n", __func__, rxr->sbq_next, r_idx); rxb->m_head = NULL; break; } } if (rxb->m_head != NULL) { sbq_e[rxr->sbq_next].addr_lo = (uint32_t)rxb->paddr; sbq_e[rxr->sbq_next].addr_hi = (uint32_t)(rxb->paddr >> 32); rxr->sbq_next++; if (rxr->sbq_next == NUM_RX_DESCRIPTORS) rxr->sbq_next = 0; rxr->sbq_free++; rxr->rx_free--; } if (rxr->sbq_free == 16) { rxr->sbq_in += 16; rxr->sbq_in = rxr->sbq_in & (NUM_RX_DESCRIPTORS - 1); rxr->sbq_free = 0; Q81_WR_SBQ_PROD_IDX(r_idx, (rxr->sbq_in)); } } } static int qls_rx_comp(qla_host_t *ha, uint32_t rxr_idx, uint32_t cq_idx, q81_rx_t *cq_e) { qla_rx_buf_t *rxb; qla_rx_ring_t *rxr; device_t dev = ha->pci_dev; struct mbuf *mp = NULL; struct ifnet *ifp = ha->ifp; #if defined(INET) || defined(INET6) struct lro_ctrl *lro; #endif struct ether_vlan_header *eh; rxr = &ha->rx_ring[rxr_idx]; #if defined(INET) || defined(INET6) lro = &rxr->lro; #endif rxb = &rxr->rx_buf[rxr->rx_next]; if (!(cq_e->flags1 & Q81_RX_FLAGS1_DS)) { device_printf(dev, "%s: DS bit not set \n", __func__); return -1; } if (rxb->paddr != cq_e->b_paddr) { device_printf(dev, "%s: (rxb->paddr != cq_e->b_paddr)[%p, %p] \n", __func__, (void *)rxb->paddr, (void *)cq_e->b_paddr); Q81_SET_CQ_INVALID(cq_idx); ha->qla_initiate_recovery = 1; return(-1); } rxr->rx_int++; if ((cq_e->flags1 & Q81_RX_FLAGS1_ERR_MASK) == 0) { mp = rxb->m_head; rxb->m_head = NULL; if (mp == NULL) { device_printf(dev, "%s: mp == NULL\n", __func__); } else { mp->m_flags |= M_PKTHDR; mp->m_pkthdr.len = cq_e->length; mp->m_pkthdr.rcvif = ifp; mp->m_len = cq_e->length; eh = mtod(mp, struct ether_vlan_header *); if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) { uint32_t *data = (uint32_t *)eh; mp->m_pkthdr.ether_vtag = ntohs(eh->evl_tag); mp->m_flags |= M_VLANTAG; *(data + 3) = *(data + 2); *(data + 2) = *(data + 1); *(data + 1) = *data; m_adj(mp, ETHER_VLAN_ENCAP_LEN); } if ((cq_e->flags1 & Q81_RX_FLAGS1_RSS_MATCH_MASK)) { rxr->rss_int++; mp->m_pkthdr.flowid = cq_e->rss; M_HASHTYPE_SET(mp, M_HASHTYPE_OPAQUE_HASH); } if (cq_e->flags0 & (Q81_RX_FLAGS0_TE | Q81_RX_FLAGS0_NU | Q81_RX_FLAGS0_IE)) { mp->m_pkthdr.csum_flags = 0; } else { mp->m_pkthdr.csum_flags = CSUM_IP_CHECKED | CSUM_IP_VALID | CSUM_DATA_VALID | CSUM_PSEUDO_HDR; mp->m_pkthdr.csum_data = 0xFFFF; } if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); #if defined(INET) || defined(INET6) if (lro->lro_cnt && (tcp_lro_rx(lro, mp, 0) == 0)) { /* LRO packet has been successfully queued */ } else #endif { (*ifp->if_input)(ifp, mp); } } } else { device_printf(dev, "%s: err [0%08x]\n", __func__, cq_e->flags1); } rxr->rx_free++; rxr->rx_next++; if (rxr->rx_next == NUM_RX_DESCRIPTORS) rxr->rx_next = 0; if ((rxr->rx_free + rxr->sbq_free) >= 16) qls_replenish_rx(ha, rxr_idx); return 0; } static void qls_cq_isr(qla_host_t *ha, uint32_t cq_idx) { q81_cq_e_t *cq_e, *cq_b; uint32_t i, cq_comp_idx; int ret = 0, tx_comp_done = 0; #if defined(INET) || defined(INET6) struct lro_ctrl *lro = &ha->rx_ring[cq_idx].lro; #endif cq_b = ha->rx_ring[cq_idx].cq_base_vaddr; cq_comp_idx = *(ha->rx_ring[cq_idx].cqi_vaddr); i = ha->rx_ring[cq_idx].cq_next; while (i != cq_comp_idx) { cq_e = &cq_b[i]; switch (cq_e->opcode) { case Q81_IOCB_TX_MAC: case Q81_IOCB_TX_TSO: qls_tx_comp(ha, cq_idx, (q81_tx_mac_comp_t *)cq_e); tx_comp_done++; break; case Q81_IOCB_RX: ret = qls_rx_comp(ha, cq_idx, i, (q81_rx_t *)cq_e); break; case Q81_IOCB_MPI: case Q81_IOCB_SYS: default: device_printf(ha->pci_dev, "%s[%d %d 0x%x]: illegal \n", __func__, i, (*(ha->rx_ring[cq_idx].cqi_vaddr)), cq_e->opcode); qls_dump_buf32(ha, __func__, cq_e, (sizeof (q81_cq_e_t) >> 2)); break; } i++; if (i == NUM_CQ_ENTRIES) i = 0; if (ret) { break; } if (i == cq_comp_idx) { cq_comp_idx = *(ha->rx_ring[cq_idx].cqi_vaddr); } if (tx_comp_done) { taskqueue_enqueue(ha->tx_tq, &ha->tx_task); tx_comp_done = 0; } } #if defined(INET) || defined(INET6) tcp_lro_flush_all(lro); #endif ha->rx_ring[cq_idx].cq_next = cq_comp_idx; if (!ret) { Q81_WR_CQ_CONS_IDX(cq_idx, (ha->rx_ring[cq_idx].cq_next)); } if (tx_comp_done) taskqueue_enqueue(ha->tx_tq, &ha->tx_task); return; } static void qls_mbx_isr(qla_host_t *ha) { uint32_t data; int i; device_t dev = ha->pci_dev; if (qls_mbx_rd_reg(ha, 0, &data) == 0) { if ((data & 0xF000) == 0x4000) { ha->mbox[0] = data; for (i = 1; i < Q81_NUM_MBX_REGISTERS; i++) { if (qls_mbx_rd_reg(ha, i, &data)) break; ha->mbox[i] = data; } ha->mbx_done = 1; } else if ((data & 0xF000) == 0x8000) { /* we have an AEN */ ha->aen[0] = data; for (i = 1; i < Q81_NUM_AEN_REGISTERS; i++) { if (qls_mbx_rd_reg(ha, i, &data)) break; ha->aen[i] = data; } device_printf(dev,"%s: AEN " "[0x%08x 0x%08x 0x%08x 0x%08x 0x%08x" " 0x%08x 0x%08x 0x%08x 0x%08x]\n", __func__, ha->aen[0], ha->aen[1], ha->aen[2], ha->aen[3], ha->aen[4], ha->aen[5], ha->aen[6], ha->aen[7], ha->aen[8]); switch ((ha->aen[0] & 0xFFFF)) { case 0x8011: ha->link_up = 1; break; case 0x8012: ha->link_up = 0; break; case 0x8130: ha->link_hw_info = ha->aen[1]; break; case 0x8131: ha->link_hw_info = 0; break; } } } WRITE_REG32(ha, Q81_CTL_HOST_CMD_STATUS, Q81_CTL_HCS_CMD_CLR_RTH_INTR); return; } void qls_isr(void *arg) { qla_ivec_t *ivec = arg; qla_host_t *ha; uint32_t status; uint32_t cq_idx; device_t dev; ha = ivec->ha; cq_idx = ivec->cq_idx; dev = ha->pci_dev; status = READ_REG32(ha, Q81_CTL_STATUS); if (status & Q81_CTL_STATUS_FE) { device_printf(dev, "%s fatal error\n", __func__); return; } if ((cq_idx == 0) && (status & Q81_CTL_STATUS_PI)) { qls_mbx_isr(ha); } status = READ_REG32(ha, Q81_CTL_INTR_STATUS1); if (status & ( 0x1 << cq_idx)) qls_cq_isr(ha, cq_idx); Q81_ENABLE_INTR(ha, cq_idx); return; } diff --git a/sys/xen/xenbus/xenbusb.h b/sys/xen/xenbus/xenbusb.h index 12f5201f70eb..f59af62a7c2c 100644 --- a/sys/xen/xenbus/xenbusb.h +++ b/sys/xen/xenbus/xenbusb.h @@ -1,301 +1,299 @@ /*- - * SPDX-License-Identifier: BSD-2-Clause - * * Core definitions and data structures shareable across OS platforms. * * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2010 Spectra Logic Corporation * Copyright (C) 2008 Doug Rabson * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions, and the following disclaimer, * without modification. * 2. Redistributions in binary form must reproduce at minimum a disclaimer * substantially similar to the "NO WARRANTY" disclaimer below * ("Disclaimer") and any redistribution must be conditioned upon * including a substantially similar Disclaimer requirement for further * binary redistribution. * * NO WARRANTY * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * * $FreeBSD$ */ #ifndef _XEN_XENBUS_XENBUSB_H #define _XEN_XENBUS_XENBUSB_H /** * \file xenbusb.h * * Datastructures and function declarations for use in implementing * bus attachements (e.g. frontend and backend device buses) for XenBus. */ /** * Enumeration of state flag values for the xbs_flags field of * the xenbusb_softc structure. */ typedef enum { /** */ XBS_ATTACH_CH_ACTIVE = 0x01 } xenbusb_softc_flag; /** * \brief Container for all state needed to manage a Xenbus Bus * attachment. */ struct xenbusb_softc { /** * XenStore watch used to monitor the subtree of the * XenStore where devices for this bus attachment arrive * and depart. */ struct xs_watch xbs_device_watch; /** Mutex used to protect fields of the xenbusb_softc. */ struct mtx xbs_lock; /** State flags. */ xenbusb_softc_flag xbs_flags; /** * A dedicated task for processing child arrival and * departure events. */ struct task xbs_probe_children; /** * Config Hook used to block boot processing until * XenBus devices complete their connection processing * with other VMs. */ struct intr_config_hook xbs_attach_ch; /** * The number of children for this bus that are still * in the connecting (to other VMs) state. This variable * is used to determine when to release xbs_attach_ch. */ u_int xbs_connecting_children; /** The NewBus device_t for this bus attachment. */ device_t xbs_dev; /** * The VM relative path to the XenStore subtree this * bus attachment manages. */ const char *xbs_node; /** * The number of path components (strings separated by the '/' * character) that make up the device ID on this bus. */ u_int xbs_id_components; }; /** * Enumeration of state flag values for the xbs_flags field of * the xenbusb_softc structure. */ typedef enum { /** * This device is contributing to the xbs_connecting_children * count of its parent bus. */ XDF_CONNECTING = 0x01 } xenbus_dev_flag; /** Instance variables for devices on a XenBus bus. */ struct xenbus_device_ivars { /** * XenStore watch used to monitor the subtree of the * XenStore where information about the otherend of * the split Xen device this device instance represents. */ struct xs_watch xd_otherend_watch; /** * XenStore watch used to monitor the XenStore sub-tree * associated with this device. This watch will fire * for modifications that we make from our domain as * well as for those made by the control domain. */ struct xs_watch xd_local_watch; /** Sleepable lock used to protect instance data. */ struct sx xd_lock; /** State flags. */ xenbus_dev_flag xd_flags; /** The NewBus device_t for this XenBus device instance. */ device_t xd_dev; /** * The VM relative path to the XenStore subtree representing * this VMs half of this device. */ char *xd_node; /** The length of xd_node. */ int xd_node_len; /** XenBus device type ("vbd", "vif", etc.). */ char *xd_type; /** * Cached version of /state node in the XenStore. */ enum xenbus_state xd_state; /** The VM identifier of the other end of this split device. */ int xd_otherend_id; /** * The path to the subtree of the XenStore where information * about the otherend of this split device instance. */ char *xd_otherend_path; /** The length of xd_otherend_path. */ int xd_otherend_path_len; }; /** * \brief Identify instances of this device type in the system. * * \param driver The driver performing this identify action. * \param parent The NewBus parent device for any devices this method adds. */ void xenbusb_identify(driver_t *driver __unused, device_t parent); /** * \brief Perform common XenBus bus attach processing. * * \param dev The NewBus device representing this XenBus bus. * \param bus_node The XenStore path to the XenStore subtree for * this XenBus bus. * \param id_components The number of '/' separated path components that * make up a unique device ID on this XenBus bus. * * \return On success, 0. Otherwise an errno value indicating the * type of failure. * * Intiailizes the softc for this bus, installs an interrupt driven * configuration hook to block boot processing until XenBus devices fully * configure, performs an initial probe/attach of the bus, and registers * a XenStore watch so we are notified when the bus topology changes. */ int xenbusb_attach(device_t dev, char *bus_node, u_int id_components); /** * \brief Perform common XenBus bus resume handling. * * \param dev The NewBus device representing this XenBus bus. * * \return On success, 0. Otherwise an errno value indicating the * type of failure. */ int xenbusb_resume(device_t dev); /** * \brief Pretty-prints information about a child of a XenBus bus. * * \param dev The NewBus device representing this XenBus bus. * \param child The NewBus device representing a child of dev%'s XenBus bus. * * \return On success, 0. Otherwise an errno value indicating the * type of failure. */ int xenbusb_print_child(device_t dev, device_t child); /** * \brief Common XenBus child instance variable read access method. * * \param dev The NewBus device representing this XenBus bus. * \param child The NewBus device representing a child of dev%'s XenBus bus. * \param index The index of the instance variable to access. * \param result The value of the instance variable accessed. * * \return On success, 0. Otherwise an errno value indicating the * type of failure. */ int xenbusb_read_ivar(device_t dev, device_t child, int index, uintptr_t *result); /** * \brief Common XenBus child instance variable write access method. * * \param dev The NewBus device representing this XenBus bus. * \param child The NewBus device representing a child of dev%'s XenBus bus. * \param index The index of the instance variable to access. * \param value The new value to set in the instance variable accessed. * * \return On success, 0. Otherwise an errno value indicating the * type of failure. */ int xenbusb_write_ivar(device_t dev, device_t child, int index, uintptr_t value); /** * \brief Common XenBus method implementing responses to peer state changes. * * \param bus The XenBus bus parent of child. * \param child The XenBus child whose peer stat has changed. * \param state The current state of the peer. */ void xenbusb_otherend_changed(device_t bus, device_t child, enum xenbus_state state); /** * \brief Common XenBus method implementing responses to local XenStore changes. * * \param bus The XenBus bus parent of child. * \param child The XenBus child whose peer stat has changed. * \param path The tree relative sub-path to the modified node. The empty * string indicates the root of the tree was destroyed. */ void xenbusb_localend_changed(device_t bus, device_t child, const char *path); /** * \brief Attempt to add a XenBus device instance to this XenBus bus. * * \param dev The NewBus device representing this XenBus bus. * \param type The device type being added (e.g. "vbd", "vif"). * \param id The device ID for this device. * * \return On success, 0. Otherwise an errno value indicating the * type of failure. Failure indicates that either the * path to this device no longer exists or insufficient * information exists in the XenStore to create a new * device. * * If successful, this routine will add a device_t with instance * variable storage to the NewBus device topology. Probe/Attach * processing is not performed by this routine, but must be scheduled * via the xbs_probe_children task. This separation of responsibilities * is required to avoid hanging up the XenStore event delivery thread * with our probe/attach work in the event a device is added via * a callback from the XenStore. */ int xenbusb_add_device(device_t dev, const char *type, const char *id); #include "xenbusb_if.h" #endif /* _XEN_XENBUS_XENBUSB_H */