static int mlx5_ib_query_device()

in hw/mlx5/main.c [799:1205]


static int mlx5_ib_query_device(struct ib_device *ibdev,
				struct ib_device_attr *props,
				struct ib_udata *uhw)
{
	size_t uhw_outlen = (uhw) ? uhw->outlen : 0;
	struct mlx5_ib_dev *dev = to_mdev(ibdev);
	struct mlx5_core_dev *mdev = dev->mdev;
	int err = -ENOMEM;
	int max_sq_desc;
	int max_rq_sg;
	int max_sq_sg;
	u64 min_page_size = 1ull << MLX5_CAP_GEN(mdev, log_pg_sz);
	bool raw_support = !mlx5_core_mp_enabled(mdev);
	struct mlx5_ib_query_device_resp resp = {};
	size_t resp_len;
	u64 max_tso;

	resp_len = sizeof(resp.comp_mask) + sizeof(resp.response_length);
	if (uhw_outlen && uhw_outlen < resp_len)
		return -EINVAL;

	resp.response_length = resp_len;

	if (uhw && uhw->inlen && !ib_is_udata_cleared(uhw, 0, uhw->inlen))
		return -EINVAL;

	memset(props, 0, sizeof(*props));
	err = mlx5_query_system_image_guid(ibdev,
					   &props->sys_image_guid);
	if (err)
		return err;

	props->max_pkeys = dev->pkey_table_len;

	err = mlx5_query_vendor_id(ibdev, &props->vendor_id);
	if (err)
		return err;

	props->fw_ver = ((u64)fw_rev_maj(dev->mdev) << 32) |
		(fw_rev_min(dev->mdev) << 16) |
		fw_rev_sub(dev->mdev);
	props->device_cap_flags    = IB_DEVICE_CHANGE_PHY_PORT |
		IB_DEVICE_PORT_ACTIVE_EVENT		|
		IB_DEVICE_SYS_IMAGE_GUID		|
		IB_DEVICE_RC_RNR_NAK_GEN;

	if (MLX5_CAP_GEN(mdev, pkv))
		props->device_cap_flags |= IB_DEVICE_BAD_PKEY_CNTR;
	if (MLX5_CAP_GEN(mdev, qkv))
		props->device_cap_flags |= IB_DEVICE_BAD_QKEY_CNTR;
	if (MLX5_CAP_GEN(mdev, apm))
		props->device_cap_flags |= IB_DEVICE_AUTO_PATH_MIG;
	if (MLX5_CAP_GEN(mdev, xrc))
		props->device_cap_flags |= IB_DEVICE_XRC;
	if (MLX5_CAP_GEN(mdev, imaicl)) {
		props->device_cap_flags |= IB_DEVICE_MEM_WINDOW |
					   IB_DEVICE_MEM_WINDOW_TYPE_2B;
		props->max_mw = 1 << MLX5_CAP_GEN(mdev, log_max_mkey);
		/* We support 'Gappy' memory registration too */
		props->device_cap_flags |= IB_DEVICE_SG_GAPS_REG;
	}
	/* IB_WR_REG_MR always requires changing the entity size with UMR */
	if (!MLX5_CAP_GEN(dev->mdev, umr_modify_entity_size_disabled))
		props->device_cap_flags |= IB_DEVICE_MEM_MGT_EXTENSIONS;
	if (MLX5_CAP_GEN(mdev, sho)) {
		props->device_cap_flags |= IB_DEVICE_INTEGRITY_HANDOVER;
		/* At this stage no support for signature handover */
		props->sig_prot_cap = IB_PROT_T10DIF_TYPE_1 |
				      IB_PROT_T10DIF_TYPE_2 |
				      IB_PROT_T10DIF_TYPE_3;
		props->sig_guard_cap = IB_GUARD_T10DIF_CRC |
				       IB_GUARD_T10DIF_CSUM;
	}
	if (MLX5_CAP_GEN(mdev, block_lb_mc))
		props->device_cap_flags |= IB_DEVICE_BLOCK_MULTICAST_LOOPBACK;

