// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* Authors: Bernard Metzler <[email protected]> */ /* Copyright (c) 2008-2019, IBM Corporation */ #include <linux/errno.h> #include <linux/types.h> #include <linux/net.h> #include <linux/scatterlist.h> #include <linux/highmem.h> #include <rdma/iw_cm.h> #include <rdma/ib_verbs.h> #include "siw.h" #include "siw_verbs.h" #include "siw_mem.h" /* * siw_rx_umem() * * Receive data of @len into target referenced by @dest_addr. * * @srx: Receive Context * @umem: siw representation of target memory * @dest_addr: user virtual address * @len: number of bytes to place */ static int siw_rx_umem(struct siw_rx_stream *srx, struct siw_umem *umem, u64 dest_addr, int len) { … } static int siw_rx_kva(struct siw_rx_stream *srx, void *kva, int len) { … } static int siw_rx_pbl(struct siw_rx_stream *srx, int *pbl_idx, struct siw_mem *mem, u64 addr, int len) { … } /* * siw_rresp_check_ntoh() * * Check incoming RRESP fragment header against expected * header values and update expected values for potential next * fragment. * * NOTE: This function must be called only if a RRESP DDP segment * starts but not for fragmented consecutive pieces of an * already started DDP segment. */ static int siw_rresp_check_ntoh(struct siw_rx_stream *srx, struct siw_rx_fpdu *frx) { … } /* * siw_write_check_ntoh() * * Check incoming WRITE fragment header against expected * header values and update expected values for potential next * fragment * * NOTE: This function must be called only if a WRITE DDP segment * starts but not for fragmented consecutive pieces of an * already started DDP segment. */ static int siw_write_check_ntoh(struct siw_rx_stream *srx, struct siw_rx_fpdu *frx) { … } /* * siw_send_check_ntoh() * * Check incoming SEND fragment header against expected * header values and update expected MSN if no next * fragment expected * * NOTE: This function must be called only if a SEND DDP segment * starts but not for fragmented consecutive pieces of an * already started DDP segment. */ static int siw_send_check_ntoh(struct siw_rx_stream *srx, struct siw_rx_fpdu *frx) { … } static struct siw_wqe *siw_rqe_get(struct siw_qp *qp) { … } static int siw_rx_data(struct siw_mem *mem_p, struct siw_rx_stream *srx, unsigned int *pbl_idx, u64 addr, int bytes) { … } /* * siw_proc_send: * * Process one incoming SEND and place data into memory referenced by * receive wqe. * * Function supports partially received sends (suspending/resuming * current receive wqe processing) * * return value: * 0: reached the end of a DDP segment * -EAGAIN: to be called again to finish the DDP segment */ int siw_proc_send(struct siw_qp *qp) { … } /* * siw_proc_write: * * Place incoming WRITE after referencing and checking target buffer * Function supports partially received WRITEs (suspending/resuming * current receive processing) * * return value: * 0: reached the end of a DDP segment * -EAGAIN: to be called again to finish the DDP segment */ int siw_proc_write(struct siw_qp *qp) { … } /* * Inbound RREQ's cannot carry user data. */ int siw_proc_rreq(struct siw_qp *qp) { … } /* * siw_init_rresp: * * Process inbound RDMA READ REQ. Produce a pseudo READ RESPONSE WQE. * Put it at the tail of the IRQ, if there is another WQE currently in * transmit processing. If not, make it the current WQE to be processed * and schedule transmit processing. * * Can be called from softirq context and from process * context (RREAD socket loopback case!) * * return value: * 0: success, * failure code otherwise */ static int siw_init_rresp(struct siw_qp *qp, struct siw_rx_stream *srx) { … } /* * Only called at start of Read.Resonse processing. * Transfer pending Read from tip of ORQ into currrent rx wqe, * but keep ORQ entry valid until Read.Response processing done. * No Queue locking needed. */ static int siw_orqe_start_rx(struct siw_qp *qp) { … } /* * siw_proc_rresp: * * Place incoming RRESP data into memory referenced by RREQ WQE * which is at the tip of the ORQ * * Function supports partially received RRESP's (suspending/resuming * current receive processing) */ int siw_proc_rresp(struct siw_qp *qp) { … } static void siw_update_skb_rcvd(struct siw_rx_stream *srx, u16 length) { … } int siw_proc_terminate(struct siw_qp *qp) { … } static int siw_get_trailer(struct siw_qp *qp, struct siw_rx_stream *srx) { … } #define MIN_DDP_HDR … static int siw_get_hdr(struct siw_rx_stream *srx) { … } static int siw_check_tx_fence(struct siw_qp *qp) { … } /* * siw_rdmap_complete() * * Complete processing of an RDMA message after receiving all * DDP segmens or ABort processing after encountering error case. * * o SENDs + RRESPs will need for completion, * o RREQs need for READ RESPONSE initialization * o WRITEs need memory dereferencing * * TODO: Failed WRITEs need local error to be surfaced. */ static int siw_rdmap_complete(struct siw_qp *qp, int error) { … } /* * siw_tcp_rx_data() * * Main routine to consume inbound TCP payload * * @rd_desc: read descriptor * @skb: socket buffer * @off: offset in skb * @len: skb->len - offset : payload in skb */ int siw_tcp_rx_data(read_descriptor_t *rd_desc, struct sk_buff *skb, unsigned int off, size_t len) { … }