Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/1160032/?format=api
{ "id": 1160032, "url": "http://patchwork.ozlabs.org/api/patches/1160032/?format=api", "web_url": "http://patchwork.ozlabs.org/project/intel-wired-lan/patch/20190910070512.31391-1-sasha.neftin@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": "<20190910070512.31391-1-sasha.neftin@intel.com>", "list_archive_url": null, "date": "2019-09-10T07:05:12", "name": "[v1] igc: Add set_rx_mode support", "commit_ref": null, "pull_url": null, "state": "superseded", "archived": false, "hash": "3b743c5876c4338ddf86bf285182e4a07cc438bd", "submitter": { "id": 69860, "url": "http://patchwork.ozlabs.org/api/people/69860/?format=api", "name": "Sasha Neftin", "email": "sasha.neftin@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/20190910070512.31391-1-sasha.neftin@intel.com/mbox/", "series": [ { "id": 129867, "url": "http://patchwork.ozlabs.org/api/series/129867/?format=api", "web_url": "http://patchwork.ozlabs.org/project/intel-wired-lan/list/?series=129867", "date": "2019-09-10T07:05:12", "name": "[v1] igc: Add set_rx_mode support", "version": 1, "mbox": "http://patchwork.ozlabs.org/series/129867/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/1160032/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/1160032/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.136; helo=silver.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 silver.osuosl.org (smtp3.osuosl.org [140.211.166.136])\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 46SGJQ2Hrcz9s00\n\tfor <incoming@patchwork.ozlabs.org>;\n\tTue, 10 Sep 2019 17:05:25 +1000 (AEST)", "from localhost (localhost [127.0.0.1])\n\tby silver.osuosl.org (Postfix) with ESMTP id 112D220403;\n\tTue, 10 Sep 2019 07:05:24 +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 JE-7A+j-Nt2Q; Tue, 10 Sep 2019 07:05:17 +0000 (UTC)", "from ash.osuosl.org (ash.osuosl.org [140.211.166.34])\n\tby silver.osuosl.org (Postfix) with ESMTP id 34EAC203F2;\n\tTue, 10 Sep 2019 07:05:17 +0000 (UTC)", "from fraxinus.osuosl.org (smtp4.osuosl.org [140.211.166.137])\n\tby ash.osuosl.org (Postfix) with ESMTP id D1EF11BF309\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tTue, 10 Sep 2019 07:05:15 +0000 (UTC)", "from localhost (localhost [127.0.0.1])\n\tby fraxinus.osuosl.org (Postfix) with ESMTP id CDC4685C63\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tTue, 10 Sep 2019 07:05:15 +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 tTxsqeEczsTK for <intel-wired-lan@lists.osuosl.org>;\n\tTue, 10 Sep 2019 07:05:14 +0000 (UTC)", "from mga11.intel.com (mga11.intel.com [192.55.52.93])\n\tby fraxinus.osuosl.org (Postfix) with ESMTPS id 461F185BC2\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tTue, 10 Sep 2019 07:05:14 +0000 (UTC)", "from fmsmga006.fm.intel.com ([10.253.24.20])\n\tby fmsmga102.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384;\n\t10 Sep 2019 00:05:13 -0700", "from ccdlinuxdev08.iil.intel.com ([143.185.161.150])\n\tby fmsmga006.fm.intel.com with ESMTP; 10 Sep 2019 00:05:12 -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.64,487,1559545200\"; d=\"scan'208\";a=\"385241898\"", "From": "Sasha Neftin <sasha.neftin@intel.com>", "To": "intel-wired-lan@lists.osuosl.org", "Date": "Tue, 10 Sep 2019 10:05:12 +0300", "Message-Id": "<20190910070512.31391-1-sasha.neftin@intel.com>", "X-Mailer": "git-send-email 2.11.0", "Subject": "[Intel-wired-lan] [PATCH v1] igc: Add set_rx_mode support", "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>", "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": "Add multicast addresses list to the MTA table.\nImplement promiscious mode and add basic rx mode support.\nAdd option for ipv6 address settings.\n\nSigned-off-by: Sasha Neftin <sasha.neftin@intel.com>\n---\n drivers/net/ethernet/intel/igc/igc.h | 4 +\n drivers/net/ethernet/intel/igc/igc_base.c | 1 +\n drivers/net/ethernet/intel/igc/igc_defines.h | 6 +\n drivers/net/ethernet/intel/igc/igc_hw.h | 2 +\n drivers/net/ethernet/intel/igc/igc_mac.c | 125 +++++++++++-\n drivers/net/ethernet/intel/igc/igc_mac.h | 3 +\n drivers/net/ethernet/intel/igc/igc_main.c | 271 +++++++++++++++++++++++++++\n drivers/net/ethernet/intel/igc/igc_regs.h | 2 +\n 8 files changed, 413 insertions(+), 1 deletion(-)", "diff": "diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h\nindex 7e16345d836e..0fc3db2efcae 100644\n--- a/drivers/net/ethernet/intel/igc/igc.h\n+++ b/drivers/net/ethernet/intel/igc/igc.h\n@@ -10,6 +10,7 @@\n #include <linux/vmalloc.h>\n #include <linux/ethtool.h>\n #include <linux/sctp.h>\n+#include <linux/if_vlan.h>\n \n #include \"igc_hw.h\"\n \n@@ -391,6 +392,9 @@ struct igc_adapter {\n \tu32 max_frame_size;\n \tu32 min_frame_size;\n \n+\tu16 mng_vlan_id;\n+\tunsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];\n+\n \t/* OS defined structs */\n \tstruct pci_dev *pdev;\n \t/* lock for statistics */\ndiff --git a/drivers/net/ethernet/intel/igc/igc_base.c b/drivers/net/ethernet/intel/igc/igc_base.c\nindex db289bcce21d..574b5928df42 100644\n--- a/drivers/net/ethernet/intel/igc/igc_base.c\n+++ b/drivers/net/ethernet/intel/igc/igc_base.c\n@@ -405,6 +405,7 @@ static struct igc_mac_operations igc_mac_ops_base = {\n \t.check_for_link\t\t= igc_check_for_copper_link,\n \t.rar_set\t\t= igc_rar_set,\n \t.read_mac_addr\t\t= igc_read_mac_addr,\n+\t.write_vfta\t\t= igc_write_vfta,\n \t.get_speed_and_duplex\t= igc_get_speed_and_duplex_copper,\n };\n \ndiff --git a/drivers/net/ethernet/intel/igc/igc_defines.h b/drivers/net/ethernet/intel/igc/igc_defines.h\nindex f3f2325fe567..0d6fa739b210 100644\n--- a/drivers/net/ethernet/intel/igc/igc_defines.h\n+++ b/drivers/net/ethernet/intel/igc/igc_defines.h\n@@ -402,4 +402,10 @@\n #define IGC_ADVTXD_TUCMD_L4T_TCP\t0x00000800 /* L4 Packet Type of TCP */\n #define IGC_ADVTXD_TUCMD_L4T_SCTP\t0x00001000 /* L4 packet TYPE of SCTP */\n \n+/* Maximum size of the MTA register table in all supported adapters */\n+#define MAX_MTA_REG\t\t\t128\n+#define IGC_VLAN_FILTER_TBL_SIZE\t128 /* VLAN Filter Table (4096 bits) */\n+#define IGC_VFTA_BLOCK_SIZE\t\t8\n+#define IGC_RCTL_VFE\t\t\t0x00040000 /* vlan filter enable */\n+\n #endif /* _IGC_DEFINES_H_ */\ndiff --git a/drivers/net/ethernet/intel/igc/igc_hw.h b/drivers/net/ethernet/intel/igc/igc_hw.h\nindex abb2d72911ff..452d3750e8ca 100644\n--- a/drivers/net/ethernet/intel/igc/igc_hw.h\n+++ b/drivers/net/ethernet/intel/igc/igc_hw.h\n@@ -36,6 +36,7 @@ struct igc_mac_operations {\n \t\t\t\t u16 *duplex);\n \ts32 (*acquire_swfw_sync)(struct igc_hw *hw, u16 mask);\n \tvoid (*release_swfw_sync)(struct igc_hw *hw, u16 mask);\n+\tvoid (*write_vfta)(struct igc_hw *hw, u32 offset, u32 value);\n };\n \n enum igc_mac_type {\n@@ -91,6 +92,7 @@ struct igc_mac_info {\n \tu16 mta_reg_count;\n \tu16 uta_reg_count;\n \n+\tu32 mta_shadow[MAX_MTA_REG];\n \tu16 rar_entry_count;\n \n \tu8 forced_speed_duplex;\ndiff --git a/drivers/net/ethernet/intel/igc/igc_mac.c b/drivers/net/ethernet/intel/igc/igc_mac.c\nindex 5eeb4c8caf4a..cbf9b96d6686 100644\n--- a/drivers/net/ethernet/intel/igc/igc_mac.c\n+++ b/drivers/net/ethernet/intel/igc/igc_mac.c\n@@ -5,7 +5,7 @@\n #include <linux/delay.h>\n \n #include \"igc_mac.h\"\n-#include \"igc_hw.h\"\n+#include \"igc.h\"\n \n /**\n * igc_disable_pcie_master - Disables PCI-express master access\n@@ -784,3 +784,126 @@ bool igc_enable_mng_pass_thru(struct igc_hw *hw)\n out:\n \treturn ret_val;\n }\n+\n+/**\n+ * igc_hash_mc_addr - Generate a multicast hash value\n+ * @hw: pointer to the HW structure\n+ * @mc_addr: pointer to a multicast address\n+ *\n+ * Generates a multicast address hash value which is used to determine\n+ * the multicast filter table array address and new table value. See\n+ * igc_mta_set()\n+ **/\n+static u32 igc_hash_mc_addr(struct igc_hw *hw, u8 *mc_addr)\n+{\n+\tu32 hash_value, hash_mask;\n+\tu8 bit_shift = 0;\n+\n+\t/* Register count multiplied by bits per register */\n+\thash_mask = (hw->mac.mta_reg_count * 32) - 1;\n+\n+\t/* For a mc_filter_type of 0, bit_shift is the number of left-shifts\n+\t * where 0xFF would still fall within the hash mask.\n+\t */\n+\twhile (hash_mask >> bit_shift != 0xFF)\n+\t\tbit_shift++;\n+\n+\t/* The portion of the address that is used for the hash table\n+\t * is determined by the mc_filter_type setting.\n+\t * The algorithm is such that there is a total of 8 bits of shifting.\n+\t * The bit_shift for a mc_filter_type of 0 represents the number of\n+\t * left-shifts where the MSB of mc_addr[5] would still fall within\n+\t * the hash_mask. Case 0 does this exactly. Since there are a total\n+\t * of 8 bits of shifting, then mc_addr[4] will shift right the\n+\t * remaining number of bits. Thus 8 - bit_shift. The rest of the\n+\t * cases are a variation of this algorithm...essentially raising the\n+\t * number of bits to shift mc_addr[5] left, while still keeping the\n+\t * 8-bit shifting total.\n+\t *\n+\t * For example, given the following Destination MAC Address and an\n+\t * mta register count of 128 (thus a 4096-bit vector and 0xFFF mask),\n+\t * we can see that the bit_shift for case 0 is 4. These are the hash\n+\t * values resulting from each mc_filter_type...\n+\t * [0] [1] [2] [3] [4] [5]\n+\t * 01 AA 00 12 34 56\n+\t * LSB MSB\n+\t *\n+\t * case 0: hash_value = ((0x34 >> 4) | (0x56 << 4)) & 0xFFF = 0x563\n+\t * case 1: hash_value = ((0x34 >> 3) | (0x56 << 5)) & 0xFFF = 0xAC6\n+\t * case 2: hash_value = ((0x34 >> 2) | (0x56 << 6)) & 0xFFF = 0x163\n+\t * case 3: hash_value = ((0x34 >> 0) | (0x56 << 8)) & 0xFFF = 0x634\n+\t */\n+\tswitch (hw->mac.mc_filter_type) {\n+\tdefault:\n+\tcase 0:\n+\t\tbreak;\n+\tcase 1:\n+\t\tbit_shift += 1;\n+\t\tbreak;\n+\tcase 2:\n+\t\tbit_shift += 2;\n+\t\tbreak;\n+\tcase 3:\n+\t\tbit_shift += 4;\n+\t\tbreak;\n+\t}\n+\n+\thash_value = hash_mask & (((mc_addr[4] >> (8 - bit_shift)) |\n+\t\t\t\t (((u16)mc_addr[5]) << bit_shift)));\n+\n+\treturn hash_value;\n+}\n+\n+/**\n+ * igc_update_mc_addr_list - Update Multicast addresses\n+ * @hw: pointer to the HW structure\n+ * @mc_addr_list: array of multicast addresses to program\n+ * @mc_addr_count: number of multicast addresses to program\n+ *\n+ * Updates entire Multicast Table Array.\n+ * The caller must have a packed mc_addr_list of multicast addresses.\n+ **/\n+void igc_update_mc_addr_list(struct igc_hw *hw,\n+\t\t\t u8 *mc_addr_list, u32 mc_addr_count)\n+{\n+\tu32 hash_value, hash_bit, hash_reg;\n+\tint i;\n+\n+\t/* clear mta_shadow */\n+\tmemset(&hw->mac.mta_shadow, 0, sizeof(hw->mac.mta_shadow));\n+\n+\t/* update mta_shadow from mc_addr_list */\n+\tfor (i = 0; (u32)i < mc_addr_count; i++) {\n+\t\thash_value = igc_hash_mc_addr(hw, mc_addr_list);\n+\n+\t\thash_reg = (hash_value >> 5) & (hw->mac.mta_reg_count - 1);\n+\t\thash_bit = hash_value & 0x1F;\n+\n+\t\thw->mac.mta_shadow[hash_reg] |= BIT(hash_bit);\n+\t\tmc_addr_list += (ETH_ALEN);\n+\t}\n+\n+\t/* replace the entire MTA table */\n+\tfor (i = hw->mac.mta_reg_count - 1; i >= 0; i--)\n+\t\tarray_wr32(IGC_MTA, i, hw->mac.mta_shadow[i]);\n+\twrfl();\n+}\n+\n+/**\n+ * igc_write_vfta - Write value to VLAN filter table\n+ * @hw: pointer to the HW structure\n+ * @offset: register offset in VLAN filter table\n+ * @value: register value written to VLAN filter table\n+ *\n+ * Writes value at the given offset in the register array which stores\n+ * the VLAN filter table.\n+ **/\n+void igc_write_vfta(struct igc_hw *hw, u32 offset, u32 value)\n+{\n+\tstruct igc_adapter *adapter = hw->back;\n+\n+\tarray_wr32(IGC_VFTA, offset, value);\n+\twrfl();\n+\n+\tadapter->shadow_vfta[offset] = value;\n+}\ndiff --git a/drivers/net/ethernet/intel/igc/igc_mac.h b/drivers/net/ethernet/intel/igc/igc_mac.h\nindex 782bc995badc..c701d946b720 100644\n--- a/drivers/net/ethernet/intel/igc/igc_mac.h\n+++ b/drivers/net/ethernet/intel/igc/igc_mac.h\n@@ -29,6 +29,9 @@ s32 igc_get_speed_and_duplex_copper(struct igc_hw *hw, u16 *speed,\n \t\t\t\t u16 *duplex);\n \n bool igc_enable_mng_pass_thru(struct igc_hw *hw);\n+void igc_update_mc_addr_list(struct igc_hw *hw,\n+\t\t\t u8 *mc_addr_list, u32 mc_addr_count);\n+void igc_write_vfta(struct igc_hw *hw, u32 offset, u32 value);\n \n enum igc_mng_mode {\n \tigc_mng_mode_none = 0,\ndiff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c\nindex 18082163316c..37d98a6eea56 100644\n--- a/drivers/net/ethernet/intel/igc/igc_main.c\n+++ b/drivers/net/ethernet/intel/igc/igc_main.c\n@@ -795,6 +795,44 @@ static int igc_set_mac(struct net_device *netdev, void *p)\n \treturn 0;\n }\n \n+/**\n+ * igc_write_mc_addr_list - write multicast addresses to MTA\n+ * @netdev: network interface device structure\n+ *\n+ * Writes multicast address list to the MTA hash table.\n+ * Returns: -ENOMEM on failure\n+ * 0 on no addresses written\n+ * X on writing X addresses to MTA\n+ **/\n+static int igc_write_mc_addr_list(struct net_device *netdev)\n+{\n+\tstruct igc_adapter *adapter = netdev_priv(netdev);\n+\tstruct igc_hw *hw = &adapter->hw;\n+\tstruct netdev_hw_addr *ha;\n+\tu8 *mta_list;\n+\tint i;\n+\n+\tif (netdev_mc_empty(netdev)) {\n+\t\t/* nothing to program, so clear mc list */\n+\t\tigc_update_mc_addr_list(hw, NULL, 0);\n+\t\treturn 0;\n+\t}\n+\n+\tmta_list = kcalloc(netdev_mc_count(netdev), 6, GFP_ATOMIC);\n+\tif (!mta_list)\n+\t\treturn -ENOMEM;\n+\n+\t/* The shared function expects a packed array of only addresses. */\n+\ti = 0;\n+\tnetdev_for_each_mc_addr(ha, netdev)\n+\t\tmemcpy(mta_list + (i++ * ETH_ALEN), ha->addr, ETH_ALEN);\n+\n+\tigc_update_mc_addr_list(hw, mta_list, i);\n+\tkfree(mta_list);\n+\n+\treturn netdev_mc_count(netdev);\n+}\n+\n static void igc_tx_ctxtdesc(struct igc_ring *tx_ring,\n \t\t\t struct igc_tx_buffer *first,\n \t\t\t u32 vlan_macip_lens, u32 type_tucmd,\n@@ -2518,6 +2556,179 @@ int igc_del_mac_steering_filter(struct igc_adapter *adapter,\n \t\t\t\t\tIGC_MAC_STATE_QUEUE_STEERING | flags);\n }\n \n+static int igc_vlan_promisc_enable(struct igc_adapter *adapter)\n+{\n+\tstruct igc_hw *hw = &adapter->hw;\n+\tu32 i;\n+\n+\tswitch (hw->mac.type) {\n+\tcase igc_i225:\n+\t\t/* VLAN filtering needed for VLAN prio filter */\n+\t\tif (adapter->netdev->features & NETIF_F_NTUPLE)\n+\t\t\tbreak;\n+\t\t/* fall through */\n+\tdefault:\n+\t\treturn 1;\n+\t}\n+\n+\t/* We are already in VLAN promisc, nothing to do */\n+\tif (adapter->flags & IGC_FLAG_VLAN_PROMISC)\n+\t\treturn 0;\n+\n+\t/* Set all bits in the VLAN filter table array */\n+\tfor (i = IGC_VLAN_FILTER_TBL_SIZE; i--;)\n+\t\thw->mac.ops.write_vfta(hw, i, ~0U);\n+\n+\t/* Set flag so we don't redo unnecessary work */\n+\tadapter->flags |= IGC_FLAG_VLAN_PROMISC;\n+\n+\treturn 0;\n+}\n+\n+static void igc_scrub_vfta(struct igc_adapter *adapter, u32 vfta_offset)\n+{\n+\tstruct igc_hw *hw = &adapter->hw;\n+\tu32 vfta[IGC_VFTA_BLOCK_SIZE] = { 0 };\n+\tu32 vid_start = vfta_offset * 32;\n+\tu32 vid_end = vid_start + (IGC_VFTA_BLOCK_SIZE * 32);\n+\tu32 i, vid, word, bits;\n+\n+\t/* guarantee that we don't scrub out management VLAN */\n+\tvid = adapter->mng_vlan_id;\n+\tif (vid >= vid_start && vid < vid_end)\n+\t\tvfta[(vid - vid_start) / 32] |= BIT(vid % 32);\n+\n+\t/* extract values from active_vlans and write back to VFTA */\n+\tfor (i = IGC_VFTA_BLOCK_SIZE; i--;) {\n+\t\tvid = (vfta_offset + i) * 32;\n+\t\tword = vid / BITS_PER_LONG;\n+\t\tbits = vid % BITS_PER_LONG;\n+\n+\t\tvfta[i] |= adapter->active_vlans[word] >> bits;\n+\n+\t\thw->mac.ops.write_vfta(hw, vfta_offset + i, vfta[i]);\n+\t}\n+}\n+\n+static void igc_vlan_promisc_disable(struct igc_adapter *adapter)\n+{\n+\tu32 i;\n+\n+\t/* We are not in VLAN promisc, nothing to do */\n+\tif (!(adapter->flags & IGC_FLAG_VLAN_PROMISC))\n+\t\treturn;\n+\n+\t/* Set flag so we don't redo unnecessary work */\n+\tadapter->flags &= ~IGC_FLAG_VLAN_PROMISC;\n+\n+\tfor (i = 0; i < IGC_VLAN_FILTER_TBL_SIZE; i += IGC_VFTA_BLOCK_SIZE)\n+\t\tigc_scrub_vfta(adapter, i);\n+}\n+\n+/* Add a MAC filter for 'addr' directing matching traffic to 'queue',\n+ * 'flags' is used to indicate what kind of match is made, match is by\n+ * default for the destination address, if matching by source address\n+ * is desired the flag IGC_MAC_STATE_SRC_ADDR can be used.\n+ */\n+static int igc_add_mac_filter(struct igc_adapter *adapter,\n+\t\t\t const u8 *addr, const u8 queue)\n+{\n+\tstruct igc_hw *hw = &adapter->hw;\n+\tint rar_entries = hw->mac.rar_entry_count;\n+\tint i;\n+\n+\tif (is_zero_ether_addr(addr))\n+\t\treturn -EINVAL;\n+\n+\t/* Search for the first empty entry in the MAC table.\n+\t * Do not touch entries at the end of the table reserved for the VF MAC\n+\t * addresses.\n+\t */\n+\tfor (i = 0; i < rar_entries; i++) {\n+\t\tif (!igc_mac_entry_can_be_used(&adapter->mac_table[i],\n+\t\t\t\t\t addr, 0))\n+\t\t\tcontinue;\n+\n+\t\tether_addr_copy(adapter->mac_table[i].addr, addr);\n+\t\tadapter->mac_table[i].queue = queue;\n+\t\tadapter->mac_table[i].state |= IGC_MAC_STATE_IN_USE;\n+\n+\t\tigc_rar_set_index(adapter, i);\n+\t\treturn i;\n+\t}\n+\n+\treturn -ENOSPC;\n+}\n+\n+/* Remove a MAC filter for 'addr' directing matching traffic to\n+ * 'queue', 'flags' is used to indicate what kind of match need to be\n+ * removed, match is by default for the destination address, if\n+ * matching by source address is to be removed the flag\n+ * IGC_MAC_STATE_SRC_ADDR can be used.\n+ */\n+static int igc_del_mac_filter(struct igc_adapter *adapter,\n+\t\t\t const u8 *addr, const u8 queue)\n+{\n+\tstruct igc_hw *hw = &adapter->hw;\n+\tint rar_entries = hw->mac.rar_entry_count;\n+\tint i;\n+\n+\tif (is_zero_ether_addr(addr))\n+\t\treturn -EINVAL;\n+\n+\t/* Search for matching entry in the MAC table based on given address\n+\t * and queue. Do not touch entries at the end of the table reserved\n+\t * for the VF MAC addresses.\n+\t */\n+\tfor (i = 0; i < rar_entries; i++) {\n+\t\tif (!(adapter->mac_table[i].state & IGC_MAC_STATE_IN_USE))\n+\t\t\tcontinue;\n+\t\tif (adapter->mac_table[i].state != 0)\n+\t\t\tcontinue;\n+\t\tif (adapter->mac_table[i].queue != queue)\n+\t\t\tcontinue;\n+\t\tif (!ether_addr_equal(adapter->mac_table[i].addr, addr))\n+\t\t\tcontinue;\n+\n+\t\t/* When a filter for the default address is \"deleted\",\n+\t\t * we return it to its initial configuration\n+\t\t */\n+\t\tif (adapter->mac_table[i].state & IGC_MAC_STATE_DEFAULT) {\n+\t\t\tadapter->mac_table[i].state =\n+\t\t\t\tIGC_MAC_STATE_DEFAULT | IGC_MAC_STATE_IN_USE;\n+\t\t\tadapter->mac_table[i].queue = 0;\n+\t\t} else {\n+\t\t\tadapter->mac_table[i].state = 0;\n+\t\t\tadapter->mac_table[i].queue = 0;\n+\t\t\tmemset(adapter->mac_table[i].addr, 0, ETH_ALEN);\n+\t\t}\n+\n+\t\tigc_rar_set_index(adapter, i);\n+\t\treturn 0;\n+\t}\n+\n+\treturn -ENOENT;\n+}\n+\n+static int igc_uc_sync(struct net_device *netdev, const unsigned char *addr)\n+{\n+\tstruct igc_adapter *adapter = netdev_priv(netdev);\n+\tint ret;\n+\n+\tret = igc_add_mac_filter(adapter, addr, adapter->num_rx_queues);\n+\n+\treturn min_t(int, ret, 0);\n+}\n+\n+static int igc_uc_unsync(struct net_device *netdev, const unsigned char *addr)\n+{\n+\tstruct igc_adapter *adapter = netdev_priv(netdev);\n+\n+\tigc_del_mac_filter(adapter, addr, adapter->num_rx_queues);\n+\n+\treturn 0;\n+}\n+\n /**\n * igc_set_rx_mode - Secondary Unicast, Multicast and Promiscuous mode set\n * @netdev: network interface device structure\n@@ -2529,6 +2740,58 @@ int igc_del_mac_steering_filter(struct igc_adapter *adapter,\n */\n static void igc_set_rx_mode(struct net_device *netdev)\n {\n+\tstruct igc_adapter *adapter = netdev_priv(netdev);\n+\tstruct igc_hw *hw = &adapter->hw;\n+\tu32 rctl = 0, rlpml = MAX_JUMBO_FRAME_SIZE;\n+\tint count;\n+\n+\t/* Check for Promiscuous and All Multicast modes */\n+\tif (netdev->flags & IFF_PROMISC) {\n+\t\trctl |= IGC_RCTL_UPE | IGC_RCTL_MPE;\n+\t} else {\n+\t\tif (netdev->flags & IFF_ALLMULTI) {\n+\t\t\trctl |= IGC_RCTL_MPE;\n+\t\t} else {\n+\t\t\t/* Write addresses to the MTA, if the attempt fails\n+\t\t\t * then we should just turn on promiscuous mode so\n+\t\t\t * that we can at least receive multicast traffic\n+\t\t\t */\n+\t\t\tcount = igc_write_mc_addr_list(netdev);\n+\t\t\tif (count < 0)\n+\t\t\t\trctl |= IGC_RCTL_MPE;\n+\t\t}\n+\t}\n+\n+\t/* Write addresses to available RAR registers, if there is not\n+\t * sufficient space to store all the addresses then enable\n+\t * unicast promiscuous mode\n+\t */\n+\tif (__dev_uc_sync(netdev, igc_uc_sync, igc_uc_unsync))\n+\t\trctl |= IGC_RCTL_UPE;\n+\n+\t/* enable VLAN filtering by default */\n+\trctl |= IGC_RCTL_VFE;\n+\n+\t/* disable VLAN filtering for modes that require it */\n+\tif ((netdev->flags & IFF_PROMISC) ||\n+\t (netdev->features & NETIF_F_RXALL)) {\n+\t\t/* if we fail to set all rules then just clear VFE */\n+\t\tif (igc_vlan_promisc_enable(adapter))\n+\t\t\trctl &= ~IGC_RCTL_VFE;\n+\t} else {\n+\t\tigc_vlan_promisc_disable(adapter);\n+\t}\n+\n+\t/* update state of unicast, multicast, and VLAN filtering modes */\n+\trctl |= rd32(IGC_RCTL) & ~(IGC_RCTL_UPE | IGC_RCTL_MPE |\n+\t\t\t\t IGC_RCTL_VFE);\n+\twr32(IGC_RCTL, rctl);\n+\n+#if (PAGE_SIZE < 8192)\n+\tif (adapter->max_frame_size <= IGC_MAX_FRAME_BUILD_SKB)\n+\t\trlpml = IGC_MAX_FRAME_BUILD_SKB;\n+#endif\n+\twr32(IGC_RLPML, rlpml);\n }\n \n /**\n@@ -3982,6 +4245,7 @@ static const struct net_device_ops igc_netdev_ops = {\n \t.ndo_open\t\t= igc_open,\n \t.ndo_stop\t\t= igc_close,\n \t.ndo_start_xmit\t\t= igc_xmit_frame,\n+\t.ndo_set_rx_mode\t= igc_set_rx_mode,\n \t.ndo_set_mac_address\t= igc_set_mac,\n \t.ndo_change_mtu\t\t= igc_change_mtu,\n \t.ndo_get_stats\t\t= igc_get_stats,\n@@ -4304,6 +4568,7 @@ static int igc_probe(struct pci_dev *pdev,\n \t\tigc_reset_phy(hw);\n err_sw_init:\n \tigc_clear_interrupt_scheme(adapter);\n+\tkfree(adapter->shadow_vfta);\n \tiounmap(adapter->io_addr);\n err_ioremap:\n \tfree_netdev(netdev);\n@@ -4442,6 +4707,12 @@ static int igc_sw_init(struct igc_adapter *adapter)\n \n \tigc_init_queue_configuration(adapter);\n \n+\t/* Setup and initialize a copy of the hw vlan table array */\n+\tadapter->shadow_vfta = kcalloc(IGC_VLAN_FILTER_TBL_SIZE, sizeof(u32),\n+\t\t\t\t GFP_KERNEL);\n+\tif (!adapter->shadow_vfta)\n+\t\treturn -ENOMEM;\n+\n \t/* This call may decrease the number of queues */\n \tif (igc_init_interrupt_scheme(adapter, true)) {\n \t\tdev_err(&pdev->dev, \"Unable to allocate memory for queues\\n\");\ndiff --git a/drivers/net/ethernet/intel/igc/igc_regs.h b/drivers/net/ethernet/intel/igc/igc_regs.h\nindex 50d7c04dccf5..cec788f1fb5b 100644\n--- a/drivers/net/ethernet/intel/igc/igc_regs.h\n+++ b/drivers/net/ethernet/intel/igc/igc_regs.h\n@@ -215,6 +215,8 @@\n /* Shadow Ram Write Register - RW */\n #define IGC_SRWR\t0x12018\n \n+#define IGC_VFTA\t0x05600 /* VLAN Filter Table Array - RW Array */\n+\n /* forward declaration */\n struct igc_hw;\n u32 igc_rd32(struct igc_hw *hw, u32 reg);\n", "prefixes": [ "v1" ] }