	if (MLX5_CAP_GEN(dev->mdev, eth_net_offloads) && raw_support) {
		if (MLX5_CAP_ETH(mdev, csum_cap)) {
			/* Legacy bit to support old userspace libraries */
			props->device_cap_flags |= IB_DEVICE_RAW_IP_CSUM;
			props->raw_packet_caps |= IB_RAW_PACKET_CAP_IP_CSUM;
		}

		if (MLX5_CAP_ETH(dev->mdev, vlan_cap))
			props->raw_packet_caps |=
				IB_RAW_PACKET_CAP_CVLAN_STRIPPING;

		if (offsetofend(typeof(resp), tso_caps) <= uhw_outlen) {
			max_tso = MLX5_CAP_ETH(mdev, max_lso_cap);
			if (max_tso) {
				resp.tso_caps.max_tso = 1 << max_tso;
				resp.tso_caps.supported_qpts |=
					1 << IB_QPT_RAW_PACKET;
				resp.response_length += sizeof(resp.tso_caps);
			}
		}

		if (offsetofend(typeof(resp), rss_caps) <= uhw_outlen) {
			resp.rss_caps.rx_hash_function =
						MLX5_RX_HASH_FUNC_TOEPLITZ;
			resp.rss_caps.rx_hash_fields_mask =
						MLX5_RX_HASH_SRC_IPV4 |
						MLX5_RX_HASH_DST_IPV4 |
						MLX5_RX_HASH_SRC_IPV6 |
						MLX5_RX_HASH_DST_IPV6 |
						MLX5_RX_HASH_SRC_PORT_TCP |
						MLX5_RX_HASH_DST_PORT_TCP |
						MLX5_RX_HASH_SRC_PORT_UDP |
						MLX5_RX_HASH_DST_PORT_UDP |
						MLX5_RX_HASH_INNER;
			if (mlx5_accel_ipsec_device_caps(dev->mdev) &
			    MLX5_ACCEL_IPSEC_CAP_DEVICE)
				resp.rss_caps.rx_hash_fields_mask |=
					MLX5_RX_HASH_IPSEC_SPI;
			resp.response_length += sizeof(resp.rss_caps);
		}
	} else {
		if (offsetofend(typeof(resp), tso_caps) <= uhw_outlen)
			resp.response_length += sizeof(resp.tso_caps);
		if (offsetofend(typeof(resp), rss_caps) <= uhw_outlen)
			resp.response_length += sizeof(resp.rss_caps);
	}

	if (MLX5_CAP_GEN(mdev, ipoib_basic_offloads)) {
		props->device_cap_flags |= IB_DEVICE_UD_IP_CSUM;
		props->device_cap_flags |= IB_DEVICE_UD_TSO;
	}

	if (MLX5_CAP_GEN(dev->mdev, rq_delay_drop) &&
	    MLX5_CAP_GEN(dev->mdev, general_notification_event) &&
	    raw_support)
		props->raw_packet_caps |= IB_RAW_PACKET_CAP_DELAY_DROP;

	if (MLX5_CAP_GEN(mdev, ipoib_enhanced_offloads) &&
	    MLX5_CAP_IPOIB_ENHANCED(mdev, csum_cap))
		props->device_cap_flags |= IB_DEVICE_UD_IP_CSUM;

	if (MLX5_CAP_GEN(dev->mdev, eth_net_offloads) &&
	    MLX5_CAP_ETH(dev->mdev, scatter_fcs) &&
	    raw_support) {
		/* Legacy bit to support old userspace libraries */
		props->device_cap_flags |= IB_DEVICE_RAW_SCATTER_FCS;
		props->raw_packet_caps |= IB_RAW_PACKET_CAP_SCATTER_FCS;
	}

	if (MLX5_CAP_DEV_MEM(mdev, memic)) {
		props->max_dm_size =
			MLX5_CAP_DEV_MEM(mdev, max_memic_size);
	}

	if (mlx5_get_flow_namespace(dev->mdev, MLX5_FLOW_NAMESPACE_BYPASS))
		props->device_cap_flags |= IB_DEVICE_MANAGED_FLOW_STEERING;

	if (MLX5_CAP_GEN(mdev, end_pad))
		props->device_cap_flags |= IB_DEVICE_PCI_WRITE_END_PADDING;

	props->vendor_part_id	   = mdev->pdev->device;
	props->hw_ver		   = mdev->pdev->revision;

