/* * Copyright (c) 2014, Cisco Systems, Inc. All rights reserved. * * LICENSE_BEGIN * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU * General Public License (GPL) Version 2, available from the file * COPYING in the main directory of this source tree, or the * BSD license below: * * 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. * * 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 HOLDER 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. * * LICENSE_END * * */ #ifndef _USNIC_DIRECT_H_ #define _USNIC_DIRECT_H_ #include #include #include #include #include #include #define USD_MAX_DEVICES 8 #define USD_MAX_DEVNAME 16 #define USD_RECV_MAX_SGE 8 #define USD_SEND_MAX_SGE 8 enum usd_link_state { USD_LINK_DOWN, USD_LINK_UP }; /* forward structure defs */ struct usd_context; struct usd_qp; struct usd_device; struct usd_dest; struct usd_connection; struct usd_mr; struct usd_device_attrs { char uda_devname[USD_MAX_DEVNAME]; char uda_ifname[IFNAMSIZ]; int uda_ifindex; uint8_t uda_mac_addr[ETH_ALEN]; /* IP config */ uint32_t uda_ipaddr_be; uint32_t uda_netmask_be; uint32_t uda_prefixlen; /* netmask length */ uint32_t uda_mtu; enum usd_link_state uda_link_state; /* HW info */ uint32_t uda_vendor_id; uint32_t uda_vendor_part_id; uint32_t uda_device_id; char uda_firmware[64]; /* usnic config */ unsigned uda_num_vf; unsigned uda_cq_per_vf; unsigned uda_qp_per_vf; unsigned uda_intr_per_vf; unsigned uda_num_comp_vectors; unsigned uda_max_cq; unsigned uda_max_qp; /* VIC constants */ uint32_t uda_bandwidth; unsigned uda_max_cqe; unsigned uda_max_send_credits; unsigned uda_max_recv_credits; /* fd that can be used to poll for device events */ int uda_event_fd; }; enum usd_completion_status { USD_COMPSTAT_SUCCESS, USD_COMPSTAT_ERROR_CRC, USD_COMPSTAT_ERROR_TRUNC, USD_COMPSTAT_ERROR_TIMEOUT, USD_COMPSTAT_ERROR_INTERNAL }; enum usd_completion_type { USD_COMPTYPE_SEND=0, USD_COMPTYPE_RECV=7, }; struct usd_completion { enum usd_completion_status uc_status; enum usd_completion_type uc_type; uint32_t uc_bytes; uint16_t uc_rkey; struct usd_qp *uc_qp; void *uc_context; u_int16_t uc_retrans; }; struct usd_recv_desc { void *urd_context; struct iovec urd_iov[USD_RECV_MAX_SGE]; size_t urd_iov_cnt; struct usd_recv_desc *urd_next; }; /* * Operations that may vary based on transport/QP type */ struct usd_qp_ops { int (*qo_post_send_one)(struct usd_qp *qp, struct usd_dest *dest, const void *buf, size_t len, uint32_t flags, void *context); int (*qo_post_send_one_prefixed)(struct usd_qp *qp, struct usd_dest *dest, const void *buf, size_t len, uint32_t flags, void *context); int (*qo_post_send_one_copy)(struct usd_qp *qp, struct usd_dest *dest, const void *buf, size_t len, uint32_t flags, void *context); int (*qo_post_send_two_copy)(struct usd_qp *qp, struct usd_dest *dest, const void *hdr, size_t hdrlen, const void *pkt, size_t pktlen, uint32_t flags, void *context); int (*qo_post_send_iov)(struct usd_qp *qp, struct usd_dest *dest, const struct iovec* iov, size_t iov_count, uint32_t flags, void *context); int (*qo_post_send_one_vlan)(struct usd_qp *qp, struct usd_dest *dest, const void *buf, size_t len, u_int16_t vlan, uint32_t flags, void *context); }; /* * user's view of a CQ */ struct usd_cq { unsigned ucq_num_entries; }; /* * User's view of a QP */ struct usd_qp { struct usd_qp_ops uq_ops; void *uq_context; /* place for user to scribble */ }; /* * Filters for QPs */ enum usd_filter_type { USD_FTY_UDP, USD_FTY_UDP_SOCK, USD_FTY_TCP, USD_FTY_MCAST, USD_FTY_8915 }; struct usd_filter { enum usd_filter_type uf_type; union { struct { uint16_t u_port; } uf_udp; struct { int u_sock; } uf_udp_sock; struct { int t_sock; struct sockaddr_in t_remote; } uf_tcp; struct { struct sockaddr_in m_addr; } uf_mcast; } uf_filter; }; /* * Local address - much like a filter * Type is defined by transport specified in create_qp */ struct usd_local_addr { union { struct { struct sockaddr_in u_addr; } ul_udp; struct { uint32_t qp_num; } ul_8915; } ul_addr; }; enum usd_qp_transport { USD_QTR_RAW, /* no header added */ USD_QTR_UDP /* create UDP header based on dest */ }; enum usd_qp_type { USD_QTY_UD, USD_QTY_UD_PIO, }; /* * Attributes of a queue pair */ struct usd_qp_attrs { enum usd_qp_transport uqa_transport; enum usd_qp_type uqa_qtype; struct usd_local_addr uqa_local_addr; unsigned uqa_max_send_credits; unsigned uqa_max_recv_credits; uint64_t uqa_pio_paddr; unsigned uqa_max_inline; unsigned uqa_hdr_len; /* length of header for this QP */ }; /* * Description of a device event which has occurred */ enum usd_device_event_type { USD_EVENT_LINK_UP, USD_EVENT_LINK_DOWN }; struct usd_device_event { union { void *ude_context; } ude_context; enum usd_device_event_type ude_type; }; /* * Returned form usd_get_available_devices() - array of currently * available usd device names */ struct usd_device_entry { char ude_devname[USD_MAX_DEVNAME]; }; /* * Send flags */ enum usd_send_flag_shift { USD_SFS_SIGNAL, }; #define USD_SF_SIGNAL (1 << USD_SFS_SIGNAL) /* * cq creation parameters */ struct usd_cq_init_attr { unsigned num_entries; /* number of requested cq elements */ int comp_fd; /* completion fd */ int comp_vec; /* requested completion vector */ int comp_req_notify; /* whether need to request notify for each completion */ void *ibv_cq; /* verbs userspace cq object if signaling through uverbs */ }; /* * Headers for defined transport types */ struct usd_udp_hdr { struct ether_header uh_eth; struct iphdr uh_ip; struct udphdr uh_udp; } __attribute__ ((__packed__)); /* * Struct and defines for usd open parameters */ #define UOPF_SKIP_LINK_CHECK 0x1 #define UOPF_SKIP_PD_ALLOC 0x2 struct usd_open_params { int flags; int cmd_fd; struct usd_context *context; }; /* **************************************************************** * Device management **************************************************************** */ int usd_get_device_list(struct usd_device_entry *dev_array, int *num_devs); int usd_open(const char *devname, struct usd_device **dev_o); int usd_open_with_params(const char *dev_name, struct usd_open_params *uop_param, struct usd_device **dev_o); int usd_close(struct usd_device *dev); int usd_get_device_attrs(struct usd_device *dev, struct usd_device_attrs *attr); int usd_get_device_event(struct usd_device *dev, struct usd_device_event *event); enum usd_capability { USD_CAP_CQ_SHARING, USD_CAP_MAP_PER_RES, USD_CAP_PIO, USD_CAP_CQ_INTR, USD_CAP_GRP_INTR, USD_CAP_MAX }; int usd_get_cap(struct usd_device *dev, enum usd_capability cap); /* **************************************************************** * Queue management **************************************************************** */ /* * Get a file descriptor which can be used to poll for completions. The * returned file descriptor will be different on each call to * usd_get_completion_fd, so that coordination is not needed when using these * fds in syscalls like poll(2). */ int usd_get_completion_fd(struct usd_device *dev, int *comp_fd_o); int usd_put_completion_fd(struct usd_device *dev, int comp_fd); /* * Request a CQ with specified attributes: * dev - device on which to create this CQ * init_attr - CQ creation parameters */ int usd_create_cq(struct usd_device *dev, struct usd_cq_init_attr *init_attr, struct usd_cq **cq_o); int usd_destroy_cq(struct usd_cq *cq); int usd_cq_intr_enable(struct usd_cq *cq); int usd_cq_intr_disable(struct usd_cq *cq); /* * Get and set interrupt coalescing delay, units are in microseconds */ int usd_cq_set_intr_coal(struct usd_cq *cq, unsigned intr_coal_delay); unsigned usd_cq_get_intr_coal(struct usd_cq *cq); /* * IN: * dev - device on which QP is to be created * transport - what transport to use on this queue * type - type of queue to create * wcq - CQ handle for send completions * rcq - CQ handle for receive completions * send_credits - Number of send credits requested * recv_credite - Number of receive buffer credits requested * port - Requested local port for QP (0 lets library choose) * qp_o - Address to receive QP handle on successful completion * OUT: * Returns 0 or code from errno.h * 0 - successful completion * EBUSY - port is in use * XXX */ int usd_create_qp(struct usd_device *dev, enum usd_qp_transport transport, enum usd_qp_type qtype, struct usd_cq *wcq, struct usd_cq *rcq, unsigned send_credits, unsigned recv_credits, struct usd_filter *filt, struct usd_qp **qp_o); int usd_destroy_qp(struct usd_qp *qp); int usd_enable_qp(struct usd_qp *qp); int usd_disable_qp(struct usd_qp *qp); int usd_get_qp_attrs(struct usd_qp *qp, struct usd_qp_attrs *qp_attrs_o); /* * Add a filter to a QP */ int usd_qp_add_filter(struct usd_qp *qp, struct usd_filter *filter); /* * Get current send credits */ unsigned usd_get_send_credits(struct usd_qp *uqp); /* * Get current recv credits */ unsigned usd_get_recv_credits(struct usd_qp *uqp); /* **************************************************************** * Memory management **************************************************************** */ int usd_reg_mr(struct usd_device *dev, void *buffer, size_t size, struct usd_mr **mr_o); int usd_dereg_mr(struct usd_mr *mr); int usd_alloc_mr(struct usd_device *dev, size_t size, void **vaddr_o); int usd_free_mr(void *vaddr); /* **************************************************************** * Destination management **************************************************************** */ /* * Return the distance metric to a specified IP address * Metric is: * 0 - same VLAN * 1..MAXINT - relative distance metric * -1 - unreachable */ int usd_get_dest_distance(struct usd_device *dev, uint32_t daddr_be, int *metric_o); /* * Settings for address resolution timeout and retry */ struct usd_dest_params { unsigned dp_arp_timeout; /* per-try timeout in ms */ unsigned dp_max_arps; }; /* * Get address resolution settings */ int usd_get_dest_params(struct usd_dest_params *params); /* * Set address resolution settings * Settings may not be changed while any resolution requests are in progress. */ int usd_set_dest_params(struct usd_dest_params *params); /* * Used to create a destination with MAC address is already known. */ int usd_create_dest_with_mac(struct usd_device *dev, uint32_t daddr_be, uint16_t port_be, uint8_t *dmac, struct usd_dest **dest_o); /* * Synchronously creates a destination */ int usd_create_dest(struct usd_device *dev, uint32_t daddr_be, uint16_t port_be, struct usd_dest **dest_o); /* * Start the necessary ARP resolution to create a destination * Resolution progress is performed in usd_create_dest_query() and * usd_create_dest_poll() */ int usd_create_dest_start(struct usd_device *dev, uint32_t daddr_be, uint16_t dport_be, void *context); /* * Cancel resolution on a not-yet-completed create_dest request */ int usd_create_dest_cancel(struct usd_device *dev, void *context); /* * Extract dest port and IP from a destination */ int usd_expand_dest(struct usd_dest *dest, uint32_t *dest_ip_be_o, uint16_t *dest_port_be_o); /* * Query completion status of a given create_dest request * If complete, newly allocated destination is returned in dest_o * Returns: * 0 - request completed, *status is valid * dest_o valid if *status == 0 * -EAGAIN - nothing is complete * other - negative errno code */ int usd_create_dest_query(struct usd_device *dev, void *context, int *status, struct usd_dest **dest_o); /* * Checks for completed destination creation. * context specified in call to usd_create_dest_start is returned, * newly allocated destination is returned in dest_o * Returns: * 0 - request completed, status and context_o valid * dest_o valid if *status == 0 * -EAGAIN - nothing is complete * other - negative errno code */ int usd_create_dest_poll(struct usd_device *dev, void **context_o, int *status, struct usd_dest **dest_o); int usd_destroy_dest(struct usd_dest *dest); /* **************************************************************** * Sending, receiving, and completions **************************************************************** */ /* * Post a receive. The number of receive credits consumed is equal * to the number of entries in the SG list of the recv_desc, or * recv_desc.urd_iov_cnt */ int usd_post_recv(struct usd_qp *qp, struct usd_recv_desc *recv_list); int usd_poll_cq_multi(struct usd_cq *cq, int max_comps, struct usd_completion *comps); int usd_poll_cq(struct usd_cq *cq, struct usd_completion *comp); int usd_poll_req_notify(struct usd_cq *ucq); unsigned usd_get_send_credits(struct usd_qp *qp); unsigned usd_get_recv_credits(struct usd_qp *qp); /* * post a single-buffer send from registered memory * IN: * qp * dest * buf - * Requires 2 send credits */ static inline int usd_post_send_one( struct usd_qp *qp, struct usd_dest *dest, const void *buf, size_t len, uint32_t flags, void *context) { return qp->uq_ops.qo_post_send_one( qp, dest, buf, len, flags, context); } /* * post a single-buffer send from registered memory to specified VLAN * IN: * qp * dest * buf - * Requires 2 send credits */ static inline int usd_post_send_one_vlan( struct usd_qp *qp, struct usd_dest *dest, const void *buf, size_t len, u_int16_t vlan, uint32_t flags, void *context) { return qp->uq_ops.qo_post_send_one_vlan( qp, dest, buf, len, vlan, flags, context); } /* * post a single-buffer send from registered memory * Caller must allow sufficient space *before* the packet for usd header * For optimal efficieny, the buffer should be aligned on XXX boundary * IN: * qp * dest * buf - * Requires 1 send credit */ static inline int usd_post_send_one_prefixed( struct usd_qp *qp, struct usd_dest *dest, const void *buf, size_t len, uint32_t flags, void *context) { return qp->uq_ops.qo_post_send_one_prefixed( qp, dest, buf, len, flags, context); } /* * post a single-buffer send from anywhere * Data is copied into registered memory by the lib for sending * IN: * qp * dest * buf - * len - number of bytes in buffer, must be less than max_inline for the QP * Requires 1 send credit */ static inline int usd_post_send_one_copy(struct usd_qp *qp, struct usd_dest *dest, const void *buf, size_t len, uint32_t flags, void *context) { return qp->uq_ops.qo_post_send_one_copy( qp, dest, buf, len, flags, context); } /* * post a two-buffer send, the first buffer is a usually a header and must * allow space *before* it for our header. * For optimal efficieny, the first buffer should be aligned XXX * Requires 2 send credits */ int usd_post_send_two_prefixed(struct usd_qp *qp, struct usd_dest *dest, const void *hdr, size_t hdr_len, const void *pkt, size_t pkt_len, uint32_t flags, void *context); /* * post a two-buffer send, the first buffer is a usually a header. * The header and the packet will be both be copied into registered * memory by usnic_direct and sent. * Requires 2 send credits */ static inline int usd_post_send_two_copy(struct usd_qp *qp, struct usd_dest *dest, const void *hdr, size_t hdrlen, const void *pkt, size_t pktlen, uint32_t flags, void *context) { return qp->uq_ops.qo_post_send_two_copy( qp, dest, hdr, hdrlen, pkt, pktlen, flags, context); } /* * Post an N-buffer send * All buffers must be in registered memory. * Requires iov_count + 1 send credits */ static inline int usd_post_send_iov(struct usd_qp *qp, struct usd_dest *dest, const struct iovec *iov, size_t iov_count, uint32_t flags, void *context) { return qp->uq_ops.qo_post_send_iov( qp, dest, iov, iov_count, flags, context); } /**************************************************************** * enum-to-string utility functions (for prettyprinting) ****************************************************************/ const char *usd_link_state_str(enum usd_link_state state); const char *usd_completion_status_str(enum usd_completion_status cstatus); const char *usd_completion_type_str(enum usd_completion_type ctype); const char *usd_filter_type_str(enum usd_filter_type ftype); const char *usd_qp_transport_str(enum usd_qp_transport qpt); const char *usd_qp_type_str(enum usd_qp_type); const char *usd_qp_event_event_type_str(enum usd_device_event_type det); const char *usd_send_flag_sift_str(enum usd_send_flag_shift sfs); const char *usd_capability(enum usd_capability cap); const char *usd_devid_to_nicname(uint32_t vendor_id, uint32_t device_id); const char *usd_devid_to_pid(uint32_t vendor_id, uint32_t device_id); /**************************************************************** * special API holes punched for implementing verbs ****************************************************************/ /* open a context, mapped to a verbs open_device call */ int usd_open_context(const char *dev_name, int cmd_fd, struct usd_context **ctx_o); int usd_close_context(struct usd_context *ctx); /* modify the destination UDP port in a usd_dest */ void usd_dest_set_udp_ports(struct usd_dest *dest, struct usd_qp *src_qp, uint16_t dest_port_be); /* create a dest with only IP addresses set */ int usd_create_ip_dest(struct usd_device *dev, uint32_t dest_ip_be, struct usd_dest **dest_o); #endif /* _USNIC_DIRECT_H_ */