#ifndef _HFI1_USER_SDMA_H #define _HFI1_USER_SDMA_H /* * Copyright(c) 2015 - 2017 Intel Corporation. * * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. * * GPL LICENSE SUMMARY * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * BSD LICENSE * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * - 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. * - Neither the name of Intel Corporation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * 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. * */ #include #include #include "common.h" #include "iowait.h" #include "user_exp_rcv.h" /* The maximum number of Data io vectors per message/request */ #define MAX_VECTORS_PER_REQ 8 /* * Maximum number of packet to send from each message/request * before moving to the next one. */ #define MAX_PKTS_PER_QUEUE 16 #define num_pages(x) (1 + ((((x) - 1) & PAGE_MASK) >> PAGE_SHIFT)) #define req_opcode(x) \ (((x) >> HFI1_SDMA_REQ_OPCODE_SHIFT) & HFI1_SDMA_REQ_OPCODE_MASK) #define req_version(x) \ (((x) >> HFI1_SDMA_REQ_VERSION_SHIFT) & HFI1_SDMA_REQ_OPCODE_MASK) #define req_iovcnt(x) \ (((x) >> HFI1_SDMA_REQ_IOVCNT_SHIFT) & HFI1_SDMA_REQ_IOVCNT_MASK) /* Number of BTH.PSN bits used for sequence number in expected rcvs */ #define BTH_SEQ_MASK 0x7ffull #define AHG_KDETH_INTR_SHIFT 12 #define AHG_KDETH_SH_SHIFT 13 #define AHG_KDETH_ARRAY_SIZE 9 #define PBC2LRH(x) ((((x) & 0xfff) << 2) - 4) #define LRH2PBC(x) ((((x) >> 2) + 1) & 0xfff) #define AHG_HEADER_SET(arr, idx, dw, bit, width, value) \ do { \ if ((idx) < ARRAY_SIZE((arr))) \ (arr)[(idx++)] = sdma_build_ahg_descriptor( \ (__force u16)(value), (dw), (bit), \ (width)); \ else \ return -ERANGE; \ } while (0) /* Tx request flag bits */ #define TXREQ_FLAGS_REQ_ACK BIT(0) /* Set the ACK bit in the header */ #define TXREQ_FLAGS_REQ_DISABLE_SH BIT(1) /* Disable header suppression */ enum pkt_q_sdma_state { SDMA_PKT_Q_ACTIVE, SDMA_PKT_Q_DEFERRED, }; /* * Maximum retry attempts to submit a TX request * before putting the process to sleep. */ #define MAX_DEFER_RETRY_COUNT 1 #define SDMA_IOWAIT_TIMEOUT 1000 /* in milliseconds */ #define SDMA_DBG(req, fmt, ...) \ hfi1_cdbg(SDMA, "[%u:%u:%u:%u] " fmt, (req)->pq->dd->unit, \ (req)->pq->ctxt, (req)->pq->subctxt, (req)->info.comp_idx, \ ##__VA_ARGS__) extern uint extended_psn; struct hfi1_user_sdma_pkt_q { u16 ctxt; u16 subctxt; u16 n_max_reqs; atomic_t n_reqs; u16 reqidx; struct hfi1_devdata *dd; struct kmem_cache *txreq_cache; struct user_sdma_request *reqs; unsigned long *req_in_use; struct iowait busy; enum pkt_q_sdma_state state; wait_queue_head_t wait; unsigned long unpinned; struct mmu_rb_handler *handler; atomic_t n_locked; struct mm_struct *mm; }; struct hfi1_user_sdma_comp_q { u16 nentries; struct hfi1_sdma_comp_entry *comps; }; struct sdma_mmu_node { struct mmu_rb_node rb; struct hfi1_user_sdma_pkt_q *pq; atomic_t refcount; struct page **pages; unsigned int npages; }; struct user_sdma_iovec { struct list_head list; struct iovec iov; /* number of pages in this vector */ unsigned int npages; /* array of pinned pages for this vector */ struct page **pages; /* * offset into the virtual address space of the vector at * which we last left off. */ u64 offset; struct sdma_mmu_node *node; }; /* evict operation argument */ struct evict_data { u32 cleared; /* count evicted so far */ u32 target; /* target count to evict */ }; struct user_sdma_request { /* This is the original header from user space */ struct hfi1_pkt_header hdr; /* Read mostly fields */ struct hfi1_user_sdma_pkt_q *pq ____cacheline_aligned_in_smp; struct hfi1_user_sdma_comp_q *cq; /* * Pointer to the SDMA engine for this request. * Since different request could be on different VLs, * each request will need it's own engine pointer. */ struct sdma_engine *sde; struct sdma_req_info info; /* TID array values copied from the tid_iov vector */ u32 *tids; /* total length of the data in the request */ u32 data_len; /* number of elements copied to the tids array */ u16 n_tids; /* * We copy the iovs for this request (based on * info.iovcnt). These are only the data vectors */ u8 data_iovs; s8 ahg_idx; /* Writeable fields shared with interrupt */ u64 seqcomp ____cacheline_aligned_in_smp; u64 seqsubmitted; /* Send side fields */ struct list_head txps ____cacheline_aligned_in_smp; u64 seqnum; /* * KDETH.OFFSET (TID) field * The offset can cover multiple packets, depending on the * size of the TID entry. */ u32 tidoffset; /* * KDETH.Offset (Eager) field * We need to remember the initial value so the headers * can be updated properly. */ u32 koffset; u32 sent; /* TID index copied from the tid_iov vector */ u16 tididx; /* progress index moving along the iovs array */ u8 iov_idx; u8 has_error; struct user_sdma_iovec iovs[MAX_VECTORS_PER_REQ]; } ____cacheline_aligned_in_smp; /* * A single txreq could span up to 3 physical pages when the MTU * is sufficiently large (> 4K). Each of the IOV pointers also * needs it's own set of flags so the vector has been handled * independently of each other. */ struct user_sdma_txreq { /* Packet header for the txreq */ struct hfi1_pkt_header hdr; struct sdma_txreq txreq; struct list_head list; struct user_sdma_request *req; u16 flags; u64 seqnum; }; int hfi1_user_sdma_alloc_queues(struct hfi1_ctxtdata *uctxt, struct hfi1_filedata *fd); int hfi1_user_sdma_free_queues(struct hfi1_filedata *fd, struct hfi1_ctxtdata *uctxt); int hfi1_user_sdma_process_request(struct hfi1_filedata *fd, struct iovec *iovec, unsigned long dim, unsigned long *count); #endif /* _HFI1_USER_SDMA_H */