	props->max_mr_size	   = ~0ull;
	props->page_size_cap	   = ~(min_page_size - 1);
	props->max_qp		   = 1 << MLX5_CAP_GEN(mdev, log_max_qp);
	props->max_qp_wr	   = 1 << MLX5_CAP_GEN(mdev, log_max_qp_sz);
	max_rq_sg =  MLX5_CAP_GEN(mdev, max_wqe_sz_rq) /
		     sizeof(struct mlx5_wqe_data_seg);
	max_sq_desc = min_t(int, MLX5_CAP_GEN(mdev, max_wqe_sz_sq), 512);
	max_sq_sg = (max_sq_desc - sizeof(struct mlx5_wqe_ctrl_seg) -
		     sizeof(struct mlx5_wqe_raddr_seg)) /
		sizeof(struct mlx5_wqe_data_seg);
	props->max_send_sge = max_sq_sg;
	props->max_recv_sge = max_rq_sg;
	props->max_sge_rd	   = MLX5_MAX_SGE_RD;
	props->max_cq		   = 1 << MLX5_CAP_GEN(mdev, log_max_cq);
	props->max_cqe = (1 << MLX5_CAP_GEN(mdev, log_max_cq_sz)) - 1;
	props->max_mr		   = 1 << MLX5_CAP_GEN(mdev, log_max_mkey);
	props->max_pd		   = 1 << MLX5_CAP_GEN(mdev, log_max_pd);
	props->max_qp_rd_atom	   = 1 << MLX5_CAP_GEN(mdev, log_max_ra_req_qp);
	props->max_qp_init_rd_atom = 1 << MLX5_CAP_GEN(mdev, log_max_ra_res_qp);
	props->max_srq		   = 1 << MLX5_CAP_GEN(mdev, log_max_srq);
	props->max_srq_wr = (1 << MLX5_CAP_GEN(mdev, log_max_srq_sz)) - 1;
	props->local_ca_ack_delay  = MLX5_CAP_GEN(mdev, local_ca_ack_delay);
	props->max_res_rd_atom	   = props->max_qp_rd_atom * props->max_qp;
	props->max_srq_sge	   = max_rq_sg - 1;
	props->max_fast_reg_page_list_len =
		1 << MLX5_CAP_GEN(mdev, log_max_klm_list_size);
	props->max_pi_fast_reg_page_list_len =
		props->max_fast_reg_page_list_len / 2;
	props->max_sgl_rd =
		MLX5_CAP_GEN(mdev, max_sgl_for_optimized_performance);
	get_atomic_caps_qp(dev, props);
	props->masked_atomic_cap   = IB_ATOMIC_NONE;
	props->max_mcast_grp	   = 1 << MLX5_CAP_GEN(mdev, log_max_mcg);
	props->max_mcast_qp_attach = MLX5_CAP_GEN(mdev, max_qp_mcg);
	props->max_total_mcast_qp_attach = props->max_mcast_qp_attach *
					   props->max_mcast_grp;
	props->max_ah = INT_MAX;
	props->hca_core_clock = MLX5_CAP_GEN(mdev, device_frequency_khz);
	props->timestamp_mask = 0x7FFFFFFFFFFFFFFFULL;

	if (IS_ENABLED(CONFIG_INFINIBAND_ON_DEMAND_PAGING)) {
		if (dev->odp_caps.general_caps & IB_ODP_SUPPORT)
			props->device_cap_flags |= IB_DEVICE_ON_DEMAND_PAGING;
		props->odp_caps = dev->odp_caps;
		if (!uhw) {
			/* ODP for kernel QPs is not implemented for receive
			 * WQEs and SRQ WQEs
			 */
			props->odp_caps.per_transport_caps.rc_odp_caps &=
				~(IB_ODP_SUPPORT_READ |
				  IB_ODP_SUPPORT_SRQ_RECV);
			props->odp_caps.per_transport_caps.uc_odp_caps &=
				~(IB_ODP_SUPPORT_READ |
				  IB_ODP_SUPPORT_SRQ_RECV);
			props->odp_caps.per_transport_caps.ud_odp_caps &=
				~(IB_ODP_SUPPORT_READ |
				  IB_ODP_SUPPORT_SRQ_RECV);
			props->odp_caps.per_transport_caps.xrc_odp_caps &=
				~(IB_ODP_SUPPORT_READ |
				  IB_ODP_SUPPORT_SRQ_RECV);
		}
	}

	if (MLX5_CAP_GEN(mdev, cd))
		props->device_cap_flags |= IB_DEVICE_CROSS_CHANNEL;

	if (mlx5_core_is_vf(mdev))
		props->device_cap_flags |= IB_DEVICE_VIRTUAL_FUNCTION;

