Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/887906/?format=api
{ "id": 887906, "url": "http://patchwork.ozlabs.org/api/patches/887906/?format=api", "web_url": "http://patchwork.ozlabs.org/project/intel-wired-lan/patch/20180319215644.31978-6-jeffrey.t.kirsher@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": "<20180319215644.31978-6-jeffrey.t.kirsher@intel.com>", "list_archive_url": null, "date": "2018-03-19T21:56:35", "name": "[v3,06/15] ice: Initialize PF and setup miscellaneous interrupt", "commit_ref": null, "pull_url": null, "state": "superseded", "archived": false, "hash": "958bc04540a9f2b9d87f9b32e6a0946c9d4a7573", "submitter": { "id": 473, "url": "http://patchwork.ozlabs.org/api/people/473/?format=api", "name": "Kirsher, Jeffrey T", "email": "jeffrey.t.kirsher@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/20180319215644.31978-6-jeffrey.t.kirsher@intel.com/mbox/", "series": [ { "id": 34702, "url": "http://patchwork.ozlabs.org/api/series/34702/?format=api", "web_url": "http://patchwork.ozlabs.org/project/intel-wired-lan/list/?series=34702", "date": "2018-03-19T21:56:30", "name": "[v3,01/15] ice: Add basic driver framework for Intel(R) E800 Series", "version": 3, "mbox": "http://patchwork.ozlabs.org/series/34702/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/887906/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/887906/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;\n\tspf=pass (mailfrom) smtp.mailfrom=osuosl.org\n\t(client-ip=140.211.166.137; helo=fraxinus.osuosl.org;\n\tenvelope-from=intel-wired-lan-bounces@osuosl.org;\n\treceiver=<UNKNOWN>)", "ozlabs.org;\n\tdmarc=none (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 AECDH-AES256-SHA (256/256 bits))\n\t(No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 404qdb6mRjz9sVr\n\tfor <incoming@patchwork.ozlabs.org>;\n\tTue, 20 Mar 2018 08:56:19 +1100 (AEDT)", "from localhost (localhost [127.0.0.1])\n\tby fraxinus.osuosl.org (Postfix) with ESMTP id 439E786787;\n\tMon, 19 Mar 2018 21:56:18 +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 DOnUNSQZwb7e; Mon, 19 Mar 2018 21:56:15 +0000 (UTC)", "from ash.osuosl.org (ash.osuosl.org [140.211.166.34])\n\tby fraxinus.osuosl.org (Postfix) with ESMTP id 8FB3E866FD;\n\tMon, 19 Mar 2018 21:56:15 +0000 (UTC)", "from hemlock.osuosl.org (smtp2.osuosl.org [140.211.166.133])\n\tby ash.osuosl.org (Postfix) with ESMTP id D61661C2272\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tMon, 19 Mar 2018 21:56:13 +0000 (UTC)", "from localhost (localhost [127.0.0.1])\n\tby hemlock.osuosl.org (Postfix) with ESMTP id C90B488ECF\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tMon, 19 Mar 2018 21:56:13 +0000 (UTC)", "from hemlock.osuosl.org ([127.0.0.1])\n\tby localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)\n\twith ESMTP id 5Ql+iZLm3KLw for <intel-wired-lan@lists.osuosl.org>;\n\tMon, 19 Mar 2018 21:56:08 +0000 (UTC)", "from mga02.intel.com (mga02.intel.com [134.134.136.20])\n\tby hemlock.osuosl.org (Postfix) with ESMTPS id 31BE088E95\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tMon, 19 Mar 2018 21:56:08 +0000 (UTC)", "from orsmga008.jf.intel.com ([10.7.209.65])\n\tby orsmga101.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384;\n\t19 Mar 2018 14:56:07 -0700", "from jtkirshe-nuc.jf.intel.com ([134.134.177.59])\n\tby orsmga008.jf.intel.com with ESMTP; 19 Mar 2018 14:56:07 -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.48,332,1517904000\"; d=\"scan'208\";a=\"26667083\"", "From": "Jeff Kirsher <jeffrey.t.kirsher@intel.com>", "To": "intel-wired-lan@lists.osuosl.org", "Date": "Mon, 19 Mar 2018 14:56:35 -0700", "Message-Id": "<20180319215644.31978-6-jeffrey.t.kirsher@intel.com>", "X-Mailer": "git-send-email 2.14.3", "In-Reply-To": "<20180319215644.31978-1-jeffrey.t.kirsher@intel.com>", "References": "<20180319215644.31978-1-jeffrey.t.kirsher@intel.com>", "Subject": "[Intel-wired-lan] [PATCH v3 06/15] ice: Initialize PF and setup\n\tmiscellaneous interrupt", "X-BeenThere": "intel-wired-lan@osuosl.org", "X-Mailman-Version": "2.1.24", "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>", "MIME-Version": "1.0", "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": "From: Anirudh Venkataramanan <anirudh.venkataramanan@intel.com>\n\nThis patch continues the initialization flow as follows:\n\n1) Allocate and initialize necessary fields (like vsi, num_alloc_vsi,\n irq_tracker, etc) in the ice_pf instance.\n\n2) Setup the miscellaneous interrupt handler. This also known as the\n \"other interrupt causes\" (OIC) handler and is used to handle non\n hotpath interrupts (like control queue events, link events,\n exceptions, etc.\n\n3) Implement a background task to process admin queue receive (ARQ)\n events received by the driver.\n\nCC: Shannon Nelson <shannon.nelson@oracle.com>\nSigned-off-by: Anirudh Venkataramanan <anirudh.venkataramanan@intel.com>\nAcked-by: Shannon Nelson <shannon.nelson@oracle.com>\n---\n drivers/net/ethernet/intel/ice/ice.h | 84 +++\n drivers/net/ethernet/intel/ice/ice_adminq_cmd.h | 2 +\n drivers/net/ethernet/intel/ice/ice_common.c | 6 +\n drivers/net/ethernet/intel/ice/ice_common.h | 3 +\n drivers/net/ethernet/intel/ice/ice_controlq.c | 101 ++++\n drivers/net/ethernet/intel/ice/ice_controlq.h | 8 +\n drivers/net/ethernet/intel/ice/ice_hw_autogen.h | 63 +++\n drivers/net/ethernet/intel/ice/ice_main.c | 719 +++++++++++++++++++++++-\n drivers/net/ethernet/intel/ice/ice_txrx.h | 43 ++\n drivers/net/ethernet/intel/ice/ice_type.h | 11 +\n 10 files changed, 1039 insertions(+), 1 deletion(-)\n create mode 100644 drivers/net/ethernet/intel/ice/ice_txrx.h", "diff": "diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h\nindex 9681e971bcab..c8079c852a48 100644\n--- a/drivers/net/ethernet/intel/ice/ice.h\n+++ b/drivers/net/ethernet/intel/ice/ice.h\n@@ -26,29 +26,113 @@\n #include <linux/compiler.h>\n #include <linux/etherdevice.h>\n #include <linux/pci.h>\n+#include <linux/workqueue.h>\n #include <linux/aer.h>\n+#include <linux/interrupt.h>\n+#include <linux/timer.h>\n #include <linux/delay.h>\n #include <linux/bitmap.h>\n+#include <linux/if_bridge.h>\n #include \"ice_devids.h\"\n #include \"ice_type.h\"\n+#include \"ice_txrx.h\"\n #include \"ice_switch.h\"\n #include \"ice_common.h\"\n #include \"ice_sched.h\"\n \n #define ICE_BAR0\t\t0\n+#define ICE_INT_NAME_STR_LEN\t(IFNAMSIZ + 16)\n #define ICE_AQ_LEN\t\t64\n+#define ICE_MIN_MSIX\t\t2\n+#define ICE_MAX_VSI_ALLOC\t130\n+#define ICE_MAX_TXQS\t\t2048\n+#define ICE_MAX_RXQS\t\t2048\n+#define ICE_RES_VALID_BIT\t0x8000\n+#define ICE_RES_MISC_VEC_ID\t(ICE_RES_VALID_BIT - 1)\n \n #define ICE_DFLT_NETIF_M (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK)\n \n+struct ice_res_tracker {\n+\tu16 num_entries;\n+\tu16 search_hint;\n+\tu16 list[1];\n+};\n+\n+struct ice_sw {\n+\tstruct ice_pf *pf;\n+\tu16 sw_id;\t\t/* switch ID for this switch */\n+\tu16 bridge_mode;\t/* VEB/VEPA/Port Virtualizer */\n+};\n+\n enum ice_state {\n \t__ICE_DOWN,\n+\t__ICE_PFR_REQ,\t\t\t/* set by driver and peers */\n+\t__ICE_ADMINQ_EVENT_PENDING,\n+\t__ICE_SERVICE_SCHED,\n \t__ICE_STATE_NBITS\t\t/* must be last */\n };\n \n+/* struct that defines a VSI, associated with a dev */\n+struct ice_vsi {\n+\tstruct net_device *netdev;\n+\tstruct ice_port_info *port_info; /* back pointer to port_info */\n+\tu16 vsi_num;\t\t\t /* HW (absolute) index of this VSI */\n+} ____cacheline_internodealigned_in_smp;\n+\n+enum ice_pf_flags {\n+\tICE_FLAG_MSIX_ENA,\n+\tICE_FLAG_FLTR_SYNC,\n+\tICE_FLAG_RSS_ENA,\n+\tICE_PF_FLAGS_NBITS\t\t/* must be last */\n+};\n+\n struct ice_pf {\n \tstruct pci_dev *pdev;\n+\tstruct msix_entry *msix_entries;\n+\tstruct ice_res_tracker *irq_tracker;\n+\tstruct ice_vsi **vsi;\t\t/* VSIs created by the driver */\n+\tstruct ice_sw *first_sw;\t/* first switch created by firmware */\n \tDECLARE_BITMAP(state, __ICE_STATE_NBITS);\n+\tDECLARE_BITMAP(avail_txqs, ICE_MAX_TXQS);\n+\tDECLARE_BITMAP(avail_rxqs, ICE_MAX_RXQS);\n+\tDECLARE_BITMAP(flags, ICE_PF_FLAGS_NBITS);\n+\tunsigned long serv_tmr_period;\n+\tunsigned long serv_tmr_prev;\n+\tstruct timer_list serv_tmr;\n+\tstruct work_struct serv_task;\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+\tu32 oicr_idx;\t\t/* Other interrupt cause vector index */\n+\tu32 num_lan_msix;\t/* Total MSIX vectors for base driver */\n+\tu32 num_avail_msix;\t/* remaining MSIX vectors left unclaimed */\n+\tu16 num_lan_tx;\t\t/* num lan tx queues setup */\n+\tu16 num_lan_rx;\t\t/* num lan rx queues setup */\n+\tu16 q_left_tx;\t\t/* remaining num tx queues left unclaimed */\n+\tu16 q_left_rx;\t\t/* remaining num rx queues left unclaimed */\n+\tu16 next_vsi;\t\t/* Next free slot in pf->vsi[] - 0-based! */\n+\tu16 num_alloc_vsi;\n+\n \tstruct ice_hw hw;\n+\tchar int_name[ICE_INT_NAME_STR_LEN];\n };\n+\n+/**\n+ * ice_irq_dynamic_ena - Enable default interrupt generation settings\n+ * @hw: pointer to hw struct\n+ */\n+static inline void ice_irq_dynamic_ena(struct ice_hw *hw)\n+{\n+\tu32 vector = ((struct ice_pf *)hw->back)->oicr_idx;\n+\tint itr = ICE_ITR_NONE;\n+\tu32 val;\n+\n+\t/* clear the PBA here, as this function is meant to clean out all\n+\t * previous interrupts and enable the interrupt\n+\t */\n+\tval = GLINT_DYN_CTL_INTENA_M | GLINT_DYN_CTL_CLEARPBA_M |\n+\t (itr << GLINT_DYN_CTL_ITR_INDX_S);\n+\n+\twr32(hw, GLINT_DYN_CTL(vector), val);\n+}\n #endif /* _ICE_H_ */\ndiff --git a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h\nindex 13e3b7f3e24d..1acd936eec49 100644\n--- a/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h\n+++ b/drivers/net/ethernet/intel/ice/ice_adminq_cmd.h\n@@ -597,11 +597,13 @@ struct ice_aq_desc {\n /* FW defined boundary for a large buffer, 4k >= Large buffer > 512 bytes */\n #define ICE_AQ_LG_BUF\t512\n \n+#define ICE_AQ_FLAG_ERR_S\t2\n #define ICE_AQ_FLAG_LB_S\t9\n #define ICE_AQ_FLAG_RD_S\t10\n #define ICE_AQ_FLAG_BUF_S\t12\n #define ICE_AQ_FLAG_SI_S\t13\n \n+#define ICE_AQ_FLAG_ERR\t\tBIT(ICE_AQ_FLAG_ERR_S) /* 0x4 */\n #define ICE_AQ_FLAG_LB\t\tBIT(ICE_AQ_FLAG_LB_S) /* 0x200 */\n #define ICE_AQ_FLAG_RD\t\tBIT(ICE_AQ_FLAG_RD_S) /* 0x400 */\n #define ICE_AQ_FLAG_BUF\t\tBIT(ICE_AQ_FLAG_BUF_S) /* 0x1000 */\ndiff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c\nindex 91f34d90a1f4..e66e9e36a580 100644\n--- a/drivers/net/ethernet/intel/ice/ice_common.c\n+++ b/drivers/net/ethernet/intel/ice/ice_common.c\n@@ -296,6 +296,12 @@ enum ice_status ice_init_hw(struct ice_hw *hw)\n \tif (status)\n \t\treturn status;\n \n+\t/* set these values to minimum allowed */\n+\thw->itr_gran_200 = ICE_ITR_GRAN_MIN_200;\n+\thw->itr_gran_100 = ICE_ITR_GRAN_MIN_100;\n+\thw->itr_gran_50 = ICE_ITR_GRAN_MIN_50;\n+\thw->itr_gran_25 = ICE_ITR_GRAN_MIN_25;\n+\n \tstatus = ice_init_all_ctrlq(hw);\n \tif (status)\n \t\tgoto err_unroll_cqinit;\ndiff --git a/drivers/net/ethernet/intel/ice/ice_common.h b/drivers/net/ethernet/intel/ice/ice_common.h\nindex 3e3b18fc421d..ab47204dfc5a 100644\n--- a/drivers/net/ethernet/intel/ice/ice_common.h\n+++ b/drivers/net/ethernet/intel/ice/ice_common.h\n@@ -31,6 +31,9 @@ enum ice_status ice_reset(struct ice_hw *hw, enum ice_reset_req req);\n enum ice_status ice_init_all_ctrlq(struct ice_hw *hw);\n void ice_shutdown_all_ctrlq(struct ice_hw *hw);\n enum ice_status\n+ice_clean_rq_elem(struct ice_hw *hw, struct ice_ctl_q_info *cq,\n+\t\t struct ice_rq_event_info *e, u16 *pending);\n+enum ice_status\n ice_acquire_res(struct ice_hw *hw, enum ice_aq_res_ids res,\n \t\tenum ice_aq_res_access_type access);\n void ice_release_res(struct ice_hw *hw, enum ice_aq_res_ids res);\ndiff --git a/drivers/net/ethernet/intel/ice/ice_controlq.c b/drivers/net/ethernet/intel/ice/ice_controlq.c\nindex b1143d66d4bd..3f63a20b45c0 100644\n--- a/drivers/net/ethernet/intel/ice/ice_controlq.c\n+++ b/drivers/net/ethernet/intel/ice/ice_controlq.c\n@@ -977,3 +977,104 @@ void ice_fill_dflt_direct_cmd_desc(struct ice_aq_desc *desc, u16 opcode)\n \tdesc->opcode = cpu_to_le16(opcode);\n \tdesc->flags = cpu_to_le16(ICE_AQ_FLAG_SI);\n }\n+\n+/**\n+ * ice_clean_rq_elem\n+ * @hw: pointer to the hw struct\n+ * @cq: pointer to the specific Control queue\n+ * @e: event info from the receive descriptor, includes any buffers\n+ * @pending: number of events that could be left to process\n+ *\n+ * This function cleans one Admin Receive Queue element and returns\n+ * the contents through e. It can also return how many events are\n+ * left to process through 'pending'.\n+ */\n+enum ice_status\n+ice_clean_rq_elem(struct ice_hw *hw, struct ice_ctl_q_info *cq,\n+\t\t struct ice_rq_event_info *e, u16 *pending)\n+{\n+\tu16 ntc = cq->rq.next_to_clean;\n+\tenum ice_status ret_code = 0;\n+\tstruct ice_aq_desc *desc;\n+\tstruct ice_dma_mem *bi;\n+\tu16 desc_idx;\n+\tu16 datalen;\n+\tu16 flags;\n+\tu16 ntu;\n+\n+\t/* pre-clean the event info */\n+\tmemset(&e->desc, 0, sizeof(e->desc));\n+\n+\t/* take the lock before we start messing with the ring */\n+\tmutex_lock(&cq->rq_lock);\n+\n+\tif (!cq->rq.count) {\n+\t\tice_debug(hw, ICE_DBG_AQ_MSG,\n+\t\t\t \"Control Receive queue not initialized.\\n\");\n+\t\tret_code = ICE_ERR_AQ_EMPTY;\n+\t\tgoto clean_rq_elem_err;\n+\t}\n+\n+\t/* set next_to_use to head */\n+\tntu = (u16)(rd32(hw, cq->rq.head) & cq->rq.head_mask);\n+\n+\tif (ntu == ntc) {\n+\t\t/* nothing to do - shouldn't need to update ring's values */\n+\t\tret_code = ICE_ERR_AQ_NO_WORK;\n+\t\tgoto clean_rq_elem_out;\n+\t}\n+\n+\t/* now clean the next descriptor */\n+\tdesc = ICE_CTL_Q_DESC(cq->rq, ntc);\n+\tdesc_idx = ntc;\n+\n+\tflags = le16_to_cpu(desc->flags);\n+\tif (flags & ICE_AQ_FLAG_ERR) {\n+\t\tret_code = ICE_ERR_AQ_ERROR;\n+\t\tcq->rq_last_status = (enum ice_aq_err)le16_to_cpu(desc->retval);\n+\t\tice_debug(hw, ICE_DBG_AQ_MSG,\n+\t\t\t \"Control Receive Queue Event received with error 0x%x\\n\",\n+\t\t\t cq->rq_last_status);\n+\t}\n+\tmemcpy(&e->desc, desc, sizeof(e->desc));\n+\tdatalen = le16_to_cpu(desc->datalen);\n+\te->msg_len = min(datalen, e->buf_len);\n+\tif (e->msg_buf && e->msg_len)\n+\t\tmemcpy(e->msg_buf, cq->rq.r.rq_bi[desc_idx].va, e->msg_len);\n+\n+\tice_debug(hw, ICE_DBG_AQ_MSG, \"ARQ: desc and buffer:\\n\");\n+\n+\tice_debug_cq(hw, ICE_DBG_AQ_CMD, (void *)desc, e->msg_buf,\n+\t\t cq->rq_buf_size);\n+\n+\t/* Restore the original datalen and buffer address in the desc,\n+\t * FW updates datalen to indicate the event message size\n+\t */\n+\tbi = &cq->rq.r.rq_bi[ntc];\n+\tmemset(desc, 0, sizeof(*desc));\n+\n+\tdesc->flags = cpu_to_le16(ICE_AQ_FLAG_BUF);\n+\tif (cq->rq_buf_size > ICE_AQ_LG_BUF)\n+\t\tdesc->flags |= cpu_to_le16(ICE_AQ_FLAG_LB);\n+\tdesc->datalen = cpu_to_le16(bi->size);\n+\tdesc->params.generic.addr_high = cpu_to_le32(upper_32_bits(bi->pa));\n+\tdesc->params.generic.addr_low = cpu_to_le32(lower_32_bits(bi->pa));\n+\n+\t/* set tail = the last cleaned desc index. */\n+\twr32(hw, cq->rq.tail, ntc);\n+\t/* ntc is updated to tail + 1 */\n+\tntc++;\n+\tif (ntc == cq->num_rq_entries)\n+\t\tntc = 0;\n+\tcq->rq.next_to_clean = ntc;\n+\tcq->rq.next_to_use = ntu;\n+\n+clean_rq_elem_out:\n+\t/* Set pending if needed, unlock and return */\n+\tif (pending)\n+\t\t*pending = (u16)((ntc > ntu ? cq->rq.count : 0) + (ntu - ntc));\n+clean_rq_elem_err:\n+\tmutex_unlock(&cq->rq_lock);\n+\n+\treturn ret_code;\n+}\ndiff --git a/drivers/net/ethernet/intel/ice/ice_controlq.h b/drivers/net/ethernet/intel/ice/ice_controlq.h\nindex 835c035419a3..403613606652 100644\n--- a/drivers/net/ethernet/intel/ice/ice_controlq.h\n+++ b/drivers/net/ethernet/intel/ice/ice_controlq.h\n@@ -81,6 +81,14 @@ struct ice_sq_cd {\n \n #define ICE_CTL_Q_DETAILS(R, i) (&(((struct ice_sq_cd *)((R).cmd_buf))[i]))\n \n+/* rq event information */\n+struct ice_rq_event_info {\n+\tstruct ice_aq_desc desc;\n+\tu16 msg_len;\n+\tu16 buf_len;\n+\tu8 *msg_buf;\n+};\n+\n /* Control Queue information */\n struct ice_ctl_q_info {\n \tenum ice_ctl_q qtype;\ndiff --git a/drivers/net/ethernet/intel/ice/ice_hw_autogen.h b/drivers/net/ethernet/intel/ice/ice_hw_autogen.h\nindex e258a12099b8..700edc7e7280 100644\n--- a/drivers/net/ethernet/intel/ice/ice_hw_autogen.h\n+++ b/drivers/net/ethernet/intel/ice/ice_hw_autogen.h\n@@ -28,6 +28,12 @@\n #define PF_FW_ARQLEN\t\t\t0x00080280\n #define PF_FW_ARQLEN_ARQLEN_S\t\t0\n #define PF_FW_ARQLEN_ARQLEN_M\t\tICE_M(0x3FF, PF_FW_ARQLEN_ARQLEN_S)\n+#define PF_FW_ARQLEN_ARQVFE_S\t\t28\n+#define PF_FW_ARQLEN_ARQVFE_M\t\tBIT(PF_FW_ARQLEN_ARQVFE_S)\n+#define PF_FW_ARQLEN_ARQOVFL_S\t\t29\n+#define PF_FW_ARQLEN_ARQOVFL_M\t\tBIT(PF_FW_ARQLEN_ARQOVFL_S)\n+#define PF_FW_ARQLEN_ARQCRIT_S\t\t30\n+#define PF_FW_ARQLEN_ARQCRIT_M\t\tBIT(PF_FW_ARQLEN_ARQCRIT_S)\n #define PF_FW_ARQLEN_ARQENABLE_S\t31\n #define PF_FW_ARQLEN_ARQENABLE_M\tBIT(PF_FW_ARQLEN_ARQENABLE_S)\n #define PF_FW_ARQT\t\t\t0x00080480\n@@ -39,6 +45,12 @@\n #define PF_FW_ATQLEN\t\t\t0x00080200\n #define PF_FW_ATQLEN_ATQLEN_S\t\t0\n #define PF_FW_ATQLEN_ATQLEN_M\t\tICE_M(0x3FF, PF_FW_ATQLEN_ATQLEN_S)\n+#define PF_FW_ATQLEN_ATQVFE_S\t\t28\n+#define PF_FW_ATQLEN_ATQVFE_M\t\tBIT(PF_FW_ATQLEN_ATQVFE_S)\n+#define PF_FW_ATQLEN_ATQOVFL_S\t\t29\n+#define PF_FW_ATQLEN_ATQOVFL_M\t\tBIT(PF_FW_ATQLEN_ATQOVFL_S)\n+#define PF_FW_ATQLEN_ATQCRIT_S\t\t30\n+#define PF_FW_ATQLEN_ATQCRIT_M\t\tBIT(PF_FW_ATQLEN_ATQCRIT_S)\n #define PF_FW_ATQLEN_ATQENABLE_S\t31\n #define PF_FW_ATQLEN_ATQENABLE_M\tBIT(PF_FW_ATQLEN_ATQENABLE_S)\n #define PF_FW_ATQT\t\t\t0x00080400\n@@ -57,6 +69,57 @@\n #define PFGEN_CTRL\t\t\t0x00091000\n #define PFGEN_CTRL_PFSWR_S\t\t0\n #define PFGEN_CTRL_PFSWR_M\t\tBIT(PFGEN_CTRL_PFSWR_S)\n+#define PFHMC_ERRORDATA\t\t\t0x00520500\n+#define PFHMC_ERRORINFO\t\t\t0x00520400\n+#define GLINT_DYN_CTL(_INT)\t\t(0x00160000 + ((_INT) * 4))\n+#define GLINT_DYN_CTL_INTENA_S\t\t0\n+#define GLINT_DYN_CTL_INTENA_M\t\tBIT(GLINT_DYN_CTL_INTENA_S)\n+#define GLINT_DYN_CTL_CLEARPBA_S\t1\n+#define GLINT_DYN_CTL_CLEARPBA_M\tBIT(GLINT_DYN_CTL_CLEARPBA_S)\n+#define GLINT_DYN_CTL_ITR_INDX_S\t3\n+#define GLINT_DYN_CTL_SW_ITR_INDX_S\t25\n+#define GLINT_DYN_CTL_SW_ITR_INDX_M\tICE_M(0x3, GLINT_DYN_CTL_SW_ITR_INDX_S)\n+#define GLINT_DYN_CTL_INTENA_MSK_S\t31\n+#define GLINT_DYN_CTL_INTENA_MSK_M\tBIT(GLINT_DYN_CTL_INTENA_MSK_S)\n+#define GLINT_ITR(_i, _INT)\t\t(0x00154000 + ((_i) * 8192 + (_INT) * 4))\n+#define PFINT_FW_CTL\t\t\t0x0016C800\n+#define PFINT_FW_CTL_MSIX_INDX_S\t0\n+#define PFINT_FW_CTL_MSIX_INDX_M\tICE_M(0x7FF, PFINT_FW_CTL_MSIX_INDX_S)\n+#define PFINT_FW_CTL_ITR_INDX_S\t\t11\n+#define PFINT_FW_CTL_ITR_INDX_M\t\tICE_M(0x3, PFINT_FW_CTL_ITR_INDX_S)\n+#define PFINT_FW_CTL_CAUSE_ENA_S\t30\n+#define PFINT_FW_CTL_CAUSE_ENA_M\tBIT(PFINT_FW_CTL_CAUSE_ENA_S)\n+#define PFINT_OICR\t\t\t0x0016CA00\n+#define PFINT_OICR_INTEVENT_S\t\t0\n+#define PFINT_OICR_INTEVENT_M\t\tBIT(PFINT_OICR_INTEVENT_S)\n+#define PFINT_OICR_HLP_RDY_S\t\t14\n+#define PFINT_OICR_HLP_RDY_M\t\tBIT(PFINT_OICR_HLP_RDY_S)\n+#define PFINT_OICR_CPM_RDY_S\t\t15\n+#define PFINT_OICR_CPM_RDY_M\t\tBIT(PFINT_OICR_CPM_RDY_S)\n+#define PFINT_OICR_ECC_ERR_S\t\t16\n+#define PFINT_OICR_ECC_ERR_M\t\tBIT(PFINT_OICR_ECC_ERR_S)\n+#define PFINT_OICR_MAL_DETECT_S\t\t19\n+#define PFINT_OICR_MAL_DETECT_M\t\tBIT(PFINT_OICR_MAL_DETECT_S)\n+#define PFINT_OICR_GRST_S\t\t20\n+#define PFINT_OICR_GRST_M\t\tBIT(PFINT_OICR_GRST_S)\n+#define PFINT_OICR_PCI_EXCEPTION_S\t21\n+#define PFINT_OICR_PCI_EXCEPTION_M\tBIT(PFINT_OICR_PCI_EXCEPTION_S)\n+#define PFINT_OICR_GPIO_S\t\t22\n+#define PFINT_OICR_GPIO_M\t\tBIT(PFINT_OICR_GPIO_S)\n+#define PFINT_OICR_STORM_DETECT_S\t24\n+#define PFINT_OICR_STORM_DETECT_M\tBIT(PFINT_OICR_STORM_DETECT_S)\n+#define PFINT_OICR_HMC_ERR_S\t\t26\n+#define PFINT_OICR_HMC_ERR_M\t\tBIT(PFINT_OICR_HMC_ERR_S)\n+#define PFINT_OICR_PE_CRITERR_S\t\t28\n+#define PFINT_OICR_PE_CRITERR_M\t\tBIT(PFINT_OICR_PE_CRITERR_S)\n+#define PFINT_OICR_CTL\t\t\t0x0016CA80\n+#define PFINT_OICR_CTL_MSIX_INDX_S\t0\n+#define PFINT_OICR_CTL_MSIX_INDX_M\tICE_M(0x7FF, PFINT_OICR_CTL_MSIX_INDX_S)\n+#define PFINT_OICR_CTL_ITR_INDX_S\t11\n+#define PFINT_OICR_CTL_ITR_INDX_M\tICE_M(0x3, PFINT_OICR_CTL_ITR_INDX_S)\n+#define PFINT_OICR_CTL_CAUSE_ENA_S\t30\n+#define PFINT_OICR_CTL_CAUSE_ENA_M\tBIT(PFINT_OICR_CTL_CAUSE_ENA_S)\n+#define PFINT_OICR_ENA\t\t\t0x0016C900\n #define GLLAN_RCTL_0\t\t\t0x002941F8\n #define GLNVM_FLA\t\t\t0x000B6108\n #define GLNVM_FLA_LOCKED_S\t\t6\ndiff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c\nindex 2ee4a0547ba3..197c64ea79e8 100644\n--- a/drivers/net/ethernet/intel/ice/ice_main.c\n+++ b/drivers/net/ethernet/intel/ice/ice_main.c\n@@ -40,6 +40,294 @@ MODULE_PARM_DESC(debug, \"netif level (0=none,...,16=all), hw debug_mask (0x8XXXX\n MODULE_PARM_DESC(debug, \"netif level (0=none,...,16=all)\");\n #endif /* !CONFIG_DYNAMIC_DEBUG */\n \n+static struct workqueue_struct *ice_wq;\n+\n+/**\n+ * ice_search_res - Search the tracker for a block of resources\n+ * @res: pointer to the resource\n+ * @needed: size of the block needed\n+ * @id: identifier to track owner\n+ * Returns the base item index of the block, or -ENOMEM for error\n+ */\n+static int ice_search_res(struct ice_res_tracker *res, u16 needed, u16 id)\n+{\n+\tint start = res->search_hint;\n+\tint end = start;\n+\n+\tid |= ICE_RES_VALID_BIT;\n+\n+\tdo {\n+\t\t/* skip already allocated entries */\n+\t\tif (res->list[end++] & ICE_RES_VALID_BIT) {\n+\t\t\tstart = end;\n+\t\t\tif ((start + needed) > res->num_entries)\n+\t\t\t\tbreak;\n+\t\t}\n+\n+\t\tif (end == (start + needed)) {\n+\t\t\tint i = start;\n+\n+\t\t\t/* there was enough, so assign it to the requestor */\n+\t\t\twhile (i != end)\n+\t\t\t\tres->list[i++] = id;\n+\n+\t\t\tif (end == res->num_entries)\n+\t\t\t\tend = 0;\n+\n+\t\t\tres->search_hint = end;\n+\t\t\treturn start;\n+\t\t}\n+\t} while (1);\n+\n+\treturn -ENOMEM;\n+}\n+\n+/**\n+ * ice_get_res - get a block of resources\n+ * @pf: board private structure\n+ * @res: pointer to the resource\n+ * @needed: size of the block needed\n+ * @id: identifier to track owner\n+ *\n+ * Returns the base item index of the block, or -ENOMEM for error\n+ * The search_hint trick and lack of advanced fit-finding only works\n+ * because we're highly likely to have all the same sized requests.\n+ * Linear search time and any fragmentation should be minimal.\n+ */\n+static int\n+ice_get_res(struct ice_pf *pf, struct ice_res_tracker *res, u16 needed, u16 id)\n+{\n+\tint ret;\n+\n+\tif (!res || !pf)\n+\t\treturn -EINVAL;\n+\n+\tif (!needed || needed > res->num_entries || id >= ICE_RES_VALID_BIT) {\n+\t\tdev_err(&pf->pdev->dev,\n+\t\t\t\"param err: needed=%d, num_entries = %d id=0x%04x\\n\",\n+\t\t\tneeded, res->num_entries, id);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\t/* search based on search_hint */\n+\tret = ice_search_res(res, needed, id);\n+\n+\tif (ret < 0) {\n+\t\t/* previous search failed. Reset search hint and try again */\n+\t\tres->search_hint = 0;\n+\t\tret = ice_search_res(res, needed, id);\n+\t}\n+\n+\treturn ret;\n+}\n+\n+/**\n+ * ice_free_res - free a block of resources\n+ * @res: pointer to the resource\n+ * @index: starting index previously returned by ice_get_res\n+ * @id: identifier to track owner\n+ * Returns number of resources freed\n+ */\n+static int ice_free_res(struct ice_res_tracker *res, u16 index, u16 id)\n+{\n+\tint count = 0;\n+\tint i;\n+\n+\tif (!res || index >= res->num_entries)\n+\t\treturn -EINVAL;\n+\n+\tid |= ICE_RES_VALID_BIT;\n+\tfor (i = index; i < res->num_entries && res->list[i] == id; i++) {\n+\t\tres->list[i] = 0;\n+\t\tcount++;\n+\t}\n+\n+\treturn count;\n+}\n+\n+/**\n+ * __ice_clean_ctrlq - helper function to clean controlq rings\n+ * @pf: ptr to struct ice_pf\n+ * @q_type: specific Control queue type\n+ */\n+static int __ice_clean_ctrlq(struct ice_pf *pf, enum ice_ctl_q q_type)\n+{\n+\tstruct ice_rq_event_info event;\n+\tstruct ice_hw *hw = &pf->hw;\n+\tstruct ice_ctl_q_info *cq;\n+\tu16 pending, i = 0;\n+\tconst char *qtype;\n+\tu32 oldval, val;\n+\n+\tswitch (q_type) {\n+\tcase ICE_CTL_Q_ADMIN:\n+\t\tcq = &hw->adminq;\n+\t\tqtype = \"Admin\";\n+\t\tbreak;\n+\tdefault:\n+\t\tdev_warn(&pf->pdev->dev, \"Unknown control queue type 0x%x\\n\",\n+\t\t\t q_type);\n+\t\treturn 0;\n+\t}\n+\n+\t/* check for error indications - PF_xx_AxQLEN register layout for\n+\t * FW/MBX/SB are identical so just use defines for PF_FW_AxQLEN.\n+\t */\n+\tval = rd32(hw, cq->rq.len);\n+\tif (val & (PF_FW_ARQLEN_ARQVFE_M | PF_FW_ARQLEN_ARQOVFL_M |\n+\t\t PF_FW_ARQLEN_ARQCRIT_M)) {\n+\t\toldval = val;\n+\t\tif (val & PF_FW_ARQLEN_ARQVFE_M)\n+\t\t\tdev_dbg(&pf->pdev->dev,\n+\t\t\t\t\"%s Receive Queue VF Error detected\\n\", qtype);\n+\t\tif (val & PF_FW_ARQLEN_ARQOVFL_M) {\n+\t\t\tdev_dbg(&pf->pdev->dev,\n+\t\t\t\t\"%s Receive Queue Overflow Error detected\\n\",\n+\t\t\t\tqtype);\n+\t\t}\n+\t\tif (val & PF_FW_ARQLEN_ARQCRIT_M)\n+\t\t\tdev_dbg(&pf->pdev->dev,\n+\t\t\t\t\"%s Receive Queue Critical Error detected\\n\",\n+\t\t\t\tqtype);\n+\t\tval &= ~(PF_FW_ARQLEN_ARQVFE_M | PF_FW_ARQLEN_ARQOVFL_M |\n+\t\t\t PF_FW_ARQLEN_ARQCRIT_M);\n+\t\tif (oldval != val)\n+\t\t\twr32(hw, cq->rq.len, val);\n+\t}\n+\n+\tval = rd32(hw, cq->sq.len);\n+\tif (val & (PF_FW_ATQLEN_ATQVFE_M | PF_FW_ATQLEN_ATQOVFL_M |\n+\t\t PF_FW_ATQLEN_ATQCRIT_M)) {\n+\t\toldval = val;\n+\t\tif (val & PF_FW_ATQLEN_ATQVFE_M)\n+\t\t\tdev_dbg(&pf->pdev->dev,\n+\t\t\t\t\"%s Send Queue VF Error detected\\n\", qtype);\n+\t\tif (val & PF_FW_ATQLEN_ATQOVFL_M) {\n+\t\t\tdev_dbg(&pf->pdev->dev,\n+\t\t\t\t\"%s Send Queue Overflow Error detected\\n\",\n+\t\t\t\tqtype);\n+\t\t}\n+\t\tif (val & PF_FW_ATQLEN_ATQCRIT_M)\n+\t\t\tdev_dbg(&pf->pdev->dev,\n+\t\t\t\t\"%s Send Queue Critical Error detected\\n\",\n+\t\t\t\tqtype);\n+\t\tval &= ~(PF_FW_ATQLEN_ATQVFE_M | PF_FW_ATQLEN_ATQOVFL_M |\n+\t\t\t PF_FW_ATQLEN_ATQCRIT_M);\n+\t\tif (oldval != val)\n+\t\t\twr32(hw, cq->sq.len, val);\n+\t}\n+\n+\tevent.buf_len = cq->rq_buf_size;\n+\tevent.msg_buf = devm_kzalloc(&pf->pdev->dev, event.buf_len,\n+\t\t\t\t GFP_KERNEL);\n+\tif (!event.msg_buf)\n+\t\treturn 0;\n+\n+\tdo {\n+\t\tenum ice_status ret;\n+\n+\t\tret = ice_clean_rq_elem(hw, cq, &event, &pending);\n+\t\tif (ret == ICE_ERR_AQ_NO_WORK)\n+\t\t\tbreak;\n+\t\tif (ret) {\n+\t\t\tdev_err(&pf->pdev->dev,\n+\t\t\t\t\"%s Receive Queue event error %d\\n\", qtype,\n+\t\t\t\tret);\n+\t\t\tbreak;\n+\t\t}\n+\t} while (pending && (i++ < ICE_DFLT_IRQ_WORK));\n+\n+\tdevm_kfree(&pf->pdev->dev, event.msg_buf);\n+\n+\treturn pending && (i == ICE_DFLT_IRQ_WORK);\n+}\n+\n+/**\n+ * ice_clean_adminq_subtask - clean the AdminQ rings\n+ * @pf: board private structure\n+ */\n+static void ice_clean_adminq_subtask(struct ice_pf *pf)\n+{\n+\tstruct ice_hw *hw = &pf->hw;\n+\tu32 val;\n+\n+\tif (!test_bit(__ICE_ADMINQ_EVENT_PENDING, pf->state))\n+\t\treturn;\n+\n+\tif (__ice_clean_ctrlq(pf, ICE_CTL_Q_ADMIN))\n+\t\treturn;\n+\n+\tclear_bit(__ICE_ADMINQ_EVENT_PENDING, pf->state);\n+\n+\t/* re-enable Admin queue interrupt causes */\n+\tval = rd32(hw, PFINT_FW_CTL);\n+\twr32(hw, PFINT_FW_CTL, (val | PFINT_FW_CTL_CAUSE_ENA_M));\n+\n+\tice_flush(hw);\n+}\n+\n+/**\n+ * ice_service_task_schedule - schedule the service task to wake up\n+ * @pf: board private structure\n+ *\n+ * If not already scheduled, this puts the task into the work queue.\n+ */\n+static void ice_service_task_schedule(struct ice_pf *pf)\n+{\n+\tif (!test_bit(__ICE_DOWN, pf->state) &&\n+\t !test_and_set_bit(__ICE_SERVICE_SCHED, pf->state))\n+\t\tqueue_work(ice_wq, &pf->serv_task);\n+}\n+\n+/**\n+ * ice_service_task_complete - finish up the service task\n+ * @pf: board private structure\n+ */\n+static void ice_service_task_complete(struct ice_pf *pf)\n+{\n+\tWARN_ON(!test_bit(__ICE_SERVICE_SCHED, pf->state));\n+\n+\t/* force memory (pf->state) to sync before next service task */\n+\tsmp_mb__before_atomic();\n+\tclear_bit(__ICE_SERVICE_SCHED, pf->state);\n+}\n+\n+/**\n+ * ice_service_timer - timer callback to schedule service task\n+ * @t: pointer to timer_list\n+ */\n+static void ice_service_timer(struct timer_list *t)\n+{\n+\tstruct ice_pf *pf = from_timer(pf, t, serv_tmr);\n+\n+\tmod_timer(&pf->serv_tmr, round_jiffies(pf->serv_tmr_period + jiffies));\n+\tice_service_task_schedule(pf);\n+}\n+\n+/**\n+ * ice_service_task - manage and run subtasks\n+ * @work: pointer to work_struct contained by the PF struct\n+ */\n+static void ice_service_task(struct work_struct *work)\n+{\n+\tstruct ice_pf *pf = container_of(work, struct ice_pf, serv_task);\n+\tunsigned long start_time = jiffies;\n+\n+\t/* subtasks */\n+\tice_clean_adminq_subtask(pf);\n+\n+\t/* Clear __ICE_SERVICE_SCHED flag to allow scheduling next event */\n+\tice_service_task_complete(pf);\n+\n+\t/* If the tasks have taken longer than one service timer period\n+\t * or there is more work to be done, reset the service timer to\n+\t * schedule the service task now.\n+\t */\n+\tif (time_after(jiffies, (start_time + pf->serv_tmr_period)) ||\n+\t test_bit(__ICE_ADMINQ_EVENT_PENDING, pf->state))\n+\t\tmod_timer(&pf->serv_tmr, jiffies);\n+}\n+\n /**\n * ice_set_ctrlq_len - helper function to set controlq length\n * @hw: pointer to the hw instance\n@@ -52,6 +340,361 @@ static void ice_set_ctrlq_len(struct ice_hw *hw)\n \thw->adminq.sq_buf_size = ICE_AQ_MAX_BUF_LEN;\n }\n \n+/**\n+ * ice_ena_misc_vector - enable the non-queue interrupts\n+ * @pf: board private structure\n+ */\n+static void ice_ena_misc_vector(struct ice_pf *pf)\n+{\n+\tstruct ice_hw *hw = &pf->hw;\n+\tu32 val;\n+\n+\t/* clear things first */\n+\twr32(hw, PFINT_OICR_ENA, 0);\t/* disable all */\n+\trd32(hw, PFINT_OICR);\t\t/* read to clear */\n+\n+\tval = (PFINT_OICR_HLP_RDY_M |\n+\t PFINT_OICR_CPM_RDY_M |\n+\t PFINT_OICR_ECC_ERR_M |\n+\t PFINT_OICR_MAL_DETECT_M |\n+\t PFINT_OICR_GRST_M |\n+\t PFINT_OICR_PCI_EXCEPTION_M |\n+\t PFINT_OICR_GPIO_M |\n+\t PFINT_OICR_STORM_DETECT_M |\n+\t PFINT_OICR_HMC_ERR_M);\n+\n+\twr32(hw, PFINT_OICR_ENA, val);\n+\n+\t/* SW_ITR_IDX = 0, but don't change INTENA */\n+\twr32(hw, GLINT_DYN_CTL(pf->oicr_idx),\n+\t GLINT_DYN_CTL_SW_ITR_INDX_M | GLINT_DYN_CTL_INTENA_MSK_M);\n+}\n+\n+/**\n+ * ice_misc_intr - misc interrupt handler\n+ * @irq: interrupt number\n+ * @data: pointer to a q_vector\n+ */\n+static irqreturn_t ice_misc_intr(int __always_unused irq, void *data)\n+{\n+\tstruct ice_pf *pf = (struct ice_pf *)data;\n+\tstruct ice_hw *hw = &pf->hw;\n+\tirqreturn_t ret = IRQ_NONE;\n+\tu32 oicr, ena_mask;\n+\n+\tset_bit(__ICE_ADMINQ_EVENT_PENDING, pf->state);\n+\n+\toicr = rd32(hw, PFINT_OICR);\n+\tena_mask = rd32(hw, PFINT_OICR_ENA);\n+\n+\tif (!(oicr & PFINT_OICR_INTEVENT_M))\n+\t\tgoto ena_intr;\n+\n+\tif (oicr & PFINT_OICR_HMC_ERR_M) {\n+\t\tena_mask &= ~PFINT_OICR_HMC_ERR_M;\n+\t\tdev_dbg(&pf->pdev->dev,\n+\t\t\t\"HMC Error interrupt - info 0x%x, data 0x%x\\n\",\n+\t\t\trd32(hw, PFHMC_ERRORINFO),\n+\t\t\trd32(hw, PFHMC_ERRORDATA));\n+\t}\n+\n+\t/* Report and mask off any remaining unexpected interrupts */\n+\toicr &= ena_mask;\n+\tif (oicr) {\n+\t\tdev_dbg(&pf->pdev->dev, \"unhandled interrupt oicr=0x%08x\\n\",\n+\t\t\toicr);\n+\t\t/* If a critical error is pending there is no choice but to\n+\t\t * reset the device.\n+\t\t */\n+\t\tif (oicr & (PFINT_OICR_PE_CRITERR_M |\n+\t\t\t PFINT_OICR_PCI_EXCEPTION_M |\n+\t\t\t PFINT_OICR_ECC_ERR_M))\n+\t\t\tset_bit(__ICE_PFR_REQ, pf->state);\n+\n+\t\tena_mask &= ~oicr;\n+\t}\n+\tret = IRQ_HANDLED;\n+\n+ena_intr:\n+\t/* re-enable interrupt causes that are not handled during this pass */\n+\twr32(hw, PFINT_OICR_ENA, ena_mask);\n+\tif (!test_bit(__ICE_DOWN, pf->state)) {\n+\t\tice_service_task_schedule(pf);\n+\t\tice_irq_dynamic_ena(hw);\n+\t}\n+\n+\treturn ret;\n+}\n+\n+/**\n+ * ice_free_irq_msix_misc - Unroll misc vector setup\n+ * @pf: board private structure\n+ */\n+static void ice_free_irq_msix_misc(struct ice_pf *pf)\n+{\n+\t/* disable OICR interrupt */\n+\twr32(&pf->hw, PFINT_OICR_ENA, 0);\n+\tice_flush(&pf->hw);\n+\n+\tif (test_bit(ICE_FLAG_MSIX_ENA, pf->flags) && pf->msix_entries) {\n+\t\tsynchronize_irq(pf->msix_entries[pf->oicr_idx].vector);\n+\t\tdevm_free_irq(&pf->pdev->dev,\n+\t\t\t pf->msix_entries[pf->oicr_idx].vector, pf);\n+\t}\n+\n+\tice_free_res(pf->irq_tracker, pf->oicr_idx, ICE_RES_MISC_VEC_ID);\n+}\n+\n+/**\n+ * ice_req_irq_msix_misc - Setup the misc vector to handle non queue events\n+ * @pf: board private structure\n+ *\n+ * This sets up the handler for MSIX 0, which is used to manage the\n+ * non-queue interrupts, e.g. AdminQ and errors. This is not used\n+ * when in MSI or Legacy interrupt mode.\n+ */\n+static int ice_req_irq_msix_misc(struct ice_pf *pf)\n+{\n+\tstruct ice_hw *hw = &pf->hw;\n+\tint oicr_idx, err = 0;\n+\tu8 itr_gran;\n+\tu32 val;\n+\n+\tif (!pf->int_name[0])\n+\t\tsnprintf(pf->int_name, sizeof(pf->int_name) - 1, \"%s-%s:misc\",\n+\t\t\t dev_driver_string(&pf->pdev->dev),\n+\t\t\t dev_name(&pf->pdev->dev));\n+\n+\t/* reserve one vector in irq_tracker for misc interrupts */\n+\toicr_idx = ice_get_res(pf, pf->irq_tracker, 1, ICE_RES_MISC_VEC_ID);\n+\tif (oicr_idx < 0)\n+\t\treturn oicr_idx;\n+\n+\tpf->oicr_idx = oicr_idx;\n+\n+\terr = devm_request_irq(&pf->pdev->dev,\n+\t\t\t pf->msix_entries[pf->oicr_idx].vector,\n+\t\t\t ice_misc_intr, 0, pf->int_name, pf);\n+\tif (err) {\n+\t\tdev_err(&pf->pdev->dev,\n+\t\t\t\"devm_request_irq for %s failed: %d\\n\",\n+\t\t\tpf->int_name, err);\n+\t\tice_free_res(pf->irq_tracker, 1, ICE_RES_MISC_VEC_ID);\n+\t\treturn err;\n+\t}\n+\n+\tice_ena_misc_vector(pf);\n+\n+\tval = (pf->oicr_idx & PFINT_OICR_CTL_MSIX_INDX_M) |\n+\t (ICE_RX_ITR & PFINT_OICR_CTL_ITR_INDX_M) |\n+\t PFINT_OICR_CTL_CAUSE_ENA_M;\n+\twr32(hw, PFINT_OICR_CTL, val);\n+\n+\t/* This enables Admin queue Interrupt causes */\n+\tval = (pf->oicr_idx & PFINT_FW_CTL_MSIX_INDX_M) |\n+\t (ICE_RX_ITR & PFINT_FW_CTL_ITR_INDX_M) |\n+\t PFINT_FW_CTL_CAUSE_ENA_M;\n+\twr32(hw, PFINT_FW_CTL, val);\n+\n+\titr_gran = hw->itr_gran_200;\n+\n+\twr32(hw, GLINT_ITR(ICE_RX_ITR, pf->oicr_idx),\n+\t ITR_TO_REG(ICE_ITR_8K, itr_gran));\n+\n+\tice_flush(hw);\n+\tice_irq_dynamic_ena(hw);\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * ice_determine_q_usage - Calculate queue distribution\n+ * @pf: board private structure\n+ *\n+ * Return -ENOMEM if we don't get enough queues for all ports\n+ */\n+static void ice_determine_q_usage(struct ice_pf *pf)\n+{\n+\tu16 q_left_tx, q_left_rx;\n+\n+\tq_left_tx = pf->hw.func_caps.common_cap.num_txq;\n+\tq_left_rx = pf->hw.func_caps.common_cap.num_rxq;\n+\n+\t/* initial support for only 1 tx and 1 rx queue */\n+\tpf->num_lan_tx = 1;\n+\tpf->num_lan_rx = 1;\n+\n+\tpf->q_left_tx = q_left_tx - pf->num_lan_tx;\n+\tpf->q_left_rx = q_left_rx - pf->num_lan_rx;\n+}\n+\n+/**\n+ * ice_deinit_pf - Unrolls initialziations done by ice_init_pf\n+ * @pf: board private structure to initialize\n+ */\n+static void ice_deinit_pf(struct ice_pf *pf)\n+{\n+\tif (pf->serv_tmr.function)\n+\t\tdel_timer_sync(&pf->serv_tmr);\n+\tif (pf->serv_task.func)\n+\t\tcancel_work_sync(&pf->serv_task);\n+\tmutex_destroy(&pf->sw_mutex);\n+\tmutex_destroy(&pf->avail_q_mutex);\n+}\n+\n+/**\n+ * ice_init_pf - Initialize general software structures (struct ice_pf)\n+ * @pf: board private structure to initialize\n+ */\n+static void ice_init_pf(struct ice_pf *pf)\n+{\n+\tbitmap_zero(pf->flags, ICE_PF_FLAGS_NBITS);\n+\tset_bit(ICE_FLAG_MSIX_ENA, pf->flags);\n+\n+\tmutex_init(&pf->sw_mutex);\n+\tmutex_init(&pf->avail_q_mutex);\n+\n+\t/* Clear avail_[t|r]x_qs bitmaps (set all to avail) */\n+\tmutex_lock(&pf->avail_q_mutex);\n+\tbitmap_zero(pf->avail_txqs, ICE_MAX_TXQS);\n+\tbitmap_zero(pf->avail_rxqs, ICE_MAX_RXQS);\n+\tmutex_unlock(&pf->avail_q_mutex);\n+\n+\t/* setup service timer and periodic service task */\n+\ttimer_setup(&pf->serv_tmr, ice_service_timer, 0);\n+\tpf->serv_tmr_period = HZ;\n+\tINIT_WORK(&pf->serv_task, ice_service_task);\n+\tclear_bit(__ICE_SERVICE_SCHED, pf->state);\n+}\n+\n+/**\n+ * ice_ena_msix_range - Request a range of MSIX vectors from the OS\n+ * @pf: board private structure\n+ *\n+ * compute the number of MSIX vectors required (v_budget) and request from\n+ * the OS. Return the number of vectors reserved or negative on failure\n+ */\n+static int ice_ena_msix_range(struct ice_pf *pf)\n+{\n+\tint v_left, v_actual, v_budget = 0;\n+\tint needed, err, i;\n+\n+\tv_left = pf->hw.func_caps.common_cap.num_msix_vectors;\n+\n+\t/* reserve one vector for miscellaneous handler */\n+\tneeded = 1;\n+\tv_budget += needed;\n+\tv_left -= needed;\n+\n+\t/* reserve vectors for LAN traffic */\n+\tpf->num_lan_msix = min_t(int, num_online_cpus(), v_left);\n+\tv_budget += pf->num_lan_msix;\n+\n+\tpf->msix_entries = devm_kcalloc(&pf->pdev->dev, v_budget,\n+\t\t\t\t\tsizeof(struct msix_entry), GFP_KERNEL);\n+\n+\tif (!pf->msix_entries) {\n+\t\terr = -ENOMEM;\n+\t\tgoto exit_err;\n+\t}\n+\n+\tfor (i = 0; i < v_budget; i++)\n+\t\tpf->msix_entries[i].entry = i;\n+\n+\t/* actually reserve the vectors */\n+\tv_actual = pci_enable_msix_range(pf->pdev, pf->msix_entries,\n+\t\t\t\t\t ICE_MIN_MSIX, v_budget);\n+\n+\tif (v_actual < 0) {\n+\t\tdev_err(&pf->pdev->dev, \"unable to reserve MSI-X vectors\\n\");\n+\t\terr = v_actual;\n+\t\tgoto msix_err;\n+\t}\n+\n+\tif (v_actual < v_budget) {\n+\t\tdev_warn(&pf->pdev->dev,\n+\t\t\t \"not enough vectors. requested = %d, obtained = %d\\n\",\n+\t\t\t v_budget, v_actual);\n+\t\tif (v_actual >= (pf->num_lan_msix + 1)) {\n+\t\t\tpf->num_avail_msix = v_actual - (pf->num_lan_msix + 1);\n+\t\t} else if (v_actual >= 2) {\n+\t\t\tpf->num_lan_msix = 1;\n+\t\t\tpf->num_avail_msix = v_actual - 2;\n+\t\t} else {\n+\t\t\tpci_disable_msix(pf->pdev);\n+\t\t\terr = -ERANGE;\n+\t\t\tgoto msix_err;\n+\t\t}\n+\t}\n+\n+\treturn v_actual;\n+\n+msix_err:\n+\tdevm_kfree(&pf->pdev->dev, pf->msix_entries);\n+\tgoto exit_err;\n+\n+exit_err:\n+\tpf->num_lan_msix = 0;\n+\tclear_bit(ICE_FLAG_MSIX_ENA, pf->flags);\n+\treturn err;\n+}\n+\n+/**\n+ * ice_dis_msix - Disable MSI-X interrupt setup in OS\n+ * @pf: board private structure\n+ */\n+static void ice_dis_msix(struct ice_pf *pf)\n+{\n+\tpci_disable_msix(pf->pdev);\n+\tdevm_kfree(&pf->pdev->dev, pf->msix_entries);\n+\tpf->msix_entries = NULL;\n+\tclear_bit(ICE_FLAG_MSIX_ENA, pf->flags);\n+}\n+\n+/**\n+ * ice_init_interrupt_scheme - Determine proper interrupt scheme\n+ * @pf: board private structure to initialize\n+ */\n+static int ice_init_interrupt_scheme(struct ice_pf *pf)\n+{\n+\tint vectors = 0;\n+\tssize_t size;\n+\n+\tif (test_bit(ICE_FLAG_MSIX_ENA, pf->flags))\n+\t\tvectors = ice_ena_msix_range(pf);\n+\telse\n+\t\treturn -ENODEV;\n+\n+\tif (vectors < 0)\n+\t\treturn vectors;\n+\n+\t/* set up vector assignment tracking */\n+\tsize = sizeof(struct ice_res_tracker) + (sizeof(u16) * vectors);\n+\n+\tpf->irq_tracker = devm_kzalloc(&pf->pdev->dev, size, GFP_KERNEL);\n+\tif (!pf->irq_tracker) {\n+\t\tice_dis_msix(pf);\n+\t\treturn -ENOMEM;\n+\t}\n+\n+\tpf->irq_tracker->num_entries = vectors;\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * ice_clear_interrupt_scheme - Undo things done by ice_init_interrupt_scheme\n+ * @pf: board private structure\n+ */\n+static void ice_clear_interrupt_scheme(struct ice_pf *pf)\n+{\n+\tif (test_bit(ICE_FLAG_MSIX_ENA, pf->flags))\n+\t\tice_dis_msix(pf);\n+\n+\tdevm_kfree(&pf->pdev->dev, pf->irq_tracker);\n+\tpf->irq_tracker = NULL;\n+}\n+\n /**\n * ice_probe - Device initialization routine\n * @pdev: PCI device information struct\n@@ -127,8 +770,70 @@ static int ice_probe(struct pci_dev *pdev,\n \t\t hw->fw_maj_ver, hw->fw_min_ver, hw->fw_build,\n \t\t hw->api_maj_ver, hw->api_min_ver);\n \n+\tice_init_pf(pf);\n+\n+\tice_determine_q_usage(pf);\n+\n+\tpf->num_alloc_vsi = min_t(u16, ICE_MAX_VSI_ALLOC,\n+\t\t\t\t hw->func_caps.guaranteed_num_vsi);\n+\tif (!pf->num_alloc_vsi) {\n+\t\terr = -EIO;\n+\t\tgoto err_init_pf_unroll;\n+\t}\n+\n+\tpf->vsi = devm_kcalloc(&pdev->dev, pf->num_alloc_vsi,\n+\t\t\t sizeof(struct ice_vsi *), GFP_KERNEL);\n+\tif (!pf->vsi) {\n+\t\terr = -ENOMEM;\n+\t\tgoto err_init_pf_unroll;\n+\t}\n+\n+\terr = ice_init_interrupt_scheme(pf);\n+\tif (err) {\n+\t\tdev_err(&pdev->dev,\n+\t\t\t\"ice_init_interrupt_scheme failed: %d\\n\", err);\n+\t\terr = -EIO;\n+\t\tgoto err_init_interrupt_unroll;\n+\t}\n+\n+\t/* In case of MSIX we are going to setup the misc vector right here\n+\t * to handle admin queue events etc. In case of legacy and MSI\n+\t * the misc functionality and queue processing is combined in\n+\t * the same vector and that gets setup at open.\n+\t */\n+\tif (test_bit(ICE_FLAG_MSIX_ENA, pf->flags)) {\n+\t\terr = ice_req_irq_msix_misc(pf);\n+\t\tif (err) {\n+\t\t\tdev_err(&pdev->dev,\n+\t\t\t\t\"setup of misc vector failed: %d\\n\", err);\n+\t\t\tgoto err_init_interrupt_unroll;\n+\t\t}\n+\t}\n+\n+\t/* create switch struct for the switch element created by FW on boot */\n+\tpf->first_sw = devm_kzalloc(&pdev->dev, sizeof(struct ice_sw),\n+\t\t\t\t GFP_KERNEL);\n+\tif (!pf->first_sw) {\n+\t\terr = -ENOMEM;\n+\t\tgoto err_msix_misc_unroll;\n+\t}\n+\n+\tpf->first_sw->bridge_mode = BRIDGE_MODE_VEB;\n+\tpf->first_sw->pf = pf;\n+\n+\t/* record the sw_id available for later use */\n+\tpf->first_sw->sw_id = hw->port_info->sw_id;\n+\n \treturn 0;\n \n+err_msix_misc_unroll:\n+\tice_free_irq_msix_misc(pf);\n+err_init_interrupt_unroll:\n+\tice_clear_interrupt_scheme(pf);\n+\tdevm_kfree(&pdev->dev, pf->vsi);\n+err_init_pf_unroll:\n+\tice_deinit_pf(pf);\n+\tice_deinit_hw(hw);\n err_exit_unroll:\n \tpci_disable_pcie_error_reporting(pdev);\n \treturn err;\n@@ -147,6 +852,9 @@ static void ice_remove(struct pci_dev *pdev)\n \n \tset_bit(__ICE_DOWN, pf->state);\n \n+\tice_free_irq_msix_misc(pf);\n+\tice_clear_interrupt_scheme(pf);\n+\tice_deinit_pf(pf);\n \tice_deinit_hw(&pf->hw);\n \tpci_disable_pcie_error_reporting(pdev);\n }\n@@ -190,9 +898,17 @@ static int __init ice_module_init(void)\n \tpr_info(\"%s - version %s\\n\", ice_driver_string, ice_drv_ver);\n \tpr_info(\"%s\\n\", ice_copyright);\n \n+\tice_wq = alloc_ordered_workqueue(\"%s\", WQ_MEM_RECLAIM, KBUILD_MODNAME);\n+\tif (!ice_wq) {\n+\t\tpr_err(\"Failed to create workqueue\\n\");\n+\t\treturn -ENOMEM;\n+\t}\n+\n \tstatus = pci_register_driver(&ice_driver);\n-\tif (status)\n+\tif (status) {\n \t\tpr_err(\"failed to register pci driver, err %d\\n\", status);\n+\t\tdestroy_workqueue(ice_wq);\n+\t}\n \n \treturn status;\n }\n@@ -207,6 +923,7 @@ module_init(ice_module_init);\n static void __exit ice_module_exit(void)\n {\n \tpci_unregister_driver(&ice_driver);\n+\tdestroy_workqueue(ice_wq);\n \tpr_info(\"module unloaded\\n\");\n }\n module_exit(ice_module_exit);\ndiff --git a/drivers/net/ethernet/intel/ice/ice_txrx.h b/drivers/net/ethernet/intel/ice/ice_txrx.h\nnew file mode 100644\nindex 000000000000..f1f872d3e09b\n--- /dev/null\n+++ b/drivers/net/ethernet/intel/ice/ice_txrx.h\n@@ -0,0 +1,43 @@\n+/* SPDX-License-Identifier: GPL-2.0-only */\n+/* Intel(R) Ethernet Connection E800 Series Linux Driver\n+ * Copyright (c) 2018, Intel Corporation.\n+ *\n+ * This program is free software; you can redistribute it and/or modify it\n+ * under the terms and conditions of the GNU General Public License,\n+ * version 2, as published by the Free Software Foundation.\n+ *\n+ * This program is distributed in the hope it will be useful, but WITHOUT\n+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\n+ * more details.\n+ *\n+ * The full GNU General Public License is included in this distribution in\n+ * the file called \"COPYING\".\n+ */\n+\n+#ifndef _ICE_TXRX_H_\n+#define _ICE_TXRX_H_\n+\n+#define ICE_DFLT_IRQ_WORK\t256\n+\n+/* this enum matches hardware bits and is meant to be used by DYN_CTLN\n+ * registers and QINT registers or more generally anywhere in the manual\n+ * mentioning ITR_INDX, ITR_NONE cannot be used as an index 'n' into any\n+ * register but instead is a special value meaning \"don't update\" ITR0/1/2.\n+ */\n+enum ice_dyn_idx_t {\n+\tICE_IDX_ITR0 = 0,\n+\tICE_IDX_ITR1 = 1,\n+\tICE_IDX_ITR2 = 2,\n+\tICE_ITR_NONE = 3\t/* ITR_NONE must not be used as an index */\n+};\n+\n+/* indices into GLINT_ITR registers */\n+#define ICE_RX_ITR\tICE_IDX_ITR0\n+#define ICE_ITR_DYNAMIC\t0x8000 /* use top bit as a flag */\n+#define ICE_ITR_8K\t0x003E\n+\n+/* apply ITR HW granularity translation to program the HW registers */\n+#define ITR_TO_REG(val, itr_gran) (((val) & ~ICE_ITR_DYNAMIC) >> (itr_gran))\n+\n+#endif /* _ICE_TXRX_H_ */\ndiff --git a/drivers/net/ethernet/intel/ice/ice_type.h b/drivers/net/ethernet/intel/ice/ice_type.h\nindex cb9104ca969d..1ae6fa5b59ba 100644\n--- a/drivers/net/ethernet/intel/ice/ice_type.h\n+++ b/drivers/net/ethernet/intel/ice/ice_type.h\n@@ -275,6 +275,17 @@ struct ice_hw {\n \tu8 fw_min_ver;\t\t/* firmware minor version */\n \tu8 fw_patch;\t\t/* firmware patch version */\n \tu32 fw_build;\t\t/* firmware build number */\n+\n+\t/* minimum allowed value for different speeds */\n+#define ICE_ITR_GRAN_MIN_200\t1\n+#define ICE_ITR_GRAN_MIN_100\t1\n+#define ICE_ITR_GRAN_MIN_50\t2\n+#define ICE_ITR_GRAN_MIN_25\t4\n+\t/* ITR granularity in 1 us */\n+\tu8 itr_gran_200;\n+\tu8 itr_gran_100;\n+\tu8 itr_gran_50;\n+\tu8 itr_gran_25;\n };\n \n /* Checksum and Shadow RAM pointers */\n", "prefixes": [ "v3", "06/15" ] }