1bd368728SMarko Zec /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 3bd368728SMarko Zec * 4bd368728SMarko Zec * Copyright (c) 2015 Bjoern A. Zeeb 5bd368728SMarko Zec * Copyright (c) 2020 Denis Salopek 6bd368728SMarko Zec * 7bd368728SMarko Zec * This software was developed by SRI International and the University of 8bd368728SMarko Zec * Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-11-C-0249 9bd368728SMarko Zec * ("MRC2"), as part of the DARPA MRC research programme. 10bd368728SMarko Zec * 11bd368728SMarko Zec * Redistribution and use in source and binary forms, with or without 12bd368728SMarko Zec * modification, are permitted provided that the following conditions 13bd368728SMarko Zec * are met: 14bd368728SMarko Zec * 1. Redistributions of source code must retain the above copyright 15bd368728SMarko Zec * notice, this list of conditions and the following disclaimer. 16bd368728SMarko Zec * 2. Redistributions in binary form must reproduce the above copyright 17bd368728SMarko Zec * notice, this list of conditions and the following disclaimer in the 18bd368728SMarko Zec * documentation and/or other materials provided with the distribution. 19bd368728SMarko Zec * 20bd368728SMarko Zec * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21bd368728SMarko Zec * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22bd368728SMarko Zec * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23bd368728SMarko Zec * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 24bd368728SMarko Zec * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25bd368728SMarko Zec * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26bd368728SMarko Zec * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27bd368728SMarko Zec * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28bd368728SMarko Zec * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29bd368728SMarko Zec * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30bd368728SMarko Zec * POSSIBILITY OF SUCH DAMAGE. 31bd368728SMarko Zec */ 32bd368728SMarko Zec 33bd368728SMarko Zec #include <sys/param.h> 34bd368728SMarko Zec #include <sys/bus.h> 35bd368728SMarko Zec #include <sys/endian.h> 36bd368728SMarko Zec #include <sys/kernel.h> 37bd368728SMarko Zec #include <sys/limits.h> 38bd368728SMarko Zec #include <sys/module.h> 39bd368728SMarko Zec #include <sys/rman.h> 40bd368728SMarko Zec #include <sys/socket.h> 41bd368728SMarko Zec #include <sys/sockio.h> 42bd368728SMarko Zec #include <sys/sysctl.h> 43bd368728SMarko Zec #include <sys/taskqueue.h> 44bd368728SMarko Zec 45bd368728SMarko Zec #include <net/if.h> 46bd368728SMarko Zec #include <net/if_media.h> 47bd368728SMarko Zec #include <net/if_types.h> 48bd368728SMarko Zec #include <net/if_var.h> 49bd368728SMarko Zec 50bd368728SMarko Zec #include <netinet/in.h> 51bd368728SMarko Zec #include <netinet/if_ether.h> 52bd368728SMarko Zec 53bd368728SMarko Zec #include <dev/pci/pcivar.h> 54bd368728SMarko Zec #include <dev/pci/pcireg.h> 55bd368728SMarko Zec 56bd368728SMarko Zec #include <machine/bus.h> 57bd368728SMarko Zec 58bd368728SMarko Zec #include "adapter.h" 59bd368728SMarko Zec 60bd368728SMarko Zec #define PCI_VENDOR_ID_XILINX 0x10ee 61bd368728SMarko Zec #define PCI_DEVICE_ID_SUME 0x7028 62bd368728SMarko Zec 63bd368728SMarko Zec /* SUME bus driver interface */ 64bd368728SMarko Zec static int sume_probe(device_t); 65bd368728SMarko Zec static int sume_attach(device_t); 66bd368728SMarko Zec static int sume_detach(device_t); 67bd368728SMarko Zec 68bd368728SMarko Zec static device_method_t sume_methods[] = { 69bd368728SMarko Zec DEVMETHOD(device_probe, sume_probe), 70bd368728SMarko Zec DEVMETHOD(device_attach, sume_attach), 71bd368728SMarko Zec DEVMETHOD(device_detach, sume_detach), 72bd368728SMarko Zec DEVMETHOD_END 73bd368728SMarko Zec }; 74bd368728SMarko Zec 75bd368728SMarko Zec static driver_t sume_driver = { 76bd368728SMarko Zec "sume", 77bd368728SMarko Zec sume_methods, 78bd368728SMarko Zec sizeof(struct sume_adapter) 79bd368728SMarko Zec }; 80bd368728SMarko Zec 81bd368728SMarko Zec /* 82bd368728SMarko Zec * The DMA engine for SUME generates interrupts for each RX/TX transaction. 83bd368728SMarko Zec * Depending on the channel (0 if packet transaction, 1 if register transaction) 84bd368728SMarko Zec * the used bits of the interrupt vector will be the lowest or the second lowest 85bd368728SMarko Zec * 5 bits. 86bd368728SMarko Zec * 87bd368728SMarko Zec * When receiving packets from SUME (RX): 88bd368728SMarko Zec * (1) SUME received a packet on one of the interfaces. 89bd368728SMarko Zec * (2) SUME generates an interrupt vector, bit 00001 is set (channel 0 - new RX 90bd368728SMarko Zec * transaction). 91bd368728SMarko Zec * (3) We read the length of the incoming packet and the offset along with the 92bd368728SMarko Zec * 'last' flag from the SUME registers. 93bd368728SMarko Zec * (4) We prepare for the DMA transaction by setting the bouncebuffer on the 94bd368728SMarko Zec * address buf_addr. For now, this is how it's done: 95bd368728SMarko Zec * - First 3*sizeof(uint32_t) bytes are: lower and upper 32 bits of physical 96bd368728SMarko Zec * address where we want the data to arrive (buf_addr[0] and buf_addr[1]), 97bd368728SMarko Zec * and length of incoming data (buf_addr[2]). 98bd368728SMarko Zec * - Data will start right after, at buf_addr+3*sizeof(uint32_t). The 99bd368728SMarko Zec * physical address buf_hw_addr is a block of contiguous memory mapped to 100bd368728SMarko Zec * buf_addr, so we can set the incoming data's physical address (buf_addr[0] 101bd368728SMarko Zec * and buf_addr[1]) to buf_hw_addr+3*sizeof(uint32_t). 102bd368728SMarko Zec * (5) We notify SUME that the bouncebuffer is ready for the transaction by 103bd368728SMarko Zec * writing the lower/upper physical address buf_hw_addr to the SUME 104bd368728SMarko Zec * registers RIFFA_TX_SG_ADDR_LO_REG_OFF and RIFFA_TX_SG_ADDR_HI_REG_OFF as 105bd368728SMarko Zec * well as the number of segments to the register RIFFA_TX_SG_LEN_REG_OFF. 106bd368728SMarko Zec * (6) SUME generates an interrupt vector, bit 00010 is set (channel 0 - 107bd368728SMarko Zec * bouncebuffer received). 108bd368728SMarko Zec * (7) SUME generates an interrupt vector, bit 00100 is set (channel 0 - 109bd368728SMarko Zec * transaction is done). 110bd368728SMarko Zec * (8) SUME can do both steps (6) and (7) using the same interrupt. 111bd368728SMarko Zec * (8) We read the first 16 bytes (metadata) of the received data and note the 112bd368728SMarko Zec * incoming interface so we can later forward it to the right one in the OS 113bd368728SMarko Zec * (sume0, sume1, sume2 or sume3). 114bd368728SMarko Zec * (10) We create an mbuf and copy the data from the bouncebuffer to the mbuf 115bd368728SMarko Zec * and set the mbuf rcvif to the incoming interface. 116bd368728SMarko Zec * (11) We forward the mbuf to the appropriate interface via ifp->if_input. 117bd368728SMarko Zec * 118bd368728SMarko Zec * When sending packets to SUME (TX): 119bd368728SMarko Zec * (1) The OS calls sume_if_start() function on TX. 120bd368728SMarko Zec * (2) We get the mbuf packet data and copy it to the 121bd368728SMarko Zec * buf_addr+3*sizeof(uint32_t) + metadata 16 bytes. 122bd368728SMarko Zec * (3) We create the metadata based on the output interface and copy it to the 123bd368728SMarko Zec * buf_addr+3*sizeof(uint32_t). 124bd368728SMarko Zec * (4) We write the offset/last and length of the packet to the SUME registers 125bd368728SMarko Zec * RIFFA_RX_OFFLAST_REG_OFF and RIFFA_RX_LEN_REG_OFF. 126bd368728SMarko Zec * (5) We fill the bouncebuffer by filling the first 3*sizeof(uint32_t) bytes 127bd368728SMarko Zec * with the physical address and length just as in RX step (4). 128bd368728SMarko Zec * (6) We notify SUME that the bouncebuffer is ready by writing to SUME 129bd368728SMarko Zec * registers RIFFA_RX_SG_ADDR_LO_REG_OFF, RIFFA_RX_SG_ADDR_HI_REG_OFF and 130bd368728SMarko Zec * RIFFA_RX_SG_LEN_REG_OFF just as in RX step (5). 131bd368728SMarko Zec * (7) SUME generates an interrupt vector, bit 01000 is set (channel 0 - 132bd368728SMarko Zec * bouncebuffer is read). 133bd368728SMarko Zec * (8) SUME generates an interrupt vector, bit 10000 is set (channel 0 - 134bd368728SMarko Zec * transaction is done). 135bd368728SMarko Zec * (9) SUME can do both steps (7) and (8) using the same interrupt. 136bd368728SMarko Zec * 137bd368728SMarko Zec * Internal registers 138bd368728SMarko Zec * Every module in the SUME hardware has its own set of internal registers 139bd368728SMarko Zec * (IDs, for debugging and statistic purposes, etc.). Their base addresses are 140bd368728SMarko Zec * defined in 'projects/reference_nic/hw/tcl/reference_nic_defines.tcl' and the 141bd368728SMarko Zec * offsets to different memory locations of every module are defined in their 142bd368728SMarko Zec * corresponding folder inside the library. These registers can be RO/RW and 143bd368728SMarko Zec * there is a special method to fetch/change this data over 1 or 2 DMA 144bd368728SMarko Zec * transactions. For writing, by calling the sume_module_reg_write(). For 145bd368728SMarko Zec * reading, by calling the sume_module_reg_write() and then 146bd368728SMarko Zec * sume_module_reg_read(). Check those functions for more information. 147bd368728SMarko Zec */ 148bd368728SMarko Zec 149bd368728SMarko Zec MALLOC_DECLARE(M_SUME); 150bd368728SMarko Zec MALLOC_DEFINE(M_SUME, "sume", "NetFPGA SUME device driver"); 151bd368728SMarko Zec 152bd368728SMarko Zec static void check_tx_queues(struct sume_adapter *); 153bd368728SMarko Zec static void sume_fill_bb_desc(struct sume_adapter *, struct riffa_chnl_dir *, 154bd368728SMarko Zec uint64_t); 155bd368728SMarko Zec 156bd368728SMarko Zec static struct unrhdr *unr; 157bd368728SMarko Zec 158bd368728SMarko Zec static struct { 159bd368728SMarko Zec uint16_t device; 160bd368728SMarko Zec char *desc; 161bd368728SMarko Zec } sume_pciids[] = { 162bd368728SMarko Zec {PCI_DEVICE_ID_SUME, "NetFPGA SUME reference NIC"}, 163bd368728SMarko Zec }; 164bd368728SMarko Zec 165bd368728SMarko Zec static inline uint32_t 166bd368728SMarko Zec read_reg(struct sume_adapter *adapter, int offset) 167bd368728SMarko Zec { 168bd368728SMarko Zec 169bd368728SMarko Zec return (bus_space_read_4(adapter->bt, adapter->bh, offset << 2)); 170bd368728SMarko Zec } 171bd368728SMarko Zec 172bd368728SMarko Zec static inline void 173bd368728SMarko Zec write_reg(struct sume_adapter *adapter, int offset, uint32_t val) 174bd368728SMarko Zec { 175bd368728SMarko Zec 176bd368728SMarko Zec bus_space_write_4(adapter->bt, adapter->bh, offset << 2, val); 177bd368728SMarko Zec } 178bd368728SMarko Zec 179bd368728SMarko Zec static int 180bd368728SMarko Zec sume_probe(device_t dev) 181bd368728SMarko Zec { 182bd368728SMarko Zec int i; 183bd368728SMarko Zec uint16_t v = pci_get_vendor(dev); 184bd368728SMarko Zec uint16_t d = pci_get_device(dev); 185bd368728SMarko Zec 186bd368728SMarko Zec if (v != PCI_VENDOR_ID_XILINX) 187bd368728SMarko Zec return (ENXIO); 188bd368728SMarko Zec 189bd368728SMarko Zec for (i = 0; i < nitems(sume_pciids); i++) { 190bd368728SMarko Zec if (d == sume_pciids[i].device) { 191bd368728SMarko Zec device_set_desc(dev, sume_pciids[i].desc); 192bd368728SMarko Zec return (BUS_PROBE_DEFAULT); 193bd368728SMarko Zec } 194bd368728SMarko Zec } 195bd368728SMarko Zec 196bd368728SMarko Zec return (ENXIO); 197bd368728SMarko Zec } 198bd368728SMarko Zec 199bd368728SMarko Zec /* 200bd368728SMarko Zec * Building mbuf for packet received from SUME. We expect to receive 'len' 201bd368728SMarko Zec * bytes of data (including metadata) written from the bouncebuffer address 202bd368728SMarko Zec * buf_addr+3*sizeof(uint32_t). Metadata will tell us which SUME interface 203bd368728SMarko Zec * received the packet (sport will be 1, 2, 4 or 8), the packet length (plen), 204bd368728SMarko Zec * and the magic word needs to be 0xcafe. When we have the packet data, we 205bd368728SMarko Zec * create an mbuf and copy the data to it using m_copyback() function, set the 206bd368728SMarko Zec * correct interface to rcvif and return the mbuf to be later sent to the OS 207bd368728SMarko Zec * with if_input. 208bd368728SMarko Zec */ 209bd368728SMarko Zec static struct mbuf * 210bd368728SMarko Zec sume_rx_build_mbuf(struct sume_adapter *adapter, uint32_t len) 211bd368728SMarko Zec { 212bd368728SMarko Zec struct nf_priv *nf_priv; 213bd368728SMarko Zec struct mbuf *m; 214cc970676SJustin Hibbits if_t ifp = NULL; 215bd368728SMarko Zec int np; 216bd368728SMarko Zec uint16_t dport, plen, magic; 217bd368728SMarko Zec device_t dev = adapter->dev; 218bd368728SMarko Zec uint8_t *indata = (uint8_t *) 219bd368728SMarko Zec adapter->recv[SUME_RIFFA_CHANNEL_DATA]->buf_addr + 220bd368728SMarko Zec sizeof(struct nf_bb_desc); 221bd368728SMarko Zec struct nf_metadata *mdata = (struct nf_metadata *) indata; 222bd368728SMarko Zec 223bd368728SMarko Zec /* The metadata header is 16 bytes. */ 224bd368728SMarko Zec if (len < sizeof(struct nf_metadata)) { 225bd368728SMarko Zec device_printf(dev, "short frame (%d)\n", len); 226bd368728SMarko Zec adapter->packets_err++; 227bd368728SMarko Zec adapter->bytes_err += len; 228bd368728SMarko Zec return (NULL); 229bd368728SMarko Zec } 230bd368728SMarko Zec 231bd368728SMarko Zec dport = le16toh(mdata->dport); 232bd368728SMarko Zec plen = le16toh(mdata->plen); 233bd368728SMarko Zec magic = le16toh(mdata->magic); 234bd368728SMarko Zec 235bd368728SMarko Zec if (sizeof(struct nf_metadata) + plen > len || 236bd368728SMarko Zec magic != SUME_RIFFA_MAGIC) { 237bd368728SMarko Zec device_printf(dev, "corrupted packet (%zd + %d > %d || magic " 238bd368728SMarko Zec "0x%04x != 0x%04x)\n", sizeof(struct nf_metadata), plen, 239bd368728SMarko Zec len, magic, SUME_RIFFA_MAGIC); 240bd368728SMarko Zec return (NULL); 241bd368728SMarko Zec } 242bd368728SMarko Zec 243bd368728SMarko Zec /* We got the packet from one of the even bits */ 244bd368728SMarko Zec np = (ffs(dport & SUME_DPORT_MASK) >> 1) - 1; 245bd368728SMarko Zec if (np > SUME_NPORTS) { 246bd368728SMarko Zec device_printf(dev, "invalid destination port 0x%04x (%d)\n", 247bd368728SMarko Zec dport, np); 248bd368728SMarko Zec adapter->packets_err++; 249bd368728SMarko Zec adapter->bytes_err += plen; 250bd368728SMarko Zec return (NULL); 251bd368728SMarko Zec } 252bd368728SMarko Zec ifp = adapter->ifp[np]; 253cc970676SJustin Hibbits nf_priv = if_getsoftc(ifp); 254bd368728SMarko Zec nf_priv->stats.rx_packets++; 255bd368728SMarko Zec nf_priv->stats.rx_bytes += plen; 256bd368728SMarko Zec 257bd368728SMarko Zec /* If the interface is down, well, we are done. */ 258cc970676SJustin Hibbits if (!(if_getflags(ifp) & IFF_UP)) { 259bd368728SMarko Zec nf_priv->stats.ifc_down_packets++; 260bd368728SMarko Zec nf_priv->stats.ifc_down_bytes += plen; 261bd368728SMarko Zec return (NULL); 262bd368728SMarko Zec } 263bd368728SMarko Zec 264bd368728SMarko Zec if (adapter->sume_debug) 265bd368728SMarko Zec printf("Building mbuf with length: %d\n", plen); 266bd368728SMarko Zec 267bd368728SMarko Zec m = m_getm(NULL, plen, M_NOWAIT, MT_DATA); 268bd368728SMarko Zec if (m == NULL) { 269bd368728SMarko Zec adapter->packets_err++; 270bd368728SMarko Zec adapter->bytes_err += plen; 271bd368728SMarko Zec return (NULL); 272bd368728SMarko Zec } 273bd368728SMarko Zec 274bd368728SMarko Zec /* Copy the data in at the right offset. */ 275bd368728SMarko Zec m_copyback(m, 0, plen, (void *) (indata + sizeof(struct nf_metadata))); 276bd368728SMarko Zec m->m_pkthdr.rcvif = ifp; 277bd368728SMarko Zec 278bd368728SMarko Zec return (m); 279bd368728SMarko Zec } 280bd368728SMarko Zec 281bd368728SMarko Zec /* 282bd368728SMarko Zec * SUME interrupt handler for when we get a valid interrupt from the board. 283bd368728SMarko Zec * Theoretically, we can receive interrupt for any of the available channels, 284bd368728SMarko Zec * but RIFFA DMA uses only 2: 0 and 1, so we use only vect0. The vector is a 32 285bd368728SMarko Zec * bit number, using 5 bits for every channel, the least significant bits 286bd368728SMarko Zec * correspond to channel 0 and the next 5 bits correspond to channel 1. Vector 287bd368728SMarko Zec * bits for RX/TX are: 288bd368728SMarko Zec * RX 289bd368728SMarko Zec * bit 0 - new transaction from SUME 290bd368728SMarko Zec * bit 1 - SUME received our bouncebuffer address 291bd368728SMarko Zec * bit 2 - SUME copied the received data to our bouncebuffer, transaction done 292bd368728SMarko Zec * TX 293bd368728SMarko Zec * bit 3 - SUME received our bouncebuffer address 294bd368728SMarko Zec * bit 4 - SUME copied the data from our bouncebuffer, transaction done 295bd368728SMarko Zec * 296bd368728SMarko Zec * There are two finite state machines (one for TX, one for RX). We loop 297bd368728SMarko Zec * through channels 0 and 1 to check and our current state and which interrupt 298bd368728SMarko Zec * bit is set. 299bd368728SMarko Zec * TX 300bd368728SMarko Zec * SUME_RIFFA_CHAN_STATE_IDLE: waiting for the first TX transaction. 301bd368728SMarko Zec * SUME_RIFFA_CHAN_STATE_READY: we prepared (filled with data) the bouncebuffer 302bd368728SMarko Zec * and triggered the SUME for the TX transaction. Waiting for interrupt bit 3 303bd368728SMarko Zec * to go to the next state. 304bd368728SMarko Zec * SUME_RIFFA_CHAN_STATE_READ: waiting for interrupt bit 4 (for SUME to send 305bd368728SMarko Zec * our packet). Then we get the length of the sent data and go back to the 306bd368728SMarko Zec * IDLE state. 307bd368728SMarko Zec * RX 308bd368728SMarko Zec * SUME_RIFFA_CHAN_STATE_IDLE: waiting for the interrupt bit 0 (new RX 309bd368728SMarko Zec * transaction). When we get it, we prepare our bouncebuffer for reading and 310bd368728SMarko Zec * trigger the SUME to start the transaction. Go to the next state. 311bd368728SMarko Zec * SUME_RIFFA_CHAN_STATE_READY: waiting for the interrupt bit 1 (SUME got our 312bd368728SMarko Zec * bouncebuffer). Go to the next state. 313bd368728SMarko Zec * SUME_RIFFA_CHAN_STATE_READ: SUME copied data and our bouncebuffer is ready, 314bd368728SMarko Zec * we can build the mbuf and go back to the IDLE state. 315bd368728SMarko Zec */ 316bd368728SMarko Zec static void 317bd368728SMarko Zec sume_intr_handler(void *arg) 318bd368728SMarko Zec { 319bd368728SMarko Zec struct sume_adapter *adapter = arg; 320bd368728SMarko Zec uint32_t vect, vect0, len; 321bd368728SMarko Zec int ch, loops; 322bd368728SMarko Zec device_t dev = adapter->dev; 323bd368728SMarko Zec struct mbuf *m = NULL; 324cc970676SJustin Hibbits if_t ifp = NULL; 325bd368728SMarko Zec struct riffa_chnl_dir *send, *recv; 326bd368728SMarko Zec 327bd368728SMarko Zec SUME_LOCK(adapter); 328bd368728SMarko Zec 329bd368728SMarko Zec vect0 = read_reg(adapter, RIFFA_IRQ_REG0_OFF); 330bd368728SMarko Zec if ((vect0 & SUME_INVALID_VECT) != 0) { 331bd368728SMarko Zec SUME_UNLOCK(adapter); 332bd368728SMarko Zec return; 333bd368728SMarko Zec } 334bd368728SMarko Zec 335bd368728SMarko Zec /* 336bd368728SMarko Zec * We only have one interrupt for all channels and no way 337bd368728SMarko Zec * to quickly lookup for which channel(s) we got an interrupt? 338bd368728SMarko Zec */ 339bd368728SMarko Zec for (ch = 0; ch < SUME_RIFFA_CHANNELS; ch++) { 340bd368728SMarko Zec vect = vect0 >> (5 * ch); 341bd368728SMarko Zec send = adapter->send[ch]; 342bd368728SMarko Zec recv = adapter->recv[ch]; 343bd368728SMarko Zec 344bd368728SMarko Zec loops = 0; 345bd368728SMarko Zec while ((vect & (SUME_MSI_TXBUF | SUME_MSI_TXDONE)) && 346bd368728SMarko Zec loops <= 5) { 347bd368728SMarko Zec if (adapter->sume_debug) 348bd368728SMarko Zec device_printf(dev, "TX ch %d state %u vect = " 349bd368728SMarko Zec "0x%08x\n", ch, send->state, vect); 350bd368728SMarko Zec switch (send->state) { 351bd368728SMarko Zec case SUME_RIFFA_CHAN_STATE_IDLE: 352bd368728SMarko Zec break; 353bd368728SMarko Zec case SUME_RIFFA_CHAN_STATE_READY: 354bd368728SMarko Zec if (!(vect & SUME_MSI_TXBUF)) { 355bd368728SMarko Zec device_printf(dev, "ch %d unexpected " 356bd368728SMarko Zec "interrupt in send+3 state %u: " 357bd368728SMarko Zec "vect = 0x%08x\n", ch, send->state, 358bd368728SMarko Zec vect); 359bd368728SMarko Zec send->recovery = 1; 360bd368728SMarko Zec break; 361bd368728SMarko Zec } 362bd368728SMarko Zec send->state = SUME_RIFFA_CHAN_STATE_READ; 363bd368728SMarko Zec vect &= ~SUME_MSI_TXBUF; 364bd368728SMarko Zec break; 365bd368728SMarko Zec case SUME_RIFFA_CHAN_STATE_READ: 366bd368728SMarko Zec if (!(vect & SUME_MSI_TXDONE)) { 367bd368728SMarko Zec device_printf(dev, "ch %d unexpected " 368bd368728SMarko Zec "interrupt in send+4 state %u: " 369bd368728SMarko Zec "vect = 0x%08x\n", ch, send->state, 370bd368728SMarko Zec vect); 371bd368728SMarko Zec send->recovery = 1; 372bd368728SMarko Zec break; 373bd368728SMarko Zec } 374bd368728SMarko Zec send->state = SUME_RIFFA_CHAN_STATE_LEN; 375bd368728SMarko Zec 376bd368728SMarko Zec len = read_reg(adapter, RIFFA_CHNL_REG(ch, 377bd368728SMarko Zec RIFFA_RX_TNFR_LEN_REG_OFF)); 378bd368728SMarko Zec if (ch == SUME_RIFFA_CHANNEL_DATA) { 379bd368728SMarko Zec send->state = 380bd368728SMarko Zec SUME_RIFFA_CHAN_STATE_IDLE; 381bd368728SMarko Zec check_tx_queues(adapter); 382bd368728SMarko Zec } else if (ch == SUME_RIFFA_CHANNEL_REG) 383bd368728SMarko Zec wakeup(&send->event); 384bd368728SMarko Zec else { 385bd368728SMarko Zec device_printf(dev, "ch %d unexpected " 386bd368728SMarko Zec "interrupt in send+4 state %u: " 387bd368728SMarko Zec "vect = 0x%08x\n", ch, send->state, 388bd368728SMarko Zec vect); 389bd368728SMarko Zec send->recovery = 1; 390bd368728SMarko Zec } 391bd368728SMarko Zec vect &= ~SUME_MSI_TXDONE; 392bd368728SMarko Zec break; 393bd368728SMarko Zec case SUME_RIFFA_CHAN_STATE_LEN: 394bd368728SMarko Zec break; 395bd368728SMarko Zec default: 396bd368728SMarko Zec device_printf(dev, "unknown TX state!\n"); 397bd368728SMarko Zec } 398bd368728SMarko Zec loops++; 399bd368728SMarko Zec } 400bd368728SMarko Zec 401bd368728SMarko Zec if ((vect & (SUME_MSI_TXBUF | SUME_MSI_TXDONE)) && 402bd368728SMarko Zec send->recovery) 403bd368728SMarko Zec device_printf(dev, "ch %d ignoring vect = 0x%08x " 404bd368728SMarko Zec "during TX; not in recovery; state = %d loops = " 405bd368728SMarko Zec "%d\n", ch, vect, send->state, loops); 406bd368728SMarko Zec 407bd368728SMarko Zec loops = 0; 408bd368728SMarko Zec while ((vect & (SUME_MSI_RXQUE | SUME_MSI_RXBUF | 409bd368728SMarko Zec SUME_MSI_RXDONE)) && loops < 5) { 410bd368728SMarko Zec if (adapter->sume_debug) 411bd368728SMarko Zec device_printf(dev, "RX ch %d state %u vect = " 412bd368728SMarko Zec "0x%08x\n", ch, recv->state, vect); 413bd368728SMarko Zec switch (recv->state) { 414bd368728SMarko Zec case SUME_RIFFA_CHAN_STATE_IDLE: 415bd368728SMarko Zec if (!(vect & SUME_MSI_RXQUE)) { 416bd368728SMarko Zec device_printf(dev, "ch %d unexpected " 417bd368728SMarko Zec "interrupt in recv+0 state %u: " 418bd368728SMarko Zec "vect = 0x%08x\n", ch, recv->state, 419bd368728SMarko Zec vect); 420bd368728SMarko Zec recv->recovery = 1; 421bd368728SMarko Zec break; 422bd368728SMarko Zec } 423bd368728SMarko Zec uint32_t max_ptr; 424bd368728SMarko Zec 425bd368728SMarko Zec /* Clear recovery state. */ 426bd368728SMarko Zec recv->recovery = 0; 427bd368728SMarko Zec 428bd368728SMarko Zec /* Get offset and length. */ 429bd368728SMarko Zec recv->offlast = read_reg(adapter, 430bd368728SMarko Zec RIFFA_CHNL_REG(ch, 431bd368728SMarko Zec RIFFA_TX_OFFLAST_REG_OFF)); 432bd368728SMarko Zec recv->len = read_reg(adapter, RIFFA_CHNL_REG(ch, 433bd368728SMarko Zec RIFFA_TX_LEN_REG_OFF)); 434bd368728SMarko Zec 435bd368728SMarko Zec /* Boundary checks. */ 436bd368728SMarko Zec max_ptr = (uint32_t)((uintptr_t)recv->buf_addr 437bd368728SMarko Zec + SUME_RIFFA_OFFSET(recv->offlast) 438bd368728SMarko Zec + SUME_RIFFA_LEN(recv->len) - 1); 439bd368728SMarko Zec if (max_ptr < 440bd368728SMarko Zec (uint32_t)((uintptr_t)recv->buf_addr)) 441bd368728SMarko Zec device_printf(dev, "receive buffer " 442bd368728SMarko Zec "wrap-around overflow.\n"); 443bd368728SMarko Zec if (SUME_RIFFA_OFFSET(recv->offlast) + 444bd368728SMarko Zec SUME_RIFFA_LEN(recv->len) > 445bd368728SMarko Zec adapter->sg_buf_size) 446bd368728SMarko Zec device_printf(dev, "receive buffer too" 447bd368728SMarko Zec " small.\n"); 448bd368728SMarko Zec 449bd368728SMarko Zec /* Fill the bouncebuf "descriptor". */ 450bd368728SMarko Zec sume_fill_bb_desc(adapter, recv, 451bd368728SMarko Zec SUME_RIFFA_LEN(recv->len)); 452bd368728SMarko Zec 453bd368728SMarko Zec bus_dmamap_sync(recv->ch_tag, recv->ch_map, 454bd368728SMarko Zec BUS_DMASYNC_PREREAD | 455bd368728SMarko Zec BUS_DMASYNC_PREWRITE); 456bd368728SMarko Zec write_reg(adapter, RIFFA_CHNL_REG(ch, 457bd368728SMarko Zec RIFFA_TX_SG_ADDR_LO_REG_OFF), 458bd368728SMarko Zec SUME_RIFFA_LO_ADDR(recv->buf_hw_addr)); 459bd368728SMarko Zec write_reg(adapter, RIFFA_CHNL_REG(ch, 460bd368728SMarko Zec RIFFA_TX_SG_ADDR_HI_REG_OFF), 461bd368728SMarko Zec SUME_RIFFA_HI_ADDR(recv->buf_hw_addr)); 462bd368728SMarko Zec write_reg(adapter, RIFFA_CHNL_REG(ch, 463bd368728SMarko Zec RIFFA_TX_SG_LEN_REG_OFF), 464bd368728SMarko Zec 4 * recv->num_sg); 465bd368728SMarko Zec bus_dmamap_sync(recv->ch_tag, recv->ch_map, 466bd368728SMarko Zec BUS_DMASYNC_POSTREAD | 467bd368728SMarko Zec BUS_DMASYNC_POSTWRITE); 468bd368728SMarko Zec 469bd368728SMarko Zec recv->state = SUME_RIFFA_CHAN_STATE_READY; 470bd368728SMarko Zec vect &= ~SUME_MSI_RXQUE; 471bd368728SMarko Zec break; 472bd368728SMarko Zec case SUME_RIFFA_CHAN_STATE_READY: 473bd368728SMarko Zec if (!(vect & SUME_MSI_RXBUF)) { 474bd368728SMarko Zec device_printf(dev, "ch %d unexpected " 475bd368728SMarko Zec "interrupt in recv+1 state %u: " 476bd368728SMarko Zec "vect = 0x%08x\n", ch, recv->state, 477bd368728SMarko Zec vect); 478bd368728SMarko Zec recv->recovery = 1; 479bd368728SMarko Zec break; 480bd368728SMarko Zec } 481bd368728SMarko Zec recv->state = SUME_RIFFA_CHAN_STATE_READ; 482bd368728SMarko Zec vect &= ~SUME_MSI_RXBUF; 483bd368728SMarko Zec break; 484bd368728SMarko Zec case SUME_RIFFA_CHAN_STATE_READ: 485bd368728SMarko Zec if (!(vect & SUME_MSI_RXDONE)) { 486bd368728SMarko Zec device_printf(dev, "ch %d unexpected " 487bd368728SMarko Zec "interrupt in recv+2 state %u: " 488bd368728SMarko Zec "vect = 0x%08x\n", ch, recv->state, 489bd368728SMarko Zec vect); 490bd368728SMarko Zec recv->recovery = 1; 491bd368728SMarko Zec break; 492bd368728SMarko Zec } 493bd368728SMarko Zec len = read_reg(adapter, RIFFA_CHNL_REG(ch, 494bd368728SMarko Zec RIFFA_TX_TNFR_LEN_REG_OFF)); 495bd368728SMarko Zec 496bd368728SMarko Zec /* Remember, len and recv->len are words. */ 497bd368728SMarko Zec if (ch == SUME_RIFFA_CHANNEL_DATA) { 498bd368728SMarko Zec m = sume_rx_build_mbuf(adapter, 499bd368728SMarko Zec len << 2); 500bd368728SMarko Zec recv->state = 501bd368728SMarko Zec SUME_RIFFA_CHAN_STATE_IDLE; 502bd368728SMarko Zec } else if (ch == SUME_RIFFA_CHANNEL_REG) 503bd368728SMarko Zec wakeup(&recv->event); 504bd368728SMarko Zec else { 505bd368728SMarko Zec device_printf(dev, "ch %d unexpected " 506bd368728SMarko Zec "interrupt in recv+2 state %u: " 507bd368728SMarko Zec "vect = 0x%08x\n", ch, recv->state, 508bd368728SMarko Zec vect); 509bd368728SMarko Zec recv->recovery = 1; 510bd368728SMarko Zec } 511bd368728SMarko Zec vect &= ~SUME_MSI_RXDONE; 512bd368728SMarko Zec break; 513bd368728SMarko Zec case SUME_RIFFA_CHAN_STATE_LEN: 514bd368728SMarko Zec break; 515bd368728SMarko Zec default: 516bd368728SMarko Zec device_printf(dev, "unknown RX state!\n"); 517bd368728SMarko Zec } 518bd368728SMarko Zec loops++; 519bd368728SMarko Zec } 520bd368728SMarko Zec 521bd368728SMarko Zec if ((vect & (SUME_MSI_RXQUE | SUME_MSI_RXBUF | 522bd368728SMarko Zec SUME_MSI_RXDONE)) && recv->recovery) { 523bd368728SMarko Zec device_printf(dev, "ch %d ignoring vect = 0x%08x " 524bd368728SMarko Zec "during RX; not in recovery; state = %d, loops = " 525bd368728SMarko Zec "%d\n", ch, vect, recv->state, loops); 526bd368728SMarko Zec 527bd368728SMarko Zec /* Clean the unfinished transaction. */ 528bd368728SMarko Zec if (ch == SUME_RIFFA_CHANNEL_REG && 529bd368728SMarko Zec vect & SUME_MSI_RXDONE) { 530bd368728SMarko Zec read_reg(adapter, RIFFA_CHNL_REG(ch, 531bd368728SMarko Zec RIFFA_TX_TNFR_LEN_REG_OFF)); 532bd368728SMarko Zec recv->recovery = 0; 533bd368728SMarko Zec } 534bd368728SMarko Zec } 535bd368728SMarko Zec } 536bd368728SMarko Zec SUME_UNLOCK(adapter); 537bd368728SMarko Zec 538bd368728SMarko Zec if (m != NULL) { 539bd368728SMarko Zec ifp = m->m_pkthdr.rcvif; 540cc970676SJustin Hibbits if_input(ifp, m); 541bd368728SMarko Zec } 542bd368728SMarko Zec } 543bd368728SMarko Zec 544bd368728SMarko Zec /* 545bd368728SMarko Zec * As we cannot disable interrupt generation, ignore early interrupts by waiting 546bd368728SMarko Zec * for the adapter to go into the 'running' state. 547bd368728SMarko Zec */ 548bd368728SMarko Zec static int 549bd368728SMarko Zec sume_intr_filter(void *arg) 550bd368728SMarko Zec { 551bd368728SMarko Zec struct sume_adapter *adapter = arg; 552bd368728SMarko Zec 553bd368728SMarko Zec if (adapter->running == 0) 554bd368728SMarko Zec return (FILTER_STRAY); 555bd368728SMarko Zec 556bd368728SMarko Zec return (FILTER_SCHEDULE_THREAD); 557bd368728SMarko Zec } 558bd368728SMarko Zec 559bd368728SMarko Zec static int 560bd368728SMarko Zec sume_probe_riffa_pci(struct sume_adapter *adapter) 561bd368728SMarko Zec { 562bd368728SMarko Zec device_t dev = adapter->dev; 563bd368728SMarko Zec int error, count, capmem; 564bd368728SMarko Zec uint32_t reg, devctl, linkctl; 565bd368728SMarko Zec 566bd368728SMarko Zec pci_enable_busmaster(dev); 567bd368728SMarko Zec 568bd368728SMarko Zec adapter->rid = PCIR_BAR(0); 569bd368728SMarko Zec adapter->bar0_addr = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 570bd368728SMarko Zec &adapter->rid, RF_ACTIVE); 571bd368728SMarko Zec if (adapter->bar0_addr == NULL) { 572bd368728SMarko Zec device_printf(dev, "unable to allocate bus resource: " 573bd368728SMarko Zec "BAR0 address\n"); 574bd368728SMarko Zec return (ENXIO); 575bd368728SMarko Zec } 576bd368728SMarko Zec adapter->bt = rman_get_bustag(adapter->bar0_addr); 577bd368728SMarko Zec adapter->bh = rman_get_bushandle(adapter->bar0_addr); 578bd368728SMarko Zec adapter->bar0_len = rman_get_size(adapter->bar0_addr); 579bd368728SMarko Zec if (adapter->bar0_len != 1024) { 580bd368728SMarko Zec device_printf(dev, "BAR0 resource length %lu != 1024\n", 581bd368728SMarko Zec adapter->bar0_len); 582bd368728SMarko Zec return (ENXIO); 583bd368728SMarko Zec } 584bd368728SMarko Zec 585bd368728SMarko Zec count = pci_msi_count(dev); 586bd368728SMarko Zec error = pci_alloc_msi(dev, &count); 587bd368728SMarko Zec if (error) { 588bd368728SMarko Zec device_printf(dev, "unable to allocate bus resource: PCI " 589bd368728SMarko Zec "MSI\n"); 590bd368728SMarko Zec return (error); 591bd368728SMarko Zec } 592bd368728SMarko Zec 593bd368728SMarko Zec adapter->irq.rid = 1; /* Should be 1, thus says pci_alloc_msi() */ 594bd368728SMarko Zec adapter->irq.res = bus_alloc_resource_any(dev, SYS_RES_IRQ, 595bd368728SMarko Zec &adapter->irq.rid, RF_SHAREABLE | RF_ACTIVE); 596bd368728SMarko Zec if (adapter->irq.res == NULL) { 597bd368728SMarko Zec device_printf(dev, "unable to allocate bus resource: IRQ " 598bd368728SMarko Zec "memory\n"); 599bd368728SMarko Zec return (ENXIO); 600bd368728SMarko Zec } 601bd368728SMarko Zec 602bd368728SMarko Zec error = bus_setup_intr(dev, adapter->irq.res, INTR_MPSAFE | 603bd368728SMarko Zec INTR_TYPE_NET, sume_intr_filter, sume_intr_handler, adapter, 604bd368728SMarko Zec &adapter->irq.tag); 605bd368728SMarko Zec if (error) { 606bd368728SMarko Zec device_printf(dev, "failed to setup interrupt for rid %d, name" 607bd368728SMarko Zec " %s: %d\n", adapter->irq.rid, "SUME_INTR", error); 608bd368728SMarko Zec return (ENXIO); 609bd368728SMarko Zec } 610bd368728SMarko Zec 611bd368728SMarko Zec if (pci_find_cap(dev, PCIY_EXPRESS, &capmem) != 0) { 612bd368728SMarko Zec device_printf(dev, "PCI not PCIe capable\n"); 613bd368728SMarko Zec return (ENXIO); 614bd368728SMarko Zec } 615bd368728SMarko Zec 616bd368728SMarko Zec devctl = pci_read_config(dev, capmem + PCIER_DEVICE_CTL, 2); 617bd368728SMarko Zec pci_write_config(dev, capmem + PCIER_DEVICE_CTL, (devctl | 618bd368728SMarko Zec PCIEM_CTL_EXT_TAG_FIELD), 2); 619bd368728SMarko Zec 620bd368728SMarko Zec devctl = pci_read_config(dev, capmem + PCIER_DEVICE_CTL2, 2); 621bd368728SMarko Zec pci_write_config(dev, capmem + PCIER_DEVICE_CTL2, (devctl | 622bd368728SMarko Zec PCIEM_CTL2_ID_ORDERED_REQ_EN), 2); 623bd368728SMarko Zec 624bd368728SMarko Zec linkctl = pci_read_config(dev, capmem + PCIER_LINK_CTL, 2); 625bd368728SMarko Zec pci_write_config(dev, capmem + PCIER_LINK_CTL, (linkctl | 626bd368728SMarko Zec PCIEM_LINK_CTL_RCB), 2); 627bd368728SMarko Zec 628bd368728SMarko Zec reg = read_reg(adapter, RIFFA_INFO_REG_OFF); 629bd368728SMarko Zec adapter->num_sg = RIFFA_SG_ELEMS * ((reg >> 19) & 0xf); 630bd368728SMarko Zec adapter->sg_buf_size = RIFFA_SG_BUF_SIZE * ((reg >> 19) & 0xf); 631bd368728SMarko Zec 632bd368728SMarko Zec error = ENODEV; 633bd368728SMarko Zec /* Check bus master is enabled. */ 634bd368728SMarko Zec if (((reg >> 4) & 0x1) != 1) { 635bd368728SMarko Zec device_printf(dev, "bus master not enabled: %d\n", 636bd368728SMarko Zec (reg >> 4) & 0x1); 637bd368728SMarko Zec return (error); 638bd368728SMarko Zec } 639bd368728SMarko Zec /* Check link parameters are valid. */ 640bd368728SMarko Zec if (((reg >> 5) & 0x3f) == 0 || ((reg >> 11) & 0x3) == 0) { 641bd368728SMarko Zec device_printf(dev, "link parameters not valid: %d %d\n", 642bd368728SMarko Zec (reg >> 5) & 0x3f, (reg >> 11) & 0x3); 643bd368728SMarko Zec return (error); 644bd368728SMarko Zec } 645bd368728SMarko Zec /* Check # of channels are within valid range. */ 646bd368728SMarko Zec if ((reg & 0xf) == 0 || (reg & 0xf) > RIFFA_MAX_CHNLS) { 647bd368728SMarko Zec device_printf(dev, "number of channels out of range: %d\n", 648bd368728SMarko Zec reg & 0xf); 649bd368728SMarko Zec return (error); 650bd368728SMarko Zec } 651bd368728SMarko Zec /* Check bus width. */ 652bd368728SMarko Zec if (((reg >> 19) & 0xf) == 0 || 653bd368728SMarko Zec ((reg >> 19) & 0xf) > RIFFA_MAX_BUS_WIDTH_PARAM) { 654bd368728SMarko Zec device_printf(dev, "bus width out of range: %d\n", 655bd368728SMarko Zec (reg >> 19) & 0xf); 656bd368728SMarko Zec return (error); 657bd368728SMarko Zec } 658bd368728SMarko Zec 659bd368728SMarko Zec device_printf(dev, "[riffa] # of channels: %d\n", 660bd368728SMarko Zec reg & 0xf); 661bd368728SMarko Zec device_printf(dev, "[riffa] bus interface width: %d\n", 662bd368728SMarko Zec ((reg >> 19) & 0xf) << 5); 663bd368728SMarko Zec device_printf(dev, "[riffa] bus master enabled: %d\n", 664bd368728SMarko Zec (reg >> 4) & 0x1); 665bd368728SMarko Zec device_printf(dev, "[riffa] negotiated link width: %d\n", 666bd368728SMarko Zec (reg >> 5) & 0x3f); 667bd368728SMarko Zec device_printf(dev, "[riffa] negotiated rate width: %d MTs\n", 668bd368728SMarko Zec ((reg >> 11) & 0x3) * 2500); 669bd368728SMarko Zec device_printf(dev, "[riffa] max downstream payload: %d B\n", 670bd368728SMarko Zec 128 << ((reg >> 13) & 0x7)); 671bd368728SMarko Zec device_printf(dev, "[riffa] max upstream payload: %d B\n", 672bd368728SMarko Zec 128 << ((reg >> 16) & 0x7)); 673bd368728SMarko Zec 674bd368728SMarko Zec return (0); 675bd368728SMarko Zec } 676bd368728SMarko Zec 677bd368728SMarko Zec /* If there is no sume_if_init, the ether_ioctl panics. */ 678bd368728SMarko Zec static void 679bd368728SMarko Zec sume_if_init(void *sc) 680bd368728SMarko Zec { 681bd368728SMarko Zec } 682bd368728SMarko Zec 683bd368728SMarko Zec /* Write the address and length for our incoming / outgoing transaction. */ 684bd368728SMarko Zec static void 685bd368728SMarko Zec sume_fill_bb_desc(struct sume_adapter *adapter, struct riffa_chnl_dir *p, 686bd368728SMarko Zec uint64_t len) 687bd368728SMarko Zec { 688bd368728SMarko Zec struct nf_bb_desc *bouncebuf = (struct nf_bb_desc *) p->buf_addr; 689bd368728SMarko Zec 690bd368728SMarko Zec bouncebuf->lower = (p->buf_hw_addr + sizeof(struct nf_bb_desc)); 691bd368728SMarko Zec bouncebuf->upper = (p->buf_hw_addr + sizeof(struct nf_bb_desc)) >> 32; 692bd368728SMarko Zec bouncebuf->len = len >> 2; 693bd368728SMarko Zec } 694bd368728SMarko Zec 695bd368728SMarko Zec /* Module register locked write. */ 696bd368728SMarko Zec static int 697bd368728SMarko Zec sume_modreg_write_locked(struct sume_adapter *adapter) 698bd368728SMarko Zec { 699bd368728SMarko Zec struct riffa_chnl_dir *send = adapter->send[SUME_RIFFA_CHANNEL_REG]; 700bd368728SMarko Zec 701bd368728SMarko Zec /* Let the FPGA know about the transfer. */ 702bd368728SMarko Zec write_reg(adapter, RIFFA_CHNL_REG(SUME_RIFFA_CHANNEL_REG, 703bd368728SMarko Zec RIFFA_RX_OFFLAST_REG_OFF), SUME_OFFLAST); 704bd368728SMarko Zec write_reg(adapter, RIFFA_CHNL_REG(SUME_RIFFA_CHANNEL_REG, 705bd368728SMarko Zec RIFFA_RX_LEN_REG_OFF), send->len); /* words */ 706bd368728SMarko Zec 707bd368728SMarko Zec /* Fill the bouncebuf "descriptor". */ 708bd368728SMarko Zec sume_fill_bb_desc(adapter, send, SUME_RIFFA_LEN(send->len)); 709bd368728SMarko Zec 710bd368728SMarko Zec /* Update the state before intiating the DMA to avoid races. */ 711bd368728SMarko Zec send->state = SUME_RIFFA_CHAN_STATE_READY; 712bd368728SMarko Zec 713bd368728SMarko Zec bus_dmamap_sync(send->ch_tag, send->ch_map, 714bd368728SMarko Zec BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 715bd368728SMarko Zec /* DMA. */ 716bd368728SMarko Zec write_reg(adapter, RIFFA_CHNL_REG(SUME_RIFFA_CHANNEL_REG, 717bd368728SMarko Zec RIFFA_RX_SG_ADDR_LO_REG_OFF), 718bd368728SMarko Zec SUME_RIFFA_LO_ADDR(send->buf_hw_addr)); 719bd368728SMarko Zec write_reg(adapter, RIFFA_CHNL_REG(SUME_RIFFA_CHANNEL_REG, 720bd368728SMarko Zec RIFFA_RX_SG_ADDR_HI_REG_OFF), 721bd368728SMarko Zec SUME_RIFFA_HI_ADDR(send->buf_hw_addr)); 722bd368728SMarko Zec write_reg(adapter, RIFFA_CHNL_REG(SUME_RIFFA_CHANNEL_REG, 723bd368728SMarko Zec RIFFA_RX_SG_LEN_REG_OFF), 4 * send->num_sg); 724bd368728SMarko Zec bus_dmamap_sync(send->ch_tag, send->ch_map, 725bd368728SMarko Zec BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 726bd368728SMarko Zec 727bd368728SMarko Zec return (0); 728bd368728SMarko Zec } 729bd368728SMarko Zec 730bd368728SMarko Zec /* 731bd368728SMarko Zec * Request a register read or write (depending on optype). 732bd368728SMarko Zec * If optype is set (0x1f) this will result in a register write, 733bd368728SMarko Zec * otherwise this will result in a register read request at the given 734bd368728SMarko Zec * address and the result will need to be DMAed back. 735bd368728SMarko Zec */ 736bd368728SMarko Zec static int 737bd368728SMarko Zec sume_module_reg_write(struct nf_priv *nf_priv, struct sume_ifreq *sifr, 738bd368728SMarko Zec uint32_t optype) 739bd368728SMarko Zec { 740bd368728SMarko Zec struct sume_adapter *adapter = nf_priv->adapter; 741bd368728SMarko Zec struct riffa_chnl_dir *send = adapter->send[SUME_RIFFA_CHANNEL_REG]; 742bd368728SMarko Zec struct nf_regop_data *data; 743bd368728SMarko Zec int error; 744bd368728SMarko Zec 745bd368728SMarko Zec /* 746bd368728SMarko Zec * 1. Make sure the channel is free; otherwise return EBUSY. 747bd368728SMarko Zec * 2. Prepare the memory in the bounce buffer (which we always 748bd368728SMarko Zec * use for regs). 749bd368728SMarko Zec * 3. Start the DMA process. 750bd368728SMarko Zec * 4. Sleep and wait for result and return success or error. 751bd368728SMarko Zec */ 752bd368728SMarko Zec SUME_LOCK(adapter); 753bd368728SMarko Zec 754bd368728SMarko Zec if (send->state != SUME_RIFFA_CHAN_STATE_IDLE) { 755bd368728SMarko Zec SUME_UNLOCK(adapter); 756bd368728SMarko Zec return (EBUSY); 757bd368728SMarko Zec } 758bd368728SMarko Zec 759bd368728SMarko Zec data = (struct nf_regop_data *) (send->buf_addr + 760bd368728SMarko Zec sizeof(struct nf_bb_desc)); 761bd368728SMarko Zec data->addr = htole32(sifr->addr); 762bd368728SMarko Zec data->val = htole32(sifr->val); 763bd368728SMarko Zec /* Tag to indentify request. */ 764bd368728SMarko Zec data->rtag = htole32(++send->rtag); 765bd368728SMarko Zec data->optype = htole32(optype); 766bd368728SMarko Zec send->len = sizeof(struct nf_regop_data) / 4; /* words */ 767bd368728SMarko Zec 768bd368728SMarko Zec error = sume_modreg_write_locked(adapter); 769bd368728SMarko Zec if (error) { 770bd368728SMarko Zec SUME_UNLOCK(adapter); 771bd368728SMarko Zec return (EFAULT); 772bd368728SMarko Zec } 773bd368728SMarko Zec 774bd368728SMarko Zec /* Timeout after 1s. */ 775bd368728SMarko Zec if (send->state != SUME_RIFFA_CHAN_STATE_LEN) 776bd368728SMarko Zec error = msleep(&send->event, &adapter->lock, 0, 777bd368728SMarko Zec "Waiting recv finish", 1 * hz); 778bd368728SMarko Zec 779bd368728SMarko Zec /* This was a write so we are done; were interrupted, or timed out. */ 780bd368728SMarko Zec if (optype != SUME_MR_READ || error != 0 || error == EWOULDBLOCK) { 781bd368728SMarko Zec send->state = SUME_RIFFA_CHAN_STATE_IDLE; 782bd368728SMarko Zec if (optype == SUME_MR_READ) 783bd368728SMarko Zec error = EWOULDBLOCK; 784bd368728SMarko Zec else 785bd368728SMarko Zec error = 0; 786bd368728SMarko Zec } else 787bd368728SMarko Zec error = 0; 788bd368728SMarko Zec 789bd368728SMarko Zec /* 790bd368728SMarko Zec * For read requests we will update state once we are done 791bd368728SMarko Zec * having read the result to avoid any two outstanding 792bd368728SMarko Zec * transactions, or we need a queue and validate tags, 793bd368728SMarko Zec * which is a lot of work for a low priority, infrequent 794bd368728SMarko Zec * event. 795bd368728SMarko Zec */ 796bd368728SMarko Zec 797bd368728SMarko Zec SUME_UNLOCK(adapter); 798bd368728SMarko Zec 799bd368728SMarko Zec return (error); 800bd368728SMarko Zec } 801bd368728SMarko Zec 802bd368728SMarko Zec /* Module register read. */ 803bd368728SMarko Zec static int 804bd368728SMarko Zec sume_module_reg_read(struct nf_priv *nf_priv, struct sume_ifreq *sifr) 805bd368728SMarko Zec { 806bd368728SMarko Zec struct sume_adapter *adapter = nf_priv->adapter; 807bd368728SMarko Zec struct riffa_chnl_dir *recv = adapter->recv[SUME_RIFFA_CHANNEL_REG]; 808bd368728SMarko Zec struct riffa_chnl_dir *send = adapter->send[SUME_RIFFA_CHANNEL_REG]; 809bd368728SMarko Zec struct nf_regop_data *data; 810bd368728SMarko Zec int error = 0; 811bd368728SMarko Zec 812bd368728SMarko Zec /* 813bd368728SMarko Zec * 0. Sleep waiting for result if needed (unless condition is 814bd368728SMarko Zec * true already). 815bd368728SMarko Zec * 1. Read DMA results. 816bd368728SMarko Zec * 2. Update state on *TX* to IDLE to allow next read to start. 817bd368728SMarko Zec */ 818bd368728SMarko Zec SUME_LOCK(adapter); 819bd368728SMarko Zec 820bd368728SMarko Zec bus_dmamap_sync(recv->ch_tag, recv->ch_map, 821bd368728SMarko Zec BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 822bd368728SMarko Zec /* 823bd368728SMarko Zec * We only need to be woken up at the end of the transaction. 824bd368728SMarko Zec * Timeout after 1s. 825bd368728SMarko Zec */ 826bd368728SMarko Zec if (recv->state != SUME_RIFFA_CHAN_STATE_READ) 827bd368728SMarko Zec error = msleep(&recv->event, &adapter->lock, 0, 828bd368728SMarko Zec "Waiting transaction finish", 1 * hz); 829bd368728SMarko Zec 830bd368728SMarko Zec if (recv->state != SUME_RIFFA_CHAN_STATE_READ || error == EWOULDBLOCK) { 831bd368728SMarko Zec SUME_UNLOCK(adapter); 832bd368728SMarko Zec device_printf(adapter->dev, "wait error: %d\n", error); 833bd368728SMarko Zec return (EWOULDBLOCK); 834bd368728SMarko Zec } 835bd368728SMarko Zec 836bd368728SMarko Zec bus_dmamap_sync(recv->ch_tag, recv->ch_map, 837bd368728SMarko Zec BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 838bd368728SMarko Zec 839bd368728SMarko Zec /* 840bd368728SMarko Zec * Read reply data and validate address and tag. 841bd368728SMarko Zec * Note: we do access the send side without lock but the state 842bd368728SMarko Zec * machine does prevent the data from changing. 843bd368728SMarko Zec */ 844bd368728SMarko Zec data = (struct nf_regop_data *) (recv->buf_addr + 845bd368728SMarko Zec sizeof(struct nf_bb_desc)); 846bd368728SMarko Zec 847bd368728SMarko Zec if (le32toh(data->rtag) != send->rtag) 848bd368728SMarko Zec device_printf(adapter->dev, "rtag error: 0x%08x 0x%08x\n", 849bd368728SMarko Zec le32toh(data->rtag), send->rtag); 850bd368728SMarko Zec 851bd368728SMarko Zec sifr->val = le32toh(data->val); 852bd368728SMarko Zec recv->state = SUME_RIFFA_CHAN_STATE_IDLE; 853bd368728SMarko Zec 854bd368728SMarko Zec /* We are done. */ 855bd368728SMarko Zec send->state = SUME_RIFFA_CHAN_STATE_IDLE; 856bd368728SMarko Zec 857bd368728SMarko Zec SUME_UNLOCK(adapter); 858bd368728SMarko Zec 859bd368728SMarko Zec return (0); 860bd368728SMarko Zec } 861bd368728SMarko Zec 862bd368728SMarko Zec /* Read value from a module register and return it to a sume_ifreq. */ 863bd368728SMarko Zec static int 864bd368728SMarko Zec get_modreg_value(struct nf_priv *nf_priv, struct sume_ifreq *sifr) 865bd368728SMarko Zec { 866bd368728SMarko Zec int error; 867bd368728SMarko Zec 868bd368728SMarko Zec error = sume_module_reg_write(nf_priv, sifr, SUME_MR_READ); 869bd368728SMarko Zec if (!error) 870bd368728SMarko Zec error = sume_module_reg_read(nf_priv, sifr); 871bd368728SMarko Zec 872bd368728SMarko Zec return (error); 873bd368728SMarko Zec } 874bd368728SMarko Zec 875bd368728SMarko Zec static int 876cc970676SJustin Hibbits sume_if_ioctl(if_t ifp, unsigned long cmd, caddr_t data) 877bd368728SMarko Zec { 878bd368728SMarko Zec struct ifreq *ifr = (struct ifreq *) data; 879cc970676SJustin Hibbits struct nf_priv *nf_priv = if_getsoftc(ifp); 880bd368728SMarko Zec struct sume_ifreq sifr; 881bd368728SMarko Zec int error = 0; 882bd368728SMarko Zec 883bd368728SMarko Zec switch (cmd) { 884bd368728SMarko Zec case SIOCGIFMEDIA: 885bd368728SMarko Zec case SIOCGIFXMEDIA: 886bd368728SMarko Zec error = ifmedia_ioctl(ifp, ifr, &nf_priv->media, cmd); 887bd368728SMarko Zec break; 888bd368728SMarko Zec 889bd368728SMarko Zec case SUME_IOCTL_CMD_WRITE_REG: 890bd368728SMarko Zec error = copyin(ifr_data_get_ptr(ifr), &sifr, sizeof(sifr)); 891bd368728SMarko Zec if (error) { 892bd368728SMarko Zec error = EINVAL; 893bd368728SMarko Zec break; 894bd368728SMarko Zec } 895bd368728SMarko Zec error = sume_module_reg_write(nf_priv, &sifr, SUME_MR_WRITE); 896bd368728SMarko Zec break; 897bd368728SMarko Zec 898bd368728SMarko Zec case SUME_IOCTL_CMD_READ_REG: 899bd368728SMarko Zec error = copyin(ifr_data_get_ptr(ifr), &sifr, sizeof(sifr)); 900bd368728SMarko Zec if (error) { 901bd368728SMarko Zec error = EINVAL; 902bd368728SMarko Zec break; 903bd368728SMarko Zec } 904bd368728SMarko Zec 905bd368728SMarko Zec error = get_modreg_value(nf_priv, &sifr); 906bd368728SMarko Zec if (error) 907bd368728SMarko Zec break; 908bd368728SMarko Zec 909bd368728SMarko Zec error = copyout(&sifr, ifr_data_get_ptr(ifr), sizeof(sifr)); 910bd368728SMarko Zec if (error) 911bd368728SMarko Zec error = EINVAL; 912bd368728SMarko Zec 913bd368728SMarko Zec break; 914bd368728SMarko Zec 915bd368728SMarko Zec case SIOCSIFFLAGS: 916bd368728SMarko Zec /* Silence tcpdump 'promisc mode not supported' warning. */ 917cc970676SJustin Hibbits if (if_getflags(ifp) & IFF_PROMISC) 918bd368728SMarko Zec break; 919bd368728SMarko Zec 920bd368728SMarko Zec default: 921bd368728SMarko Zec error = ether_ioctl(ifp, cmd, data); 922bd368728SMarko Zec break; 923bd368728SMarko Zec } 924bd368728SMarko Zec 925bd368728SMarko Zec return (error); 926bd368728SMarko Zec } 927bd368728SMarko Zec 928bd368728SMarko Zec static int 929cc970676SJustin Hibbits sume_media_change(if_t ifp) 930bd368728SMarko Zec { 931cc970676SJustin Hibbits struct nf_priv *nf_priv = if_getsoftc(ifp); 932bd368728SMarko Zec struct ifmedia *ifm = &nf_priv->media; 933bd368728SMarko Zec 934bd368728SMarko Zec if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) 935bd368728SMarko Zec return (EINVAL); 936bd368728SMarko Zec 937bd368728SMarko Zec if (IFM_SUBTYPE(ifm->ifm_media) == IFM_10G_SR) 938cc970676SJustin Hibbits if_setbaudrate(ifp, ifmedia_baudrate(IFM_ETHER | IFM_10G_SR)); 939bd368728SMarko Zec else 940cc970676SJustin Hibbits if_setbaudrate(ifp, ifmedia_baudrate(ifm->ifm_media)); 941bd368728SMarko Zec 942bd368728SMarko Zec return (0); 943bd368728SMarko Zec } 944bd368728SMarko Zec 945bd368728SMarko Zec static void 946cc970676SJustin Hibbits sume_update_link_status(if_t ifp) 947bd368728SMarko Zec { 948cc970676SJustin Hibbits struct nf_priv *nf_priv = if_getsoftc(ifp); 949bd368728SMarko Zec struct sume_adapter *adapter = nf_priv->adapter; 950bd368728SMarko Zec struct sume_ifreq sifr; 951bd368728SMarko Zec int link_status; 952bd368728SMarko Zec 953bd368728SMarko Zec sifr.addr = SUME_STATUS_ADDR(nf_priv->port); 954bd368728SMarko Zec sifr.val = 0; 955bd368728SMarko Zec 956bd368728SMarko Zec if (get_modreg_value(nf_priv, &sifr)) 957bd368728SMarko Zec return; 958bd368728SMarko Zec 959bd368728SMarko Zec link_status = SUME_LINK_STATUS(sifr.val); 960bd368728SMarko Zec 961bd368728SMarko Zec if (!link_status && nf_priv->link_up) { 962bd368728SMarko Zec if_link_state_change(ifp, LINK_STATE_DOWN); 963bd368728SMarko Zec nf_priv->link_up = 0; 964bd368728SMarko Zec if (adapter->sume_debug) 965bd368728SMarko Zec device_printf(adapter->dev, "port %d link state " 966bd368728SMarko Zec "changed to DOWN\n", nf_priv->unit); 967bd368728SMarko Zec } else if (link_status && !nf_priv->link_up) { 968bd368728SMarko Zec nf_priv->link_up = 1; 969bd368728SMarko Zec if_link_state_change(ifp, LINK_STATE_UP); 970bd368728SMarko Zec if (adapter->sume_debug) 971bd368728SMarko Zec device_printf(adapter->dev, "port %d link state " 972bd368728SMarko Zec "changed to UP\n", nf_priv->unit); 973bd368728SMarko Zec } 974bd368728SMarko Zec } 975bd368728SMarko Zec 976bd368728SMarko Zec static void 977cc970676SJustin Hibbits sume_media_status(if_t ifp, struct ifmediareq *ifmr) 978bd368728SMarko Zec { 979cc970676SJustin Hibbits struct nf_priv *nf_priv = if_getsoftc(ifp); 980bd368728SMarko Zec struct ifmedia *ifm = &nf_priv->media; 981bd368728SMarko Zec 982bd368728SMarko Zec if (ifm->ifm_cur->ifm_media == (IFM_ETHER | IFM_10G_SR) && 983cc970676SJustin Hibbits (if_getflags(ifp) & IFF_UP)) 984bd368728SMarko Zec ifmr->ifm_active = IFM_ETHER | IFM_10G_SR; 985bd368728SMarko Zec else 986bd368728SMarko Zec ifmr->ifm_active = ifm->ifm_cur->ifm_media; 987bd368728SMarko Zec 988bd368728SMarko Zec ifmr->ifm_status |= IFM_AVALID; 989bd368728SMarko Zec 990bd368728SMarko Zec sume_update_link_status(ifp); 991bd368728SMarko Zec 992bd368728SMarko Zec if (nf_priv->link_up) 993bd368728SMarko Zec ifmr->ifm_status |= IFM_ACTIVE; 994bd368728SMarko Zec } 995bd368728SMarko Zec 996bd368728SMarko Zec /* 997bd368728SMarko Zec * Packet to transmit. We take the packet data from the mbuf and copy it to the 998bd368728SMarko Zec * bouncebuffer address buf_addr+3*sizeof(uint32_t)+16. The 16 bytes before the 999bd368728SMarko Zec * packet data are for metadata: sport/dport (depending on our source 1000bd368728SMarko Zec * interface), packet length and magic 0xcafe. We tell the SUME about the 1001bd368728SMarko Zec * transfer, fill the first 3*sizeof(uint32_t) bytes of the bouncebuffer with 1002bd368728SMarko Zec * the information about the start and length of the packet and trigger the 1003bd368728SMarko Zec * transaction. 1004bd368728SMarko Zec */ 1005bd368728SMarko Zec static int 1006cc970676SJustin Hibbits sume_if_start_locked(if_t ifp) 1007bd368728SMarko Zec { 1008bd368728SMarko Zec struct mbuf *m; 1009cc970676SJustin Hibbits struct nf_priv *nf_priv = if_getsoftc(ifp); 1010bd368728SMarko Zec struct sume_adapter *adapter = nf_priv->adapter; 1011bd368728SMarko Zec struct riffa_chnl_dir *send = adapter->send[SUME_RIFFA_CHANNEL_DATA]; 1012bd368728SMarko Zec uint8_t *outbuf; 1013bd368728SMarko Zec struct nf_metadata *mdata; 1014bd368728SMarko Zec int plen = SUME_MIN_PKT_SIZE; 1015bd368728SMarko Zec 1016bd368728SMarko Zec KASSERT(mtx_owned(&adapter->lock), ("SUME lock not owned")); 1017bd368728SMarko Zec KASSERT(send->state == SUME_RIFFA_CHAN_STATE_IDLE, 1018bd368728SMarko Zec ("SUME not in IDLE state")); 1019bd368728SMarko Zec 1020cc970676SJustin Hibbits m = if_dequeue(ifp); 1021bd368728SMarko Zec if (m == NULL) 1022bd368728SMarko Zec return (EINVAL); 1023bd368728SMarko Zec 1024bd368728SMarko Zec /* Packets large enough do not need to be padded */ 1025bd368728SMarko Zec if (m->m_pkthdr.len > SUME_MIN_PKT_SIZE) 1026bd368728SMarko Zec plen = m->m_pkthdr.len; 1027bd368728SMarko Zec 1028bd368728SMarko Zec if (adapter->sume_debug) 1029bd368728SMarko Zec device_printf(adapter->dev, "sending %d bytes to %s%d\n", plen, 1030bd368728SMarko Zec SUME_ETH_DEVICE_NAME, nf_priv->unit); 1031bd368728SMarko Zec 1032bd368728SMarko Zec outbuf = (uint8_t *) send->buf_addr + sizeof(struct nf_bb_desc); 1033bd368728SMarko Zec mdata = (struct nf_metadata *) outbuf; 1034bd368728SMarko Zec 1035bd368728SMarko Zec /* Clear the recovery flag. */ 1036bd368728SMarko Zec send->recovery = 0; 1037bd368728SMarko Zec 1038bd368728SMarko Zec /* Make sure we fit with the 16 bytes nf_metadata. */ 1039bd368728SMarko Zec if (m->m_pkthdr.len + sizeof(struct nf_metadata) > 1040bd368728SMarko Zec adapter->sg_buf_size) { 1041bd368728SMarko Zec device_printf(adapter->dev, "packet too big for bounce buffer " 1042bd368728SMarko Zec "(%d)\n", m->m_pkthdr.len); 1043bd368728SMarko Zec m_freem(m); 1044bd368728SMarko Zec nf_priv->stats.tx_dropped++; 1045bd368728SMarko Zec return (ENOMEM); 1046bd368728SMarko Zec } 1047bd368728SMarko Zec 1048bd368728SMarko Zec bus_dmamap_sync(send->ch_tag, send->ch_map, 1049bd368728SMarko Zec BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1050bd368728SMarko Zec 1051bd368728SMarko Zec /* Zero out the padded data */ 1052bd368728SMarko Zec if (m->m_pkthdr.len < SUME_MIN_PKT_SIZE) 1053bd368728SMarko Zec bzero(outbuf + sizeof(struct nf_metadata), SUME_MIN_PKT_SIZE); 1054bd368728SMarko Zec /* Skip the first 16 bytes for the metadata. */ 1055bd368728SMarko Zec m_copydata(m, 0, m->m_pkthdr.len, outbuf + sizeof(struct nf_metadata)); 1056bd368728SMarko Zec send->len = (sizeof(struct nf_metadata) + plen + 3) / 4; 1057bd368728SMarko Zec 1058bd368728SMarko Zec /* Fill in the metadata: CPU(DMA) ports are odd, MAC ports are even. */ 1059bd368728SMarko Zec mdata->sport = htole16(1 << (nf_priv->port * 2 + 1)); 1060bd368728SMarko Zec mdata->dport = htole16(1 << (nf_priv->port * 2)); 1061bd368728SMarko Zec mdata->plen = htole16(plen); 1062bd368728SMarko Zec mdata->magic = htole16(SUME_RIFFA_MAGIC); 1063bd368728SMarko Zec mdata->t1 = htole32(0); 1064bd368728SMarko Zec mdata->t2 = htole32(0); 1065bd368728SMarko Zec 1066bd368728SMarko Zec /* Let the FPGA know about the transfer. */ 1067bd368728SMarko Zec write_reg(adapter, RIFFA_CHNL_REG(SUME_RIFFA_CHANNEL_DATA, 1068bd368728SMarko Zec RIFFA_RX_OFFLAST_REG_OFF), SUME_OFFLAST); 1069bd368728SMarko Zec write_reg(adapter, RIFFA_CHNL_REG(SUME_RIFFA_CHANNEL_DATA, 1070bd368728SMarko Zec RIFFA_RX_LEN_REG_OFF), send->len); 1071bd368728SMarko Zec 1072bd368728SMarko Zec /* Fill the bouncebuf "descriptor". */ 1073bd368728SMarko Zec sume_fill_bb_desc(adapter, send, SUME_RIFFA_LEN(send->len)); 1074bd368728SMarko Zec 1075bd368728SMarko Zec /* Update the state before intiating the DMA to avoid races. */ 1076bd368728SMarko Zec send->state = SUME_RIFFA_CHAN_STATE_READY; 1077bd368728SMarko Zec 1078bd368728SMarko Zec /* DMA. */ 1079bd368728SMarko Zec write_reg(adapter, RIFFA_CHNL_REG(SUME_RIFFA_CHANNEL_DATA, 1080bd368728SMarko Zec RIFFA_RX_SG_ADDR_LO_REG_OFF), 1081bd368728SMarko Zec SUME_RIFFA_LO_ADDR(send->buf_hw_addr)); 1082bd368728SMarko Zec write_reg(adapter, RIFFA_CHNL_REG(SUME_RIFFA_CHANNEL_DATA, 1083bd368728SMarko Zec RIFFA_RX_SG_ADDR_HI_REG_OFF), 1084bd368728SMarko Zec SUME_RIFFA_HI_ADDR(send->buf_hw_addr)); 1085bd368728SMarko Zec write_reg(adapter, RIFFA_CHNL_REG(SUME_RIFFA_CHANNEL_DATA, 1086bd368728SMarko Zec RIFFA_RX_SG_LEN_REG_OFF), 4 * send->num_sg); 1087bd368728SMarko Zec 1088bd368728SMarko Zec bus_dmamap_sync(send->ch_tag, send->ch_map, 1089bd368728SMarko Zec BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1090bd368728SMarko Zec 1091bd368728SMarko Zec nf_priv->stats.tx_packets++; 1092bd368728SMarko Zec nf_priv->stats.tx_bytes += plen; 1093bd368728SMarko Zec 1094bd368728SMarko Zec /* We can free as long as we use the bounce buffer. */ 1095bd368728SMarko Zec m_freem(m); 1096bd368728SMarko Zec 1097bd368728SMarko Zec adapter->last_ifc = nf_priv->port; 1098bd368728SMarko Zec 1099bd368728SMarko Zec /* Reset watchdog counter. */ 1100bd368728SMarko Zec adapter->wd_counter = 0; 1101bd368728SMarko Zec 1102bd368728SMarko Zec return (0); 1103bd368728SMarko Zec } 1104bd368728SMarko Zec 1105bd368728SMarko Zec static void 1106cc970676SJustin Hibbits sume_if_start(if_t ifp) 1107bd368728SMarko Zec { 1108cc970676SJustin Hibbits struct nf_priv *nf_priv = if_getsoftc(ifp); 1109bd368728SMarko Zec struct sume_adapter *adapter = nf_priv->adapter; 1110bd368728SMarko Zec 1111cc970676SJustin Hibbits if (!adapter->running || !(if_getflags(ifp) & IFF_UP)) 1112bd368728SMarko Zec return; 1113bd368728SMarko Zec 1114bd368728SMarko Zec SUME_LOCK(adapter); 1115bd368728SMarko Zec if (adapter->send[SUME_RIFFA_CHANNEL_DATA]->state == 1116bd368728SMarko Zec SUME_RIFFA_CHAN_STATE_IDLE) 1117bd368728SMarko Zec sume_if_start_locked(ifp); 1118bd368728SMarko Zec SUME_UNLOCK(adapter); 1119bd368728SMarko Zec } 1120bd368728SMarko Zec 1121bd368728SMarko Zec /* 1122bd368728SMarko Zec * We call this function at the end of every TX transaction to check for 1123bd368728SMarko Zec * remaining packets in the TX queues for every UP interface. 1124bd368728SMarko Zec */ 1125bd368728SMarko Zec static void 1126bd368728SMarko Zec check_tx_queues(struct sume_adapter *adapter) 1127bd368728SMarko Zec { 1128bd368728SMarko Zec int i, last_ifc; 1129bd368728SMarko Zec 1130bd368728SMarko Zec KASSERT(mtx_owned(&adapter->lock), ("SUME lock not owned")); 1131bd368728SMarko Zec 1132bd368728SMarko Zec last_ifc = adapter->last_ifc; 1133bd368728SMarko Zec 1134bd368728SMarko Zec /* Check all interfaces */ 1135bd368728SMarko Zec for (i = last_ifc + 1; i < last_ifc + SUME_NPORTS + 1; i++) { 1136cc970676SJustin Hibbits if_t ifp = adapter->ifp[i % SUME_NPORTS]; 1137bd368728SMarko Zec 1138cc970676SJustin Hibbits if (!(if_getflags(ifp) & IFF_UP)) 1139bd368728SMarko Zec continue; 1140bd368728SMarko Zec 1141bd368728SMarko Zec if (!sume_if_start_locked(ifp)) 1142bd368728SMarko Zec break; 1143bd368728SMarko Zec } 1144bd368728SMarko Zec } 1145bd368728SMarko Zec 1146aa386085SZhenlei Huang static void 1147bd368728SMarko Zec sume_ifp_alloc(struct sume_adapter *adapter, uint32_t port) 1148bd368728SMarko Zec { 1149cc970676SJustin Hibbits if_t ifp; 1150bd368728SMarko Zec struct nf_priv *nf_priv = malloc(sizeof(struct nf_priv), M_SUME, 1151bd368728SMarko Zec M_ZERO | M_WAITOK); 1152bd368728SMarko Zec 1153bd368728SMarko Zec ifp = if_alloc(IFT_ETHER); 1154bd368728SMarko Zec adapter->ifp[port] = ifp; 1155cc970676SJustin Hibbits if_setsoftc(ifp, nf_priv); 1156bd368728SMarko Zec 1157bd368728SMarko Zec nf_priv->adapter = adapter; 1158bd368728SMarko Zec nf_priv->unit = alloc_unr(unr); 1159bd368728SMarko Zec nf_priv->port = port; 1160bd368728SMarko Zec nf_priv->link_up = 0; 1161bd368728SMarko Zec 1162bd368728SMarko Zec if_initname(ifp, SUME_ETH_DEVICE_NAME, nf_priv->unit); 1163cc970676SJustin Hibbits if_setflags(ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST); 1164bd368728SMarko Zec 1165cc970676SJustin Hibbits if_setinitfn(ifp, sume_if_init); 1166cc970676SJustin Hibbits if_setstartfn(ifp, sume_if_start); 1167cc970676SJustin Hibbits if_setioctlfn(ifp, sume_if_ioctl); 1168bd368728SMarko Zec 1169bd368728SMarko Zec uint8_t hw_addr[ETHER_ADDR_LEN] = DEFAULT_ETHER_ADDRESS; 1170bd368728SMarko Zec hw_addr[ETHER_ADDR_LEN-1] = nf_priv->unit; 1171bd368728SMarko Zec ether_ifattach(ifp, hw_addr); 1172bd368728SMarko Zec 1173bd368728SMarko Zec ifmedia_init(&nf_priv->media, IFM_IMASK, sume_media_change, 1174bd368728SMarko Zec sume_media_status); 1175bd368728SMarko Zec ifmedia_add(&nf_priv->media, IFM_ETHER | IFM_10G_SR, 0, NULL); 1176bd368728SMarko Zec ifmedia_set(&nf_priv->media, IFM_ETHER | IFM_10G_SR); 1177bd368728SMarko Zec 1178cc970676SJustin Hibbits if_setdrvflagbits(ifp, IFF_DRV_RUNNING, 0); 1179bd368728SMarko Zec } 1180bd368728SMarko Zec 1181bd368728SMarko Zec static void 1182bd368728SMarko Zec callback_dma(void *arg, bus_dma_segment_t *segs, int nseg, int err) 1183bd368728SMarko Zec { 1184bd368728SMarko Zec if (err) 1185bd368728SMarko Zec return; 1186bd368728SMarko Zec 1187bd368728SMarko Zec KASSERT(nseg == 1, ("%d segments returned!", nseg)); 1188bd368728SMarko Zec 1189bd368728SMarko Zec *(bus_addr_t *) arg = segs[0].ds_addr; 1190bd368728SMarko Zec } 1191bd368728SMarko Zec 1192bd368728SMarko Zec static int 1193bd368728SMarko Zec sume_probe_riffa_buffer(const struct sume_adapter *adapter, 1194bd368728SMarko Zec struct riffa_chnl_dir ***p, const char *dir) 1195bd368728SMarko Zec { 1196bd368728SMarko Zec struct riffa_chnl_dir **rp; 1197bd368728SMarko Zec bus_addr_t hw_addr; 1198*761339c5SZhenlei Huang int ch; 1199bd368728SMarko Zec device_t dev = adapter->dev; 1200bd368728SMarko Zec 1201bd368728SMarko Zec *p = malloc(SUME_RIFFA_CHANNELS * sizeof(struct riffa_chnl_dir *), 1202bd368728SMarko Zec M_SUME, M_ZERO | M_WAITOK); 1203bd368728SMarko Zec 1204bd368728SMarko Zec rp = *p; 1205bd368728SMarko Zec /* Allocate the chnl_dir structs themselves. */ 1206bd368728SMarko Zec for (ch = 0; ch < SUME_RIFFA_CHANNELS; ch++) { 1207bd368728SMarko Zec /* One direction. */ 1208bd368728SMarko Zec rp[ch] = malloc(sizeof(struct riffa_chnl_dir), M_SUME, 1209bd368728SMarko Zec M_ZERO | M_WAITOK); 1210bd368728SMarko Zec 1211bd368728SMarko Zec int err = bus_dma_tag_create(bus_get_dma_tag(dev), 1212bd368728SMarko Zec 4, 0, 1213bd368728SMarko Zec BUS_SPACE_MAXADDR, 1214bd368728SMarko Zec BUS_SPACE_MAXADDR, 1215bd368728SMarko Zec NULL, NULL, 1216bd368728SMarko Zec adapter->sg_buf_size, 1217bd368728SMarko Zec 1, 1218bd368728SMarko Zec adapter->sg_buf_size, 1219bd368728SMarko Zec 0, 1220bd368728SMarko Zec NULL, 1221bd368728SMarko Zec NULL, 1222bd368728SMarko Zec &rp[ch]->ch_tag); 1223bd368728SMarko Zec 1224bd368728SMarko Zec if (err) { 1225bd368728SMarko Zec device_printf(dev, "bus_dma_tag_create(%s[%d]) " 1226bd368728SMarko Zec "failed.\n", dir, ch); 1227bd368728SMarko Zec return (err); 1228bd368728SMarko Zec } 1229bd368728SMarko Zec 1230bd368728SMarko Zec err = bus_dmamem_alloc(rp[ch]->ch_tag, (void **) 1231bd368728SMarko Zec &rp[ch]->buf_addr, BUS_DMA_WAITOK | BUS_DMA_COHERENT | 1232bd368728SMarko Zec BUS_DMA_ZERO, &rp[ch]->ch_map); 1233bd368728SMarko Zec if (err) { 1234bd368728SMarko Zec device_printf(dev, "bus_dmamem_alloc(%s[%d]) failed.\n", 1235bd368728SMarko Zec dir, ch); 1236bd368728SMarko Zec return (err); 1237bd368728SMarko Zec } 1238bd368728SMarko Zec 1239bd368728SMarko Zec bzero(rp[ch]->buf_addr, adapter->sg_buf_size); 1240bd368728SMarko Zec 1241bd368728SMarko Zec err = bus_dmamap_load(rp[ch]->ch_tag, rp[ch]->ch_map, 1242bd368728SMarko Zec rp[ch]->buf_addr, adapter->sg_buf_size, callback_dma, 1243bd368728SMarko Zec &hw_addr, BUS_DMA_NOWAIT); 1244bd368728SMarko Zec if (err) { 1245bd368728SMarko Zec device_printf(dev, "bus_dmamap_load(%s[%d]) failed.\n", 1246bd368728SMarko Zec dir, ch); 1247bd368728SMarko Zec return (err); 1248bd368728SMarko Zec } 1249bd368728SMarko Zec rp[ch]->buf_hw_addr = hw_addr; 1250bd368728SMarko Zec rp[ch]->num_sg = 1; 1251bd368728SMarko Zec rp[ch]->state = SUME_RIFFA_CHAN_STATE_IDLE; 1252bd368728SMarko Zec 1253bd368728SMarko Zec rp[ch]->rtag = SUME_INIT_RTAG; 1254bd368728SMarko Zec } 1255bd368728SMarko Zec 1256bd368728SMarko Zec return (0); 1257bd368728SMarko Zec } 1258bd368728SMarko Zec 1259bd368728SMarko Zec static int 1260bd368728SMarko Zec sume_probe_riffa_buffers(struct sume_adapter *adapter) 1261bd368728SMarko Zec { 1262bd368728SMarko Zec int error; 1263bd368728SMarko Zec 1264bd368728SMarko Zec error = sume_probe_riffa_buffer(adapter, &adapter->recv, "recv"); 1265bd368728SMarko Zec if (error) 1266bd368728SMarko Zec return (error); 1267bd368728SMarko Zec 1268bd368728SMarko Zec error = sume_probe_riffa_buffer(adapter, &adapter->send, "send"); 1269bd368728SMarko Zec 1270bd368728SMarko Zec return (error); 1271bd368728SMarko Zec } 1272bd368728SMarko Zec 1273bd368728SMarko Zec static void 1274bd368728SMarko Zec sume_sysctl_init(struct sume_adapter *adapter) 1275bd368728SMarko Zec { 1276bd368728SMarko Zec device_t dev = adapter->dev; 1277bd368728SMarko Zec struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev); 1278bd368728SMarko Zec struct sysctl_oid *tree = device_get_sysctl_tree(dev); 1279bd368728SMarko Zec struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree); 1280bd368728SMarko Zec struct sysctl_oid *tmp_tree; 1281bd368728SMarko Zec char namebuf[MAX_IFC_NAME_LEN]; 1282bd368728SMarko Zec int i; 1283bd368728SMarko Zec 1284bd368728SMarko Zec tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "sume", CTLFLAG_RW, 1285bd368728SMarko Zec 0, "SUME top-level tree"); 1286bd368728SMarko Zec if (tree == NULL) { 1287bd368728SMarko Zec device_printf(dev, "SYSCTL_ADD_NODE failed.\n"); 1288bd368728SMarko Zec return; 1289bd368728SMarko Zec } 1290bd368728SMarko Zec SYSCTL_ADD_INT(ctx, child, OID_AUTO, "debug", CTLFLAG_RW, 1291bd368728SMarko Zec &adapter->sume_debug, 0, "debug int leaf"); 1292bd368728SMarko Zec 1293bd368728SMarko Zec /* total RX error stats */ 1294bd368728SMarko Zec SYSCTL_ADD_U64(ctx, child, OID_AUTO, "rx_epkts", 1295bd368728SMarko Zec CTLFLAG_RD, &adapter->packets_err, 0, "rx errors"); 1296bd368728SMarko Zec SYSCTL_ADD_U64(ctx, child, OID_AUTO, "rx_ebytes", 1297bd368728SMarko Zec CTLFLAG_RD, &adapter->bytes_err, 0, "rx error bytes"); 1298bd368728SMarko Zec 1299bd368728SMarko Zec for (i = SUME_NPORTS - 1; i >= 0; i--) { 1300cc970676SJustin Hibbits if_t ifp = adapter->ifp[i]; 1301bd368728SMarko Zec if (ifp == NULL) 1302bd368728SMarko Zec continue; 1303bd368728SMarko Zec 1304cc970676SJustin Hibbits struct nf_priv *nf_priv = if_getsoftc(ifp); 1305bd368728SMarko Zec 1306bd368728SMarko Zec snprintf(namebuf, MAX_IFC_NAME_LEN, "%s%d", 1307bd368728SMarko Zec SUME_ETH_DEVICE_NAME, nf_priv->unit); 1308bd368728SMarko Zec tmp_tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf, 1309bd368728SMarko Zec CTLFLAG_RW, 0, "SUME ifc tree"); 1310bd368728SMarko Zec if (tmp_tree == NULL) { 1311bd368728SMarko Zec device_printf(dev, "SYSCTL_ADD_NODE failed.\n"); 1312bd368728SMarko Zec return; 1313bd368728SMarko Zec } 1314bd368728SMarko Zec 1315bd368728SMarko Zec /* Packets dropped by down interface. */ 1316bd368728SMarko Zec SYSCTL_ADD_U64(ctx, SYSCTL_CHILDREN(tmp_tree), OID_AUTO, 1317bd368728SMarko Zec "ifc_down_bytes", CTLFLAG_RD, 1318bd368728SMarko Zec &nf_priv->stats.ifc_down_bytes, 0, "ifc_down bytes"); 1319bd368728SMarko Zec SYSCTL_ADD_U64(ctx, SYSCTL_CHILDREN(tmp_tree), OID_AUTO, 1320bd368728SMarko Zec "ifc_down_packets", CTLFLAG_RD, 1321bd368728SMarko Zec &nf_priv->stats.ifc_down_packets, 0, "ifc_down packets"); 1322bd368728SMarko Zec 1323bd368728SMarko Zec /* HW RX stats */ 1324bd368728SMarko Zec SYSCTL_ADD_U64(ctx, SYSCTL_CHILDREN(tmp_tree), OID_AUTO, 1325bd368728SMarko Zec "hw_rx_packets", CTLFLAG_RD, &nf_priv->stats.hw_rx_packets, 1326bd368728SMarko Zec 0, "hw_rx packets"); 1327bd368728SMarko Zec 1328bd368728SMarko Zec /* HW TX stats */ 1329bd368728SMarko Zec SYSCTL_ADD_U64(ctx, SYSCTL_CHILDREN(tmp_tree), OID_AUTO, 1330bd368728SMarko Zec "hw_tx_packets", CTLFLAG_RD, &nf_priv->stats.hw_tx_packets, 1331bd368728SMarko Zec 0, "hw_tx packets"); 1332bd368728SMarko Zec 1333bd368728SMarko Zec /* RX stats */ 1334bd368728SMarko Zec SYSCTL_ADD_U64(ctx, SYSCTL_CHILDREN(tmp_tree), OID_AUTO, 1335bd368728SMarko Zec "rx_bytes", CTLFLAG_RD, &nf_priv->stats.rx_bytes, 0, 1336bd368728SMarko Zec "rx bytes"); 1337bd368728SMarko Zec SYSCTL_ADD_U64(ctx, SYSCTL_CHILDREN(tmp_tree), OID_AUTO, 1338bd368728SMarko Zec "rx_dropped", CTLFLAG_RD, &nf_priv->stats.rx_dropped, 0, 1339bd368728SMarko Zec "rx dropped"); 1340bd368728SMarko Zec SYSCTL_ADD_U64(ctx, SYSCTL_CHILDREN(tmp_tree), OID_AUTO, 1341bd368728SMarko Zec "rx_packets", CTLFLAG_RD, &nf_priv->stats.rx_packets, 0, 1342bd368728SMarko Zec "rx packets"); 1343bd368728SMarko Zec 1344bd368728SMarko Zec /* TX stats */ 1345bd368728SMarko Zec SYSCTL_ADD_U64(ctx, SYSCTL_CHILDREN(tmp_tree), OID_AUTO, 1346bd368728SMarko Zec "tx_bytes", CTLFLAG_RD, &nf_priv->stats.tx_bytes, 0, 1347bd368728SMarko Zec "tx bytes"); 1348bd368728SMarko Zec SYSCTL_ADD_U64(ctx, SYSCTL_CHILDREN(tmp_tree), OID_AUTO, 1349bd368728SMarko Zec "tx_dropped", CTLFLAG_RD, &nf_priv->stats.tx_dropped, 0, 1350bd368728SMarko Zec "tx dropped"); 1351bd368728SMarko Zec SYSCTL_ADD_U64(ctx, SYSCTL_CHILDREN(tmp_tree), OID_AUTO, 1352bd368728SMarko Zec "tx_packets", CTLFLAG_RD, &nf_priv->stats.tx_packets, 0, 1353bd368728SMarko Zec "tx packets"); 1354bd368728SMarko Zec } 1355bd368728SMarko Zec } 1356bd368728SMarko Zec 1357bd368728SMarko Zec static void 1358bd368728SMarko Zec sume_local_timer(void *arg) 1359bd368728SMarko Zec { 1360bd368728SMarko Zec struct sume_adapter *adapter = arg; 1361bd368728SMarko Zec 1362bd368728SMarko Zec if (!adapter->running) 1363bd368728SMarko Zec return; 1364bd368728SMarko Zec 1365bd368728SMarko Zec taskqueue_enqueue(adapter->tq, &adapter->stat_task); 1366bd368728SMarko Zec 1367bd368728SMarko Zec SUME_LOCK(adapter); 1368bd368728SMarko Zec if (adapter->send[SUME_RIFFA_CHANNEL_DATA]->state != 1369bd368728SMarko Zec SUME_RIFFA_CHAN_STATE_IDLE && ++adapter->wd_counter >= 3) { 1370bd368728SMarko Zec /* Resetting interfaces if stuck for 3 seconds. */ 1371bd368728SMarko Zec device_printf(adapter->dev, "TX stuck, resetting adapter.\n"); 1372bd368728SMarko Zec read_reg(adapter, RIFFA_INFO_REG_OFF); 1373bd368728SMarko Zec 1374bd368728SMarko Zec adapter->send[SUME_RIFFA_CHANNEL_DATA]->state = 1375bd368728SMarko Zec SUME_RIFFA_CHAN_STATE_IDLE; 1376bd368728SMarko Zec adapter->wd_counter = 0; 1377bd368728SMarko Zec 1378bd368728SMarko Zec check_tx_queues(adapter); 1379bd368728SMarko Zec } 1380bd368728SMarko Zec SUME_UNLOCK(adapter); 1381bd368728SMarko Zec 1382bd368728SMarko Zec callout_reset(&adapter->timer, 1 * hz, sume_local_timer, adapter); 1383bd368728SMarko Zec } 1384bd368728SMarko Zec 1385bd368728SMarko Zec static void 1386bd368728SMarko Zec sume_get_stats(void *context, int pending) 1387bd368728SMarko Zec { 1388bd368728SMarko Zec struct sume_adapter *adapter = context; 1389bd368728SMarko Zec int i; 1390bd368728SMarko Zec 1391bd368728SMarko Zec for (i = 0; i < SUME_NPORTS; i++) { 1392cc970676SJustin Hibbits if_t ifp = adapter->ifp[i]; 1393bd368728SMarko Zec 1394cc970676SJustin Hibbits if (if_getflags(ifp) & IFF_UP) { 1395cc970676SJustin Hibbits struct nf_priv *nf_priv = if_getsoftc(ifp); 1396bd368728SMarko Zec struct sume_ifreq sifr; 1397bd368728SMarko Zec 1398bd368728SMarko Zec sume_update_link_status(ifp); 1399bd368728SMarko Zec 1400bd368728SMarko Zec /* Get RX counter. */ 1401bd368728SMarko Zec sifr.addr = SUME_STAT_RX_ADDR(nf_priv->port); 1402bd368728SMarko Zec sifr.val = 0; 1403bd368728SMarko Zec 1404bd368728SMarko Zec if (!get_modreg_value(nf_priv, &sifr)) 1405bd368728SMarko Zec nf_priv->stats.hw_rx_packets += sifr.val; 1406bd368728SMarko Zec 1407bd368728SMarko Zec /* Get TX counter. */ 1408bd368728SMarko Zec sifr.addr = SUME_STAT_TX_ADDR(nf_priv->port); 1409bd368728SMarko Zec sifr.val = 0; 1410bd368728SMarko Zec 1411bd368728SMarko Zec if (!get_modreg_value(nf_priv, &sifr)) 1412bd368728SMarko Zec nf_priv->stats.hw_tx_packets += sifr.val; 1413bd368728SMarko Zec } 1414bd368728SMarko Zec } 1415bd368728SMarko Zec } 1416bd368728SMarko Zec 1417bd368728SMarko Zec static int 1418bd368728SMarko Zec sume_attach(device_t dev) 1419bd368728SMarko Zec { 1420bd368728SMarko Zec struct sume_adapter *adapter = device_get_softc(dev); 1421bd368728SMarko Zec adapter->dev = dev; 1422bd368728SMarko Zec int error, i; 1423bd368728SMarko Zec 1424bd368728SMarko Zec mtx_init(&adapter->lock, "Global lock", NULL, MTX_DEF); 1425bd368728SMarko Zec 1426bd368728SMarko Zec adapter->running = 0; 1427bd368728SMarko Zec 1428bd368728SMarko Zec /* OK finish up RIFFA. */ 1429bd368728SMarko Zec error = sume_probe_riffa_pci(adapter); 1430bd368728SMarko Zec if (error != 0) 1431bd368728SMarko Zec goto error; 1432bd368728SMarko Zec 1433bd368728SMarko Zec error = sume_probe_riffa_buffers(adapter); 1434bd368728SMarko Zec if (error != 0) 1435bd368728SMarko Zec goto error; 1436bd368728SMarko Zec 1437bd368728SMarko Zec /* Now do the network interfaces. */ 1438aa386085SZhenlei Huang for (i = 0; i < SUME_NPORTS; i++) 1439aa386085SZhenlei Huang sume_ifp_alloc(adapter, i); 1440bd368728SMarko Zec 1441bd368728SMarko Zec /* Register stats and register sysctls. */ 1442bd368728SMarko Zec sume_sysctl_init(adapter); 1443bd368728SMarko Zec 1444bd368728SMarko Zec /* Reset the HW. */ 1445bd368728SMarko Zec read_reg(adapter, RIFFA_INFO_REG_OFF); 1446bd368728SMarko Zec 1447bd368728SMarko Zec /* Ready to go, "enable" IRQ. */ 1448bd368728SMarko Zec adapter->running = 1; 1449bd368728SMarko Zec 1450bd368728SMarko Zec callout_init(&adapter->timer, 1); 1451bd368728SMarko Zec TASK_INIT(&adapter->stat_task, 0, sume_get_stats, adapter); 1452bd368728SMarko Zec 1453bd368728SMarko Zec adapter->tq = taskqueue_create("sume_stats", M_NOWAIT, 1454bd368728SMarko Zec taskqueue_thread_enqueue, &adapter->tq); 1455bd368728SMarko Zec taskqueue_start_threads(&adapter->tq, 1, PI_NET, "%s stattaskq", 1456bd368728SMarko Zec device_get_nameunit(adapter->dev)); 1457bd368728SMarko Zec 1458bd368728SMarko Zec callout_reset(&adapter->timer, 1 * hz, sume_local_timer, adapter); 1459bd368728SMarko Zec 1460bd368728SMarko Zec return (0); 1461bd368728SMarko Zec 1462bd368728SMarko Zec error: 1463bd368728SMarko Zec sume_detach(dev); 1464bd368728SMarko Zec 1465bd368728SMarko Zec return (error); 1466bd368728SMarko Zec } 1467bd368728SMarko Zec 1468bd368728SMarko Zec static void 1469bd368728SMarko Zec sume_remove_riffa_buffer(const struct sume_adapter *adapter, 1470bd368728SMarko Zec struct riffa_chnl_dir **pp) 1471bd368728SMarko Zec { 1472bd368728SMarko Zec int ch; 1473bd368728SMarko Zec 1474bd368728SMarko Zec for (ch = 0; ch < SUME_RIFFA_CHANNELS; ch++) { 1475bd368728SMarko Zec if (pp[ch] == NULL) 1476bd368728SMarko Zec continue; 1477bd368728SMarko Zec 1478bd368728SMarko Zec if (pp[ch]->buf_hw_addr != 0) { 1479bd368728SMarko Zec bus_dmamem_free(pp[ch]->ch_tag, pp[ch]->buf_addr, 1480bd368728SMarko Zec pp[ch]->ch_map); 1481bd368728SMarko Zec pp[ch]->buf_hw_addr = 0; 1482bd368728SMarko Zec } 1483bd368728SMarko Zec 1484bd368728SMarko Zec free(pp[ch], M_SUME); 1485bd368728SMarko Zec } 1486bd368728SMarko Zec } 1487bd368728SMarko Zec 1488bd368728SMarko Zec static void 1489bd368728SMarko Zec sume_remove_riffa_buffers(struct sume_adapter *adapter) 1490bd368728SMarko Zec { 1491bd368728SMarko Zec if (adapter->send != NULL) { 1492bd368728SMarko Zec sume_remove_riffa_buffer(adapter, adapter->send); 1493bd368728SMarko Zec free(adapter->send, M_SUME); 1494bd368728SMarko Zec adapter->send = NULL; 1495bd368728SMarko Zec } 1496bd368728SMarko Zec if (adapter->recv != NULL) { 1497bd368728SMarko Zec sume_remove_riffa_buffer(adapter, adapter->recv); 1498bd368728SMarko Zec free(adapter->recv, M_SUME); 1499bd368728SMarko Zec adapter->recv = NULL; 1500bd368728SMarko Zec } 1501bd368728SMarko Zec } 1502bd368728SMarko Zec 1503bd368728SMarko Zec static int 1504bd368728SMarko Zec sume_detach(device_t dev) 1505bd368728SMarko Zec { 1506bd368728SMarko Zec struct sume_adapter *adapter = device_get_softc(dev); 1507bd368728SMarko Zec int i; 1508bd368728SMarko Zec struct nf_priv *nf_priv; 1509bd368728SMarko Zec 1510bd368728SMarko Zec KASSERT(mtx_initialized(&adapter->lock), ("SUME mutex not " 1511bd368728SMarko Zec "initialized")); 1512bd368728SMarko Zec adapter->running = 0; 1513bd368728SMarko Zec 1514bd368728SMarko Zec /* Drain the stats callout and task queue. */ 1515bd368728SMarko Zec callout_drain(&adapter->timer); 1516bd368728SMarko Zec 1517bd368728SMarko Zec if (adapter->tq) { 1518bd368728SMarko Zec taskqueue_drain(adapter->tq, &adapter->stat_task); 1519bd368728SMarko Zec taskqueue_free(adapter->tq); 1520bd368728SMarko Zec } 1521bd368728SMarko Zec 1522bd368728SMarko Zec for (i = 0; i < SUME_NPORTS; i++) { 1523cc970676SJustin Hibbits if_t ifp = adapter->ifp[i]; 1524bd368728SMarko Zec if (ifp == NULL) 1525bd368728SMarko Zec continue; 1526bd368728SMarko Zec 1527cc970676SJustin Hibbits if_setdrvflagbits(ifp, 0, IFF_DRV_RUNNING); 1528cc970676SJustin Hibbits nf_priv = if_getsoftc(ifp); 1529bd368728SMarko Zec 1530cc970676SJustin Hibbits if (if_getflags(ifp) & IFF_UP) 1531bd368728SMarko Zec if_down(ifp); 1532bd368728SMarko Zec ifmedia_removeall(&nf_priv->media); 1533bd368728SMarko Zec free_unr(unr, nf_priv->unit); 1534bd368728SMarko Zec 1535cc970676SJustin Hibbits if_setflagbits(ifp, 0, IFF_UP); 1536bd368728SMarko Zec ether_ifdetach(ifp); 1537bd368728SMarko Zec if_free(ifp); 1538bd368728SMarko Zec 1539bd368728SMarko Zec free(nf_priv, M_SUME); 1540bd368728SMarko Zec } 1541bd368728SMarko Zec 1542bd368728SMarko Zec sume_remove_riffa_buffers(adapter); 1543bd368728SMarko Zec 1544bd368728SMarko Zec if (adapter->irq.tag) 1545bd368728SMarko Zec bus_teardown_intr(dev, adapter->irq.res, adapter->irq.tag); 1546bd368728SMarko Zec if (adapter->irq.res) 1547bd368728SMarko Zec bus_release_resource(dev, SYS_RES_IRQ, adapter->irq.rid, 1548bd368728SMarko Zec adapter->irq.res); 1549bd368728SMarko Zec 1550bd368728SMarko Zec pci_release_msi(dev); 1551bd368728SMarko Zec 1552bd368728SMarko Zec if (adapter->bar0_addr) 1553bd368728SMarko Zec bus_release_resource(dev, SYS_RES_MEMORY, adapter->rid, 1554bd368728SMarko Zec adapter->bar0_addr); 1555bd368728SMarko Zec 1556bd368728SMarko Zec mtx_destroy(&adapter->lock); 1557bd368728SMarko Zec 1558bd368728SMarko Zec return (0); 1559bd368728SMarko Zec } 1560bd368728SMarko Zec 1561bd368728SMarko Zec static int 1562bd368728SMarko Zec mod_event(module_t mod, int cmd, void *arg) 1563bd368728SMarko Zec { 1564bd368728SMarko Zec switch (cmd) { 1565bd368728SMarko Zec case MOD_LOAD: 1566bd368728SMarko Zec unr = new_unrhdr(0, INT_MAX, NULL); 1567bd368728SMarko Zec break; 1568bd368728SMarko Zec 1569bd368728SMarko Zec case MOD_UNLOAD: 1570bd368728SMarko Zec delete_unrhdr(unr); 1571bd368728SMarko Zec break; 1572bd368728SMarko Zec } 1573bd368728SMarko Zec 1574bd368728SMarko Zec return (0); 1575bd368728SMarko Zec } 1576bd368728SMarko Zec 157710155347SJohn Baldwin DRIVER_MODULE(sume, pci, sume_driver, mod_event, NULL); 1578bd368728SMarko Zec MODULE_VERSION(sume, 1); 1579