	if (mlx5_ib_port_link_layer(ibdev, 1) ==
	    IB_LINK_LAYER_ETHERNET && raw_support) {
		props->rss_caps.max_rwq_indirection_tables =
			1 << MLX5_CAP_GEN(dev->mdev, log_max_rqt);
		props->rss_caps.max_rwq_indirection_table_size =
			1 << MLX5_CAP_GEN(dev->mdev, log_max_rqt_size);
		props->rss_caps.supported_qpts = 1 << IB_QPT_RAW_PACKET;
		props->max_wq_type_rq =
			1 << MLX5_CAP_GEN(dev->mdev, log_max_rq);
	}

	if (MLX5_CAP_GEN(mdev, tag_matching)) {
		props->tm_caps.max_num_tags =
			(1 << MLX5_CAP_GEN(mdev, log_tag_matching_list_sz)) - 1;
		props->tm_caps.max_ops =
			1 << MLX5_CAP_GEN(mdev, log_max_qp_sz);
		props->tm_caps.max_sge = MLX5_TM_MAX_SGE;
	}

	if (MLX5_CAP_GEN(mdev, tag_matching) &&
	    MLX5_CAP_GEN(mdev, rndv_offload_rc)) {
		props->tm_caps.flags = IB_TM_CAP_RNDV_RC;
		props->tm_caps.max_rndv_hdr_size = MLX5_TM_MAX_RNDV_MSG_SIZE;
	}

	if (MLX5_CAP_GEN(dev->mdev, cq_moderation)) {
		props->cq_caps.max_cq_moderation_count =
						MLX5_MAX_CQ_COUNT;
		props->cq_caps.max_cq_moderation_period =
						MLX5_MAX_CQ_PERIOD;
	}

	if (offsetofend(typeof(resp), cqe_comp_caps) <= uhw_outlen) {
		resp.response_length += sizeof(resp.cqe_comp_caps);

		if (MLX5_CAP_GEN(dev->mdev, cqe_compression)) {
			resp.cqe_comp_caps.max_num =
				MLX5_CAP_GEN(dev->mdev,
					     cqe_compression_max_num);

			resp.cqe_comp_caps.supported_format =
				MLX5_IB_CQE_RES_FORMAT_HASH |
				MLX5_IB_CQE_RES_FORMAT_CSUM;

			if (MLX5_CAP_GEN(dev->mdev, mini_cqe_resp_stride_index))
				resp.cqe_comp_caps.supported_format |=
					MLX5_IB_CQE_RES_FORMAT_CSUM_STRIDX;
		}
	}

	if (offsetofend(typeof(resp), packet_pacing_caps) <= uhw_outlen &&
	    raw_support) {
		if (MLX5_CAP_QOS(mdev, packet_pacing) &&
		    MLX5_CAP_GEN(mdev, qos)) {
			resp.packet_pacing_caps.qp_rate_limit_max =
				MLX5_CAP_QOS(mdev, packet_pacing_max_rate);
			resp.packet_pacing_caps.qp_rate_limit_min =
				MLX5_CAP_QOS(mdev, packet_pacing_min_rate);
			resp.packet_pacing_caps.supported_qpts |=
				1 << IB_QPT_RAW_PACKET;
			if (MLX5_CAP_QOS(mdev, packet_pacing_burst_bound) &&
			    MLX5_CAP_QOS(mdev, packet_pacing_typical_size))
				resp.packet_pacing_caps.cap_flags |=
					MLX5_IB_PP_SUPPORT_BURST;
		}
		resp.response_length += sizeof(resp.packet_pacing_caps);
	}

	if (offsetofend(typeof(resp), mlx5_ib_support_multi_pkt_send_wqes) <=
	    uhw_outlen) {
		if (MLX5_CAP_ETH(mdev, multi_pkt_send_wqe))
			resp.mlx5_ib_support_multi_pkt_send_wqes =
				MLX5_IB_ALLOW_MPW;

		if (MLX5_CAP_ETH(mdev, enhanced_multi_pkt_send_wqe))
			resp.mlx5_ib_support_multi_pkt_send_wqes |=
				MLX5_IB_SUPPORT_EMPW;

		resp.response_length +=
			sizeof(resp.mlx5_ib_support_multi_pkt_send_wqes);
	}

	if (offsetofend(typeof(resp), flags) <= uhw_outlen) {
		resp.response_length += sizeof(resp.flags);

		if (MLX5_CAP_GEN(mdev, cqe_compression_128))
			resp.flags |=
				MLX5_IB_QUERY_DEV_RESP_FLAGS_CQE_128B_COMP;

		if (MLX5_CAP_GEN(mdev, cqe_128_always))
			resp.flags |= MLX5_IB_QUERY_DEV_RESP_FLAGS_CQE_128B_PAD;
		if (MLX5_CAP_GEN(mdev, qp_packet_based))
			resp.flags |=
				MLX5_IB_QUERY_DEV_RESP_PACKET_BASED_CREDIT_MODE;

		resp.flags |= MLX5_IB_QUERY_DEV_RESP_FLAGS_SCAT2CQE_DCT;
	}

