Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1759559AbcLUJXB (ORCPT ); Wed, 21 Dec 2016 04:23:01 -0500 Received: from mail-bl2nam02on0089.outbound.protection.outlook.com ([104.47.38.89]:31040 "EHLO NAM02-BL2-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1757177AbcLUJWz (ORCPT ); Wed, 21 Dec 2016 04:22:55 -0500 X-Greylist: delayed 1217 seconds by postgrey-1.27 at vger.kernel.org; Wed, 21 Dec 2016 04:22:55 EST Authentication-Results: spf=none (sender IP is ) smtp.mailfrom=Satha.Rao@cavium.com; From: Satha Koteswara Rao To: CC: , , , , , , , , , Subject: [RFC PATCH 2/7] VF driver changes to enable hooks to get kernel notifications Date: Wed, 21 Dec 2016 14:16:46 +0530 Message-ID: <1482310011-1862-3-git-send-email-satha.rao@caviumnetworks.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1482310011-1862-1-git-send-email-satha.rao@caviumnetworks.com> References: <1482310011-1862-1-git-send-email-satha.rao@caviumnetworks.com> MIME-Version: 1.0 Content-Type: text/plain X-Originating-IP: [111.93.218.67] X-ClientProxiedBy: MAXPR01CA0030.INDPRD01.PROD.OUTLOOK.COM (10.164.147.37) To CY4PR07MB2838.namprd07.prod.outlook.com (10.169.252.16) X-MS-Office365-Filtering-Correlation-Id: ef31fd85-be94-4ec7-5892-08d4297e181a X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:(22001);SRVR:CY4PR07MB2838; X-Microsoft-Exchange-Diagnostics: 1;CY4PR07MB2838;3:hAqIyMH4fmmhdkyH09if3vLOp9Iwj1N8EHf353W/9nhew/CuJfdNcQCrKd06EknwrPXX+QgvbxpmdiUni1Rih9BSA2pO6vKuBhMhHjtizg75VcG1EcIBuqDobkUTnhq/jLleiE910f+sYTz3xkwkPayAUKUcjvzBVVFfu2B/bUcz3IgeRISC6lSeKeFjGPyVZ6jTS1/aNNwpyMhUAhD33mCF5MlIpWsK49grfZdZBUOScnlthHQAeNm6wo39VYNWfUSxY0p/GrCGwJavXJa9MA== X-Microsoft-Exchange-Diagnostics: 1;CY4PR07MB2838;25:09vdMKMCG1Nrg74qnuybALMIeyYrDCPndd7M53WGwBjZsLO4pGHrswdFUNpuTiQUZ01b0Lj79kACzkOrFfBYkjfHJYG3vHK9FTnwDONqjWnYfwbweCkY+hggZfmqF1i9CJHUsxsoOTY6b96OtEh119AImmiestG7vWU4Mza8dif2zkIp5nUYSZkKcXb+elPWa5iYSdgzh5dfzAQ9MtRaYo6O0hJh7+K3KldQCYdV/uF2jhRs4L3Pl8NXXT/GC+49yUDUF9mGx7HqZ+nQXXRmszM82MMQrSieAOozG10vmSSADmKqVmZDrHJmDW9X/vdtV+ntYOxFeUhUVVpTLACpn5yDQVBB7YSlxualKUbkm42YrMXug9GzjGvTdrMZodngoagnP4+iUbr17gNDrzbZqDvIckBoobZG+7TlNv0hGVSH79MtVb8bMzBLevJ61frCApJHSwPfzrd4qi5ikFZbUXNpyF2lBgjf9BYprHE8+9N7xc/2W0WHAXKiDU2hr+StHRbKFFkBU9+EUcwFsKhD6l+aQGgombbvqVj+9hD+X64KwkX2hkRXcSRBAMr11iPDkA8dT+RRlDM8vM2lJz2BwyBtw9/z71l8OnEXma9VT4lJ8iJKJYma4vuc/GDwM0seNh6WOEzFuhCAwNiR6Ol6+5rdP9IK27fYqdZI/RlyGhtvwEpz5/aIfjccqnRByBNUaH4BuAHH1Wy3Jy3h7rsK8wZXpf3V5w28hzvUQps0mI12KmqWIXOK3yjRVb6UVVap+e75tkEwAB1oUPt/7JA8BKSZvsVG1JgAe9ChEyt3NUHipMNTnWVhUSyf/uOlW3tK8nJvD38k4lJnRt24c+rNZC42tmd2RCJ/NdZczWT8170= X-Microsoft-Exchange-Diagnostics: 1;CY4PR07MB2838;31:+vFhhjRx5b/bKTTfNWaDrQfDKhmA9JweOwW+FEzVH00CBH6uvCGbfYWuNOGk6PVFxSns3KGjgyJSVepsNDf42Ldj0kgB2cRxODbbb7mhp3qzY5qV44IckfixVsr/gMN17ZpnHZdrPoxNZapGqKupdghojGJCZoyn3o1eQ97uGjsuJ8fqDM65bhTanB4RGFw9sUjL/a9bUB5MwL6en1c0CfS6Lq1Cv7NRYiQyDDCo44lql9qlC0XtrIkDGLnkZbFCRTrQnQmS/6LOhHboFA5qCg==;20:CEQuMiFbmLkPGT0XZWiD8Somh4fT+CdTmLrpt2Xg0eyrT4KAGvtWPXii/2Lu27jwGx3Y9EF7cx1xAaTQ+HPb2SbqLGZ3CWH3W710mjPlLLS/TtNn0WpEeWVAZTE158hqX6PNK7xLhZBXlXnux8EaQYkI1nA8qiMMEQ9qgAEA771Z474/Li8ebRPUdRENEkIczL+cxmnXJ71NHOXecMwDsdU5uW+mfelRTnvDNudTeUtxoDsFRQsrezXVLux53aoz5WALsTltpjcecasN0mQsD+Ji36ArJKQdmZ7prLgD8ybyu83S41vMTr0CNsCBk9gScaebqETc8oLAB1PbwCBr4Cfcg6HnY1w5Pi4I0dmHgSNdyUPCX1Y+VEEBbzpBcmusIEjXRB7C838hbXYBAMbTjdN237nCwyku3p48uE/z21RFc9GvgzxR5o6eWAcMuIWjyY97cHypmiwxDbGSF6yGSvIm+lYo1gMo+DjcRy4KVCIsd4OH4LqH70dnr1EA8ianrq1V5KVmLDmzLJYhkw/lAgItvgLkD1LNql/WjVMZtrG5+PL6Vyjs9tva8YWPQj1UNRzF/zktwvFzImG2LdVEFgnCwS8G2pMK0LqMhv/2LOM= X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:; X-Exchange-Antispam-Report-CFA-Test: BCL:0;PCL:0;RULEID:(6040375)(601004)(2401047)(5005006)(8121501046)(10201501046)(3002001)(6041248)(20161123562025)(20161123564025)(20161123560025)(20161123555025)(6072148);SRVR:CY4PR07MB2838;BCL:0;PCL:0;RULEID:;SRVR:CY4PR07MB2838; X-Microsoft-Exchange-Diagnostics: 1;CY4PR07MB2838;4:Eu07Mck0ME2F5Z6emA2oBgMg6RW8cF7KWNk9FuFt41F+VZWFvz8StSCtPCV1w6lfEpPj515722dlomyb4KDpiGkYnug5E0FeXMT6qb+S10AyCofXx9fLLMFJD3yDoVFfRPdsOqOpoq7Dqi6P6mQdzwK6JGdwYx7qyvW63BR0ySueOJXyWyXRZAETLWz7HP4gwmOq8XekG4H00Ha8uYjIOY83Vje5F+6YQtyWBSlGBXLLrxVMFM84hC6gaE2sTScJcX7cOJoHFMkJeFLx6bAwcc/xIFaZWoakATOn+UIW8Q6NpjRuUPKW0t/P40MKfl2D6uoJxldaU/uxA7Hzc/Bg1M2vSvhmQgizAq17eXg76gr4D0U45HD+idLOrBliTbguNpIM+W+dLrAN4oNQngfMjfn5gQ+JbO/BhtD6Xg20Nqx7FUp+kCaGJgnZf69XYLA1Thi7K2lF6RwR2P+gPjuoyxKE50vGNp991P4kB/hi+ahzsF1cOQPmZOvImy1rpwJV28EcWnvfqHaGrG+kwDF8LFldKKobC+nVKnnKcB9u693rByuzT1I75pAjXETkyO2LiMdMLeq+wcmhc4dJfcL2xg== X-Forefront-PRVS: 01630974C0 X-Forefront-Antispam-Report: SFV:NSPM;SFS:(10009020)(4630300001)(6069001)(6009001)(7916002)(39450400003)(189002)(199003)(2906002)(15650500001)(4326007)(101416001)(33646002)(5009440100003)(106356001)(2351001)(68736007)(105586002)(8676002)(5890100001)(50986999)(5003940100001)(53416004)(76506005)(76176999)(48376002)(81156014)(81166006)(42186005)(66066001)(5660300001)(92566002)(50466002)(6506006)(110136003)(7736002)(6916009)(47776003)(189998001)(36756003)(6116002)(6666003)(50226002)(3846002)(97736004)(42882006)(25786008)(2950100002)(305945005)(6512006)(69596002)(38730400001)(6486002)(4720700003)(7099028)(217873001);DIR:OUT;SFP:1101;SCL:1;SRVR:CY4PR07MB2838;H:localhost.caveonetworks.com;FPR:;SPF:None;PTR:InfoNoRecords;MX:1;A:1;LANG:en; X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1;CY4PR07MB2838;23:CMIumhthAxz9vAUZIh8GeG3Aj0ePSsGP82X2G9cUR?= =?us-ascii?Q?HQaLK2YKnDAhSET04HDLW8bW88j+/gjfZf2s7Dt5dimDHKiA4Ab0o4iMOFii?= =?us-ascii?Q?Xzf3QXi7AVPUblt5Jp4rmZWIvvKN8lfzTgIVwtZ75bI9E/W4+c0FbvFlgm13?= =?us-ascii?Q?o/xhdxKOU8o9JPMiF4dKsxJy1zRRN1EUN1cCb7LTVQITeM9/SKSnqpIZyDTM?= =?us-ascii?Q?sJ/e8lEmg59DKQx3F7gvJcarO5b+5F0muxCPw6NTIC3dfL+qH6pETbuzx/hu?= =?us-ascii?Q?Dgftmz87lqXiEJEFyQLLRnS6DQy+rPSqED8TbtgtOZhM5ITO5gB9/9Pq3th7?= =?us-ascii?Q?H/2bV11DVL1hRHqRM7egCGDe1b4pasAXPXfHigTp89pJCQIYjF6Zi+EP5PVV?= =?us-ascii?Q?uXuVovRKSWe7nd8pQ6Xs/EanDWGkmPwP9m9nFEVfXnZTMmixB3wyVKuz2z32?= =?us-ascii?Q?nWRd7at1GlctQPVVCp9a4Mok7eBuIx+yy68R133uuqBmH01mk6HqbSWaeht1?= =?us-ascii?Q?QE0xjGM79NiEHPqLcE78qBuoHLP3ePC0vZF4HS2dzCKSwwXfp1sEupnOQH3F?= =?us-ascii?Q?eA8IO9MDsrmtI2/Bs1ioMd6sNlIWTV4aCmBjl3aXwXhB9H5y2W+KjkQ4L5aH?= =?us-ascii?Q?AXVhFU7f8MRvK4UnvyvCae0cn3kgWg90ek1jDU+CAd6l2YE6+6eU94llkl9y?= =?us-ascii?Q?i1SYN0Z3tPL9cr7aMzB0xQfndO+hSPm6kKwtlKEX47hlCmfKvlFqtc5cz/To?= =?us-ascii?Q?PyiBUy2Rn8S/g0vlvayDeZbwm6rlDZBUliEIK5IsBbllP1ogdX/vfmgKwQLd?= =?us-ascii?Q?ZldYdL3VRZDB2rAiVfJeoio4/K5/k1s4I/IrXJFTVZ/01M/ohFgAidFqVels?= =?us-ascii?Q?pE/nEXyb8HSe2bsMw1bgSBc0f61o5OCNe8KinHOmw5UZpFgkPN+yd6KB4jpl?= =?us-ascii?Q?xW7fN/PhnCWHp0WS3swX14jDXxKEPBr8pNYrojqYEj3ouud5/bc9cx4TtMUv?= =?us-ascii?Q?0NGPc046eMKUGQWPg9EvArAXy7m4FjOZg/J7Pp2ieeciIAd7qflKWw144bQG?= =?us-ascii?Q?Wcp0tbP1cxSE335vamHsNGYip4dDYaNNzaH4NelZYlEs1TLTyHNYPwKn9kbM?= =?us-ascii?Q?lelHrYr7gmasvSj9h9Nru8wiKwtPdQBg/dvjXSUTcRJaHxU8+pdmrKL5FyHb?= =?us-ascii?Q?ZaBke8d1iGZCIsVRVH7uyBEnlps8Gr/DkGS8UjeBggPq7nDxMVUq0NppTOvW?= =?us-ascii?Q?lu74XnMEw5Gq8PFgTJUJ1Vkm2V6W71w8Ej9iKr6gdoXe5NmUiSZoOosDB0m7?= =?us-ascii?Q?EB03mPLXfxbO7xA0d38wHuBhe9cLM+58pU/Qy58thid?= X-Microsoft-Exchange-Diagnostics: 1;CY4PR07MB2838;6:pCfb7O9FQa47zLqYv8aVerf+nrRVNIm53gSlEM0wt2MAwy/Au+IfbyuxfJvSCQS6slfHB/svkw/EEot3eSrrL39u9VZxz8+/+r/ZVx7AM1RV1vVJ070YgyWIyy2slhZHaApltQEebLoDw6o5OCXlZJU8F5uyQmvk+eO1lZA+5YiYdUx39m+HMdAygVGfmEOnjz+AQ0t7HOpdNH9Drd0fiJqqQeaM1FTc0rYdZJwGykhMJrlXF3T1rB0rm8jNX/8Dv/Yt3ul1QgSY0vWvF2qxBdjqsawcz8PLtYMe81RRNn7clKmZMrubZ2Fiod3Pd9rySSodC1b9WOmjhT0IXjKeE9n8jA7AwAVjr/PC96aZlBm8y+0RyVODyqhAtjEj0pkeqkgrvf2316J7FkTazIN9JrCKO4LmOkcl/+dR54CLgdA=;5:MQNTywWUqUl0+TZAm2Gq7j18hL7WwYTB1/IQF5vLKQDxNhyjdFpPcrkmBm8IJN4HBLXOzSzhcWRIYXrPHCFP6JA063OOEAX5c/Wfs4+HJXv+Sej+FdRExMxnXHxAKJofdxmyP78jXz8Aypdmy8jnJA==;24:c424aWZkmmQO8WYOanOFF3SDWPW6iN+N3cu3Pwgsqo3K1mvkpl8qfiiCr9mwKJUdCGZVN5e7fkkwjRQnjADd9/b9GIqoWguRhzK+K2pwj1U= SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-Microsoft-Exchange-Diagnostics: 1;CY4PR07MB2838;7:DRqy7ZsIQkT+Mb+tjLVwyG0zaOVncESq9AKmw6hErV+voKriNKkCXOrZbMs2dhCj4+N2XBpPqtZDpsYGCMAO9sVW0TaJMBAJne+IT8s43SzJBuaAeytjQ+frJTZvNbectxZEw9HwlFhqfAPTfxFFIYBQazkW9U+NM5a2g8OG2GwG8Zw1n2RrZ6bkvb104tGmYy0uW4+/BpoZflJDYehP9773WxxQh7yr8QoJJntj/sda4TZvvsdojShm0ceiw9k+Wuwrq9M556o+cSiChNgQ+PX9RtKvlKlNPTY1Ul/9bmtyKnfyD3B6w8viAH8qLoi/roh5ilKffJ/jK+kFJnQPG6u8EOH2xmsn10tYRRiq/GMAjiabNH30kiOuP9Dp/9yJ8Vua/GuvilGvO8UP8Azef9nob627nW5vsZJmV+YXQx/ApzhNOCB/paL59ziE6Mq41ojcL+WHIeYEAey6AL8QQQ== X-OriginatorOrg: caviumnetworks.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 21 Dec 2016 08:48:08.0913 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-Transport-CrossTenantHeadersStamped: CY4PR07MB2838 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 22570 Lines: 783 --- drivers/net/ethernet/cavium/thunder/nicvf_main.c | 579 ++++++++++++++++++++++- 1 file changed, 565 insertions(+), 14 deletions(-) diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_main.c b/drivers/net/ethernet/cavium/thunder/nicvf_main.c index 8a37012..8f00bc7 100644 --- a/drivers/net/ethernet/cavium/thunder/nicvf_main.c +++ b/drivers/net/ethernet/cavium/thunder/nicvf_main.c @@ -52,6 +52,11 @@ MODULE_VERSION(DRV_VERSION); MODULE_DEVICE_TABLE(pci, nicvf_id_table); +static int veb_enabled; + +int uc_mc_list; +module_param(uc_mc_list, int, 0644); + static int debug = 0x00; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Debug message level bitmap"); @@ -61,6 +66,132 @@ MODULE_PARM_DESC(cpi_alg, "PFC algorithm (0=none, 1=VLAN, 2=VLAN16, 3=IP Diffserv)"); +/* Initialize the Shadow List */ +void nicvf_shadow_list_init(struct netdev_hw_addr_list *list) +{ + INIT_LIST_HEAD(&list->list); + list->count = 0; +} + +/*Set the sync it of the addr structure */ +void nicvf_shadow_list_setsync(struct netdev_hw_addr_list *list, int sync) +{ + struct netdev_hw_addr *ha, *tmp; + + list_for_each_entry_safe(ha, tmp, &list->list, list) { + ha->synced = sync; + } +} + +/*Flush the entire list */ +void nicvf_shadow_list_flush(struct netdev_hw_addr_list *list) +{ + struct netdev_hw_addr *ha, *tmp; + + list_for_each_entry_safe(ha, tmp, &list->list, list) { + list_del(&ha->list); + kfree(ha); + } + list->count = 0; +} + +/*Return the number of items in the list */ +int nicvf_shadow_list_count(struct netdev_hw_addr_list *list) +{ + return list->count; +} + +/*Check if the list is empty */ +int nicvf_shadow_list_empty(struct netdev_hw_addr_list *list) +{ + return (list->count == 0); +} + +/* Add item to list */ +int nicvf_shadow_list_add(struct netdev_hw_addr_list *list, unsigned char *addr) +{ + struct netdev_hw_addr *ha; + int alloc_size; + + alloc_size = sizeof(*ha); + ha = kmalloc(alloc_size, GFP_ATOMIC); + if (!ha) + return -ENOMEM; + ether_addr_copy(ha->addr, addr); + ha->synced = 0; + list_add_tail(&ha->list, &list->list); + list->count++; + return 0; +} + +/* Delete item in the list given the address */ +void nicvf_shadow_list_del_ha(struct netdev_hw_addr_list *list, + struct netdev_hw_addr *ha) +{ + list_del(&ha->list); + kfree(ha); + list->count--; +} + +/* Delete item in list by address */ +int nicvf_shadow_list_del(struct netdev_hw_addr_list *list, unsigned char *addr) +{ + struct netdev_hw_addr *ha, *tmp; + + list_for_each_entry_safe(ha, tmp, &list->list, list) + if (ether_addr_equal(ha->addr, addr)) + nicvf_shadow_list_del_ha(list, ha); + + return -ENOENT; +} + +/* Delete the addresses that are not in the netdev list and send delete + * notification + */ +int nicvf_shadow_list_delsync(struct netdev_hw_addr_list *list, + struct nicvf *nic, int addr_type) +{ + int is_modified = 0; + union nic_mbx mbx = {}; + struct netdev_hw_addr *ha, *tmp; + + list_for_each_entry_safe(ha, tmp, &list->list, list) { + if (ha->synced == 1) { + if (!uc_mc_list) { + mbx.msg.msg = NIC_MBOX_MSG_UC_MC; + mbx.uc_mc_cfg.vf_id = nic->vf_id; + mbx.uc_mc_cfg.addr_type = addr_type; + mbx.uc_mc_cfg.is_flush = 0; + mbx.uc_mc_cfg.is_add = 0; + ether_addr_copy(mbx.uc_mc_cfg.mac_addr, + ha->addr); + if (nicvf_send_msg_to_pf(nic, &mbx)) { + netdev_err(nic->netdev, + "PF not respond to MSG_UC_MC\n"); + } + } + is_modified = 1; + nicvf_shadow_list_del_ha(list, ha); + } + } + return is_modified; +} + +/*Check if an entry with the mac address exits in the list */ +int nicvf_shadow_list_find(struct netdev_hw_addr_list *list, + unsigned char *addr) +{ + struct netdev_hw_addr *ha; + + list_for_each_entry(ha, &list->list, list) { + if (ether_addr_equal(ha->addr, addr)) { + ha->synced = 0; + return 0; + } + } + return -ENOENT; +} + static inline u8 nicvf_netdev_qidx(struct nicvf *nic, u8 qidx) { if (nic->sqs_mode) @@ -113,22 +244,198 @@ static void nicvf_write_to_mbx(struct nicvf *nic, union nic_mbx *mbx) nicvf_reg_write(nic, NIC_VF_PF_MAILBOX_0_1 + 8, msg[1]); } +bool pf_ack_required(struct nicvf *nic, union nic_mbx *mbx) +{ + if (mbx->msg.msg == NIC_MBOX_MSG_PROMISC || + !nic->wait_for_ack) + return false; + + return true; +} + +void submit_uc_mc_mbox_msg(struct nicvf *nic, int vf, int flush, int addr_type, + u8 *mac) +{ + union nic_mbx mbx = {}; + + mbx.msg.msg = NIC_MBOX_MSG_UC_MC; + mbx.uc_mc_cfg.vf_id = vf; + mbx.uc_mc_cfg.addr_type = addr_type; + mbx.uc_mc_cfg.is_flush = flush; + mbx.uc_mc_cfg.is_add = !flush; + if (mac) + ether_addr_copy(mbx.uc_mc_cfg.mac_addr, mac); + + if (nicvf_send_msg_to_pf(nic, &mbx) == -EBUSY) { + netdev_err(nic->netdev, + "PF didn't respond to MSG_UC_MC flush\n"); + } +} + +void send_uc_mc_msg(struct work_struct *work) +{ + struct nicvf *nic = container_of(work, struct nicvf, dwork.work); + struct net_device *netdev = nic->netdev; + union nic_mbx mbx = {}; + int is_modified1 = 0; + int is_modified2 = 0; + + if (nic->send_op_link_status) { + mbx.msg.msg = nic->link_up ? NIC_MBOX_MSG_OP_UP : + NIC_MBOX_MSG_OP_DOWN; + if (nicvf_send_msg_to_pf(nic, &mbx)) { + netdev_err(nic->netdev, + "PF not respond to msg %d\n", mbx.msg.msg); + } + nic->send_op_link_status = false; + return; + } + + /* If the netdev list is empty */ + if (netdev_uc_empty(netdev)) { + /* If shadow list is not empty */ + if (!nicvf_shadow_list_empty(&nic->uc_shadow)) { + /* send uc flush notifcation */ + nicvf_shadow_list_flush(&nic->uc_shadow); + submit_uc_mc_mbox_msg(nic, nic->vf_id, 1, 0, NULL); + } + } else { + /* If shadow list is empty add all and notify */ + if (nicvf_shadow_list_empty(&nic->uc_shadow)) { + struct netdev_hw_addr *ha; + + netdev_for_each_uc_addr(ha, netdev) { + nicvf_shadow_list_add(&nic->uc_shadow, + ha->addr); + submit_uc_mc_mbox_msg(nic, nic->vf_id, 0, 0, + ha->addr); + } + } else { + struct netdev_hw_addr *ha; + + nicvf_shadow_list_setsync(&nic->uc_shadow, 1); + /* ADD the entries which are present in netdev list + * and not present in shadow list + */ + netdev_for_each_uc_addr(ha, netdev) { + if (nicvf_shadow_list_find(&nic->uc_shadow, + ha->addr)) { + is_modified1 = 1; + nicvf_shadow_list_add(&nic->uc_shadow, + ha->addr); + if (uc_mc_list) + continue; + submit_uc_mc_mbox_msg(nic, nic->vf_id, + 0, 0, ha->addr); + } + } + /* Delete items that are not present in netdev list and + * present in shadow list + */ + is_modified2 = nicvf_shadow_list_delsync( + &nic->uc_shadow, nic, 0); + if (uc_mc_list && (is_modified1 || is_modified2)) { + /* Now the shadow list is updated, + * send the entire list + */ + netdev_for_each_uc_addr(ha, netdev) + submit_uc_mc_mbox_msg(nic, nic->vf_id, + 0, 0, ha->addr); + } + } + } + + is_modified1 = 0; + is_modified2 = 0; + if (netdev_mc_empty(netdev)) { // If the netdev list is empty + /* If shadow list is not empty */ + if (!nicvf_shadow_list_empty(&nic->mc_shadow)) { + // send uc flush notifcation + nicvf_shadow_list_flush(&nic->mc_shadow); + submit_uc_mc_mbox_msg(nic, nic->vf_id, 1, 1, NULL); + } + } else { + /* If shadow list is empty add all and notfy */ + if (nicvf_shadow_list_empty(&nic->mc_shadow)) { + struct netdev_hw_addr *ha; + + netdev_for_each_mc_addr(ha, netdev) { + nicvf_shadow_list_add(&nic->mc_shadow, + ha->addr); + submit_uc_mc_mbox_msg(nic, nic->vf_id, 0, 1, + ha->addr); + } + } else { + struct netdev_hw_addr *ha; + + nicvf_shadow_list_setsync(&nic->mc_shadow, 1); + /* ADD the entries which are present in netdev list and + * not present in shadow list + */ + netdev_for_each_mc_addr(ha, netdev) { + if (nicvf_shadow_list_find(&nic->mc_shadow, + ha->addr)) { + is_modified1 = 1; + nicvf_shadow_list_add(&nic->mc_shadow, + ha->addr); + if (!uc_mc_list) + submit_uc_mc_mbox_msg( + nic, nic->vf_id, 0, 1, + ha->addr); + } + } + /* Delete items that are not present in netdev list and + * present in shadow list + */ + is_modified2 = nicvf_shadow_list_delsync( + &nic->mc_shadow, nic, 1); + if (uc_mc_list && (is_modified1 || is_modified2)) { + /* Now the shadow list is updated, send the + * entire list + */ + netdev_for_each_mc_addr(ha, netdev) + submit_uc_mc_mbox_msg(nic, nic->vf_id, + 0, 1, ha->addr); + } + } + } +} + int nicvf_send_msg_to_pf(struct nicvf *nic, union nic_mbx *mbx) { int timeout = NIC_MBOX_MSG_TIMEOUT; int sleep = 10; + if (nic->pf_ack_waiting) { + timeout += 20; + while (nic->pf_ack_waiting) { + msleep(sleep); + if (!timeout) + break; + timeout -= sleep; + } + timeout = NIC_MBOX_MSG_TIMEOUT; + } nic->pf_acked = false; nic->pf_nacked = false; + nic->pf_ack_waiting = true; nicvf_write_to_mbx(nic, mbx); + if (!pf_ack_required(nic, mbx)) { + nic->pf_ack_waiting = false; + nic->pf_acked = true; + nic->pf_nacked = true; + return 0; + } /* Wait for previous message to be acked, timeout 2sec */ while (!nic->pf_acked) { if (nic->pf_nacked) { - netdev_err(nic->netdev, - "PF NACK to mbox msg 0x%02x from VF%d\n", - (mbx->msg.msg & 0xFF), nic->vf_id); + if (mbx->msg.msg != NIC_MBOX_MSG_READY) + netdev_info(nic->netdev, + "PF NACK to mbox msg 0x%02x from VF%d\n", + (mbx->msg.msg & 0xFF), nic->vf_id); + nic->pf_ack_waiting = false; return -EINVAL; } msleep(sleep); @@ -139,9 +446,11 @@ int nicvf_send_msg_to_pf(struct nicvf *nic, union nic_mbx *mbx) netdev_err(nic->netdev, "PF didn't ACK to mbox msg 0x%02x from VF%d\n", (mbx->msg.msg & 0xFF), nic->vf_id); + nic->pf_ack_waiting = false; return -EBUSY; } } + nic->pf_ack_waiting = false; return 0; } @@ -151,9 +460,14 @@ int nicvf_send_msg_to_pf(struct nicvf *nic, union nic_mbx *mbx) static int nicvf_check_pf_ready(struct nicvf *nic) { union nic_mbx mbx = {}; + int ret = 0; mbx.msg.msg = NIC_MBOX_MSG_READY; - if (nicvf_send_msg_to_pf(nic, &mbx)) { + ret = nicvf_send_msg_to_pf(nic, &mbx); + if (ret == -EINVAL) { + /* VF disabled through module parameter */ + return 0; + } else if (ret) { netdev_err(nic->netdev, "PF didn't respond to READY msg\n"); return 0; @@ -193,12 +507,22 @@ static void nicvf_handle_mbx_intr(struct nicvf *nic) nic->vf_id = mbx.nic_cfg.vf_id & 0x7F; nic->tns_mode = mbx.nic_cfg.tns_mode & 0x7F; nic->node = mbx.nic_cfg.node_id; + nic->true_vf = mbx.nic_cfg.is_pf; + if (!veb_enabled) + veb_enabled = mbx.nic_cfg.veb_enabled; + if (veb_enabled) + snprintf(nic->phys_port_name, IFNAMSIZ, "%d %d %d %d", + nic->node, mbx.nic_cfg.bgx_id, + mbx.nic_cfg.lmac, mbx.nic_cfg.chan); if (!nic->set_mac_pending) ether_addr_copy(nic->netdev->dev_addr, mbx.nic_cfg.mac_addr); nic->sqs_mode = mbx.nic_cfg.sqs_mode; nic->loopback_supported = mbx.nic_cfg.loopback_supported; - nic->link_up = false; + if (veb_enabled) + nic->link_up = mbx.nic_cfg.pf_up; + else + nic->link_up = false; nic->duplex = 0; nic->speed = 0; break; @@ -208,6 +532,12 @@ static void nicvf_handle_mbx_intr(struct nicvf *nic) case NIC_MBOX_MSG_NACK: nic->pf_nacked = true; break; + case NIC_MBOX_MSG_ADMIN_VLAN: + if (mbx.vlan_cfg.vlan_add && nic->admin_vlan_id == -1) + nic->admin_vlan_id = mbx.vlan_cfg.vlan_id; + else if (!mbx.vlan_cfg.vlan_add) + nic->admin_vlan_id = -1; + break; case NIC_MBOX_MSG_RSS_SIZE: nic->rss_info.rss_size = mbx.rss_size.ind_tbl_size; nic->pf_acked = true; @@ -216,16 +546,21 @@ static void nicvf_handle_mbx_intr(struct nicvf *nic) nicvf_read_bgx_stats(nic, &mbx.bgx_stats); nic->pf_acked = true; break; - case NIC_MBOX_MSG_BGX_LINK_CHANGE: + case NIC_MBOX_MSG_CFG_DONE: nic->pf_acked = true; nic->link_up = mbx.link_status.link_up; nic->duplex = mbx.link_status.duplex; nic->speed = mbx.link_status.speed; + break; + case NIC_MBOX_MSG_BGX_LINK_CHANGE: + nic->link_up = mbx.link_status.link_up; + nic->duplex = mbx.link_status.duplex; + nic->speed = mbx.link_status.speed; if (nic->link_up) { netdev_info(nic->netdev, "%s: Link is Up %d Mbps %s\n", nic->netdev->name, nic->speed, nic->duplex == DUPLEX_FULL ? - "Full duplex" : "Half duplex"); + "Full duplex" : "Half duplex"); netif_carrier_on(nic->netdev); netif_tx_start_all_queues(nic->netdev); } else { @@ -563,6 +898,14 @@ static inline void nicvf_set_rxhash(struct net_device *netdev, skb_set_hash(skb, hash, hash_type); } +static inline bool is_vf_vlan(struct nicvf *nic, u16 vid) +{ + if (veb_enabled && ((nic->admin_vlan_id & 0xFFF) == vid)) + return false; + + return true; +} + static void nicvf_rcv_pkt_handler(struct net_device *netdev, struct napi_struct *napi, struct cqe_rx_t *cqe_rx) @@ -617,7 +960,8 @@ static void nicvf_rcv_pkt_handler(struct net_device *netdev, skb->protocol = eth_type_trans(skb, netdev); /* Check for stripped VLAN */ - if (cqe_rx->vlan_found && cqe_rx->vlan_stripped) + if (cqe_rx->vlan_found && cqe_rx->vlan_stripped && + is_vf_vlan(nic, (ntohs(cqe_rx->vlan_tci) & 0xFFF))) __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), ntohs((__force __be16)cqe_rx->vlan_tci)); @@ -1151,6 +1495,8 @@ int nicvf_stop(struct net_device *netdev) /* disable mailbox interrupt */ nicvf_disable_intr(nic, NICVF_INTR_MBOX, 0); + //MBOX interrupts disabled, don't expect any ACK's from PF + nic->wait_for_ack = false; nicvf_unregister_interrupts(nic); nicvf_free_cq_poll(nic); @@ -1182,6 +1528,8 @@ int nicvf_open(struct net_device *netdev) netif_carrier_off(netdev); + //MBOX interrupts enabled, so wait for ACK from PF + nic->wait_for_ack = true; err = nicvf_register_misc_interrupt(nic); if (err) return err; @@ -1202,7 +1550,8 @@ int nicvf_open(struct net_device *netdev) } /* Check if we got MAC address from PF or else generate a radom MAC */ - if (!nic->sqs_mode && is_zero_ether_addr(netdev->dev_addr)) { + if ((veb_enabled || !nic->sqs_mode) && + is_zero_ether_addr(netdev->dev_addr)) { eth_hw_addr_random(netdev); nicvf_hw_set_mac_addr(nic, netdev); } @@ -1268,7 +1617,17 @@ int nicvf_open(struct net_device *netdev) /* Send VF config done msg to PF */ mbx.msg.msg = NIC_MBOX_MSG_CFG_DONE; - nicvf_write_to_mbx(nic, &mbx); + if (veb_enabled) + nicvf_send_msg_to_pf(nic, &mbx); + else + nicvf_write_to_mbx(nic, &mbx); + + if (veb_enabled && nic->link_up) { + nic->send_op_link_status = true; + queue_delayed_work(nic->uc_mc_msg, &nic->dwork, 0); + netif_carrier_on(netdev); + netif_tx_start_all_queues(netdev); + } return 0; cleanup: @@ -1299,6 +1658,8 @@ static int nicvf_change_mtu(struct net_device *netdev, int new_mtu) return -EINVAL; netdev->mtu = new_mtu; + if (!nic->link_up) + return 0; if (!netif_running(netdev)) return 0; @@ -1508,6 +1869,142 @@ static int nicvf_set_features(struct net_device *netdev, return 0; } +static int nicvf_vlan_rx_add_vid(struct net_device *netdev, + __always_unused __be16 proto, u16 vid) +{ + struct nicvf *nic = netdev_priv(netdev); + union nic_mbx mbx = {}; + int ret = 0; + + if (!veb_enabled) + return 0; + + if (nic->admin_vlan_id != -1) { + netdev_err(nic->netdev, + "VF %d could not add VLAN %d\n", nic->vf_id, vid); + return -1; + } + mbx.msg.msg = NIC_MBOX_MSG_VLAN; + mbx.vlan_cfg.vf_id = nic->vf_id; + mbx.vlan_cfg.vlan_id = vid; + mbx.vlan_cfg.vlan_add = 1; + ret = nicvf_send_msg_to_pf(nic, &mbx); + if (ret == -EINVAL) { + netdev_err(nic->netdev, "VF %d could not add VLAN %d\n", + nic->vf_id, vid); + } else if (ret == -EBUSY) { + netdev_err(nic->netdev, + "PF didn't respond to VLAN msg VLAN ID: %d VF: %d\n", + vid, nic->vf_id); + } + return ret; +} + +static int nicvf_vlan_rx_kill_vid(struct net_device *netdev, + __always_unused __be16 proto, u16 vid) +{ + struct nicvf *nic = netdev_priv(netdev); + union nic_mbx mbx = {}; + + if (!veb_enabled) + return 0; + + mbx.msg.msg = NIC_MBOX_MSG_VLAN; + mbx.vlan_cfg.vf_id = nic->vf_id; + mbx.vlan_cfg.vlan_id = vid; + mbx.vlan_cfg.vlan_add = 0; + if (nicvf_send_msg_to_pf(nic, &mbx)) { + netdev_err(nic->netdev, + "PF didn't respond to VLAN msg VLAN ID: %d VF: %d\n", + vid, nic->vf_id); + return -1; + } + return 0; +} + +void nicvf_set_rx_mode(struct net_device *netdev) +{ + struct nicvf *nic = netdev_priv(netdev); + + if (!veb_enabled) + return; + + queue_delayed_work(nic->uc_mc_msg, &nic->dwork, 0); +} + +void nicvf_change_rx_flags(struct net_device *netdev, int flags) +{ + struct nicvf *nic = netdev_priv(netdev); + union nic_mbx mbx = {}; + + if (!veb_enabled) + return; + + mbx.msg.msg = NIC_MBOX_MSG_PROMISC; + mbx.promisc_cfg.vf_id = nic->vf_id; + mbx.promisc_cfg.on = netdev->flags & IFF_PROMISC; + if (nicvf_send_msg_to_pf(nic, &mbx)) { + netdev_err(nic->netdev, + "PF didn't respond to PROMISC Mode\n"); + return; + } +} + +int nicvf_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan, u8 qos, + __be16 vlan_proto) +{ + struct nicvf *nic = netdev_priv(netdev); + int is_add = (vlan | qos); + union nic_mbx mbx = {}; + int ret = 0; + + if (!veb_enabled) + return 0; + + mbx.msg.msg = NIC_MBOX_MSG_ADMIN_VLAN; + mbx.vlan_cfg.vf_id = vf; + mbx.vlan_cfg.vlan_add = is_add; + mbx.vlan_cfg.vlan_id = vlan; + + ret = nicvf_send_msg_to_pf(nic, &mbx); + if (ret == -EINVAL) { + netdev_err(nic->netdev, "ADMIN VLAN %s failed For Vf %d\n", + is_add ? "Add" : "Delete", vf); + } else if (ret == -EBUSY) { + netdev_err(nic->netdev, + "PF didn't respond to ADMIN VLAN UPDATE msg\n"); + } + return ret; +} + +static int nicvf_get_phys_port_name(struct net_device *netdev, char *name, + size_t len) +{ + struct nicvf *nic = netdev_priv(netdev); + int plen; + + plen = snprintf(name, len, "%s", nic->phys_port_name); + + if (plen >= len) + return -EINVAL; + + return 0; +} + +static int nicvf_get_phys_port_id(struct net_device *netdev, + struct netdev_phys_item_id *ppid) +{ + struct nicvf *nic = netdev_priv(netdev); + + if (veb_enabled && !nic->true_vf) + return -EOPNOTSUPP; + + ppid->id_len = min_t(int, sizeof(netdev->dev_addr), sizeof(ppid->id)); + memcpy(ppid->id, netdev->dev_addr, ppid->id_len); + + return 0; +} + static const struct net_device_ops nicvf_netdev_ops = { .ndo_open = nicvf_open, .ndo_stop = nicvf_stop, @@ -1518,6 +2015,13 @@ static int nicvf_set_features(struct net_device *netdev, .ndo_tx_timeout = nicvf_tx_timeout, .ndo_fix_features = nicvf_fix_features, .ndo_set_features = nicvf_set_features, + .ndo_vlan_rx_add_vid = nicvf_vlan_rx_add_vid, + .ndo_vlan_rx_kill_vid = nicvf_vlan_rx_kill_vid, + .ndo_set_rx_mode = nicvf_set_rx_mode, + .ndo_change_rx_flags = nicvf_change_rx_flags, + .ndo_set_vf_vlan = nicvf_set_vf_vlan, + .ndo_get_phys_port_name = nicvf_get_phys_port_name, + .ndo_get_phys_port_id = nicvf_get_phys_port_id, }; static int nicvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) @@ -1576,6 +2080,7 @@ static int nicvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) nic->pdev = pdev; nic->pnicvf = nic; nic->max_queues = qcount; + nic->pf_ack_waiting = false; /* MAP VF's configuration registers */ nic->reg_base = pcim_iomap(pdev, PCI_CFG_REG_BAR_NUM, 0); @@ -1595,6 +2100,8 @@ static int nicvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (err) goto err_free_netdev; + //MBOX interrupts enabled, so wait for ACK from PF + nic->wait_for_ack = true; /* Check if PF is alive and get MAC address for this VF */ err = nicvf_register_misc_interrupt(nic); if (err) @@ -1619,12 +2126,13 @@ static int nicvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) netdev->hw_features = (NETIF_F_RXCSUM | NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_TSO | NETIF_F_GRO | - NETIF_F_HW_VLAN_CTAG_RX); - - netdev->hw_features |= NETIF_F_RXHASH; + NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_RXHASH); netdev->features |= netdev->hw_features; - netdev->hw_features |= NETIF_F_LOOPBACK; + if (veb_enabled) + netdev->features |= NETIF_F_HW_VLAN_CTAG_FILTER; + else + netdev->hw_features |= NETIF_F_LOOPBACK; netdev->vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO; @@ -1642,6 +2150,37 @@ static int nicvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) nic->msg_enable = debug; nicvf_set_ethtool_ops(netdev); + if (veb_enabled) { + int bgx, lmac, chan, node, ret; + + ret = sscanf(nic->phys_port_name, "%d %d %d %d", &node, &bgx, + &lmac, &chan); + if (nic->true_vf) { + dev_info(dev, + "interface %s enabled with node %d VF %d channel %d directly attached to physical port n%d-bgx-%d-%d\n", + netdev->name, node, nic->vf_id, chan, node, + bgx, lmac); + } else { + dev_info(dev, + "interface %s enabled with node %d VF %d channel %d attached to physical port n%d-bgx-%d-%d\n", + netdev->name, node, nic->vf_id, chan, node, + bgx, lmac); + } + snprintf(nic->phys_port_name, IFNAMSIZ, "n%d-bgx-%d-%d", + node, bgx, lmac); + nicvf_shadow_list_init(&nic->uc_shadow); + nicvf_shadow_list_init(&nic->mc_shadow); + + nic->admin_vlan_id = -1; + nic->send_op_link_status = false; + nic->uc_mc_msg = alloc_workqueue("uc_mc_msg", WQ_UNBOUND | + WQ_MEM_RECLAIM, 1); + if (!nic->uc_mc_msg) + return -ENOMEM; + INIT_DELAYED_WORK(&nic->dwork, send_uc_mc_msg); + } else { + strlcpy(nic->phys_port_name, netdev->name, IFNAMSIZ); + } return 0; @@ -1669,6 +2208,12 @@ static void nicvf_remove(struct pci_dev *pdev) return; nic = netdev_priv(netdev); + if (veb_enabled) { + if (nicvf_shadow_list_count(&nic->uc_shadow)) + nicvf_shadow_list_flush(&nic->uc_shadow); + if (nicvf_shadow_list_count(&nic->mc_shadow)) + nicvf_shadow_list_flush(&nic->mc_shadow); + } pnetdev = nic->pnicvf->netdev; /* Check if this Qset is assigned to different VF. @@ -1678,6 +2223,12 @@ static void nicvf_remove(struct pci_dev *pdev) unregister_netdev(pnetdev); nicvf_unregister_interrupts(nic); pci_set_drvdata(pdev, NULL); + if (veb_enabled) { + if (nic->uc_mc_msg) { + cancel_delayed_work_sync(&nic->dwork); + destroy_workqueue(nic->uc_mc_msg); + } + } if (nic->drv_stats) free_percpu(nic->drv_stats); free_netdev(netdev); -- 1.8.3.1