Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/1182469/?format=api
{ "id": 1182469, "url": "http://patchwork.ozlabs.org/api/patches/1182469/?format=api", "web_url": "http://patchwork.ozlabs.org/project/intel-wired-lan/patch/20191023115501.41055-1-anthony.l.nguyen@intel.com/", "project": { "id": 46, "url": "http://patchwork.ozlabs.org/api/projects/46/?format=api", "name": "Intel Wired Ethernet development", "link_name": "intel-wired-lan", "list_id": "intel-wired-lan.osuosl.org", "list_email": "intel-wired-lan@osuosl.org", "web_url": "", "scm_url": "", "webscm_url": "", "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<20191023115501.41055-1-anthony.l.nguyen@intel.com>", "list_archive_url": null, "date": "2019-10-23T11:55:00", "name": "[v3,1/2] ice: Initialize and register multi-function device to provide RDMA", "commit_ref": null, "pull_url": null, "state": "changes-requested", "archived": false, "hash": "93bc802cf560f104df2c865865e411f766c781ca", "submitter": { "id": 68875, "url": "http://patchwork.ozlabs.org/api/people/68875/?format=api", "name": "Tony Nguyen", "email": "anthony.l.nguyen@intel.com" }, "delegate": { "id": 68, "url": "http://patchwork.ozlabs.org/api/users/68/?format=api", "username": "jtkirshe", "first_name": "Jeff", "last_name": "Kirsher", "email": "jeffrey.t.kirsher@intel.com" }, "mbox": "http://patchwork.ozlabs.org/project/intel-wired-lan/patch/20191023115501.41055-1-anthony.l.nguyen@intel.com/mbox/", "series": [ { "id": 138181, "url": "http://patchwork.ozlabs.org/api/series/138181/?format=api", "web_url": "http://patchwork.ozlabs.org/project/intel-wired-lan/list/?series=138181", "date": "2019-10-23T11:55:00", "name": "[v3,1/2] ice: Initialize and register multi-function device to provide RDMA", "version": 3, "mbox": "http://patchwork.ozlabs.org/series/138181/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/1182469/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/1182469/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "<intel-wired-lan-bounces@osuosl.org>", "X-Original-To": [ "incoming@patchwork.ozlabs.org", "intel-wired-lan@lists.osuosl.org" ], "Delivered-To": [ "patchwork-incoming@bilbo.ozlabs.org", "intel-wired-lan@lists.osuosl.org" ], "Authentication-Results": [ "ozlabs.org; spf=pass (sender SPF authorized)\n\tsmtp.mailfrom=osuosl.org (client-ip=140.211.166.137;\n\thelo=fraxinus.osuosl.org;\n\tenvelope-from=intel-wired-lan-bounces@osuosl.org;\n\treceiver=<UNKNOWN>)", "ozlabs.org;\n\tdmarc=fail (p=none dis=none) header.from=intel.com" ], "Received": [ "from fraxinus.osuosl.org (smtp4.osuosl.org [140.211.166.137])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256\n\tbits)) (No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 46z21w1Z0dz9sP6\n\tfor <incoming@patchwork.ozlabs.org>;\n\tThu, 24 Oct 2019 07:25:39 +1100 (AEDT)", "from localhost (localhost [127.0.0.1])\n\tby fraxinus.osuosl.org (Postfix) with ESMTP id 1ED4886599;\n\tWed, 23 Oct 2019 20:25:38 +0000 (UTC)", "from fraxinus.osuosl.org ([127.0.0.1])\n\tby localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)\n\twith ESMTP id fMs5DY_IM6Vo; Wed, 23 Oct 2019 20:25:34 +0000 (UTC)", "from ash.osuosl.org (ash.osuosl.org [140.211.166.34])\n\tby fraxinus.osuosl.org (Postfix) with ESMTP id 8C01386447;\n\tWed, 23 Oct 2019 20:25:34 +0000 (UTC)", "from silver.osuosl.org (smtp3.osuosl.org [140.211.166.136])\n\tby ash.osuosl.org (Postfix) with ESMTP id F3D671BF5A5\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tWed, 23 Oct 2019 20:25:32 +0000 (UTC)", "from localhost (localhost [127.0.0.1])\n\tby silver.osuosl.org (Postfix) with ESMTP id E12F822C6B\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tWed, 23 Oct 2019 20:25:32 +0000 (UTC)", "from silver.osuosl.org ([127.0.0.1])\n\tby localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)\n\twith ESMTP id wrwioD5w6Gwr for <intel-wired-lan@lists.osuosl.org>;\n\tWed, 23 Oct 2019 20:25:29 +0000 (UTC)", "from mga04.intel.com (mga04.intel.com [192.55.52.120])\n\tby silver.osuosl.org (Postfix) with ESMTPS id ED76C1FE0A\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tWed, 23 Oct 2019 20:25:28 +0000 (UTC)", "from fmsmga002.fm.intel.com ([10.253.24.26])\n\tby fmsmga104.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384;\n\t23 Oct 2019 13:25:28 -0700", "from unknown (HELO localhost.jf.intel.com) ([10.166.244.174])\n\tby fmsmga002.fm.intel.com with ESMTP; 23 Oct 2019 13:25:28 -0700" ], "X-Virus-Scanned": [ "amavisd-new at osuosl.org", "amavisd-new at osuosl.org" ], "X-Greylist": "domain auto-whitelisted by SQLgrey-1.7.6", "X-Amp-Result": "SKIPPED(no attachment in message)", "X-Amp-File-Uploaded": "False", "X-ExtLoop1": "1", "X-IronPort-AV": "E=Sophos;i=\"5.68,222,1569308400\"; d=\"scan'208\";a=\"228253694\"", "From": "Tony Nguyen <anthony.l.nguyen@intel.com>", "To": "intel-wired-lan@lists.osuosl.org", "Date": "Wed, 23 Oct 2019 04:55:00 -0700", "Message-Id": "<20191023115501.41055-1-anthony.l.nguyen@intel.com>", "X-Mailer": "git-send-email 2.20.1", "MIME-Version": "1.0", "Subject": "[Intel-wired-lan] [PATCH v3 1/2] ice: Initialize and register\n\tmulti-function device to provide RDMA", "X-BeenThere": "intel-wired-lan@osuosl.org", "X-Mailman-Version": "2.1.29", "Precedence": "list", "List-Id": "Intel Wired Ethernet Linux Kernel Driver Development\n\t<intel-wired-lan.osuosl.org>", "List-Unsubscribe": "<https://lists.osuosl.org/mailman/options/intel-wired-lan>, \n\t<mailto:intel-wired-lan-request@osuosl.org?subject=unsubscribe>", "List-Archive": "<http://lists.osuosl.org/pipermail/intel-wired-lan/>", "List-Post": "<mailto:intel-wired-lan@osuosl.org>", "List-Help": "<mailto:intel-wired-lan-request@osuosl.org?subject=help>", "List-Subscribe": "<https://lists.osuosl.org/mailman/listinfo/intel-wired-lan>, \n\t<mailto:intel-wired-lan-request@osuosl.org?subject=subscribe>", "Content-Type": "text/plain; charset=\"us-ascii\"", "Content-Transfer-Encoding": "7bit", "Errors-To": "intel-wired-lan-bounces@osuosl.org", "Sender": "\"Intel-wired-lan\" <intel-wired-lan-bounces@osuosl.org>" }, "content": "The RDMA block does not have its own PCI function, instead it must utilize\nthe ice driver to gain access to the PCI device. Create an MFD device\nfor the RDMA driver to bind to the device data. The device data contains\nall of the relevant information that the IRDMA peer will need to access\nthis PF's IIDC API callbacks.\n\nNote the header file iidc.h is located under include/linux/net/intel\nas this is a unified header file to be used by all consumers of the\nIIDC interface.\n\nSigned-off-by: Dave Ertman <david.m.ertman@intel.com>\nSigned-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>\n---\nv2:\n- Remove version information\n- Change peer device name to \"ice_rdma\"\n---\n MAINTAINERS | 1 +\n drivers/net/ethernet/intel/Kconfig | 1 +\n drivers/net/ethernet/intel/ice/Makefile | 1 +\n drivers/net/ethernet/intel/ice/ice.h | 16 +\n .../net/ethernet/intel/ice/ice_adminq_cmd.h | 1 +\n drivers/net/ethernet/intel/ice/ice_common.c | 5 +\n drivers/net/ethernet/intel/ice/ice_dcb_lib.c | 31 ++\n drivers/net/ethernet/intel/ice/ice_dcb_lib.h | 3 +\n .../net/ethernet/intel/ice/ice_hw_autogen.h | 1 +\n drivers/net/ethernet/intel/ice/ice_idc.c | 440 ++++++++++++++++++\n drivers/net/ethernet/intel/ice/ice_idc_int.h | 81 ++++\n drivers/net/ethernet/intel/ice/ice_lib.c | 11 +\n drivers/net/ethernet/intel/ice/ice_lib.h | 2 +-\n drivers/net/ethernet/intel/ice/ice_main.c | 70 ++-\n drivers/net/ethernet/intel/ice/ice_type.h | 1 +\n include/linux/net/intel/iidc.h | 334 +++++++++++++\n 16 files changed, 996 insertions(+), 3 deletions(-)\n create mode 100644 drivers/net/ethernet/intel/ice/ice_idc.c\n create mode 100644 drivers/net/ethernet/intel/ice/ice_idc_int.h\n create mode 100644 include/linux/net/intel/iidc.h", "diff": "diff --git a/MAINTAINERS b/MAINTAINERS\nindex aaa6ee71c000..9a4482890c61 100644\n--- a/MAINTAINERS\n+++ b/MAINTAINERS\n@@ -8234,6 +8234,7 @@ F:\tDocumentation/networking/device_drivers/intel/ice.rst\n F:\tdrivers/net/ethernet/intel/\n F:\tdrivers/net/ethernet/intel/*/\n F:\tinclude/linux/avf/virtchnl.h\n+F:\tinclude/linux/net/intel/iidc.h\n \n INTEL FRAMEBUFFER DRIVER (excluding 810 and 815)\n M:\tMaik Broemme <mbroemme@libmpq.org>\ndiff --git a/drivers/net/ethernet/intel/Kconfig b/drivers/net/ethernet/intel/Kconfig\nindex 154e2e818ec6..48ec63f27869 100644\n--- a/drivers/net/ethernet/intel/Kconfig\n+++ b/drivers/net/ethernet/intel/Kconfig\n@@ -294,6 +294,7 @@ config ICE\n \ttristate \"Intel(R) Ethernet Connection E800 Series Support\"\n \tdefault n\n \tdepends on PCI_MSI\n+\tselect MFD_CORE\n \t---help---\n \t This driver supports Intel(R) Ethernet Connection E800 Series of\n \t devices. For more information on how to identify your adapter, go\ndiff --git a/drivers/net/ethernet/intel/ice/Makefile b/drivers/net/ethernet/intel/ice/Makefile\nindex 9edde960b4f2..2f0ba4aa4957 100644\n--- a/drivers/net/ethernet/intel/ice/Makefile\n+++ b/drivers/net/ethernet/intel/ice/Makefile\n@@ -16,6 +16,7 @@ ice-y := ice_main.o\t\\\n \t ice_lib.o\t\\\n \t ice_txrx.o\t\\\n \t ice_flex_pipe.o\t\\\n+\t ice_idc.o\t\\\n \t ice_ethtool.o\n ice-$(CONFIG_PCI_IOV) += ice_virtchnl_pf.o ice_sriov.o\n ice-$(CONFIG_DCB) += ice_dcb.o ice_dcb_lib.o\ndiff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h\nindex 45e100666049..7160556ec55e 100644\n--- a/drivers/net/ethernet/intel/ice/ice.h\n+++ b/drivers/net/ethernet/intel/ice/ice.h\n@@ -32,6 +32,7 @@\n #include <linux/if_bridge.h>\n #include <linux/ctype.h>\n #include <linux/avf/virtchnl.h>\n+#include <linux/mfd/core.h>\n #include <net/ipv6.h>\n #include \"ice_devids.h\"\n #include \"ice_type.h\"\n@@ -40,6 +41,7 @@\n #include \"ice_switch.h\"\n #include \"ice_common.h\"\n #include \"ice_sched.h\"\n+#include \"ice_idc_int.h\"\n #include \"ice_virtchnl_pf.h\"\n #include \"ice_sriov.h\"\n \n@@ -69,6 +71,7 @@ extern const char ice_drv_ver[];\n #define ICE_MAX_SMALL_RSS_QS\t8\n #define ICE_RES_VALID_BIT\t0x8000\n #define ICE_RES_MISC_VEC_ID\t(ICE_RES_VALID_BIT - 1)\n+#define ICE_RES_RDMA_VEC_ID\t(ICE_RES_MISC_VEC_ID - 1)\n #define ICE_INVAL_Q_INDEX\t0xffff\n #define ICE_INVAL_VFID\t\t256\n \n@@ -303,11 +306,13 @@ struct ice_q_vector {\n \n enum ice_pf_flags {\n \tICE_FLAG_FLTR_SYNC,\n+\tICE_FLAG_IWARP_ENA,\n \tICE_FLAG_RSS_ENA,\n \tICE_FLAG_SRIOV_ENA,\n \tICE_FLAG_SRIOV_CAPABLE,\n \tICE_FLAG_DCB_CAPABLE,\n \tICE_FLAG_DCB_ENA,\n+\tICE_FLAG_PEER_ENA,\n \tICE_FLAG_ADV_FEATURES,\n \tICE_FLAG_LINK_DOWN_ON_CLOSE_ENA,\n \tICE_FLAG_NO_MEDIA,\n@@ -347,6 +352,9 @@ struct ice_pf {\n \tstruct mutex avail_q_mutex;\t/* protects access to avail_[rx|tx]qs */\n \tstruct mutex sw_mutex;\t\t/* lock for protecting VSI alloc flow */\n \tu32 msg_enable;\n+\t/* Total number of MSIX vectors reserved for base driver */\n+\tu32 num_rdma_msix;\n+\tu32 rdma_base_vector;\n \tu32 hw_csum_rx_error;\n \tu32 oicr_idx;\t\t/* Other interrupt cause MSIX vector index */\n \tu32 num_avail_sw_msix;\t/* remaining MSIX SW vectors left unclaimed */\n@@ -373,6 +381,8 @@ struct ice_pf {\n \tunsigned long tx_timeout_last_recovery;\n \tu32 tx_timeout_recovery_level;\n \tchar int_name[ICE_INT_NAME_STR_LEN];\n+\tstruct ice_peer_dev_int **peers;\n+\tint peer_idx;\n \tu32 sw_int_count;\n };\n \n@@ -380,6 +390,8 @@ struct ice_netdev_priv {\n \tstruct ice_vsi *vsi;\n };\n \n+extern struct ida ice_peer_index_ida;\n+\n /**\n * ice_irq_dynamic_ena - Enable default interrupt generation settings\n * @hw: pointer to HW struct\n@@ -447,6 +459,10 @@ int ice_set_rss(struct ice_vsi *vsi, u8 *seed, u8 *lut, u16 lut_size);\n int ice_get_rss(struct ice_vsi *vsi, u8 *seed, u8 *lut, u16 lut_size);\n void ice_fill_rss_lut(u8 *lut, u16 rss_table_size, u16 rss_size);\n void ice_print_link_msg(struct ice_vsi *vsi, bool isup);\n+int ice_init_peer_devices(struct ice_pf *pf);\n+int\n+ice_for_each_peer(struct ice_pf *pf, void *data,\n+\t\t int (*fn)(struct ice_peer_dev_int *, void *));\n #ifdef CONFIG_DCB\n int ice_pf_ena_all_vsi(struct ice_pf *pf, bool locked);\n void ice_pf_dis_all_vsi(struct ice_pf *pf, bool locked);\ndiff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h\nindex 023e3d2fee5f..c54e78492395 100644\n--- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h\n+++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h\n@@ -108,6 +108,7 @@ struct ice_aqc_list_caps_elem {\n #define ICE_AQC_CAPS_TXQS\t\t\t\t0x0042\n #define ICE_AQC_CAPS_MSIX\t\t\t\t0x0043\n #define ICE_AQC_CAPS_MAX_MTU\t\t\t\t0x0047\n+#define ICE_AQC_CAPS_IWARP\t\t\t\t0x0051\n \n \tu8 major_ver;\n \tu8 minor_ver;\ndiff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c\nindex 3a6b3950eb0e..ed59eec57a52 100644\n--- a/drivers/net/ethernet/intel/ice/ice_common.c\n+++ b/drivers/net/ethernet/intel/ice/ice_common.c\n@@ -1748,6 +1748,11 @@ ice_parse_caps(struct ice_hw *hw, void *buf, u32 cap_count,\n \t\t\t\t \"%s: msix_vector_first_id = %d\\n\", prefix,\n \t\t\t\t caps->msix_vector_first_id);\n \t\t\tbreak;\n+\t\tcase ICE_AQC_CAPS_IWARP:\n+\t\t\tcaps->iwarp = (number == 1);\n+\t\t\tice_debug(hw, ICE_DBG_INIT,\n+\t\t\t\t \"%s: iwarp = %d\\n\", prefix, caps->iwarp);\n+\t\t\tbreak;\n \t\tcase ICE_AQC_CAPS_MAX_MTU:\n \t\t\tcaps->max_mtu = number;\n \t\t\tice_debug(hw, ICE_DBG_INIT, \"%s: max_mtu = %d\\n\",\ndiff --git a/drivers/net/ethernet/intel/ice/ice_dcb_lib.c b/drivers/net/ethernet/intel/ice/ice_dcb_lib.c\nindex dd47869c4ad4..ed639ef5da42 100644\n--- a/drivers/net/ethernet/intel/ice/ice_dcb_lib.c\n+++ b/drivers/net/ethernet/intel/ice/ice_dcb_lib.c\n@@ -613,6 +613,37 @@ ice_tx_prepare_vlan_flags_dcb(struct ice_ring *tx_ring,\n \treturn 0;\n }\n \n+/**\n+ * ice_setup_dcb_qos_info - Setup DCB QoS information\n+ * @pf: ptr to ice_pf\n+ * @qos_info: QoS param instance\n+ */\n+void ice_setup_dcb_qos_info(struct ice_pf *pf, struct iidc_qos_params *qos_info)\n+{\n+\tstruct ice_dcbx_cfg *dcbx_cfg;\n+\tu32 up2tc;\n+\tint i;\n+\n+\tdcbx_cfg = &pf->hw.port_info->local_dcbx_cfg;\n+\tup2tc = rd32(&pf->hw, PRTDCB_TUP2TC);\n+\tqos_info->num_apps = dcbx_cfg->numapps;\n+\n+\tqos_info->num_tc = ice_dcb_get_num_tc(dcbx_cfg);\n+\n+\tfor (i = 0; i < IIDC_MAX_USER_PRIORITY; i++)\n+\t\tqos_info->up2tc[i] = (up2tc >> (i * 3)) & 0x7;\n+\n+\tfor (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++)\n+\t\tqos_info->tc_info[i].rel_bw =\n+\t\t\tdcbx_cfg->etscfg.tcbwtable[i];\n+\n+\tfor (i = 0; i < qos_info->num_apps; i++) {\n+\t\tqos_info->apps[i].priority = dcbx_cfg->app[i].priority;\n+\t\tqos_info->apps[i].prot_id = dcbx_cfg->app[i].prot_id;\n+\t\tqos_info->apps[i].selector = dcbx_cfg->app[i].selector;\n+\t}\n+}\n+\n /**\n * ice_dcb_process_lldp_set_mib_change - Process MIB change\n * @pf: ptr to ice_pf\ndiff --git a/drivers/net/ethernet/intel/ice/ice_dcb_lib.h b/drivers/net/ethernet/intel/ice/ice_dcb_lib.h\nindex 661a6f7bca64..6c0585d1bc97 100644\n--- a/drivers/net/ethernet/intel/ice/ice_dcb_lib.h\n+++ b/drivers/net/ethernet/intel/ice/ice_dcb_lib.h\n@@ -20,6 +20,8 @@ int\n ice_tx_prepare_vlan_flags_dcb(struct ice_ring *tx_ring,\n \t\t\t struct ice_tx_buf *first);\n void\n+ice_setup_dcb_qos_info(struct ice_pf *pf, struct iidc_qos_params *qos_info);\n+void\n ice_dcb_process_lldp_set_mib_change(struct ice_pf *pf,\n \t\t\t\t struct ice_rq_event_info *event);\n void ice_vsi_cfg_netdev_tc(struct ice_vsi *vsi, u8 ena_tc);\n@@ -57,6 +59,7 @@ ice_tx_prepare_vlan_flags_dcb(struct ice_ring __always_unused *tx_ring,\n \n #define ice_update_dcb_stats(pf) do {} while (0)\n #define ice_vsi_cfg_dcb_rings(vsi) do {} while (0)\n+#define ice_setup_dcb_qos_info(pf, qos_info) do {} while (0)\n #define ice_dcb_process_lldp_set_mib_change(pf, event) do {} while (0)\n #define ice_set_cgd_num(tlan_ctx, ring) do {} while (0)\n #define ice_vsi_cfg_netdev_tc(vsi, ena_tc) do {} while (0)\ndiff --git a/drivers/net/ethernet/intel/ice/ice_hw_autogen.h b/drivers/net/ethernet/intel/ice/ice_hw_autogen.h\nindex 152fbd556e9b..05a71f223c5d 100644\n--- a/drivers/net/ethernet/intel/ice/ice_hw_autogen.h\n+++ b/drivers/net/ethernet/intel/ice/ice_hw_autogen.h\n@@ -55,6 +55,7 @@\n #define PRTDCB_GENS\t\t\t\t0x00083020\n #define PRTDCB_GENS_DCBX_STATUS_S\t\t0\n #define PRTDCB_GENS_DCBX_STATUS_M\t\tICE_M(0x7, 0)\n+#define PRTDCB_TUP2TC\t\t\t\t0x001D26C0\n #define GL_PREEXT_L2_PMASK0(_i)\t\t\t(0x0020F0FC + ((_i) * 4))\n #define GL_PREEXT_L2_PMASK1(_i)\t\t\t(0x0020F108 + ((_i) * 4))\n #define GLFLXP_RXDID_FLAGS(_i, _j)\t\t(0x0045D000 + ((_i) * 4 + (_j) * 256))\ndiff --git a/drivers/net/ethernet/intel/ice/ice_idc.c b/drivers/net/ethernet/intel/ice/ice_idc.c\nnew file mode 100644\nindex 000000000000..5e02321449ec\n--- /dev/null\n+++ b/drivers/net/ethernet/intel/ice/ice_idc.c\n@@ -0,0 +1,440 @@\n+// SPDX-License-Identifier: GPL-2.0\n+/* Copyright (c) 2019, Intel Corporation. */\n+\n+/* Inter-Driver Communication */\n+#include \"ice.h\"\n+#include \"ice_lib.h\"\n+#include \"ice_dcb_lib.h\"\n+\n+DEFINE_IDA(ice_peer_index_ida);\n+\n+static struct mfd_cell ice_mfd_cells[] = ASSIGN_PEER_INFO;\n+\n+/**\n+ * ice_peer_state_change - manage state machine for peer\n+ * @peer_dev: pointer to peer's configuration\n+ * @new_state: the state requested to transition into\n+ * @locked: boolean to determine if call made with mutex held\n+ *\n+ * This function handles all state transitions for peer devices.\n+ * The state machine is as follows:\n+ *\n+ * +<-----------------------+<-----------------------------+\n+ *\t\t\t\t|<-------+<----------+\t +\n+ *\t\t\t\t\\/\t +\t +\t +\n+ * INIT --------------> PROBED --> OPENING\t CLOSED --> REMOVED\n+ *\t\t\t\t\t + +\n+ *\t\t\t\t OPENED --> CLOSING\n+ *\t\t\t\t\t +\t +\n+ *\t\t\t\t PREP_RST\t +\n+ *\t\t\t\t\t +\t +\n+ *\t\t\t\t PREPPED\t +\n+ *\t\t\t\t\t +---------->+\n+ */\n+static void\n+ice_peer_state_change(struct ice_peer_dev_int *peer_dev, long new_state,\n+\t\t bool locked)\n+{\n+\tstruct device *dev;\n+\n+\tdev = bus_find_device_by_name(&platform_bus_type, NULL,\n+\t\t\t\t peer_dev->plat_name);\n+\n+\tif (!locked)\n+\t\tmutex_lock(&peer_dev->peer_dev_state_mutex);\n+\n+\tswitch (new_state) {\n+\tcase ICE_PEER_DEV_STATE_INIT:\n+\t\tif (test_and_clear_bit(ICE_PEER_DEV_STATE_REMOVED,\n+\t\t\t\t peer_dev->state)) {\n+\t\t\tset_bit(ICE_PEER_DEV_STATE_INIT, peer_dev->state);\n+\t\t\tdev_dbg(dev,\n+\t\t\t\t\"state transition from _REMOVED to _INIT\\n\");\n+\t\t} else {\n+\t\t\tset_bit(ICE_PEER_DEV_STATE_INIT, peer_dev->state);\n+\t\t\tif (dev)\n+\t\t\t\tdev_dbg(dev, \"state set to _INIT\\n\");\n+\t\t}\n+\t\tbreak;\n+\tcase ICE_PEER_DEV_STATE_PROBED:\n+\t\tif (test_and_clear_bit(ICE_PEER_DEV_STATE_INIT,\n+\t\t\t\t peer_dev->state)) {\n+\t\t\tset_bit(ICE_PEER_DEV_STATE_PROBED, peer_dev->state);\n+\t\t\tdev_dbg(dev,\n+\t\t\t\t\"state transition from _INIT to _PROBED\\n\");\n+\t\t} else if (test_and_clear_bit(ICE_PEER_DEV_STATE_REMOVED,\n+\t\t\t\t\t peer_dev->state)) {\n+\t\t\tset_bit(ICE_PEER_DEV_STATE_PROBED, peer_dev->state);\n+\t\t\tdev_dbg(dev,\n+\t\t\t\t\"state transition from _REMOVED to _PROBED\\n\");\n+\t\t} else if (test_and_clear_bit(ICE_PEER_DEV_STATE_OPENING,\n+\t\t\t\t\t peer_dev->state)) {\n+\t\t\tset_bit(ICE_PEER_DEV_STATE_PROBED, peer_dev->state);\n+\t\t\tdev_dbg(dev,\n+\t\t\t\t\"state transition from _OPENING to _PROBED\\n\");\n+\t\t}\n+\t\tbreak;\n+\tcase ICE_PEER_DEV_STATE_OPENING:\n+\t\tif (test_and_clear_bit(ICE_PEER_DEV_STATE_PROBED,\n+\t\t\t\t peer_dev->state)) {\n+\t\t\tset_bit(ICE_PEER_DEV_STATE_OPENING, peer_dev->state);\n+\t\t\tdev_dbg(dev,\n+\t\t\t\t\"state transition from _PROBED to _OPENING\\n\");\n+\t\t} else if (test_and_clear_bit(ICE_PEER_DEV_STATE_CLOSED,\n+\t\t\t\t\t peer_dev->state)) {\n+\t\t\tset_bit(ICE_PEER_DEV_STATE_OPENING, peer_dev->state);\n+\t\t\tdev_dbg(dev,\n+\t\t\t\t\"state transition from _CLOSED to _OPENING\\n\");\n+\t\t}\n+\t\tbreak;\n+\tcase ICE_PEER_DEV_STATE_OPENED:\n+\t\tif (test_and_clear_bit(ICE_PEER_DEV_STATE_OPENING,\n+\t\t\t\t peer_dev->state)) {\n+\t\t\tset_bit(ICE_PEER_DEV_STATE_OPENED, peer_dev->state);\n+\t\t\tdev_dbg(dev,\n+\t\t\t\t\"state transition from _OPENING to _OPENED\\n\");\n+\t\t}\n+\t\tbreak;\n+\tcase ICE_PEER_DEV_STATE_PREP_RST:\n+\t\tif (test_and_clear_bit(ICE_PEER_DEV_STATE_OPENED,\n+\t\t\t\t peer_dev->state)) {\n+\t\t\tset_bit(ICE_PEER_DEV_STATE_PREP_RST, peer_dev->state);\n+\t\t\tdev_dbg(dev,\n+\t\t\t\t\"state transition from _OPENED to _PREP_RST\\n\");\n+\t\t}\n+\t\tbreak;\n+\tcase ICE_PEER_DEV_STATE_PREPPED:\n+\t\tif (test_and_clear_bit(ICE_PEER_DEV_STATE_PREP_RST,\n+\t\t\t\t peer_dev->state)) {\n+\t\t\tset_bit(ICE_PEER_DEV_STATE_PREPPED, peer_dev->state);\n+\t\t\tdev_dbg(dev,\n+\t\t\t\t\"state transition _PREP_RST to _PREPPED\\n\");\n+\t\t}\n+\t\tbreak;\n+\tcase ICE_PEER_DEV_STATE_CLOSING:\n+\t\tif (test_and_clear_bit(ICE_PEER_DEV_STATE_OPENED,\n+\t\t\t\t peer_dev->state)) {\n+\t\t\tset_bit(ICE_PEER_DEV_STATE_CLOSING, peer_dev->state);\n+\t\t\tdev_dbg(dev,\n+\t\t\t\t\"state transition from _OPENED to _CLOSING\\n\");\n+\t\t}\n+\t\tif (test_and_clear_bit(ICE_PEER_DEV_STATE_PREPPED,\n+\t\t\t\t peer_dev->state)) {\n+\t\t\tset_bit(ICE_PEER_DEV_STATE_CLOSING, peer_dev->state);\n+\t\t\tdev_dbg(dev, \"state transition _PREPPED to _CLOSING\\n\");\n+\t\t}\n+\t\t/* NOTE - up to peer to handle this situation correctly */\n+\t\tif (test_and_clear_bit(ICE_PEER_DEV_STATE_PREP_RST,\n+\t\t\t\t peer_dev->state)) {\n+\t\t\tset_bit(ICE_PEER_DEV_STATE_CLOSING, peer_dev->state);\n+\t\t\tdev_warn(dev,\n+\t\t\t\t \"WARN: Peer state PREP_RST to _CLOSING\\n\");\n+\t\t}\n+\t\tbreak;\n+\tcase ICE_PEER_DEV_STATE_CLOSED:\n+\t\tif (test_and_clear_bit(ICE_PEER_DEV_STATE_CLOSING,\n+\t\t\t\t peer_dev->state)) {\n+\t\t\tset_bit(ICE_PEER_DEV_STATE_CLOSED, peer_dev->state);\n+\t\t\tdev_dbg(dev,\n+\t\t\t\t\"state transition from _CLOSING to _CLOSED\\n\");\n+\t\t}\n+\t\tbreak;\n+\tcase ICE_PEER_DEV_STATE_REMOVED:\n+\t\tif (test_and_clear_bit(ICE_PEER_DEV_STATE_OPENED,\n+\t\t\t\t peer_dev->state) ||\n+\t\t test_and_clear_bit(ICE_PEER_DEV_STATE_CLOSED,\n+\t\t\t\t peer_dev->state)) {\n+\t\t\tset_bit(ICE_PEER_DEV_STATE_REMOVED, peer_dev->state);\n+\t\t\tdev_dbg(dev,\n+\t\t\t\t\"state from _OPENED/_CLOSED to _REMOVED\\n\");\n+\t\t\t/* Clear registration for events when peer removed */\n+\t\t\tbitmap_zero(peer_dev->events, ICE_PEER_DEV_STATE_NBITS);\n+\t\t}\n+\t\tbreak;\n+\tdefault:\n+\t\tbreak;\n+\t}\n+\n+\tif (!locked)\n+\t\tmutex_unlock(&peer_dev->peer_dev_state_mutex);\n+}\n+\n+/**\n+ * ice_peer_update_vsi - update the pf_vsi info in peer_dev struct\n+ * @peer_dev_int: pointer to peer dev internal struct\n+ * @data: opaque pointer - VSI to be updated\n+ */\n+int ice_peer_update_vsi(struct ice_peer_dev_int *peer_dev_int, void *data)\n+{\n+\tstruct ice_vsi *vsi = (struct ice_vsi *)data;\n+\tstruct iidc_peer_dev *peer_dev;\n+\n+\tpeer_dev = ice_get_peer_dev(peer_dev_int);\n+\tif (!peer_dev)\n+\t\treturn 0;\n+\n+\tpeer_dev->pf_vsi_num = vsi->vsi_num;\n+\treturn 0;\n+}\n+\n+/**\n+ * ice_for_each_peer - iterate across and call function for each peer dev\n+ * @pf: pointer to private board struct\n+ * @data: data to pass to function on each call\n+ * @fn: pointer to function to call for each peer\n+ */\n+int\n+ice_for_each_peer(struct ice_pf *pf, void *data,\n+\t\t int (*fn)(struct ice_peer_dev_int *, void *))\n+{\n+\tint i;\n+\n+\tif (!pf->peers)\n+\t\treturn 0;\n+\n+\tfor (i = 0; i < ARRAY_SIZE(ice_mfd_cells); i++) {\n+\t\tstruct ice_peer_dev_int *peer_dev_int;\n+\n+\t\tpeer_dev_int = pf->peers[i];\n+\t\tif (peer_dev_int) {\n+\t\t\tint ret = fn(peer_dev_int, data);\n+\n+\t\t\tif (ret)\n+\t\t\t\treturn ret;\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * ice_unreg_peer_device - unregister specified device\n+ * @peer_dev_int: ptr to peer device internal\n+ * @data: ptr to opaque data\n+ *\n+ * This function invokes device unregistration, removes ID associated with\n+ * the specified device.\n+ */\n+int\n+ice_unreg_peer_device(struct ice_peer_dev_int *peer_dev_int,\n+\t\t void __always_unused *data)\n+{\n+\tstruct ice_peer_drv_int *peer_drv_int;\n+\tstruct iidc_peer_dev *peer_dev;\n+\tstruct pci_dev *pdev;\n+\tstruct ice_pf *pf;\n+\n+\tif (!peer_dev_int)\n+\t\treturn 0;\n+\n+\tpeer_dev = ice_get_peer_dev(peer_dev_int);\n+\tpdev = peer_dev->pdev;\n+\tif (!pdev)\n+\t\treturn 0;\n+\n+\tpf = pci_get_drvdata(pdev);\n+\tif (!pf)\n+\t\treturn 0;\n+\n+\tmfd_remove_devices(&pdev->dev);\n+\n+\tpeer_drv_int = peer_dev_int->peer_drv_int;\n+\n+\tif (peer_dev_int->ice_peer_wq) {\n+\t\tif (peer_dev_int->peer_prep_task.func)\n+\t\t\tcancel_work_sync(&peer_dev_int->peer_prep_task);\n+\n+\t\tif (peer_dev_int->peer_close_task.func)\n+\t\t\tcancel_work_sync(&peer_dev_int->peer_close_task);\n+\t\tdestroy_workqueue(peer_dev_int->ice_peer_wq);\n+\t}\n+\n+\tdevm_kfree(&pf->pdev->dev, peer_drv_int);\n+\n+\tdevm_kfree(&pf->pdev->dev, peer_dev_int);\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * ice_unroll_peer - destroy peers and peer_wq in case of error\n+ * @peer_dev_int: ptr to peer device internal struct\n+ * @data: ptr to opaque data\n+ *\n+ * This function releases resources in the event of a failure in creating\n+ * peer devices or their individual work_queues. Meant to be called from\n+ * a ice_for_each_peer invocation\n+ */\n+int\n+ice_unroll_peer(struct ice_peer_dev_int *peer_dev_int,\n+\t\tvoid __always_unused *data)\n+{\n+\tstruct iidc_peer_dev *peer_dev;\n+\tstruct ice_pf *pf;\n+\n+\tpeer_dev = ice_get_peer_dev(peer_dev_int);\n+\tif (!peer_dev)\n+\t\treturn 0;\n+\n+\tpf = pci_get_drvdata(peer_dev->pdev);\n+\tif (!pf)\n+\t\treturn 0;\n+\n+\tif (peer_dev_int->ice_peer_wq)\n+\t\tdestroy_workqueue(peer_dev_int->ice_peer_wq);\n+\tdevm_kfree(&pf->pdev->dev, peer_dev_int);\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * ice_reserve_peer_qvector - Reserve vector resources for peer drivers\n+ * @pf: board private structure to initialize\n+ */\n+static int ice_reserve_peer_qvector(struct ice_pf *pf)\n+{\n+\tif (test_bit(ICE_FLAG_IWARP_ENA, pf->flags)) {\n+\t\tint index;\n+\n+\t\tindex = ice_get_res(pf, pf->irq_tracker, pf->num_rdma_msix,\n+\t\t\t\t ICE_RES_RDMA_VEC_ID);\n+\t\tif (index < 0)\n+\t\t\treturn index;\n+\t\tpf->num_avail_sw_msix -= pf->num_rdma_msix;\n+\t\tpf->rdma_base_vector = index;\n+\t}\n+\treturn 0;\n+}\n+\n+/**\n+ * ice_init_peer_devices - initializes peer devices\n+ * @pf: ptr to ice_pf\n+ *\n+ * This function initializes peer devices and associates them with specified\n+ * pci_dev as their parent.\n+ */\n+int ice_init_peer_devices(struct ice_pf *pf)\n+{\n+\tstruct ice_vsi *vsi = pf->vsi[0];\n+\tstruct pci_dev *pdev = pf->pdev;\n+\tstruct device *dev = &pdev->dev;\n+\tint status = 0;\n+\tint i;\n+\n+\t/* Reserve vector resources */\n+\tstatus = ice_reserve_peer_qvector(pf);\n+\tif (status < 0) {\n+\t\tdev_err(dev, \"failed to reserve vectors for peer drivers\\n\");\n+\t\treturn status;\n+\t}\n+\tfor (i = 0; i < ARRAY_SIZE(ice_mfd_cells); i++) {\n+\t\tstruct iidc_peer_dev_platform_data *platform_data;\n+\t\tstruct ice_peer_dev_int *peer_dev_int;\n+\t\tstruct ice_peer_drv_int *peer_drv_int;\n+\t\tstruct iidc_qos_params *qos_info;\n+\t\tstruct msix_entry *entry = NULL;\n+\t\tstruct iidc_peer_dev *peer_dev;\n+\t\tint j;\n+\n+\t\tpeer_dev_int = devm_kzalloc(dev, sizeof(*peer_dev_int),\n+\t\t\t\t\t GFP_KERNEL);\n+\t\tif (!peer_dev_int)\n+\t\t\treturn -ENOMEM;\n+\t\tpf->peers[i] = peer_dev_int;\n+\n+\t\tpeer_drv_int = devm_kzalloc(dev, sizeof(*peer_drv_int),\n+\t\t\t\t\t GFP_KERNEL);\n+\t\tif (!peer_drv_int) {\n+\t\t\tdevm_kfree(&pf->pdev->dev, peer_dev_int);\n+\t\t\treturn -ENOMEM;\n+\t\t}\n+\n+\t\tpeer_dev_int->peer_drv_int = peer_drv_int;\n+\n+\t\t/* Initialize driver values */\n+\t\tfor (j = 0; j < IIDC_EVENT_NBITS; j++)\n+\t\t\tbitmap_zero(peer_drv_int->current_events[j].type,\n+\t\t\t\t IIDC_EVENT_NBITS);\n+\n+\t\tmutex_init(&peer_dev_int->peer_dev_state_mutex);\n+\n+\t\tpeer_dev = ice_get_peer_dev(peer_dev_int);\n+\t\tpeer_dev_int->plat_data.peer_dev = peer_dev;\n+\t\tplatform_data = &peer_dev_int->plat_data;\n+\t\tpeer_dev->peer_ops = NULL;\n+\t\tpeer_dev->hw_addr = (u8 __iomem *)pf->hw.hw_addr;\n+\t\tpeer_dev->peer_dev_id = ice_mfd_cells[i].id;\n+\t\tpeer_dev->pf_vsi_num = vsi->vsi_num;\n+\t\tpeer_dev->netdev = vsi->netdev;\n+\n+\t\tice_mfd_cells[i].platform_data = platform_data;\n+\t\tice_mfd_cells[i].pdata_size = sizeof(*platform_data);\n+\n+\t\tpeer_dev_int->ice_peer_wq =\n+\t\t\talloc_ordered_workqueue(\"ice_peer_wq_%d\", WQ_UNBOUND,\n+\t\t\t\t\t\ti);\n+\t\tif (!peer_dev_int->ice_peer_wq)\n+\t\t\treturn -ENOMEM;\n+\n+\t\tpeer_dev->pdev = pdev;\n+\t\tqos_info = &peer_dev->initial_qos_info;\n+\n+\t\t/* setup qos_info fields with defaults */\n+\t\tqos_info->num_apps = 0;\n+\t\tqos_info->num_tc = 1;\n+\n+\t\tfor (j = 0; j < IIDC_MAX_USER_PRIORITY; j++)\n+\t\t\tqos_info->up2tc[j] = 0;\n+\n+\t\tqos_info->tc_info[0].rel_bw = 100;\n+\t\tfor (j = 1; j < IEEE_8021QAZ_MAX_TCS; j++)\n+\t\t\tqos_info->tc_info[j].rel_bw = 0;\n+\n+\t\t/* for DCB, override the qos_info defaults. */\n+\t\tice_setup_dcb_qos_info(pf, qos_info);\n+\n+\t\t/* make sure peer specific resources such as msix_count and\n+\t\t * msix_entries are initialized\n+\t\t */\n+\t\tswitch (ice_mfd_cells[i].id) {\n+\t\tcase IIDC_PEER_RDMA_ID:\n+\t\t\tif (test_bit(ICE_FLAG_IWARP_ENA, pf->flags)) {\n+\t\t\t\tpeer_dev->msix_count = pf->num_rdma_msix;\n+\t\t\t\tentry = &pf->msix_entries[pf->rdma_base_vector];\n+\t\t\t}\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\tpeer_dev->msix_entries = entry;\n+\t\tice_peer_state_change(peer_dev_int, ICE_PEER_DEV_STATE_INIT,\n+\t\t\t\t false);\n+\t}\n+\n+\tstatus = ida_simple_get(&ice_peer_index_ida, 0, 0, GFP_KERNEL);\n+\tif (status < 0) {\n+\t\tdev_err(&pdev->dev,\n+\t\t\t\"failed to get unique index for device\\n\");\n+\t\treturn status;\n+\t}\n+\n+\tpf->peer_idx = status;\n+\n+\tstatus = mfd_add_devices(dev, pf->peer_idx, ice_mfd_cells,\n+\t\t\t\t ARRAY_SIZE(ice_mfd_cells), NULL, 0, NULL);\n+\tif (status)\n+\t\tdev_err(dev, \"Failure adding MFD devs for peers: %d\\n\", status);\n+\n+\tfor (i = 0; i < ARRAY_SIZE(ice_mfd_cells); i++) {\n+\t\tsnprintf(pf->peers[i]->plat_name, ICE_MAX_PEER_NAME, \"%s.%d\",\n+\t\t\t ice_mfd_cells[i].name,\n+\t\t\t pf->peer_idx + ice_mfd_cells[i].id);\n+\t\tdev = bus_find_device_by_name(&platform_bus_type, NULL,\n+\t\t\t\t\t pf->peers[i]->plat_name);\n+\t\tdev_dbg(dev, \"Peer Created: %s %d\\n\", pf->peers[i]->plat_name,\n+\t\t\tpf->peer_idx);\n+\t}\n+\n+\treturn status;\n+}\ndiff --git a/drivers/net/ethernet/intel/ice/ice_idc_int.h b/drivers/net/ethernet/intel/ice/ice_idc_int.h\nnew file mode 100644\nindex 000000000000..26ecd45faf16\n--- /dev/null\n+++ b/drivers/net/ethernet/intel/ice/ice_idc_int.h\n@@ -0,0 +1,81 @@\n+/* SPDX-License-Identifier: GPL-2.0 */\n+/* Copyright (c) 2019, Intel Corporation. */\n+\n+#ifndef _ICE_IDC_INT_H_\n+#define _ICE_IDC_INT_H_\n+\n+#include <linux/net/intel/iidc.h>\n+#include \"ice.h\"\n+\n+enum ice_peer_dev_state {\n+\tICE_PEER_DEV_STATE_INIT,\n+\tICE_PEER_DEV_STATE_PROBED,\n+\tICE_PEER_DEV_STATE_OPENING,\n+\tICE_PEER_DEV_STATE_OPENED,\n+\tICE_PEER_DEV_STATE_PREP_RST,\n+\tICE_PEER_DEV_STATE_PREPPED,\n+\tICE_PEER_DEV_STATE_CLOSING,\n+\tICE_PEER_DEV_STATE_CLOSED,\n+\tICE_PEER_DEV_STATE_REMOVED,\n+\tICE_PEER_DEV_STATE_API_RDY,\n+\tICE_PEER_DEV_STATE_NBITS, /* must be last */\n+};\n+\n+enum ice_peer_drv_state {\n+\tICE_PEER_DRV_STATE_MBX_RDY,\n+\tICE_PEER_DRV_STATE_NBITS, /* must be last */\n+};\n+\n+struct ice_peer_drv_int {\n+\tstruct iidc_peer_drv *peer_drv;\n+\n+\t/* States associated with peer driver */\n+\tDECLARE_BITMAP(state, ICE_PEER_DRV_STATE_NBITS);\n+\n+\t/* if this peer_dev is the originator of an event, these are the\n+\t * most recent events of each type\n+\t */\n+\tstruct iidc_event current_events[IIDC_EVENT_NBITS];\n+};\n+\n+#define ICE_MAX_PEER_NAME 64\n+\n+struct ice_peer_dev_int {\n+\tstruct iidc_peer_dev peer_dev;\n+\tstruct ice_peer_drv_int *peer_drv_int; /* driver private structure */\n+\tchar plat_name[ICE_MAX_PEER_NAME];\n+\tstruct iidc_peer_dev_platform_data plat_data;\n+\n+\t/* if this peer_dev is the originator of an event, these are the\n+\t * most recent events of each type\n+\t */\n+\tstruct iidc_event current_events[IIDC_EVENT_NBITS];\n+\t/* Events a peer has registered to be notified about */\n+\tDECLARE_BITMAP(events, IIDC_EVENT_NBITS);\n+\n+\t/* States associated with peer device */\n+\tDECLARE_BITMAP(state, ICE_PEER_DEV_STATE_NBITS);\n+\tstruct mutex peer_dev_state_mutex; /* peer_dev state mutex */\n+\n+\t/* per peer workqueue */\n+\tstruct workqueue_struct *ice_peer_wq;\n+\n+\tstruct work_struct peer_prep_task;\n+\tstruct work_struct peer_close_task;\n+\n+\tenum iidc_close_reason rst_type;\n+};\n+\n+int ice_peer_update_vsi(struct ice_peer_dev_int *peer_dev_int, void *data);\n+int ice_unroll_peer(struct ice_peer_dev_int *peer_dev_int, void *data);\n+int ice_unreg_peer_device(struct ice_peer_dev_int *peer_dev_int, void *data);\n+\n+static inline struct\n+iidc_peer_dev *ice_get_peer_dev(struct ice_peer_dev_int *peer_dev_int)\n+{\n+\tif (peer_dev_int)\n+\t\treturn &peer_dev_int->peer_dev;\n+\telse\n+\t\treturn NULL;\n+}\n+#endif /* !_ICE_IDC_INT_H_ */\ndiff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c\nindex cc755382df25..d3d317df34f0 100644\n--- a/drivers/net/ethernet/intel/ice/ice_lib.c\n+++ b/drivers/net/ethernet/intel/ice/ice_lib.c\n@@ -763,6 +763,17 @@ bool ice_is_safe_mode(struct ice_pf *pf)\n \treturn !test_bit(ICE_FLAG_ADV_FEATURES, pf->flags);\n }\n \n+/**\n+ * ice_is_peer_ena\n+ * @pf: pointer to the PF struct\n+ *\n+ * returns true if peer devices/drivers are supported, false otherwise\n+ */\n+bool ice_is_peer_ena(struct ice_pf *pf)\n+{\n+\treturn test_bit(ICE_FLAG_PEER_ENA, pf->flags);\n+}\n+\n /**\n * ice_rss_clean - Delete RSS related VSI structures that hold user inputs\n * @vsi: the VSI being removed\ndiff --git a/drivers/net/ethernet/intel/ice/ice_lib.h b/drivers/net/ethernet/intel/ice/ice_lib.h\nindex 47bc033fff20..613a732ceb09 100644\n--- a/drivers/net/ethernet/intel/ice/ice_lib.h\n+++ b/drivers/net/ethernet/intel/ice/ice_lib.h\n@@ -124,6 +124,6 @@ char *ice_nvm_version_str(struct ice_hw *hw);\n \n enum ice_status\n ice_vsi_cfg_mac_fltr(struct ice_vsi *vsi, const u8 *macaddr, bool set);\n-\n bool ice_is_safe_mode(struct ice_pf *pf);\n+bool ice_is_peer_ena(struct ice_pf *pf);\n #endif /* !_ICE_LIB_H_ */\ndiff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c\nindex 214cd6eca405..cfdfcd44735f 100644\n--- a/drivers/net/ethernet/intel/ice/ice_main.c\n+++ b/drivers/net/ethernet/intel/ice/ice_main.c\n@@ -2321,6 +2321,12 @@ static void ice_set_pf_caps(struct ice_pf *pf)\n {\n \tstruct ice_hw_func_caps *func_caps = &pf->hw.func_caps;\n \n+\tclear_bit(ICE_FLAG_IWARP_ENA, pf->flags);\n+\tclear_bit(ICE_FLAG_PEER_ENA, pf->flags);\n+\tif (func_caps->common_cap.iwarp) {\n+\t\tset_bit(ICE_FLAG_IWARP_ENA, pf->flags);\n+\t\tset_bit(ICE_FLAG_PEER_ENA, pf->flags);\n+\t}\n \tclear_bit(ICE_FLAG_DCB_CAPABLE, pf->flags);\n \tif (func_caps->common_cap.dcb)\n \t\tset_bit(ICE_FLAG_DCB_CAPABLE, pf->flags);\n@@ -2400,6 +2406,17 @@ static int ice_ena_msix_range(struct ice_pf *pf)\n \tv_budget += needed;\n \tv_left -= needed;\n \n+\t/* reserve vectors for RDMA peer driver */\n+\tif (test_bit(ICE_FLAG_IWARP_ENA, pf->flags)) {\n+\t\t/* RDMA peer driver needs one extra to handle misc causes */\n+\t\tneeded = min_t(int, num_online_cpus(), v_left) + 1;\n+\t\tif (v_left < needed)\n+\t\t\tgoto no_hw_vecs_left_err;\n+\t\tpf->num_rdma_msix = needed;\n+\t\tv_budget += needed;\n+\t\tv_left -= needed;\n+\t}\n+\n \tpf->msix_entries = devm_kcalloc(&pf->pdev->dev, v_budget,\n \t\t\t\t\tsizeof(*pf->msix_entries), GFP_KERNEL);\n \n@@ -2425,16 +2442,19 @@ static int ice_ena_msix_range(struct ice_pf *pf)\n \t\tdev_warn(&pf->pdev->dev,\n \t\t\t \"not enough OS MSI-X vectors. requested = %d, obtained = %d\\n\",\n \t\t\t v_budget, v_actual);\n-/* 2 vectors for LAN (traffic + OICR) */\n+/* 2 vectors for LAN and RDMA (traffic + OICR) */\n #define ICE_MIN_LAN_VECS 2\n+#define ICE_MIN_RDMA_VECS 2\n+#define ICE_MIN_VECS (ICE_MIN_LAN_VECS + ICE_MIN_RDMA_VECS)\n \n-\t\tif (v_actual < ICE_MIN_LAN_VECS) {\n+\t\tif (v_actual < ICE_MIN_VECS) {\n \t\t\t/* error if we can't get minimum vectors */\n \t\t\tpci_disable_msix(pf->pdev);\n \t\t\terr = -ERANGE;\n \t\t\tgoto msix_err;\n \t\t} else {\n \t\t\tpf->num_lan_msix = ICE_MIN_LAN_VECS;\n+\t\t\tpf->num_rdma_msix = ICE_MIN_RDMA_VECS;\n \t\t}\n \t}\n \n@@ -2451,6 +2471,7 @@ static int ice_ena_msix_range(struct ice_pf *pf)\n \terr = -ERANGE;\n exit_err:\n \tpf->num_lan_msix = 0;\n+\tpf->num_rdma_msix = 0;\n \treturn err;\n }\n \n@@ -2968,6 +2989,27 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)\n \n \t/* initialize DDP driven features */\n \n+\t/* init peers only if supported */\n+\tif (ice_is_peer_ena(pf)) {\n+\t\tpf->peers = devm_kcalloc(dev, IIDC_MAX_NUM_PEERS,\n+\t\t\t\t\t sizeof(*pf->peers), GFP_KERNEL);\n+\t\tif (!pf->peers) {\n+\t\t\terr = -ENOMEM;\n+\t\t\tgoto err_init_peer_unroll;\n+\t\t}\n+\n+\t\terr = ice_init_peer_devices(pf);\n+\t\tif (err) {\n+\t\t\tdev_err(dev,\n+\t\t\t\t\"Failed to initialize peer devices: 0x%x\\n\",\n+\t\t\t\terr);\n+\t\t\terr = -EIO;\n+\t\t\tgoto err_init_peer_unroll;\n+\t\t}\n+\t} else {\n+\t\tdev_warn(dev, \"RDMA is not supported on this device\\n\");\n+\t}\n+\n \t/* Note: DCB init failure is non-fatal to load */\n \tif (ice_init_pf_dcb(pf, false)) {\n \t\tclear_bit(ICE_FLAG_DCB_CAPABLE, pf->flags);\n@@ -2978,6 +3020,14 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)\n \n \treturn 0;\n \n+err_init_peer_unroll:\n+\tif (ice_is_peer_ena(pf)) {\n+\t\tice_for_each_peer(pf, NULL, ice_unroll_peer);\n+\t\tif (pf->peers) {\n+\t\t\tdevm_kfree(dev, pf->peers);\n+\t\t\tpf->peers = NULL;\n+\t\t}\n+\t}\n err_alloc_sw_unroll:\n \tset_bit(__ICE_SERVICE_DIS, pf->state);\n \tset_bit(__ICE_DOWN, pf->state);\n@@ -3019,6 +3069,7 @@ static void ice_remove(struct pci_dev *pdev)\n \tif (test_bit(ICE_FLAG_SRIOV_ENA, pf->flags))\n \t\tice_free_vfs(pf);\n \tice_vsi_release_all(pf);\n+\tice_for_each_peer(pf, NULL, ice_unreg_peer_device);\n \tice_free_irq_msix_misc(pf);\n \tice_for_each_vsi(pf, i) {\n \t\tif (!pf->vsi[i])\n@@ -3223,6 +3274,7 @@ static int __init ice_module_init(void)\n \tif (status) {\n \t\tpr_err(\"failed to register PCI driver, err %d\\n\", status);\n \t\tdestroy_workqueue(ice_wq);\n+\t\tida_destroy(&ice_peer_index_ida);\n \t}\n \n \treturn status;\n@@ -3239,6 +3291,10 @@ static void __exit ice_module_exit(void)\n {\n \tpci_unregister_driver(&ice_driver);\n \tdestroy_workqueue(ice_wq);\n+\t/* release all cached layer within ida tree, associated with\n+\t * ice_peer_index_ida object\n+\t */\n+\tida_destroy(&ice_peer_index_ida);\n \tpr_info(\"module unloaded\\n\");\n }\n module_exit(ice_module_exit);\n@@ -4291,6 +4347,16 @@ static void ice_rebuild(struct ice_pf *pf, enum ice_reset_req reset_type)\n \t\tgoto err_vsi_rebuild;\n \t}\n \n+\tif (ice_is_peer_ena(pf)) {\n+\t\tstruct ice_vsi *vsi = ice_get_main_vsi(pf);\n+\n+\t\tif (!vsi) {\n+\t\t\tdev_err(dev, \"No PF_VSI to update peer\\n\");\n+\t\t\tgoto err_vsi_rebuild;\n+\t\t}\n+\t\tice_for_each_peer(pf, vsi, ice_peer_update_vsi);\n+\t}\n+\n \tif (test_bit(ICE_FLAG_SRIOV_ENA, pf->flags)) {\n \t\terr = ice_vsi_rebuild_by_type(pf, ICE_VSI_VF);\n \t\tif (err) {\ndiff --git a/drivers/net/ethernet/intel/ice/ice_type.h b/drivers/net/ethernet/intel/ice/ice_type.h\nindex 6667d17a4206..d3e44a220d5d 100644\n--- a/drivers/net/ethernet/intel/ice/ice_type.h\n+++ b/drivers/net/ethernet/intel/ice/ice_type.h\n@@ -174,6 +174,7 @@ struct ice_hw_common_caps {\n \tu8 rss_table_entry_width;\t/* RSS Entry width in bits */\n \n \tu8 dcb;\n+\tu8 iwarp;\n };\n \n /* Function specific capabilities */\ndiff --git a/include/linux/net/intel/iidc.h b/include/linux/net/intel/iidc.h\nnew file mode 100644\nindex 000000000000..50188b49bf1f\n--- /dev/null\n+++ b/include/linux/net/intel/iidc.h\n@@ -0,0 +1,334 @@\n+/* SPDX-License-Identifier: GPL-2.0 */\n+/* Copyright (c) 2019, Intel Corporation. */\n+\n+#ifndef _IIDC_H_\n+#define _IIDC_H_\n+\n+#include <linux/dcbnl.h>\n+#include <linux/device.h>\n+#include <linux/if_ether.h>\n+#include <linux/kernel.h>\n+#include <linux/netdevice.h>\n+\n+enum iidc_event_type {\n+\tIIDC_EVENT_LINK_CHANGE,\n+\tIIDC_EVENT_MTU_CHANGE,\n+\tIIDC_EVENT_TC_CHANGE,\n+\tIIDC_EVENT_API_CHANGE,\n+\tIIDC_EVENT_MBX_CHANGE,\n+\tIIDC_EVENT_NBITS\t\t/* must be last */\n+};\n+\n+enum iidc_res_type {\n+\tIIDC_INVAL_RES,\n+\tIIDC_VSI,\n+\tIIDC_VEB,\n+\tIIDC_EVENT_Q,\n+\tIIDC_EGRESS_CMPL_Q,\n+\tIIDC_CMPL_EVENT_Q,\n+\tIIDC_ASYNC_EVENT_Q,\n+\tIIDC_DOORBELL_Q,\n+\tIIDC_RDMA_QSETS_TXSCHED,\n+};\n+\n+enum iidc_peer_reset_type {\n+\tIIDC_PEER_PFR,\n+\tIIDC_PEER_CORER,\n+\tIIDC_PEER_CORER_SW_CORE,\n+\tIIDC_PEER_CORER_SW_FULL,\n+\tIIDC_PEER_GLOBR,\n+};\n+\n+/* reason notified to peer driver as part of event handling */\n+enum iidc_close_reason {\n+\tIIDC_REASON_INVAL,\n+\tIIDC_REASON_HW_UNRESPONSIVE,\n+\tIIDC_REASON_INTERFACE_DOWN, /* Administrative down */\n+\tIIDC_REASON_PEER_DRV_UNREG, /* peer driver getting unregistered */\n+\tIIDC_REASON_PEER_DEV_UNINIT,\n+\tIIDC_REASON_GLOBR_REQ,\n+\tIIDC_REASON_CORER_REQ,\n+\tIIDC_REASON_EMPR_REQ,\n+\tIIDC_REASON_PFR_REQ,\n+\tIIDC_REASON_HW_RESET_PENDING,\n+\tIIDC_REASON_RECOVERY_MODE,\n+\tIIDC_REASON_PARAM_CHANGE,\n+};\n+\n+enum iidc_rdma_filter {\n+\tIIDC_RDMA_FILTER_INVAL,\n+\tIIDC_RDMA_FILTER_IWARP,\n+\tIIDC_RDMA_FILTER_ROCEV2,\n+\tIIDC_RDMA_FILTER_BOTH,\n+};\n+\n+/* Struct to hold per DCB APP info */\n+struct iidc_dcb_app_info {\n+\tu8 priority;\n+\tu8 selector;\n+\tu16 prot_id;\n+};\n+\n+struct iidc_peer_dev;\n+\n+#define IIDC_MAX_USER_PRIORITY\t\t8\n+#define IIDC_MAX_APPS\t\t\t8\n+\n+/* Struct to hold per RDMA Qset info */\n+struct iidc_rdma_qset_params {\n+\tu32 teid;\t/* qset TEID */\n+\tu16 qs_handle; /* RDMA driver provides this */\n+\tu16 vsi_id; /* VSI index */\n+\tu8 tc; /* TC branch the QSet should belong to */\n+\tu8 reserved[3];\n+};\n+\n+struct iidc_res_base {\n+\t/* Union for future provision e.g. other res_type */\n+\tunion {\n+\t\tstruct iidc_rdma_qset_params qsets;\n+\t} res;\n+};\n+\n+struct iidc_res {\n+\t/* Type of resource. Filled by peer driver */\n+\tenum iidc_res_type res_type;\n+\t/* Count requested by peer driver */\n+\tu16 cnt_req;\n+\n+\t/* Number of resources allocated. Filled in by callee.\n+\t * Based on this value, caller to fill up \"resources\"\n+\t */\n+\tu16 res_allocated;\n+\n+\t/* Unique handle to resources allocated. Zero if call fails.\n+\t * Allocated by callee and for now used by caller for internal\n+\t * tracking purpose.\n+\t */\n+\tu32 res_handle;\n+\n+\t/* Peer driver has to allocate sufficient memory, to accommodate\n+\t * cnt_requested before calling this function.\n+\t * Memory has to be zero initialized. It is input/output param.\n+\t * As a result of alloc_res API, this structures will be populated.\n+\t */\n+\tstruct iidc_res_base res[1];\n+};\n+\n+struct iidc_qos_info {\n+\tu64 tc_ctx;\n+\tu8 rel_bw;\n+\tu8 prio_type;\n+\tu8 egress_virt_up;\n+\tu8 ingress_virt_up;\n+};\n+\n+/* Struct to hold QoS info */\n+struct iidc_qos_params {\n+\tstruct iidc_qos_info tc_info[IEEE_8021QAZ_MAX_TCS];\n+\tu8 up2tc[IIDC_MAX_USER_PRIORITY];\n+\tu8 vsi_relative_bw;\n+\tu8 vsi_priority_type;\n+\tu32 num_apps;\n+\tstruct iidc_dcb_app_info apps[IIDC_MAX_APPS];\n+\tu8 num_tc;\n+};\n+\n+union iidc_event_info {\n+\t/* IIDC_EVENT_LINK_CHANGE */\n+\tstruct {\n+\t\tstruct net_device *lwr_nd;\n+\t\tu16 vsi_num; /* HW index of VSI corresponding to lwr ndev */\n+\t\tu8 new_link_state;\n+\t\tu8 lport;\n+\t} link_info;\n+\t/* IIDC_EVENT_MTU_CHANGE */\n+\tu16 mtu;\n+\t/* IIDC_EVENT_TC_CHANGE */\n+\tstruct iidc_qos_params port_qos;\n+\t/* IIDC_EVENT_API_CHANGE */\n+\tu8 api_rdy;\n+\t/* IIDC_EVENT_MBX_CHANGE */\n+\tu8 mbx_rdy;\n+};\n+\n+/* iidc_event elements are to be passed back and forth between the device\n+ * owner and the peer drivers. They are to be used to both register/unregister\n+ * for event reporting and to report an event (events can be either device\n+ * owner generated or peer generated).\n+ *\n+ * For (un)registering for events, the structure needs to be populated with:\n+ * reporter - pointer to the iidc_peer_dev struct of the peer (un)registering\n+ * type - bitmap with bits set for event types to (un)register for\n+ *\n+ * For reporting events, the structure needs to be populated with:\n+ * reporter - pointer to peer that generated the event (NULL for ice)\n+ * type - bitmap with single bit set for this event type\n+ * info - union containing data relevant to this event type\n+ */\n+struct iidc_event {\n+\tstruct iidc_peer_dev *reporter;\n+\tDECLARE_BITMAP(type, IIDC_EVENT_NBITS);\n+\tunion iidc_event_info info;\n+};\n+\n+/* Following APIs are implemented by device owner and invoked by peer\n+ * drivers\n+ */\n+struct iidc_ops {\n+\t/* APIs to allocate resources such as VEB, VSI, Doorbell queues,\n+\t * completion queues, Tx/Rx queues, etc...\n+\t */\n+\tint (*alloc_res)(struct iidc_peer_dev *peer_dev,\n+\t\t\t struct iidc_res *res,\n+\t\t\t int partial_acceptable);\n+\tint (*free_res)(struct iidc_peer_dev *peer_dev,\n+\t\t\tstruct iidc_res *res);\n+\n+\tint (*is_vsi_ready)(struct iidc_peer_dev *peer_dev);\n+\tint (*peer_register)(struct iidc_peer_dev *peer_dev);\n+\tint (*peer_unregister)(struct iidc_peer_dev *peer_dev);\n+\tint (*request_reset)(struct iidc_peer_dev *dev,\n+\t\t\t enum iidc_peer_reset_type reset_type);\n+\n+\tvoid (*notify_state_change)(struct iidc_peer_dev *dev,\n+\t\t\t\t struct iidc_event *event);\n+\n+\t/* Notification APIs */\n+\tvoid (*reg_for_notification)(struct iidc_peer_dev *dev,\n+\t\t\t\t struct iidc_event *event);\n+\tvoid (*unreg_for_notification)(struct iidc_peer_dev *dev,\n+\t\t\t\t struct iidc_event *event);\n+\tint (*update_vsi_filter)(struct iidc_peer_dev *peer_dev,\n+\t\t\t\t enum iidc_rdma_filter filter, bool enable);\n+\tint (*vc_send)(struct iidc_peer_dev *peer_dev, u32 vf_id, u8 *msg,\n+\t\t u16 len);\n+};\n+\n+/* Following APIs are implemented by peer drivers and invoked by device\n+ * owner\n+ */\n+struct iidc_peer_ops {\n+\tvoid (*event_handler)(struct iidc_peer_dev *peer_dev,\n+\t\t\t struct iidc_event *event);\n+\n+\t/* Why we have 'open' and when it is expected to be called:\n+\t * 1. symmetric set of API w.r.t close\n+\t * 2. To be invoked form driver initialization path\n+\t * - call peer_driver:open once device owner is fully\n+\t * initialized\n+\t * 3. To be invoked upon RESET complete\n+\t */\n+\tint (*open)(struct iidc_peer_dev *peer_dev);\n+\n+\t/* Peer's close function is to be called when the peer needs to be\n+\t * quiesced. This can be for a variety of reasons (enumerated in the\n+\t * iidc_close_reason enum struct). A call to close will only be\n+\t * followed by a call to either remove or open. No IDC calls from the\n+\t * peer should be accepted until it is re-opened.\n+\t *\n+\t * The *reason* parameter is the reason for the call to close. This\n+\t * can be for any reason enumerated in the iidc_close_reason struct.\n+\t * It's primary reason is for the peer's bookkeeping and in case the\n+\t * peer want to perform any different tasks dictated by the reason.\n+\t */\n+\tvoid (*close)(struct iidc_peer_dev *peer_dev,\n+\t\t enum iidc_close_reason reason);\n+\n+\tint (*vc_receive)(struct iidc_peer_dev *peer_dev, u32 vf_id, u8 *msg,\n+\t\t\t u16 len);\n+\t/* tell RDMA peer to prepare for TC change in a blocking call\n+\t * that will directly precede the change event\n+\t */\n+\tvoid (*prep_tc_change)(struct iidc_peer_dev *peer_dev);\n+};\n+\n+#define IIDC_PEER_RDMA_NAME\t\"ice_rdma\"\n+#define IIDC_PEER_RDMA_ID\t0x00000010\n+#define IIDC_MAX_NUM_PEERS\t4\n+\n+/* The const struct that instantiates peer_dev_id needs to be initialized\n+ * in the .c with the macro ASSIGN_PEER_INFO.\n+ * For example:\n+ * static const struct peer_dev_id peer_dev_ids[] = ASSIGN_PEER_INFO;\n+ */\n+struct peer_dev_id {\n+\tchar *name;\n+\tint id;\n+};\n+\n+#define ASSIGN_PEER_INFO\t\t\t\t\t\t\\\n+{\t\t\t\t\t\t\t\t\t\\\n+\t{ .name = IIDC_PEER_RDMA_NAME, .id = IIDC_PEER_RDMA_ID },\t\\\n+}\n+\n+#define iidc_peer_priv(x) ((x)->peer_priv)\n+\n+/* Structure representing peer specific information, each peer using the IIDC\n+ * interface will have an instance of this struct dedicated to it.\n+ */\n+struct iidc_peer_dev {\n+\tstruct pci_dev *pdev; /* PCI device of corresponding to main function */\n+\t/* KVA / Linear address corresponding to BAR0 of underlying\n+\t * pci_device.\n+\t */\n+\tu8 __iomem *hw_addr;\n+\tint peer_dev_id;\n+\n+\t/* Opaque pointer for peer specific data tracking. This memory will\n+\t * be alloc'd and freed by the peer driver and used for private data\n+\t * accessible only to the specific peer. It is stored here so that\n+\t * when this struct is passed to the peer via an IDC call, the data\n+\t * can be accessed by the peer at that time.\n+\t * The peers should only retrieve the pointer by the macro:\n+\t * iidc_peer_priv(struct iidc_peer_dev *)\n+\t */\n+\tvoid *peer_priv;\n+\n+\tu8 ftype;\t/* PF(false) or VF (true) */\n+\n+\t/* Data VSI created by driver */\n+\tu16 pf_vsi_num;\n+\n+\tstruct iidc_qos_params initial_qos_info;\n+\tstruct net_device *netdev;\n+\n+\t/* Based on peer driver type, this shall point to corresponding MSIx\n+\t * entries in pf->msix_entries (which were allocated as part of driver\n+\t * initialization) e.g. for RDMA driver, msix_entries reserved will be\n+\t * num_online_cpus + 1.\n+\t */\n+\tu16 msix_count; /* How many vectors are reserved for this device */\n+\tstruct msix_entry *msix_entries;\n+\n+\t/* Following struct contains function pointers to be initialized\n+\t * by device owner and called by peer driver\n+\t */\n+\tconst struct iidc_ops *ops;\n+\n+\t/* Following struct contains function pointers to be initialized\n+\t * by peer driver and called by device owner\n+\t */\n+\tconst struct iidc_peer_ops *peer_ops;\n+\n+\t/* Pointer to peer_drv struct to be populated by peer driver */\n+\tstruct iidc_peer_drv *peer_drv;\n+};\n+\n+struct iidc_peer_dev_platform_data {\n+\tstruct iidc_peer_dev *peer_dev;\n+};\n+\n+/* structure representing peer driver\n+ * Peer driver to initialize those function ptrs and it will be invoked\n+ * by device owner as part of driver_registration via bus infrastructure\n+ */\n+struct iidc_peer_drv {\n+\tu16 driver_id;\n+#define IIDC_PEER_DEVICE_OWNER\t\t0\n+#define IIDC_PEER_RDMA_DRIVER\t\t4\n+\n+\tconst char *name;\n+\n+};\n+#endif /* _IIDC_H_*/\n", "prefixes": [ "v3", "1/2" ] }