	if (offsetofend(typeof(resp), sw_parsing_caps) <= uhw_outlen) {
		resp.response_length += sizeof(resp.sw_parsing_caps);
		if (MLX5_CAP_ETH(mdev, swp)) {
			resp.sw_parsing_caps.sw_parsing_offloads |=
				MLX5_IB_SW_PARSING;

			if (MLX5_CAP_ETH(mdev, swp_csum))
				resp.sw_parsing_caps.sw_parsing_offloads |=
					MLX5_IB_SW_PARSING_CSUM;

			if (MLX5_CAP_ETH(mdev, swp_lso))
				resp.sw_parsing_caps.sw_parsing_offloads |=
					MLX5_IB_SW_PARSING_LSO;

			if (resp.sw_parsing_caps.sw_parsing_offloads)
				resp.sw_parsing_caps.supported_qpts =
					BIT(IB_QPT_RAW_PACKET);
		}
	}

	if (offsetofend(typeof(resp), striding_rq_caps) <= uhw_outlen &&
	    raw_support) {
		resp.response_length += sizeof(resp.striding_rq_caps);
		if (MLX5_CAP_GEN(mdev, striding_rq)) {
			resp.striding_rq_caps.min_single_stride_log_num_of_bytes =
				MLX5_MIN_SINGLE_STRIDE_LOG_NUM_BYTES;
			resp.striding_rq_caps.max_single_stride_log_num_of_bytes =
				MLX5_MAX_SINGLE_STRIDE_LOG_NUM_BYTES;
			if (MLX5_CAP_GEN(dev->mdev, ext_stride_num_range))
				resp.striding_rq_caps
					.min_single_wqe_log_num_of_strides =
					MLX5_EXT_MIN_SINGLE_WQE_LOG_NUM_STRIDES;
			else
				resp.striding_rq_caps
					.min_single_wqe_log_num_of_strides =
					MLX5_MIN_SINGLE_WQE_LOG_NUM_STRIDES;
			resp.striding_rq_caps.max_single_wqe_log_num_of_strides =
				MLX5_MAX_SINGLE_WQE_LOG_NUM_STRIDES;
			resp.striding_rq_caps.supported_qpts =
				BIT(IB_QPT_RAW_PACKET);
		}
	}

	if (offsetofend(typeof(resp), tunnel_offloads_caps) <= uhw_outlen) {
		resp.response_length += sizeof(resp.tunnel_offloads_caps);
		if (MLX5_CAP_ETH(mdev, tunnel_stateless_vxlan))
			resp.tunnel_offloads_caps |=
				MLX5_IB_TUNNELED_OFFLOADS_VXLAN;
		if (MLX5_CAP_ETH(mdev, tunnel_stateless_geneve_rx))
			resp.tunnel_offloads_caps |=
				MLX5_IB_TUNNELED_OFFLOADS_GENEVE;
		if (MLX5_CAP_ETH(mdev, tunnel_stateless_gre))
			resp.tunnel_offloads_caps |=
				MLX5_IB_TUNNELED_OFFLOADS_GRE;
		if (MLX5_CAP_ETH(mdev, tunnel_stateless_mpls_over_gre))
			resp.tunnel_offloads_caps |=
				MLX5_IB_TUNNELED_OFFLOADS_MPLS_GRE;
		if (MLX5_CAP_ETH(mdev, tunnel_stateless_mpls_over_udp))
			resp.tunnel_offloads_caps |=
				MLX5_IB_TUNNELED_OFFLOADS_MPLS_UDP;
	}

	if (offsetofend(typeof(resp), dci_streams_caps) <= uhw_outlen) {
		resp.response_length += sizeof(resp.dci_streams_caps);

		resp.dci_streams_caps.max_log_num_concurent =
			MLX5_CAP_GEN(mdev, log_max_dci_stream_channels);

		resp.dci_streams_caps.max_log_num_errored =
			MLX5_CAP_GEN(mdev, log_max_dci_errored_streams);
	}

	if (uhw_outlen) {
		err = ib_copy_to_udata(uhw, &resp, resp.response_length);

		if (err)
			return err;
	}

	return 0;
}