From nobody Tue Dec 2 02:32:03 2025 Received: from canpmsgout04.his.huawei.com (canpmsgout04.his.huawei.com [113.46.200.219]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 389BF3596E6; Wed, 19 Nov 2025 12:44:05 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=113.46.200.219 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763556250; cv=none; b=jJ8i4eiOOXlSZileFvnYaYsaEvT8UY1clKd7vyF3klccrRWvVHkIy+AK3omFRyJQSrc4Obu3REQ81UB11IxRG0XG5M1gEhwNcvapq3ZbX/Q+Q8hJ/XtXFC0oYXjP2fVywquC8gQSUpL5rXr9iyiq2fpmS9wSFljQQscCT/mfYcE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763556250; c=relaxed/simple; bh=0Y3Cvw+kKr93+miw7bEGKYGzgJez3nQErgDbsHvflJc=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=n3doc/ZyMJltldNcFhbXKwz5ndE/SBoDuPaJ5GouBeeK4WlQWVmTr+6taPdgSAd3gImX4o9em9FqQKu+fPLtIQ78+98bZ4Ejl7gizeEeHvb2L5FFXZlHeK5D/PsYhhCw381P9wibh8tCpkQVPkzYafl7wCouwL2P84NUVq/Y4yk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com; spf=pass smtp.mailfrom=huawei.com; dkim=pass (1024-bit key) header.d=huawei.com header.i=@huawei.com header.b=F4oUKx2P; arc=none smtp.client-ip=113.46.200.219 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huawei.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=huawei.com header.i=@huawei.com header.b="F4oUKx2P" dkim-signature: v=1; a=rsa-sha256; d=huawei.com; s=dkim; c=relaxed/relaxed; q=dns/txt; h=From; bh=1R0asz8w9wWtbnTE6+YHorZTK7F5d2Z4iEVgJjFjuAI=; b=F4oUKx2P79le9wkJLW8dymk8LTEgSVHDIgERgGfOiQPl5TpLnijpr/xwKU7SjUOSocLY+MHdU pGPbHP5TaBZDuROTN6NnwcnCVLx9NItepetC38ant2IGL/dwFrgS0d6cOylTAZ/i8Qagn5l/oom 9C/EgMDADpKZTiTdegTXjjI= Received: from mail.maildlp.com (unknown [172.19.163.48]) by canpmsgout04.his.huawei.com (SkyGuard) with ESMTPS id 4dBLj053tKz1prLF; Wed, 19 Nov 2025 20:42:12 +0800 (CST) Received: from kwepemf100013.china.huawei.com (unknown [7.202.181.12]) by mail.maildlp.com (Postfix) with ESMTPS id 48023180477; Wed, 19 Nov 2025 20:43:57 +0800 (CST) Received: from DESKTOP-62GVMTR.china.huawei.com (10.174.188.120) by kwepemf100013.china.huawei.com (7.202.181.12) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.11; Wed, 19 Nov 2025 20:43:55 +0800 From: Fan Gong To: Fan Gong , Zhu Yikai , , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Andrew Lunn , Markus Elfring , Pavan Chebbi , ALOK TIWARI CC: , , luosifu , Xin Guo , Shen Chenyang , Zhou Shuai , Wu Like , Shi Jing , Luo Yang , Meny Yossefi , Gur Stavi Subject: [PATCH net-next v07 2/9] hinic3: Add PF management interfaces Date: Wed, 19 Nov 2025 20:43:35 +0800 Message-ID: <42f0b74c6365a4e1bf1016b12d688d0d06e390f8.1763555878.git.zhuyikai1@h-partners.com> X-Mailer: git-send-email 2.51.0.windows.1 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: kwepems200002.china.huawei.com (7.221.188.68) To kwepemf100013.china.huawei.com (7.202.181.12) Content-Type: text/plain; charset="utf-8" Add management and communication pathways between PF and HW. Co-developed-by: Zhu Yikai Signed-off-by: Zhu Yikai Signed-off-by: Fan Gong --- .../ethernet/huawei/hinic3/hinic3_hw_intf.h | 2 + .../net/ethernet/huawei/hinic3/hinic3_hwdev.c | 51 ++- .../net/ethernet/huawei/hinic3/hinic3_hwdev.h | 1 + .../net/ethernet/huawei/hinic3/hinic3_main.c | 2 + .../net/ethernet/huawei/hinic3/hinic3_mbox.c | 13 + .../net/ethernet/huawei/hinic3/hinic3_mbox.h | 2 + .../net/ethernet/huawei/hinic3/hinic3_mgmt.c | 311 +++++++++++++++++- .../net/ethernet/huawei/hinic3/hinic3_mgmt.h | 53 +++ .../huawei/hinic3/hinic3_mgmt_interface.h | 1 + .../huawei/hinic3/hinic3_netdev_ops.c | 35 ++ .../ethernet/huawei/hinic3/hinic3_nic_cfg.c | 28 ++ .../ethernet/huawei/hinic3/hinic3_nic_cfg.h | 18 + .../ethernet/huawei/hinic3/hinic3_nic_dev.h | 3 + 13 files changed, 518 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_hw_intf.h b/drivers/= net/ethernet/huawei/hinic3/hinic3_hw_intf.h index a0422ec0500f..329a9c464ff9 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_hw_intf.h +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_hw_intf.h @@ -39,6 +39,8 @@ enum mgmt_mod_type { /* Configuration module */ MGMT_MOD_CFGM =3D 7, MGMT_MOD_HILINK =3D 14, + /* hardware max module id */ + MGMT_MOD_HW_MAX =3D 20, }; =20 static inline void mgmt_msg_params_init_default(struct mgmt_msg_params *ms= g_params, diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_hwdev.c b/drivers/ne= t/ethernet/huawei/hinic3/hinic3_hwdev.c index 2b1f1036620e..25e375b20174 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_hwdev.c +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_hwdev.c @@ -211,6 +211,36 @@ static int init_ceqs_msix_attr(struct hinic3_hwdev *hw= dev) return 0; } =20 +static int hinic3_comm_pf_to_mgmt_init(struct hinic3_hwdev *hwdev) +{ + int err; + + if (HINIC3_IS_VF(hwdev)) + return 0; + + err =3D hinic3_pf_to_mgmt_init(hwdev); + if (err) + return err; + + set_bit(HINIC3_HWDEV_MGMT_INITED, &hwdev->func_state); + + return 0; +} + +static void hinic3_comm_pf_to_mgmt_free(struct hinic3_hwdev *hwdev) +{ + if (HINIC3_IS_VF(hwdev)) + return; + + spin_lock_bh(&hwdev->channel_lock); + clear_bit(HINIC3_HWDEV_MGMT_INITED, &hwdev->func_state); + spin_unlock_bh(&hwdev->channel_lock); + + hinic3_aeq_unregister_cb(hwdev, HINIC3_MSG_FROM_FW); + + hinic3_pf_to_mgmt_free(hwdev); +} + static int init_basic_mgmt_channel(struct hinic3_hwdev *hwdev) { int err; @@ -412,10 +442,14 @@ static int hinic3_init_comm_ch(struct hinic3_hwdev *h= wdev) if (err) return err; =20 - err =3D init_basic_attributes(hwdev); + err =3D hinic3_comm_pf_to_mgmt_init(hwdev); if (err) goto err_free_basic_mgmt_ch; =20 + err =3D init_basic_attributes(hwdev); + if (err) + goto err_free_comm_pf_to_mgmt; + err =3D init_cmdqs_channel(hwdev); if (err) { dev_err(hwdev->dev, "Failed to init cmdq channel\n"); @@ -428,6 +462,8 @@ static int hinic3_init_comm_ch(struct hinic3_hwdev *hwd= ev) =20 err_clear_func_svc_used_state: hinic3_set_func_svc_used_state(hwdev, COMM_FUNC_SVC_T_COMM, 0); +err_free_comm_pf_to_mgmt: + hinic3_comm_pf_to_mgmt_free(hwdev); err_free_basic_mgmt_ch: free_base_mgmt_channel(hwdev); =20 @@ -439,6 +475,7 @@ static void hinic3_uninit_comm_ch(struct hinic3_hwdev *= hwdev) hinic3_set_pf_status(hwdev->hwif, HINIC3_PF_STATUS_INIT); hinic3_free_cmdqs_channel(hwdev); hinic3_set_func_svc_used_state(hwdev, COMM_FUNC_SVC_T_COMM, 0); + hinic3_comm_pf_to_mgmt_free(hwdev); free_base_mgmt_channel(hwdev); } =20 @@ -581,9 +618,21 @@ void hinic3_free_hwdev(struct hinic3_hwdev *hwdev) =20 void hinic3_set_api_stop(struct hinic3_hwdev *hwdev) { + struct hinic3_recv_msg *recv_resp_msg; struct hinic3_mbox *mbox; =20 spin_lock_bh(&hwdev->channel_lock); + if (HINIC3_IS_PF(hwdev) && + test_bit(HINIC3_HWDEV_MGMT_INITED, &hwdev->func_state)) { + recv_resp_msg =3D &hwdev->pf_to_mgmt->recv_resp_msg_from_mgmt; + spin_lock_bh(&hwdev->pf_to_mgmt->sync_event_lock); + if (hwdev->pf_to_mgmt->event_flag =3D=3D COMM_SEND_EVENT_START) { + complete(&recv_resp_msg->recv_done); + hwdev->pf_to_mgmt->event_flag =3D COMM_SEND_EVENT_TIMEOUT; + } + spin_unlock_bh(&hwdev->pf_to_mgmt->sync_event_lock); + } + if (test_bit(HINIC3_HWDEV_MBOX_INITED, &hwdev->func_state)) { mbox =3D hwdev->mbox; spin_lock(&mbox->mbox_lock); diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_hwdev.h b/drivers/ne= t/ethernet/huawei/hinic3/hinic3_hwdev.h index 78cface6ddd7..3c15f22973fe 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_hwdev.h +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_hwdev.h @@ -51,6 +51,7 @@ struct hinic3_hwdev { struct hinic3_cmdqs *cmdqs; struct delayed_work sync_time_task; struct workqueue_struct *workq; + struct hinic3_msg_pf_to_mgmt *pf_to_mgmt; /* protect channel init and uninit */ spinlock_t channel_lock; u64 features[COMM_MAX_FEATURE_QWORD]; diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_main.c b/drivers/net= /ethernet/huawei/hinic3/hinic3_main.c index 9249dd588feb..ce10ae7c0d9e 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_main.c +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_main.c @@ -133,6 +133,8 @@ static int hinic3_sw_init(struct net_device *netdev) u8 mac_addr[ETH_ALEN]; int err; =20 + mutex_init(&nic_dev->port_state_mutex); + nic_dev->q_params.sq_depth =3D HINIC3_SQ_DEPTH; nic_dev->q_params.rq_depth =3D HINIC3_RQ_DEPTH; =20 diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_mbox.c b/drivers/net= /ethernet/huawei/hinic3/hinic3_mbox.c index 1cb0d88911a2..90e704107e7e 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_mbox.c +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_mbox.c @@ -858,6 +858,19 @@ int hinic3_send_mbox_to_mgmt(struct hinic3_hwdev *hwde= v, u8 mod, u16 cmd, return err; } =20 +void hinic3_response_mbox_to_mgmt(struct hinic3_hwdev *hwdev, u8 mod, u16 = cmd, + const void *buf_in, u32 in_size, u16 msg_id) +{ + struct mbox_msg_info msg_info; + + msg_info.msg_id =3D (u8)msg_id; + msg_info.status =3D 0; + + send_mbox_msg(hwdev->mbox, mod, cmd, buf_in, in_size, + MBOX_MGMT_FUNC_ID, MBOX_MSG_RESP, + MBOX_MSG_NO_ACK, &msg_info); +} + int hinic3_send_mbox_to_mgmt_no_ack(struct hinic3_hwdev *hwdev, u8 mod, u1= 6 cmd, const struct mgmt_msg_params *msg_params) { diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_mbox.h b/drivers/net= /ethernet/huawei/hinic3/hinic3_mbox.h index e71629e95086..e26f22d1d564 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_mbox.h +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_mbox.h @@ -135,6 +135,8 @@ void hinic3_free_mbox(struct hinic3_hwdev *hwdev); =20 int hinic3_send_mbox_to_mgmt(struct hinic3_hwdev *hwdev, u8 mod, u16 cmd, const struct mgmt_msg_params *msg_params); +void hinic3_response_mbox_to_mgmt(struct hinic3_hwdev *hwdev, u8 mod, u16 = cmd, + const void *buf_in, u32 in_size, u16 msg_id); int hinic3_send_mbox_to_mgmt_no_ack(struct hinic3_hwdev *hwdev, u8 mod, u1= 6 cmd, const struct mgmt_msg_params *msg_params); =20 diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt.c b/drivers/net= /ethernet/huawei/hinic3/hinic3_mgmt.c index c38d10cd7fac..e1d2a4444663 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt.c +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt.c @@ -3,19 +3,328 @@ =20 #include "hinic3_eqs.h" #include "hinic3_hwdev.h" +#include "hinic3_hwif.h" #include "hinic3_mbox.h" #include "hinic3_mgmt.h" =20 +#define HINIC3_MSG_TO_MGMT_MAX_LEN 2016 + +#define MGMT_MAX_PF_BUF_SIZE 2048UL +#define MGMT_SEG_LEN_MAX 48 +#define MGMT_ASYNC_MSG_FLAG 0x8 + +#define HINIC3_MGMT_WQ_NAME "hinic3_mgmt" + +/* Bogus sequence ID to prevent accidental match following partial message= */ +#define MGMT_BOGUS_SEQ_ID \ + (MGMT_MAX_PF_BUF_SIZE / MGMT_SEG_LEN_MAX + 1) + +static void +hinic3_mgmt_resp_msg_handler(struct hinic3_msg_pf_to_mgmt *pf_to_mgmt, + struct hinic3_recv_msg *recv_msg) +{ + struct device *dev =3D pf_to_mgmt->hwdev->dev; + + /* Ignore async msg */ + if (recv_msg->msg_id & MGMT_ASYNC_MSG_FLAG) + return; + + spin_lock(&pf_to_mgmt->sync_event_lock); + if (recv_msg->msg_id !=3D pf_to_mgmt->sync_msg_id) { + dev_err(dev, "msg id mismatch, send msg id: 0x%x, recv msg id: 0x%x, eve= nt state: %d\n", + pf_to_mgmt->sync_msg_id, recv_msg->msg_id, + pf_to_mgmt->event_flag); + } else if (pf_to_mgmt->event_flag =3D=3D COMM_SEND_EVENT_START) { + pf_to_mgmt->event_flag =3D COMM_SEND_EVENT_SUCCESS; + complete(&recv_msg->recv_done); + } else { + dev_err(dev, "Wait timeout, send msg id: 0x%x, recv msg id: 0x%x, event = state: %d\n", + pf_to_mgmt->sync_msg_id, recv_msg->msg_id, + pf_to_mgmt->event_flag); + } + spin_unlock(&pf_to_mgmt->sync_event_lock); +} + +static void hinic3_recv_mgmt_msg_work_handler(struct work_struct *work) +{ + struct hinic3_msg_pf_to_mgmt *pf_to_mgmt; + struct mgmt_msg_handle_work *mgmt_work; + struct mgmt_msg_head *ack_cmd; + + mgmt_work =3D container_of(work, struct mgmt_msg_handle_work, work); + + /* At the moment, we do not expect any meaningful messages but if the + * sender expects an ACK we still need to provide one with "unsupported" + * status. + */ + if (mgmt_work->async_mgmt_to_pf) + goto out; + + pf_to_mgmt =3D mgmt_work->pf_to_mgmt; + ack_cmd =3D pf_to_mgmt->mgmt_ack_buf; + memset(ack_cmd, 0, sizeof(*ack_cmd)); + ack_cmd->status =3D MGMT_STATUS_CMD_UNSUPPORTED; + + hinic3_response_mbox_to_mgmt(pf_to_mgmt->hwdev, mgmt_work->mod, + mgmt_work->cmd, ack_cmd, sizeof(*ack_cmd), + mgmt_work->msg_id); + +out: + kfree(mgmt_work->msg); + kfree(mgmt_work); +} + +static int hinic3_recv_msg_add_seg(struct hinic3_recv_msg *recv_msg, + __le64 msg_header, const void *seg_data, + bool *is_complete) +{ + u8 seq_id, msg_id, seg_len, is_last; + char *msg_buff; + u32 offset; + + seg_len =3D MBOX_MSG_HEADER_GET(msg_header, SEG_LEN); + is_last =3D MBOX_MSG_HEADER_GET(msg_header, LAST); + seq_id =3D MBOX_MSG_HEADER_GET(msg_header, SEQID); + msg_id =3D MBOX_MSG_HEADER_GET(msg_header, MSG_ID); + + if (seg_len > MGMT_SEG_LEN_MAX) + return -EINVAL; + + /* All segments but last must be of maximal size */ + if (seg_len !=3D MGMT_SEG_LEN_MAX && !is_last) + return -EINVAL; + + if (seq_id =3D=3D 0) { + recv_msg->seq_id =3D seq_id; + recv_msg->msg_id =3D msg_id; + } else if (seq_id !=3D recv_msg->seq_id + 1 || + msg_id !=3D recv_msg->msg_id) { + return -EINVAL; + } + + offset =3D seq_id * MGMT_SEG_LEN_MAX; + if (offset + seg_len > MGMT_MAX_PF_BUF_SIZE) + return -EINVAL; + + msg_buff =3D recv_msg->msg; + memcpy(msg_buff + offset, seg_data, seg_len); + recv_msg->msg_len =3D offset + seg_len; + recv_msg->seq_id =3D seq_id; + *is_complete =3D !!is_last; + + return 0; +} + +static void hinic3_init_mgmt_msg_work(struct hinic3_msg_pf_to_mgmt *pf_to_= mgmt, + struct hinic3_recv_msg *recv_msg) +{ + struct mgmt_msg_handle_work *mgmt_work; + + mgmt_work =3D kmalloc(sizeof(*mgmt_work), GFP_KERNEL); + if (!mgmt_work) + return; + + if (recv_msg->msg_len) { + mgmt_work->msg =3D kmalloc(recv_msg->msg_len, GFP_KERNEL); + if (!mgmt_work->msg) { + kfree(mgmt_work); + return; + } + } + + mgmt_work->pf_to_mgmt =3D pf_to_mgmt; + mgmt_work->msg_len =3D recv_msg->msg_len; + memcpy(mgmt_work->msg, recv_msg->msg, recv_msg->msg_len); + mgmt_work->msg_id =3D recv_msg->msg_id; + mgmt_work->mod =3D recv_msg->mod; + mgmt_work->cmd =3D recv_msg->cmd; + mgmt_work->async_mgmt_to_pf =3D recv_msg->async_mgmt_to_pf; + + INIT_WORK(&mgmt_work->work, hinic3_recv_mgmt_msg_work_handler); + queue_work(pf_to_mgmt->workq, &mgmt_work->work); +} + +static void +hinic3_recv_mgmt_msg_handler(struct hinic3_msg_pf_to_mgmt *pf_to_mgmt, + const u8 *header, + struct hinic3_recv_msg *recv_msg) +{ + struct hinic3_hwdev *hwdev =3D pf_to_mgmt->hwdev; + const void *seg_data; + __le64 msg_header; + bool is_complete; + u8 dir, msg_id; + int err; + + msg_header =3D *(__force __le64 *)header; + dir =3D MBOX_MSG_HEADER_GET(msg_header, DIRECTION); + msg_id =3D MBOX_MSG_HEADER_GET(msg_header, MSG_ID); + /* Don't need to get anything from hw when cmd is async */ + if (dir =3D=3D MBOX_MSG_RESP && (msg_id & MGMT_ASYNC_MSG_FLAG)) + return; + + seg_data =3D header + sizeof(msg_header); + err =3D hinic3_recv_msg_add_seg(recv_msg, msg_header, + seg_data, &is_complete); + if (err) { + dev_err(hwdev->dev, "invalid receive segment\n"); + /* set seq_id to invalid seq_id */ + recv_msg->seq_id =3D MGMT_BOGUS_SEQ_ID; + + return; + } + + if (!is_complete) + return; + + recv_msg->cmd =3D MBOX_MSG_HEADER_GET(msg_header, CMD); + recv_msg->mod =3D MBOX_MSG_HEADER_GET(msg_header, MODULE); + recv_msg->async_mgmt_to_pf =3D MBOX_MSG_HEADER_GET(msg_header, NO_ACK); + recv_msg->seq_id =3D MGMT_BOGUS_SEQ_ID; + + if (dir =3D=3D MBOX_MSG_RESP) + hinic3_mgmt_resp_msg_handler(pf_to_mgmt, recv_msg); + else + hinic3_init_mgmt_msg_work(pf_to_mgmt, recv_msg); +} + +static int alloc_recv_msg(struct hinic3_recv_msg *recv_msg) +{ + recv_msg->seq_id =3D MGMT_BOGUS_SEQ_ID; + + recv_msg->msg =3D kzalloc(MGMT_MAX_PF_BUF_SIZE, GFP_KERNEL); + if (!recv_msg->msg) + return -ENOMEM; + + return 0; +} + +static void free_recv_msg(struct hinic3_recv_msg *recv_msg) +{ + kfree(recv_msg->msg); +} + +static int alloc_msg_buf(struct hinic3_msg_pf_to_mgmt *pf_to_mgmt) +{ + struct device *dev =3D pf_to_mgmt->hwdev->dev; + int err; + + err =3D alloc_recv_msg(&pf_to_mgmt->recv_msg_from_mgmt); + if (err) { + dev_err(dev, "Failed to allocate recv msg\n"); + return err; + } + + err =3D alloc_recv_msg(&pf_to_mgmt->recv_resp_msg_from_mgmt); + if (err) { + dev_err(dev, "Failed to allocate resp recv msg\n"); + goto err_free_msg_from_mgmt; + } + + pf_to_mgmt->mgmt_ack_buf =3D kzalloc(MGMT_MAX_PF_BUF_SIZE, GFP_KERNEL); + if (!pf_to_mgmt->mgmt_ack_buf) { + err =3D -ENOMEM; + goto err_free_resp_msg_from_mgmt; + } + + return 0; + +err_free_resp_msg_from_mgmt: + free_recv_msg(&pf_to_mgmt->recv_resp_msg_from_mgmt); +err_free_msg_from_mgmt: + free_recv_msg(&pf_to_mgmt->recv_msg_from_mgmt); + + return err; +} + +static void free_msg_buf(struct hinic3_msg_pf_to_mgmt *pf_to_mgmt) +{ + kfree(pf_to_mgmt->mgmt_ack_buf); + + free_recv_msg(&pf_to_mgmt->recv_resp_msg_from_mgmt); + free_recv_msg(&pf_to_mgmt->recv_msg_from_mgmt); +} + +int hinic3_pf_to_mgmt_init(struct hinic3_hwdev *hwdev) +{ + struct hinic3_msg_pf_to_mgmt *pf_to_mgmt; + int err; + + pf_to_mgmt =3D kzalloc(sizeof(*pf_to_mgmt), GFP_KERNEL); + if (!pf_to_mgmt) + return -ENOMEM; + + hwdev->pf_to_mgmt =3D pf_to_mgmt; + pf_to_mgmt->hwdev =3D hwdev; + spin_lock_init(&pf_to_mgmt->sync_event_lock); + pf_to_mgmt->workq =3D create_singlethread_workqueue(HINIC3_MGMT_WQ_NAME); + if (!pf_to_mgmt->workq) { + dev_err(hwdev->dev, "Failed to initialize MGMT workqueue\n"); + err =3D -ENOMEM; + goto err_free_pf_to_mgmt; + } + + err =3D alloc_msg_buf(pf_to_mgmt); + if (err) { + dev_err(hwdev->dev, "Failed to allocate msg buffers\n"); + goto err_destroy_workqueue; + } + + return 0; + +err_destroy_workqueue: + destroy_workqueue(pf_to_mgmt->workq); +err_free_pf_to_mgmt: + kfree(pf_to_mgmt); + + return err; +} + +void hinic3_pf_to_mgmt_free(struct hinic3_hwdev *hwdev) +{ + struct hinic3_msg_pf_to_mgmt *pf_to_mgmt =3D hwdev->pf_to_mgmt; + + /* destroy workqueue before free related pf_to_mgmt resources in case of + * illegal resource access + */ + destroy_workqueue(pf_to_mgmt->workq); + + free_msg_buf(pf_to_mgmt); + kfree(pf_to_mgmt); +} + void hinic3_flush_mgmt_workq(struct hinic3_hwdev *hwdev) { if (hwdev->aeqs) flush_workqueue(hwdev->aeqs->workq); + + if (HINIC3_IS_PF(hwdev) && hwdev->pf_to_mgmt) + flush_workqueue(hwdev->pf_to_mgmt->workq); } =20 void hinic3_mgmt_msg_aeqe_handler(struct hinic3_hwdev *hwdev, u8 *header, u8 size) { + struct hinic3_msg_pf_to_mgmt *pf_to_mgmt; + struct hinic3_recv_msg *recv_msg; + __le64 msg_header; + bool is_send_dir; + if (MBOX_MSG_HEADER_GET(*(__force __le64 *)header, SOURCE) =3D=3D - MBOX_MSG_FROM_MBOX) + MBOX_MSG_FROM_MBOX) { hinic3_mbox_func_aeqe_handler(hwdev, header, size); + + return; + } + + pf_to_mgmt =3D hwdev->pf_to_mgmt; + msg_header =3D *(__force __le64 *)header; + + is_send_dir =3D (MBOX_MSG_HEADER_GET(msg_header, DIRECTION) =3D=3D + MBOX_MSG_SEND) ? true : false; + + recv_msg =3D is_send_dir ? &pf_to_mgmt->recv_msg_from_mgmt : + &pf_to_mgmt->recv_resp_msg_from_mgmt; + + hinic3_recv_mgmt_msg_handler(pf_to_mgmt, header, recv_msg); } diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt.h b/drivers/net= /ethernet/huawei/hinic3/hinic3_mgmt.h index bbef3b32a6ec..56f48d5442bc 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt.h +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt.h @@ -6,8 +6,61 @@ =20 #include =20 +#include "hinic3_mbox.h" +#include "hinic3_hw_intf.h" + struct hinic3_hwdev; =20 +struct hinic3_recv_msg { + /* Preallocated buffer of size MAX_PF_MGMT_BUF_SIZE that accumulates + * receive message, segment-by-segment. + */ + void *msg; + /* Message id for which segments are accumulated. */ + u8 msg_id; + /* Sequence id of last received segment of current message. */ + u8 seq_id; + u16 msg_len; + int async_mgmt_to_pf; + enum mgmt_mod_type mod; + u16 cmd; + struct completion recv_done; +}; + +enum comm_pf_to_mgmt_event_state { + COMM_SEND_EVENT_UNINIT, + COMM_SEND_EVENT_START, + COMM_SEND_EVENT_SUCCESS, + COMM_SEND_EVENT_TIMEOUT, +}; + +struct hinic3_msg_pf_to_mgmt { + struct hinic3_hwdev *hwdev; + struct workqueue_struct *workq; + void *mgmt_ack_buf; + struct hinic3_recv_msg recv_msg_from_mgmt; + struct hinic3_recv_msg recv_resp_msg_from_mgmt; + u16 async_msg_id; + u16 sync_msg_id; + void *async_msg_cb_data[MGMT_MOD_HW_MAX]; + /* synchronizes message send with message receives via event queue */ + spinlock_t sync_event_lock; + enum comm_pf_to_mgmt_event_state event_flag; +}; + +struct mgmt_msg_handle_work { + struct work_struct work; + struct hinic3_msg_pf_to_mgmt *pf_to_mgmt; + void *msg; + u16 msg_len; + enum mgmt_mod_type mod; + u16 cmd; + u16 msg_id; + int async_mgmt_to_pf; +}; + +int hinic3_pf_to_mgmt_init(struct hinic3_hwdev *hwdev); +void hinic3_pf_to_mgmt_free(struct hinic3_hwdev *hwdev); void hinic3_flush_mgmt_workq(struct hinic3_hwdev *hwdev); void hinic3_mgmt_msg_aeqe_handler(struct hinic3_hwdev *hwdev, u8 *header, u8 size); diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt_interface.h b/d= rivers/net/ethernet/huawei/hinic3/hinic3_mgmt_interface.h index f9a3222b1b46..3a6d3ee534d0 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt_interface.h +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_mgmt_interface.h @@ -190,6 +190,7 @@ enum l2nic_ucode_cmd { =20 /* hilink mac group command */ enum mag_cmd { + MAG_CMD_SET_PORT_ENABLE =3D 6, MAG_CMD_GET_LINK_STATUS =3D 7, }; =20 diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c b/drive= rs/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c index 0fa3c7900225..3d371291ad04 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_netdev_ops.c @@ -327,6 +327,31 @@ static void hinic3_close_channel(struct net_device *ne= tdev) hinic3_free_qp_ctxts(nic_dev); } =20 +static int hinic3_maybe_set_port_state(struct net_device *netdev, bool ena= ble) +{ + struct hinic3_nic_dev *nic_dev =3D netdev_priv(netdev); + int err; + + mutex_lock(&nic_dev->port_state_mutex); + err =3D hinic3_set_port_enable(nic_dev->hwdev, enable); + mutex_unlock(&nic_dev->port_state_mutex); + + return err; +} + +static void hinic3_print_link_message(struct net_device *netdev, + bool link_status_up) +{ + struct hinic3_nic_dev *nic_dev =3D netdev_priv(netdev); + + if (nic_dev->link_status_up =3D=3D link_status_up) + return; + + nic_dev->link_status_up =3D link_status_up; + + netdev_dbg(netdev, "Link is %s\n", str_up_down(link_status_up)); +} + static int hinic3_vport_up(struct net_device *netdev) { struct hinic3_nic_dev *nic_dev =3D netdev_priv(netdev); @@ -341,6 +366,12 @@ static int hinic3_vport_up(struct net_device *netdev) goto err_flush_qps_res; } =20 + err =3D hinic3_maybe_set_port_state(netdev, true); + if (err) { + netdev_err(netdev, "Failed to enable port\n"); + goto err_disable_vport; + } + err =3D netif_set_real_num_queues(netdev, nic_dev->q_params.num_qps, nic_dev->q_params.num_qps); if (err) { @@ -353,8 +384,12 @@ static int hinic3_vport_up(struct net_device *netdev) if (!err && link_status_up) netif_carrier_on(netdev); =20 + hinic3_print_link_message(netdev, link_status_up); + return 0; =20 +err_disable_vport: + hinic3_set_vport_enable(nic_dev->hwdev, glb_func_id, false); err_flush_qps_res: hinic3_flush_qps_res(nic_dev->hwdev); /* wait to guarantee that no packets will be sent to host */ diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.c b/drivers/= net/ethernet/huawei/hinic3/hinic3_nic_cfg.c index e784f1b04a41..7fec13bbe60e 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.c +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.c @@ -366,6 +366,34 @@ int hinic3_force_drop_tx_pkt(struct hinic3_hwdev *hwde= v) return pkt_drop.msg_head.status; } =20 +int hinic3_set_port_enable(struct hinic3_hwdev *hwdev, bool enable) +{ + struct mag_cmd_set_port_enable en_state =3D {}; + struct mgmt_msg_params msg_params =3D {}; + int err; + + if (HINIC3_IS_VF(hwdev)) + return 0; + + en_state.function_id =3D hinic3_global_func_id(hwdev); + en_state.state =3D enable ? MAG_CMD_TX_ENABLE | MAG_CMD_RX_ENABLE : + MAG_CMD_PORT_DISABLE; + + mgmt_msg_params_init_default(&msg_params, &en_state, + sizeof(en_state)); + + err =3D hinic3_send_mbox_to_mgmt(hwdev, MGMT_MOD_HILINK, + MAG_CMD_SET_PORT_ENABLE, &msg_params); + + if (err || en_state.head.status) { + dev_err(hwdev->dev, "Failed to set port state, err: %d, status: 0x%x\n", + err, en_state.head.status); + return -EFAULT; + } + + return 0; +} + int hinic3_sync_dcb_state(struct hinic3_hwdev *hwdev, u8 op_code, u8 state) { struct l2nic_cmd_set_dcb_state dcb_state =3D {}; diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.h b/drivers/= net/ethernet/huawei/hinic3/hinic3_nic_cfg.h index 08bf14679bf8..d4326937db48 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.h +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_nic_cfg.h @@ -34,6 +34,23 @@ struct hinic3_sq_attr { u64 ci_dma_base; }; =20 +#define MAG_CMD_PORT_DISABLE 0x0 +#define MAG_CMD_TX_ENABLE 0x1 +#define MAG_CMD_RX_ENABLE 0x2 +/* the physical port is disabled only when all pf of the port are set to d= own, + * if any pf is enabled, the port is enabled + */ +struct mag_cmd_set_port_enable { + struct mgmt_msg_head head; + + u16 function_id; + u16 rsvd0; + + /* bitmap bit0:tx_en bit1:rx_en */ + u8 state; + u8 rsvd1[3]; +}; + int hinic3_get_nic_feature_from_hw(struct hinic3_nic_dev *nic_dev); int hinic3_set_nic_feature_to_hw(struct hinic3_nic_dev *nic_dev); bool hinic3_test_support(struct hinic3_nic_dev *nic_dev, @@ -57,6 +74,7 @@ int hinic3_flush_qps_res(struct hinic3_hwdev *hwdev); int hinic3_force_drop_tx_pkt(struct hinic3_hwdev *hwdev); =20 int hinic3_sync_dcb_state(struct hinic3_hwdev *hwdev, u8 op_code, u8 state= ); +int hinic3_set_port_enable(struct hinic3_hwdev *hwdev, bool enable); int hinic3_get_link_status(struct hinic3_hwdev *hwdev, bool *link_status_u= p); int hinic3_set_vport_enable(struct hinic3_hwdev *hwdev, u16 func_id, bool enable); diff --git a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_dev.h b/drivers/= net/ethernet/huawei/hinic3/hinic3_nic_dev.h index 5ba83261616c..52bcf6fb14f2 100644 --- a/drivers/net/ethernet/huawei/hinic3/hinic3_nic_dev.h +++ b/drivers/net/ethernet/huawei/hinic3/hinic3_nic_dev.h @@ -83,6 +83,9 @@ struct hinic3_nic_dev { =20 struct hinic3_intr_coal_info *intr_coalesce; =20 + /* lock for enable/disable port */ + struct mutex port_state_mutex; + bool link_status_up; }; =20 --=20 2.43.0