18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright Gavin Shan, IBM Corporation 2016. 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/module.h> 78c2ecf20Sopenharmony_ci#include <linux/kernel.h> 88c2ecf20Sopenharmony_ci#include <linux/init.h> 98c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 108c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 118c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <net/ncsi.h> 148c2ecf20Sopenharmony_ci#include <net/net_namespace.h> 158c2ecf20Sopenharmony_ci#include <net/sock.h> 168c2ecf20Sopenharmony_ci#include <net/genetlink.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include "internal.h" 198c2ecf20Sopenharmony_ci#include "ncsi-pkt.h" 208c2ecf20Sopenharmony_ci#include "ncsi-netlink.h" 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci/* Nibbles within [0xA, 0xF] add zero "0" to the returned value. 238c2ecf20Sopenharmony_ci * Optional fields (encoded as 0xFF) will default to zero. 248c2ecf20Sopenharmony_ci */ 258c2ecf20Sopenharmony_cistatic u8 decode_bcd_u8(u8 x) 268c2ecf20Sopenharmony_ci{ 278c2ecf20Sopenharmony_ci int lo = x & 0xF; 288c2ecf20Sopenharmony_ci int hi = x >> 4; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci lo = lo < 0xA ? lo : 0; 318c2ecf20Sopenharmony_ci hi = hi < 0xA ? hi : 0; 328c2ecf20Sopenharmony_ci return lo + hi * 10; 338c2ecf20Sopenharmony_ci} 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistatic int ncsi_validate_rsp_pkt(struct ncsi_request *nr, 368c2ecf20Sopenharmony_ci unsigned short payload) 378c2ecf20Sopenharmony_ci{ 388c2ecf20Sopenharmony_ci struct ncsi_rsp_pkt_hdr *h; 398c2ecf20Sopenharmony_ci u32 checksum; 408c2ecf20Sopenharmony_ci __be32 *pchecksum; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci /* Check NCSI packet header. We don't need validate 438c2ecf20Sopenharmony_ci * the packet type, which should have been checked 448c2ecf20Sopenharmony_ci * before calling this function. 458c2ecf20Sopenharmony_ci */ 468c2ecf20Sopenharmony_ci h = (struct ncsi_rsp_pkt_hdr *)skb_network_header(nr->rsp); 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci if (h->common.revision != NCSI_PKT_REVISION) { 498c2ecf20Sopenharmony_ci netdev_dbg(nr->ndp->ndev.dev, 508c2ecf20Sopenharmony_ci "NCSI: unsupported header revision\n"); 518c2ecf20Sopenharmony_ci return -EINVAL; 528c2ecf20Sopenharmony_ci } 538c2ecf20Sopenharmony_ci if (ntohs(h->common.length) != payload) { 548c2ecf20Sopenharmony_ci netdev_dbg(nr->ndp->ndev.dev, 558c2ecf20Sopenharmony_ci "NCSI: payload length mismatched\n"); 568c2ecf20Sopenharmony_ci return -EINVAL; 578c2ecf20Sopenharmony_ci } 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci /* Check on code and reason */ 608c2ecf20Sopenharmony_ci if (ntohs(h->code) != NCSI_PKT_RSP_C_COMPLETED || 618c2ecf20Sopenharmony_ci ntohs(h->reason) != NCSI_PKT_RSP_R_NO_ERROR) { 628c2ecf20Sopenharmony_ci netdev_dbg(nr->ndp->ndev.dev, 638c2ecf20Sopenharmony_ci "NCSI: non zero response/reason code %04xh, %04xh\n", 648c2ecf20Sopenharmony_ci ntohs(h->code), ntohs(h->reason)); 658c2ecf20Sopenharmony_ci return -EPERM; 668c2ecf20Sopenharmony_ci } 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci /* Validate checksum, which might be zeroes if the 698c2ecf20Sopenharmony_ci * sender doesn't support checksum according to NCSI 708c2ecf20Sopenharmony_ci * specification. 718c2ecf20Sopenharmony_ci */ 728c2ecf20Sopenharmony_ci pchecksum = (__be32 *)((void *)(h + 1) + ALIGN(payload, 4) - 4); 738c2ecf20Sopenharmony_ci if (ntohl(*pchecksum) == 0) 748c2ecf20Sopenharmony_ci return 0; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci checksum = ncsi_calculate_checksum((unsigned char *)h, 778c2ecf20Sopenharmony_ci sizeof(*h) + payload - 4); 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci if (*pchecksum != htonl(checksum)) { 808c2ecf20Sopenharmony_ci netdev_dbg(nr->ndp->ndev.dev, 818c2ecf20Sopenharmony_ci "NCSI: checksum mismatched; recd: %08x calc: %08x\n", 828c2ecf20Sopenharmony_ci *pchecksum, htonl(checksum)); 838c2ecf20Sopenharmony_ci return -EINVAL; 848c2ecf20Sopenharmony_ci } 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci return 0; 878c2ecf20Sopenharmony_ci} 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_cistatic int ncsi_rsp_handler_cis(struct ncsi_request *nr) 908c2ecf20Sopenharmony_ci{ 918c2ecf20Sopenharmony_ci struct ncsi_rsp_pkt *rsp; 928c2ecf20Sopenharmony_ci struct ncsi_dev_priv *ndp = nr->ndp; 938c2ecf20Sopenharmony_ci struct ncsi_package *np; 948c2ecf20Sopenharmony_ci struct ncsi_channel *nc; 958c2ecf20Sopenharmony_ci unsigned char id; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp); 988c2ecf20Sopenharmony_ci ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, &np, &nc); 998c2ecf20Sopenharmony_ci if (!nc) { 1008c2ecf20Sopenharmony_ci if (ndp->flags & NCSI_DEV_PROBED) 1018c2ecf20Sopenharmony_ci return -ENXIO; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci id = NCSI_CHANNEL_INDEX(rsp->rsp.common.channel); 1048c2ecf20Sopenharmony_ci nc = ncsi_add_channel(np, id); 1058c2ecf20Sopenharmony_ci } 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci return nc ? 0 : -ENODEV; 1088c2ecf20Sopenharmony_ci} 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_cistatic int ncsi_rsp_handler_sp(struct ncsi_request *nr) 1118c2ecf20Sopenharmony_ci{ 1128c2ecf20Sopenharmony_ci struct ncsi_rsp_pkt *rsp; 1138c2ecf20Sopenharmony_ci struct ncsi_dev_priv *ndp = nr->ndp; 1148c2ecf20Sopenharmony_ci struct ncsi_package *np; 1158c2ecf20Sopenharmony_ci unsigned char id; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci /* Add the package if it's not existing. Otherwise, 1188c2ecf20Sopenharmony_ci * to change the state of its child channels. 1198c2ecf20Sopenharmony_ci */ 1208c2ecf20Sopenharmony_ci rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp); 1218c2ecf20Sopenharmony_ci ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, 1228c2ecf20Sopenharmony_ci &np, NULL); 1238c2ecf20Sopenharmony_ci if (!np) { 1248c2ecf20Sopenharmony_ci if (ndp->flags & NCSI_DEV_PROBED) 1258c2ecf20Sopenharmony_ci return -ENXIO; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci id = NCSI_PACKAGE_INDEX(rsp->rsp.common.channel); 1288c2ecf20Sopenharmony_ci np = ncsi_add_package(ndp, id); 1298c2ecf20Sopenharmony_ci if (!np) 1308c2ecf20Sopenharmony_ci return -ENODEV; 1318c2ecf20Sopenharmony_ci } 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci return 0; 1348c2ecf20Sopenharmony_ci} 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_cistatic int ncsi_rsp_handler_dp(struct ncsi_request *nr) 1378c2ecf20Sopenharmony_ci{ 1388c2ecf20Sopenharmony_ci struct ncsi_rsp_pkt *rsp; 1398c2ecf20Sopenharmony_ci struct ncsi_dev_priv *ndp = nr->ndp; 1408c2ecf20Sopenharmony_ci struct ncsi_package *np; 1418c2ecf20Sopenharmony_ci struct ncsi_channel *nc; 1428c2ecf20Sopenharmony_ci unsigned long flags; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci /* Find the package */ 1458c2ecf20Sopenharmony_ci rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp); 1468c2ecf20Sopenharmony_ci ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, 1478c2ecf20Sopenharmony_ci &np, NULL); 1488c2ecf20Sopenharmony_ci if (!np) 1498c2ecf20Sopenharmony_ci return -ENODEV; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci /* Change state of all channels attached to the package */ 1528c2ecf20Sopenharmony_ci NCSI_FOR_EACH_CHANNEL(np, nc) { 1538c2ecf20Sopenharmony_ci spin_lock_irqsave(&nc->lock, flags); 1548c2ecf20Sopenharmony_ci nc->state = NCSI_CHANNEL_INACTIVE; 1558c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&nc->lock, flags); 1568c2ecf20Sopenharmony_ci } 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci return 0; 1598c2ecf20Sopenharmony_ci} 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_cistatic int ncsi_rsp_handler_ec(struct ncsi_request *nr) 1628c2ecf20Sopenharmony_ci{ 1638c2ecf20Sopenharmony_ci struct ncsi_rsp_pkt *rsp; 1648c2ecf20Sopenharmony_ci struct ncsi_dev_priv *ndp = nr->ndp; 1658c2ecf20Sopenharmony_ci struct ncsi_channel *nc; 1668c2ecf20Sopenharmony_ci struct ncsi_channel_mode *ncm; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci /* Find the package and channel */ 1698c2ecf20Sopenharmony_ci rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp); 1708c2ecf20Sopenharmony_ci ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, 1718c2ecf20Sopenharmony_ci NULL, &nc); 1728c2ecf20Sopenharmony_ci if (!nc) 1738c2ecf20Sopenharmony_ci return -ENODEV; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci ncm = &nc->modes[NCSI_MODE_ENABLE]; 1768c2ecf20Sopenharmony_ci if (ncm->enable) 1778c2ecf20Sopenharmony_ci return 0; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci ncm->enable = 1; 1808c2ecf20Sopenharmony_ci return 0; 1818c2ecf20Sopenharmony_ci} 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_cistatic int ncsi_rsp_handler_dc(struct ncsi_request *nr) 1848c2ecf20Sopenharmony_ci{ 1858c2ecf20Sopenharmony_ci struct ncsi_rsp_pkt *rsp; 1868c2ecf20Sopenharmony_ci struct ncsi_dev_priv *ndp = nr->ndp; 1878c2ecf20Sopenharmony_ci struct ncsi_channel *nc; 1888c2ecf20Sopenharmony_ci struct ncsi_channel_mode *ncm; 1898c2ecf20Sopenharmony_ci int ret; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci ret = ncsi_validate_rsp_pkt(nr, 4); 1928c2ecf20Sopenharmony_ci if (ret) 1938c2ecf20Sopenharmony_ci return ret; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci /* Find the package and channel */ 1968c2ecf20Sopenharmony_ci rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp); 1978c2ecf20Sopenharmony_ci ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, 1988c2ecf20Sopenharmony_ci NULL, &nc); 1998c2ecf20Sopenharmony_ci if (!nc) 2008c2ecf20Sopenharmony_ci return -ENODEV; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci ncm = &nc->modes[NCSI_MODE_ENABLE]; 2038c2ecf20Sopenharmony_ci if (!ncm->enable) 2048c2ecf20Sopenharmony_ci return 0; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci ncm->enable = 0; 2078c2ecf20Sopenharmony_ci return 0; 2088c2ecf20Sopenharmony_ci} 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_cistatic int ncsi_rsp_handler_rc(struct ncsi_request *nr) 2118c2ecf20Sopenharmony_ci{ 2128c2ecf20Sopenharmony_ci struct ncsi_rsp_pkt *rsp; 2138c2ecf20Sopenharmony_ci struct ncsi_dev_priv *ndp = nr->ndp; 2148c2ecf20Sopenharmony_ci struct ncsi_channel *nc; 2158c2ecf20Sopenharmony_ci unsigned long flags; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci /* Find the package and channel */ 2188c2ecf20Sopenharmony_ci rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp); 2198c2ecf20Sopenharmony_ci ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, 2208c2ecf20Sopenharmony_ci NULL, &nc); 2218c2ecf20Sopenharmony_ci if (!nc) 2228c2ecf20Sopenharmony_ci return -ENODEV; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci /* Update state for the specified channel */ 2258c2ecf20Sopenharmony_ci spin_lock_irqsave(&nc->lock, flags); 2268c2ecf20Sopenharmony_ci nc->state = NCSI_CHANNEL_INACTIVE; 2278c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&nc->lock, flags); 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci return 0; 2308c2ecf20Sopenharmony_ci} 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_cistatic int ncsi_rsp_handler_ecnt(struct ncsi_request *nr) 2338c2ecf20Sopenharmony_ci{ 2348c2ecf20Sopenharmony_ci struct ncsi_rsp_pkt *rsp; 2358c2ecf20Sopenharmony_ci struct ncsi_dev_priv *ndp = nr->ndp; 2368c2ecf20Sopenharmony_ci struct ncsi_channel *nc; 2378c2ecf20Sopenharmony_ci struct ncsi_channel_mode *ncm; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci /* Find the package and channel */ 2408c2ecf20Sopenharmony_ci rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp); 2418c2ecf20Sopenharmony_ci ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, 2428c2ecf20Sopenharmony_ci NULL, &nc); 2438c2ecf20Sopenharmony_ci if (!nc) 2448c2ecf20Sopenharmony_ci return -ENODEV; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci ncm = &nc->modes[NCSI_MODE_TX_ENABLE]; 2478c2ecf20Sopenharmony_ci if (ncm->enable) 2488c2ecf20Sopenharmony_ci return 0; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci ncm->enable = 1; 2518c2ecf20Sopenharmony_ci return 0; 2528c2ecf20Sopenharmony_ci} 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_cistatic int ncsi_rsp_handler_dcnt(struct ncsi_request *nr) 2558c2ecf20Sopenharmony_ci{ 2568c2ecf20Sopenharmony_ci struct ncsi_rsp_pkt *rsp; 2578c2ecf20Sopenharmony_ci struct ncsi_dev_priv *ndp = nr->ndp; 2588c2ecf20Sopenharmony_ci struct ncsi_channel *nc; 2598c2ecf20Sopenharmony_ci struct ncsi_channel_mode *ncm; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci /* Find the package and channel */ 2628c2ecf20Sopenharmony_ci rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp); 2638c2ecf20Sopenharmony_ci ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, 2648c2ecf20Sopenharmony_ci NULL, &nc); 2658c2ecf20Sopenharmony_ci if (!nc) 2668c2ecf20Sopenharmony_ci return -ENODEV; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci ncm = &nc->modes[NCSI_MODE_TX_ENABLE]; 2698c2ecf20Sopenharmony_ci if (!ncm->enable) 2708c2ecf20Sopenharmony_ci return 0; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci ncm->enable = 0; 2738c2ecf20Sopenharmony_ci return 0; 2748c2ecf20Sopenharmony_ci} 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_cistatic int ncsi_rsp_handler_ae(struct ncsi_request *nr) 2778c2ecf20Sopenharmony_ci{ 2788c2ecf20Sopenharmony_ci struct ncsi_cmd_ae_pkt *cmd; 2798c2ecf20Sopenharmony_ci struct ncsi_rsp_pkt *rsp; 2808c2ecf20Sopenharmony_ci struct ncsi_dev_priv *ndp = nr->ndp; 2818c2ecf20Sopenharmony_ci struct ncsi_channel *nc; 2828c2ecf20Sopenharmony_ci struct ncsi_channel_mode *ncm; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci /* Find the package and channel */ 2858c2ecf20Sopenharmony_ci rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp); 2868c2ecf20Sopenharmony_ci ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, 2878c2ecf20Sopenharmony_ci NULL, &nc); 2888c2ecf20Sopenharmony_ci if (!nc) 2898c2ecf20Sopenharmony_ci return -ENODEV; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci /* Check if the AEN has been enabled */ 2928c2ecf20Sopenharmony_ci ncm = &nc->modes[NCSI_MODE_AEN]; 2938c2ecf20Sopenharmony_ci if (ncm->enable) 2948c2ecf20Sopenharmony_ci return 0; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci /* Update to AEN configuration */ 2978c2ecf20Sopenharmony_ci cmd = (struct ncsi_cmd_ae_pkt *)skb_network_header(nr->cmd); 2988c2ecf20Sopenharmony_ci ncm->enable = 1; 2998c2ecf20Sopenharmony_ci ncm->data[0] = cmd->mc_id; 3008c2ecf20Sopenharmony_ci ncm->data[1] = ntohl(cmd->mode); 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci return 0; 3038c2ecf20Sopenharmony_ci} 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_cistatic int ncsi_rsp_handler_sl(struct ncsi_request *nr) 3068c2ecf20Sopenharmony_ci{ 3078c2ecf20Sopenharmony_ci struct ncsi_cmd_sl_pkt *cmd; 3088c2ecf20Sopenharmony_ci struct ncsi_rsp_pkt *rsp; 3098c2ecf20Sopenharmony_ci struct ncsi_dev_priv *ndp = nr->ndp; 3108c2ecf20Sopenharmony_ci struct ncsi_channel *nc; 3118c2ecf20Sopenharmony_ci struct ncsi_channel_mode *ncm; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci /* Find the package and channel */ 3148c2ecf20Sopenharmony_ci rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp); 3158c2ecf20Sopenharmony_ci ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, 3168c2ecf20Sopenharmony_ci NULL, &nc); 3178c2ecf20Sopenharmony_ci if (!nc) 3188c2ecf20Sopenharmony_ci return -ENODEV; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci cmd = (struct ncsi_cmd_sl_pkt *)skb_network_header(nr->cmd); 3218c2ecf20Sopenharmony_ci ncm = &nc->modes[NCSI_MODE_LINK]; 3228c2ecf20Sopenharmony_ci ncm->data[0] = ntohl(cmd->mode); 3238c2ecf20Sopenharmony_ci ncm->data[1] = ntohl(cmd->oem_mode); 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci return 0; 3268c2ecf20Sopenharmony_ci} 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_cistatic int ncsi_rsp_handler_gls(struct ncsi_request *nr) 3298c2ecf20Sopenharmony_ci{ 3308c2ecf20Sopenharmony_ci struct ncsi_rsp_gls_pkt *rsp; 3318c2ecf20Sopenharmony_ci struct ncsi_dev_priv *ndp = nr->ndp; 3328c2ecf20Sopenharmony_ci struct ncsi_channel *nc; 3338c2ecf20Sopenharmony_ci struct ncsi_channel_mode *ncm; 3348c2ecf20Sopenharmony_ci unsigned long flags; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci /* Find the package and channel */ 3378c2ecf20Sopenharmony_ci rsp = (struct ncsi_rsp_gls_pkt *)skb_network_header(nr->rsp); 3388c2ecf20Sopenharmony_ci ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, 3398c2ecf20Sopenharmony_ci NULL, &nc); 3408c2ecf20Sopenharmony_ci if (!nc) 3418c2ecf20Sopenharmony_ci return -ENODEV; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci ncm = &nc->modes[NCSI_MODE_LINK]; 3448c2ecf20Sopenharmony_ci ncm->data[2] = ntohl(rsp->status); 3458c2ecf20Sopenharmony_ci ncm->data[3] = ntohl(rsp->other); 3468c2ecf20Sopenharmony_ci ncm->data[4] = ntohl(rsp->oem_status); 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci if (nr->flags & NCSI_REQ_FLAG_EVENT_DRIVEN) 3498c2ecf20Sopenharmony_ci return 0; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci /* Reset the channel monitor if it has been enabled */ 3528c2ecf20Sopenharmony_ci spin_lock_irqsave(&nc->lock, flags); 3538c2ecf20Sopenharmony_ci nc->monitor.state = NCSI_CHANNEL_MONITOR_START; 3548c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&nc->lock, flags); 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci return 0; 3578c2ecf20Sopenharmony_ci} 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_cistatic int ncsi_rsp_handler_svf(struct ncsi_request *nr) 3608c2ecf20Sopenharmony_ci{ 3618c2ecf20Sopenharmony_ci struct ncsi_cmd_svf_pkt *cmd; 3628c2ecf20Sopenharmony_ci struct ncsi_rsp_pkt *rsp; 3638c2ecf20Sopenharmony_ci struct ncsi_dev_priv *ndp = nr->ndp; 3648c2ecf20Sopenharmony_ci struct ncsi_channel *nc; 3658c2ecf20Sopenharmony_ci struct ncsi_channel_vlan_filter *ncf; 3668c2ecf20Sopenharmony_ci unsigned long flags; 3678c2ecf20Sopenharmony_ci void *bitmap; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci /* Find the package and channel */ 3708c2ecf20Sopenharmony_ci rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp); 3718c2ecf20Sopenharmony_ci ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, 3728c2ecf20Sopenharmony_ci NULL, &nc); 3738c2ecf20Sopenharmony_ci if (!nc) 3748c2ecf20Sopenharmony_ci return -ENODEV; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci cmd = (struct ncsi_cmd_svf_pkt *)skb_network_header(nr->cmd); 3778c2ecf20Sopenharmony_ci ncf = &nc->vlan_filter; 3788c2ecf20Sopenharmony_ci if (cmd->index == 0 || cmd->index > ncf->n_vids) 3798c2ecf20Sopenharmony_ci return -ERANGE; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci /* Add or remove the VLAN filter. Remember HW indexes from 1 */ 3828c2ecf20Sopenharmony_ci spin_lock_irqsave(&nc->lock, flags); 3838c2ecf20Sopenharmony_ci bitmap = &ncf->bitmap; 3848c2ecf20Sopenharmony_ci if (!(cmd->enable & 0x1)) { 3858c2ecf20Sopenharmony_ci if (test_and_clear_bit(cmd->index - 1, bitmap)) 3868c2ecf20Sopenharmony_ci ncf->vids[cmd->index - 1] = 0; 3878c2ecf20Sopenharmony_ci } else { 3888c2ecf20Sopenharmony_ci set_bit(cmd->index - 1, bitmap); 3898c2ecf20Sopenharmony_ci ncf->vids[cmd->index - 1] = ntohs(cmd->vlan); 3908c2ecf20Sopenharmony_ci } 3918c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&nc->lock, flags); 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci return 0; 3948c2ecf20Sopenharmony_ci} 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_cistatic int ncsi_rsp_handler_ev(struct ncsi_request *nr) 3978c2ecf20Sopenharmony_ci{ 3988c2ecf20Sopenharmony_ci struct ncsi_cmd_ev_pkt *cmd; 3998c2ecf20Sopenharmony_ci struct ncsi_rsp_pkt *rsp; 4008c2ecf20Sopenharmony_ci struct ncsi_dev_priv *ndp = nr->ndp; 4018c2ecf20Sopenharmony_ci struct ncsi_channel *nc; 4028c2ecf20Sopenharmony_ci struct ncsi_channel_mode *ncm; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci /* Find the package and channel */ 4058c2ecf20Sopenharmony_ci rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp); 4068c2ecf20Sopenharmony_ci ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, 4078c2ecf20Sopenharmony_ci NULL, &nc); 4088c2ecf20Sopenharmony_ci if (!nc) 4098c2ecf20Sopenharmony_ci return -ENODEV; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci /* Check if VLAN mode has been enabled */ 4128c2ecf20Sopenharmony_ci ncm = &nc->modes[NCSI_MODE_VLAN]; 4138c2ecf20Sopenharmony_ci if (ncm->enable) 4148c2ecf20Sopenharmony_ci return 0; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci /* Update to VLAN mode */ 4178c2ecf20Sopenharmony_ci cmd = (struct ncsi_cmd_ev_pkt *)skb_network_header(nr->cmd); 4188c2ecf20Sopenharmony_ci ncm->enable = 1; 4198c2ecf20Sopenharmony_ci ncm->data[0] = ntohl(cmd->mode); 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci return 0; 4228c2ecf20Sopenharmony_ci} 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_cistatic int ncsi_rsp_handler_dv(struct ncsi_request *nr) 4258c2ecf20Sopenharmony_ci{ 4268c2ecf20Sopenharmony_ci struct ncsi_rsp_pkt *rsp; 4278c2ecf20Sopenharmony_ci struct ncsi_dev_priv *ndp = nr->ndp; 4288c2ecf20Sopenharmony_ci struct ncsi_channel *nc; 4298c2ecf20Sopenharmony_ci struct ncsi_channel_mode *ncm; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci /* Find the package and channel */ 4328c2ecf20Sopenharmony_ci rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp); 4338c2ecf20Sopenharmony_ci ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, 4348c2ecf20Sopenharmony_ci NULL, &nc); 4358c2ecf20Sopenharmony_ci if (!nc) 4368c2ecf20Sopenharmony_ci return -ENODEV; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci /* Check if VLAN mode has been enabled */ 4398c2ecf20Sopenharmony_ci ncm = &nc->modes[NCSI_MODE_VLAN]; 4408c2ecf20Sopenharmony_ci if (!ncm->enable) 4418c2ecf20Sopenharmony_ci return 0; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci /* Update to VLAN mode */ 4448c2ecf20Sopenharmony_ci ncm->enable = 0; 4458c2ecf20Sopenharmony_ci return 0; 4468c2ecf20Sopenharmony_ci} 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_cistatic int ncsi_rsp_handler_sma(struct ncsi_request *nr) 4498c2ecf20Sopenharmony_ci{ 4508c2ecf20Sopenharmony_ci struct ncsi_cmd_sma_pkt *cmd; 4518c2ecf20Sopenharmony_ci struct ncsi_rsp_pkt *rsp; 4528c2ecf20Sopenharmony_ci struct ncsi_dev_priv *ndp = nr->ndp; 4538c2ecf20Sopenharmony_ci struct ncsi_channel *nc; 4548c2ecf20Sopenharmony_ci struct ncsi_channel_mac_filter *ncf; 4558c2ecf20Sopenharmony_ci unsigned long flags; 4568c2ecf20Sopenharmony_ci void *bitmap; 4578c2ecf20Sopenharmony_ci bool enabled; 4588c2ecf20Sopenharmony_ci int index; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci /* Find the package and channel */ 4628c2ecf20Sopenharmony_ci rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp); 4638c2ecf20Sopenharmony_ci ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, 4648c2ecf20Sopenharmony_ci NULL, &nc); 4658c2ecf20Sopenharmony_ci if (!nc) 4668c2ecf20Sopenharmony_ci return -ENODEV; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci /* According to NCSI spec 1.01, the mixed filter table 4698c2ecf20Sopenharmony_ci * isn't supported yet. 4708c2ecf20Sopenharmony_ci */ 4718c2ecf20Sopenharmony_ci cmd = (struct ncsi_cmd_sma_pkt *)skb_network_header(nr->cmd); 4728c2ecf20Sopenharmony_ci enabled = cmd->at_e & 0x1; 4738c2ecf20Sopenharmony_ci ncf = &nc->mac_filter; 4748c2ecf20Sopenharmony_ci bitmap = &ncf->bitmap; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci if (cmd->index == 0 || 4778c2ecf20Sopenharmony_ci cmd->index > ncf->n_uc + ncf->n_mc + ncf->n_mixed) 4788c2ecf20Sopenharmony_ci return -ERANGE; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci index = (cmd->index - 1) * ETH_ALEN; 4818c2ecf20Sopenharmony_ci spin_lock_irqsave(&nc->lock, flags); 4828c2ecf20Sopenharmony_ci if (enabled) { 4838c2ecf20Sopenharmony_ci set_bit(cmd->index - 1, bitmap); 4848c2ecf20Sopenharmony_ci memcpy(&ncf->addrs[index], cmd->mac, ETH_ALEN); 4858c2ecf20Sopenharmony_ci } else { 4868c2ecf20Sopenharmony_ci clear_bit(cmd->index - 1, bitmap); 4878c2ecf20Sopenharmony_ci eth_zero_addr(&ncf->addrs[index]); 4888c2ecf20Sopenharmony_ci } 4898c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&nc->lock, flags); 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci return 0; 4928c2ecf20Sopenharmony_ci} 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_cistatic int ncsi_rsp_handler_ebf(struct ncsi_request *nr) 4958c2ecf20Sopenharmony_ci{ 4968c2ecf20Sopenharmony_ci struct ncsi_cmd_ebf_pkt *cmd; 4978c2ecf20Sopenharmony_ci struct ncsi_rsp_pkt *rsp; 4988c2ecf20Sopenharmony_ci struct ncsi_dev_priv *ndp = nr->ndp; 4998c2ecf20Sopenharmony_ci struct ncsi_channel *nc; 5008c2ecf20Sopenharmony_ci struct ncsi_channel_mode *ncm; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci /* Find the package and channel */ 5038c2ecf20Sopenharmony_ci rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp); 5048c2ecf20Sopenharmony_ci ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, NULL, &nc); 5058c2ecf20Sopenharmony_ci if (!nc) 5068c2ecf20Sopenharmony_ci return -ENODEV; 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci /* Check if broadcast filter has been enabled */ 5098c2ecf20Sopenharmony_ci ncm = &nc->modes[NCSI_MODE_BC]; 5108c2ecf20Sopenharmony_ci if (ncm->enable) 5118c2ecf20Sopenharmony_ci return 0; 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci /* Update to broadcast filter mode */ 5148c2ecf20Sopenharmony_ci cmd = (struct ncsi_cmd_ebf_pkt *)skb_network_header(nr->cmd); 5158c2ecf20Sopenharmony_ci ncm->enable = 1; 5168c2ecf20Sopenharmony_ci ncm->data[0] = ntohl(cmd->mode); 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci return 0; 5198c2ecf20Sopenharmony_ci} 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_cistatic int ncsi_rsp_handler_dbf(struct ncsi_request *nr) 5228c2ecf20Sopenharmony_ci{ 5238c2ecf20Sopenharmony_ci struct ncsi_rsp_pkt *rsp; 5248c2ecf20Sopenharmony_ci struct ncsi_dev_priv *ndp = nr->ndp; 5258c2ecf20Sopenharmony_ci struct ncsi_channel *nc; 5268c2ecf20Sopenharmony_ci struct ncsi_channel_mode *ncm; 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp); 5298c2ecf20Sopenharmony_ci ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, 5308c2ecf20Sopenharmony_ci NULL, &nc); 5318c2ecf20Sopenharmony_ci if (!nc) 5328c2ecf20Sopenharmony_ci return -ENODEV; 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci /* Check if broadcast filter isn't enabled */ 5358c2ecf20Sopenharmony_ci ncm = &nc->modes[NCSI_MODE_BC]; 5368c2ecf20Sopenharmony_ci if (!ncm->enable) 5378c2ecf20Sopenharmony_ci return 0; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci /* Update to broadcast filter mode */ 5408c2ecf20Sopenharmony_ci ncm->enable = 0; 5418c2ecf20Sopenharmony_ci ncm->data[0] = 0; 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci return 0; 5448c2ecf20Sopenharmony_ci} 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_cistatic int ncsi_rsp_handler_egmf(struct ncsi_request *nr) 5478c2ecf20Sopenharmony_ci{ 5488c2ecf20Sopenharmony_ci struct ncsi_cmd_egmf_pkt *cmd; 5498c2ecf20Sopenharmony_ci struct ncsi_rsp_pkt *rsp; 5508c2ecf20Sopenharmony_ci struct ncsi_dev_priv *ndp = nr->ndp; 5518c2ecf20Sopenharmony_ci struct ncsi_channel *nc; 5528c2ecf20Sopenharmony_ci struct ncsi_channel_mode *ncm; 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci /* Find the channel */ 5558c2ecf20Sopenharmony_ci rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp); 5568c2ecf20Sopenharmony_ci ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, 5578c2ecf20Sopenharmony_ci NULL, &nc); 5588c2ecf20Sopenharmony_ci if (!nc) 5598c2ecf20Sopenharmony_ci return -ENODEV; 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci /* Check if multicast filter has been enabled */ 5628c2ecf20Sopenharmony_ci ncm = &nc->modes[NCSI_MODE_MC]; 5638c2ecf20Sopenharmony_ci if (ncm->enable) 5648c2ecf20Sopenharmony_ci return 0; 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci /* Update to multicast filter mode */ 5678c2ecf20Sopenharmony_ci cmd = (struct ncsi_cmd_egmf_pkt *)skb_network_header(nr->cmd); 5688c2ecf20Sopenharmony_ci ncm->enable = 1; 5698c2ecf20Sopenharmony_ci ncm->data[0] = ntohl(cmd->mode); 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci return 0; 5728c2ecf20Sopenharmony_ci} 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_cistatic int ncsi_rsp_handler_dgmf(struct ncsi_request *nr) 5758c2ecf20Sopenharmony_ci{ 5768c2ecf20Sopenharmony_ci struct ncsi_rsp_pkt *rsp; 5778c2ecf20Sopenharmony_ci struct ncsi_dev_priv *ndp = nr->ndp; 5788c2ecf20Sopenharmony_ci struct ncsi_channel *nc; 5798c2ecf20Sopenharmony_ci struct ncsi_channel_mode *ncm; 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp); 5828c2ecf20Sopenharmony_ci ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, 5838c2ecf20Sopenharmony_ci NULL, &nc); 5848c2ecf20Sopenharmony_ci if (!nc) 5858c2ecf20Sopenharmony_ci return -ENODEV; 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci /* Check if multicast filter has been enabled */ 5888c2ecf20Sopenharmony_ci ncm = &nc->modes[NCSI_MODE_MC]; 5898c2ecf20Sopenharmony_ci if (!ncm->enable) 5908c2ecf20Sopenharmony_ci return 0; 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci /* Update to multicast filter mode */ 5938c2ecf20Sopenharmony_ci ncm->enable = 0; 5948c2ecf20Sopenharmony_ci ncm->data[0] = 0; 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci return 0; 5978c2ecf20Sopenharmony_ci} 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_cistatic int ncsi_rsp_handler_snfc(struct ncsi_request *nr) 6008c2ecf20Sopenharmony_ci{ 6018c2ecf20Sopenharmony_ci struct ncsi_cmd_snfc_pkt *cmd; 6028c2ecf20Sopenharmony_ci struct ncsi_rsp_pkt *rsp; 6038c2ecf20Sopenharmony_ci struct ncsi_dev_priv *ndp = nr->ndp; 6048c2ecf20Sopenharmony_ci struct ncsi_channel *nc; 6058c2ecf20Sopenharmony_ci struct ncsi_channel_mode *ncm; 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci /* Find the channel */ 6088c2ecf20Sopenharmony_ci rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp); 6098c2ecf20Sopenharmony_ci ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, 6108c2ecf20Sopenharmony_ci NULL, &nc); 6118c2ecf20Sopenharmony_ci if (!nc) 6128c2ecf20Sopenharmony_ci return -ENODEV; 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci /* Check if flow control has been enabled */ 6158c2ecf20Sopenharmony_ci ncm = &nc->modes[NCSI_MODE_FC]; 6168c2ecf20Sopenharmony_ci if (ncm->enable) 6178c2ecf20Sopenharmony_ci return 0; 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci /* Update to flow control mode */ 6208c2ecf20Sopenharmony_ci cmd = (struct ncsi_cmd_snfc_pkt *)skb_network_header(nr->cmd); 6218c2ecf20Sopenharmony_ci ncm->enable = 1; 6228c2ecf20Sopenharmony_ci ncm->data[0] = cmd->mode; 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci return 0; 6258c2ecf20Sopenharmony_ci} 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci/* Response handler for Mellanox command Get Mac Address */ 6288c2ecf20Sopenharmony_cistatic int ncsi_rsp_handler_oem_mlx_gma(struct ncsi_request *nr) 6298c2ecf20Sopenharmony_ci{ 6308c2ecf20Sopenharmony_ci struct ncsi_dev_priv *ndp = nr->ndp; 6318c2ecf20Sopenharmony_ci struct net_device *ndev = ndp->ndev.dev; 6328c2ecf20Sopenharmony_ci const struct net_device_ops *ops = ndev->netdev_ops; 6338c2ecf20Sopenharmony_ci struct ncsi_rsp_oem_pkt *rsp; 6348c2ecf20Sopenharmony_ci struct sockaddr saddr; 6358c2ecf20Sopenharmony_ci int ret = 0; 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci /* Get the response header */ 6388c2ecf20Sopenharmony_ci rsp = (struct ncsi_rsp_oem_pkt *)skb_network_header(nr->rsp); 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci saddr.sa_family = ndev->type; 6418c2ecf20Sopenharmony_ci ndev->priv_flags |= IFF_LIVE_ADDR_CHANGE; 6428c2ecf20Sopenharmony_ci memcpy(saddr.sa_data, &rsp->data[MLX_MAC_ADDR_OFFSET], ETH_ALEN); 6438c2ecf20Sopenharmony_ci /* Set the flag for GMA command which should only be called once */ 6448c2ecf20Sopenharmony_ci ndp->gma_flag = 1; 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci ret = ops->ndo_set_mac_address(ndev, &saddr); 6478c2ecf20Sopenharmony_ci if (ret < 0) 6488c2ecf20Sopenharmony_ci netdev_warn(ndev, "NCSI: 'Writing mac address to device failed\n"); 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci return ret; 6518c2ecf20Sopenharmony_ci} 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci/* Response handler for Mellanox card */ 6548c2ecf20Sopenharmony_cistatic int ncsi_rsp_handler_oem_mlx(struct ncsi_request *nr) 6558c2ecf20Sopenharmony_ci{ 6568c2ecf20Sopenharmony_ci struct ncsi_rsp_oem_mlx_pkt *mlx; 6578c2ecf20Sopenharmony_ci struct ncsi_rsp_oem_pkt *rsp; 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci /* Get the response header */ 6608c2ecf20Sopenharmony_ci rsp = (struct ncsi_rsp_oem_pkt *)skb_network_header(nr->rsp); 6618c2ecf20Sopenharmony_ci mlx = (struct ncsi_rsp_oem_mlx_pkt *)(rsp->data); 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci if (mlx->cmd == NCSI_OEM_MLX_CMD_GMA && 6648c2ecf20Sopenharmony_ci mlx->param == NCSI_OEM_MLX_CMD_GMA_PARAM) 6658c2ecf20Sopenharmony_ci return ncsi_rsp_handler_oem_mlx_gma(nr); 6668c2ecf20Sopenharmony_ci return 0; 6678c2ecf20Sopenharmony_ci} 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci/* Response handler for Broadcom command Get Mac Address */ 6708c2ecf20Sopenharmony_cistatic int ncsi_rsp_handler_oem_bcm_gma(struct ncsi_request *nr) 6718c2ecf20Sopenharmony_ci{ 6728c2ecf20Sopenharmony_ci struct ncsi_dev_priv *ndp = nr->ndp; 6738c2ecf20Sopenharmony_ci struct net_device *ndev = ndp->ndev.dev; 6748c2ecf20Sopenharmony_ci const struct net_device_ops *ops = ndev->netdev_ops; 6758c2ecf20Sopenharmony_ci struct ncsi_rsp_oem_pkt *rsp; 6768c2ecf20Sopenharmony_ci struct sockaddr saddr; 6778c2ecf20Sopenharmony_ci int ret = 0; 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci /* Get the response header */ 6808c2ecf20Sopenharmony_ci rsp = (struct ncsi_rsp_oem_pkt *)skb_network_header(nr->rsp); 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci saddr.sa_family = ndev->type; 6838c2ecf20Sopenharmony_ci ndev->priv_flags |= IFF_LIVE_ADDR_CHANGE; 6848c2ecf20Sopenharmony_ci memcpy(saddr.sa_data, &rsp->data[BCM_MAC_ADDR_OFFSET], ETH_ALEN); 6858c2ecf20Sopenharmony_ci /* Increase mac address by 1 for BMC's address */ 6868c2ecf20Sopenharmony_ci eth_addr_inc((u8 *)saddr.sa_data); 6878c2ecf20Sopenharmony_ci if (!is_valid_ether_addr((const u8 *)saddr.sa_data)) 6888c2ecf20Sopenharmony_ci return -ENXIO; 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci /* Set the flag for GMA command which should only be called once */ 6918c2ecf20Sopenharmony_ci ndp->gma_flag = 1; 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci ret = ops->ndo_set_mac_address(ndev, &saddr); 6948c2ecf20Sopenharmony_ci if (ret < 0) 6958c2ecf20Sopenharmony_ci netdev_warn(ndev, "NCSI: 'Writing mac address to device failed\n"); 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci return ret; 6988c2ecf20Sopenharmony_ci} 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci/* Response handler for Broadcom card */ 7018c2ecf20Sopenharmony_cistatic int ncsi_rsp_handler_oem_bcm(struct ncsi_request *nr) 7028c2ecf20Sopenharmony_ci{ 7038c2ecf20Sopenharmony_ci struct ncsi_rsp_oem_bcm_pkt *bcm; 7048c2ecf20Sopenharmony_ci struct ncsi_rsp_oem_pkt *rsp; 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci /* Get the response header */ 7078c2ecf20Sopenharmony_ci rsp = (struct ncsi_rsp_oem_pkt *)skb_network_header(nr->rsp); 7088c2ecf20Sopenharmony_ci bcm = (struct ncsi_rsp_oem_bcm_pkt *)(rsp->data); 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci if (bcm->type == NCSI_OEM_BCM_CMD_GMA) 7118c2ecf20Sopenharmony_ci return ncsi_rsp_handler_oem_bcm_gma(nr); 7128c2ecf20Sopenharmony_ci return 0; 7138c2ecf20Sopenharmony_ci} 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_cistatic struct ncsi_rsp_oem_handler { 7168c2ecf20Sopenharmony_ci unsigned int mfr_id; 7178c2ecf20Sopenharmony_ci int (*handler)(struct ncsi_request *nr); 7188c2ecf20Sopenharmony_ci} ncsi_rsp_oem_handlers[] = { 7198c2ecf20Sopenharmony_ci { NCSI_OEM_MFR_MLX_ID, ncsi_rsp_handler_oem_mlx }, 7208c2ecf20Sopenharmony_ci { NCSI_OEM_MFR_BCM_ID, ncsi_rsp_handler_oem_bcm } 7218c2ecf20Sopenharmony_ci}; 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci/* Response handler for OEM command */ 7248c2ecf20Sopenharmony_cistatic int ncsi_rsp_handler_oem(struct ncsi_request *nr) 7258c2ecf20Sopenharmony_ci{ 7268c2ecf20Sopenharmony_ci struct ncsi_rsp_oem_handler *nrh = NULL; 7278c2ecf20Sopenharmony_ci struct ncsi_rsp_oem_pkt *rsp; 7288c2ecf20Sopenharmony_ci unsigned int mfr_id, i; 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci /* Get the response header */ 7318c2ecf20Sopenharmony_ci rsp = (struct ncsi_rsp_oem_pkt *)skb_network_header(nr->rsp); 7328c2ecf20Sopenharmony_ci mfr_id = ntohl(rsp->mfr_id); 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci /* Check for manufacturer id and Find the handler */ 7358c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ncsi_rsp_oem_handlers); i++) { 7368c2ecf20Sopenharmony_ci if (ncsi_rsp_oem_handlers[i].mfr_id == mfr_id) { 7378c2ecf20Sopenharmony_ci if (ncsi_rsp_oem_handlers[i].handler) 7388c2ecf20Sopenharmony_ci nrh = &ncsi_rsp_oem_handlers[i]; 7398c2ecf20Sopenharmony_ci else 7408c2ecf20Sopenharmony_ci nrh = NULL; 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci break; 7438c2ecf20Sopenharmony_ci } 7448c2ecf20Sopenharmony_ci } 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci if (!nrh) { 7478c2ecf20Sopenharmony_ci netdev_err(nr->ndp->ndev.dev, "Received unrecognized OEM packet with MFR-ID (0x%x)\n", 7488c2ecf20Sopenharmony_ci mfr_id); 7498c2ecf20Sopenharmony_ci return -ENOENT; 7508c2ecf20Sopenharmony_ci } 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci /* Process the packet */ 7538c2ecf20Sopenharmony_ci return nrh->handler(nr); 7548c2ecf20Sopenharmony_ci} 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_cistatic int ncsi_rsp_handler_gvi(struct ncsi_request *nr) 7578c2ecf20Sopenharmony_ci{ 7588c2ecf20Sopenharmony_ci struct ncsi_rsp_gvi_pkt *rsp; 7598c2ecf20Sopenharmony_ci struct ncsi_dev_priv *ndp = nr->ndp; 7608c2ecf20Sopenharmony_ci struct ncsi_channel *nc; 7618c2ecf20Sopenharmony_ci struct ncsi_channel_version *ncv; 7628c2ecf20Sopenharmony_ci int i; 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci /* Find the channel */ 7658c2ecf20Sopenharmony_ci rsp = (struct ncsi_rsp_gvi_pkt *)skb_network_header(nr->rsp); 7668c2ecf20Sopenharmony_ci ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, 7678c2ecf20Sopenharmony_ci NULL, &nc); 7688c2ecf20Sopenharmony_ci if (!nc) 7698c2ecf20Sopenharmony_ci return -ENODEV; 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci /* Update channel's version info 7728c2ecf20Sopenharmony_ci * 7738c2ecf20Sopenharmony_ci * Major, minor, and update fields are supposed to be 7748c2ecf20Sopenharmony_ci * unsigned integers encoded as packed BCD. 7758c2ecf20Sopenharmony_ci * 7768c2ecf20Sopenharmony_ci * Alpha1 and alpha2 are ISO/IEC 8859-1 characters. 7778c2ecf20Sopenharmony_ci */ 7788c2ecf20Sopenharmony_ci ncv = &nc->version; 7798c2ecf20Sopenharmony_ci ncv->major = decode_bcd_u8(rsp->major); 7808c2ecf20Sopenharmony_ci ncv->minor = decode_bcd_u8(rsp->minor); 7818c2ecf20Sopenharmony_ci ncv->update = decode_bcd_u8(rsp->update); 7828c2ecf20Sopenharmony_ci ncv->alpha1 = rsp->alpha1; 7838c2ecf20Sopenharmony_ci ncv->alpha2 = rsp->alpha2; 7848c2ecf20Sopenharmony_ci memcpy(ncv->fw_name, rsp->fw_name, 12); 7858c2ecf20Sopenharmony_ci ncv->fw_version = ntohl(rsp->fw_version); 7868c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ncv->pci_ids); i++) 7878c2ecf20Sopenharmony_ci ncv->pci_ids[i] = ntohs(rsp->pci_ids[i]); 7888c2ecf20Sopenharmony_ci ncv->mf_id = ntohl(rsp->mf_id); 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci return 0; 7918c2ecf20Sopenharmony_ci} 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_cistatic int ncsi_rsp_handler_gc(struct ncsi_request *nr) 7948c2ecf20Sopenharmony_ci{ 7958c2ecf20Sopenharmony_ci struct ncsi_rsp_gc_pkt *rsp; 7968c2ecf20Sopenharmony_ci struct ncsi_dev_priv *ndp = nr->ndp; 7978c2ecf20Sopenharmony_ci struct ncsi_channel *nc; 7988c2ecf20Sopenharmony_ci size_t size; 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci /* Find the channel */ 8018c2ecf20Sopenharmony_ci rsp = (struct ncsi_rsp_gc_pkt *)skb_network_header(nr->rsp); 8028c2ecf20Sopenharmony_ci ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, 8038c2ecf20Sopenharmony_ci NULL, &nc); 8048c2ecf20Sopenharmony_ci if (!nc) 8058c2ecf20Sopenharmony_ci return -ENODEV; 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ci /* Update channel's capabilities */ 8088c2ecf20Sopenharmony_ci nc->caps[NCSI_CAP_GENERIC].cap = ntohl(rsp->cap) & 8098c2ecf20Sopenharmony_ci NCSI_CAP_GENERIC_MASK; 8108c2ecf20Sopenharmony_ci nc->caps[NCSI_CAP_BC].cap = ntohl(rsp->bc_cap) & 8118c2ecf20Sopenharmony_ci NCSI_CAP_BC_MASK; 8128c2ecf20Sopenharmony_ci nc->caps[NCSI_CAP_MC].cap = ntohl(rsp->mc_cap) & 8138c2ecf20Sopenharmony_ci NCSI_CAP_MC_MASK; 8148c2ecf20Sopenharmony_ci nc->caps[NCSI_CAP_BUFFER].cap = ntohl(rsp->buf_cap); 8158c2ecf20Sopenharmony_ci nc->caps[NCSI_CAP_AEN].cap = ntohl(rsp->aen_cap) & 8168c2ecf20Sopenharmony_ci NCSI_CAP_AEN_MASK; 8178c2ecf20Sopenharmony_ci nc->caps[NCSI_CAP_VLAN].cap = rsp->vlan_mode & 8188c2ecf20Sopenharmony_ci NCSI_CAP_VLAN_MASK; 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci size = (rsp->uc_cnt + rsp->mc_cnt + rsp->mixed_cnt) * ETH_ALEN; 8218c2ecf20Sopenharmony_ci nc->mac_filter.addrs = kzalloc(size, GFP_ATOMIC); 8228c2ecf20Sopenharmony_ci if (!nc->mac_filter.addrs) 8238c2ecf20Sopenharmony_ci return -ENOMEM; 8248c2ecf20Sopenharmony_ci nc->mac_filter.n_uc = rsp->uc_cnt; 8258c2ecf20Sopenharmony_ci nc->mac_filter.n_mc = rsp->mc_cnt; 8268c2ecf20Sopenharmony_ci nc->mac_filter.n_mixed = rsp->mixed_cnt; 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci nc->vlan_filter.vids = kcalloc(rsp->vlan_cnt, 8298c2ecf20Sopenharmony_ci sizeof(*nc->vlan_filter.vids), 8308c2ecf20Sopenharmony_ci GFP_ATOMIC); 8318c2ecf20Sopenharmony_ci if (!nc->vlan_filter.vids) 8328c2ecf20Sopenharmony_ci return -ENOMEM; 8338c2ecf20Sopenharmony_ci /* Set VLAN filters active so they are cleared in the first 8348c2ecf20Sopenharmony_ci * configuration state 8358c2ecf20Sopenharmony_ci */ 8368c2ecf20Sopenharmony_ci nc->vlan_filter.bitmap = U64_MAX; 8378c2ecf20Sopenharmony_ci nc->vlan_filter.n_vids = rsp->vlan_cnt; 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci return 0; 8408c2ecf20Sopenharmony_ci} 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_cistatic int ncsi_rsp_handler_gp(struct ncsi_request *nr) 8438c2ecf20Sopenharmony_ci{ 8448c2ecf20Sopenharmony_ci struct ncsi_channel_vlan_filter *ncvf; 8458c2ecf20Sopenharmony_ci struct ncsi_channel_mac_filter *ncmf; 8468c2ecf20Sopenharmony_ci struct ncsi_dev_priv *ndp = nr->ndp; 8478c2ecf20Sopenharmony_ci struct ncsi_rsp_gp_pkt *rsp; 8488c2ecf20Sopenharmony_ci struct ncsi_channel *nc; 8498c2ecf20Sopenharmony_ci unsigned short enable; 8508c2ecf20Sopenharmony_ci unsigned char *pdata; 8518c2ecf20Sopenharmony_ci unsigned long flags; 8528c2ecf20Sopenharmony_ci void *bitmap; 8538c2ecf20Sopenharmony_ci int i; 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci /* Find the channel */ 8568c2ecf20Sopenharmony_ci rsp = (struct ncsi_rsp_gp_pkt *)skb_network_header(nr->rsp); 8578c2ecf20Sopenharmony_ci ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, 8588c2ecf20Sopenharmony_ci NULL, &nc); 8598c2ecf20Sopenharmony_ci if (!nc) 8608c2ecf20Sopenharmony_ci return -ENODEV; 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci /* Modes with explicit enabled indications */ 8638c2ecf20Sopenharmony_ci if (ntohl(rsp->valid_modes) & 0x1) { /* BC filter mode */ 8648c2ecf20Sopenharmony_ci nc->modes[NCSI_MODE_BC].enable = 1; 8658c2ecf20Sopenharmony_ci nc->modes[NCSI_MODE_BC].data[0] = ntohl(rsp->bc_mode); 8668c2ecf20Sopenharmony_ci } 8678c2ecf20Sopenharmony_ci if (ntohl(rsp->valid_modes) & 0x2) /* Channel enabled */ 8688c2ecf20Sopenharmony_ci nc->modes[NCSI_MODE_ENABLE].enable = 1; 8698c2ecf20Sopenharmony_ci if (ntohl(rsp->valid_modes) & 0x4) /* Channel Tx enabled */ 8708c2ecf20Sopenharmony_ci nc->modes[NCSI_MODE_TX_ENABLE].enable = 1; 8718c2ecf20Sopenharmony_ci if (ntohl(rsp->valid_modes) & 0x8) /* MC filter mode */ 8728c2ecf20Sopenharmony_ci nc->modes[NCSI_MODE_MC].enable = 1; 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci /* Modes without explicit enabled indications */ 8758c2ecf20Sopenharmony_ci nc->modes[NCSI_MODE_LINK].enable = 1; 8768c2ecf20Sopenharmony_ci nc->modes[NCSI_MODE_LINK].data[0] = ntohl(rsp->link_mode); 8778c2ecf20Sopenharmony_ci nc->modes[NCSI_MODE_VLAN].enable = 1; 8788c2ecf20Sopenharmony_ci nc->modes[NCSI_MODE_VLAN].data[0] = rsp->vlan_mode; 8798c2ecf20Sopenharmony_ci nc->modes[NCSI_MODE_FC].enable = 1; 8808c2ecf20Sopenharmony_ci nc->modes[NCSI_MODE_FC].data[0] = rsp->fc_mode; 8818c2ecf20Sopenharmony_ci nc->modes[NCSI_MODE_AEN].enable = 1; 8828c2ecf20Sopenharmony_ci nc->modes[NCSI_MODE_AEN].data[0] = ntohl(rsp->aen_mode); 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci /* MAC addresses filter table */ 8858c2ecf20Sopenharmony_ci pdata = (unsigned char *)rsp + 48; 8868c2ecf20Sopenharmony_ci enable = rsp->mac_enable; 8878c2ecf20Sopenharmony_ci ncmf = &nc->mac_filter; 8888c2ecf20Sopenharmony_ci spin_lock_irqsave(&nc->lock, flags); 8898c2ecf20Sopenharmony_ci bitmap = &ncmf->bitmap; 8908c2ecf20Sopenharmony_ci for (i = 0; i < rsp->mac_cnt; i++, pdata += 6) { 8918c2ecf20Sopenharmony_ci if (!(enable & (0x1 << i))) 8928c2ecf20Sopenharmony_ci clear_bit(i, bitmap); 8938c2ecf20Sopenharmony_ci else 8948c2ecf20Sopenharmony_ci set_bit(i, bitmap); 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci memcpy(&ncmf->addrs[i * ETH_ALEN], pdata, ETH_ALEN); 8978c2ecf20Sopenharmony_ci } 8988c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&nc->lock, flags); 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci /* VLAN filter table */ 9018c2ecf20Sopenharmony_ci enable = ntohs(rsp->vlan_enable); 9028c2ecf20Sopenharmony_ci ncvf = &nc->vlan_filter; 9038c2ecf20Sopenharmony_ci bitmap = &ncvf->bitmap; 9048c2ecf20Sopenharmony_ci spin_lock_irqsave(&nc->lock, flags); 9058c2ecf20Sopenharmony_ci for (i = 0; i < rsp->vlan_cnt; i++, pdata += 2) { 9068c2ecf20Sopenharmony_ci if (!(enable & (0x1 << i))) 9078c2ecf20Sopenharmony_ci clear_bit(i, bitmap); 9088c2ecf20Sopenharmony_ci else 9098c2ecf20Sopenharmony_ci set_bit(i, bitmap); 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci ncvf->vids[i] = ntohs(*(__be16 *)pdata); 9128c2ecf20Sopenharmony_ci } 9138c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&nc->lock, flags); 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci return 0; 9168c2ecf20Sopenharmony_ci} 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_cistatic int ncsi_rsp_handler_gcps(struct ncsi_request *nr) 9198c2ecf20Sopenharmony_ci{ 9208c2ecf20Sopenharmony_ci struct ncsi_rsp_gcps_pkt *rsp; 9218c2ecf20Sopenharmony_ci struct ncsi_dev_priv *ndp = nr->ndp; 9228c2ecf20Sopenharmony_ci struct ncsi_channel *nc; 9238c2ecf20Sopenharmony_ci struct ncsi_channel_stats *ncs; 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci /* Find the channel */ 9268c2ecf20Sopenharmony_ci rsp = (struct ncsi_rsp_gcps_pkt *)skb_network_header(nr->rsp); 9278c2ecf20Sopenharmony_ci ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, 9288c2ecf20Sopenharmony_ci NULL, &nc); 9298c2ecf20Sopenharmony_ci if (!nc) 9308c2ecf20Sopenharmony_ci return -ENODEV; 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci /* Update HNC's statistics */ 9338c2ecf20Sopenharmony_ci ncs = &nc->stats; 9348c2ecf20Sopenharmony_ci ncs->hnc_cnt_hi = ntohl(rsp->cnt_hi); 9358c2ecf20Sopenharmony_ci ncs->hnc_cnt_lo = ntohl(rsp->cnt_lo); 9368c2ecf20Sopenharmony_ci ncs->hnc_rx_bytes = ntohl(rsp->rx_bytes); 9378c2ecf20Sopenharmony_ci ncs->hnc_tx_bytes = ntohl(rsp->tx_bytes); 9388c2ecf20Sopenharmony_ci ncs->hnc_rx_uc_pkts = ntohl(rsp->rx_uc_pkts); 9398c2ecf20Sopenharmony_ci ncs->hnc_rx_mc_pkts = ntohl(rsp->rx_mc_pkts); 9408c2ecf20Sopenharmony_ci ncs->hnc_rx_bc_pkts = ntohl(rsp->rx_bc_pkts); 9418c2ecf20Sopenharmony_ci ncs->hnc_tx_uc_pkts = ntohl(rsp->tx_uc_pkts); 9428c2ecf20Sopenharmony_ci ncs->hnc_tx_mc_pkts = ntohl(rsp->tx_mc_pkts); 9438c2ecf20Sopenharmony_ci ncs->hnc_tx_bc_pkts = ntohl(rsp->tx_bc_pkts); 9448c2ecf20Sopenharmony_ci ncs->hnc_fcs_err = ntohl(rsp->fcs_err); 9458c2ecf20Sopenharmony_ci ncs->hnc_align_err = ntohl(rsp->align_err); 9468c2ecf20Sopenharmony_ci ncs->hnc_false_carrier = ntohl(rsp->false_carrier); 9478c2ecf20Sopenharmony_ci ncs->hnc_runt_pkts = ntohl(rsp->runt_pkts); 9488c2ecf20Sopenharmony_ci ncs->hnc_jabber_pkts = ntohl(rsp->jabber_pkts); 9498c2ecf20Sopenharmony_ci ncs->hnc_rx_pause_xon = ntohl(rsp->rx_pause_xon); 9508c2ecf20Sopenharmony_ci ncs->hnc_rx_pause_xoff = ntohl(rsp->rx_pause_xoff); 9518c2ecf20Sopenharmony_ci ncs->hnc_tx_pause_xon = ntohl(rsp->tx_pause_xon); 9528c2ecf20Sopenharmony_ci ncs->hnc_tx_pause_xoff = ntohl(rsp->tx_pause_xoff); 9538c2ecf20Sopenharmony_ci ncs->hnc_tx_s_collision = ntohl(rsp->tx_s_collision); 9548c2ecf20Sopenharmony_ci ncs->hnc_tx_m_collision = ntohl(rsp->tx_m_collision); 9558c2ecf20Sopenharmony_ci ncs->hnc_l_collision = ntohl(rsp->l_collision); 9568c2ecf20Sopenharmony_ci ncs->hnc_e_collision = ntohl(rsp->e_collision); 9578c2ecf20Sopenharmony_ci ncs->hnc_rx_ctl_frames = ntohl(rsp->rx_ctl_frames); 9588c2ecf20Sopenharmony_ci ncs->hnc_rx_64_frames = ntohl(rsp->rx_64_frames); 9598c2ecf20Sopenharmony_ci ncs->hnc_rx_127_frames = ntohl(rsp->rx_127_frames); 9608c2ecf20Sopenharmony_ci ncs->hnc_rx_255_frames = ntohl(rsp->rx_255_frames); 9618c2ecf20Sopenharmony_ci ncs->hnc_rx_511_frames = ntohl(rsp->rx_511_frames); 9628c2ecf20Sopenharmony_ci ncs->hnc_rx_1023_frames = ntohl(rsp->rx_1023_frames); 9638c2ecf20Sopenharmony_ci ncs->hnc_rx_1522_frames = ntohl(rsp->rx_1522_frames); 9648c2ecf20Sopenharmony_ci ncs->hnc_rx_9022_frames = ntohl(rsp->rx_9022_frames); 9658c2ecf20Sopenharmony_ci ncs->hnc_tx_64_frames = ntohl(rsp->tx_64_frames); 9668c2ecf20Sopenharmony_ci ncs->hnc_tx_127_frames = ntohl(rsp->tx_127_frames); 9678c2ecf20Sopenharmony_ci ncs->hnc_tx_255_frames = ntohl(rsp->tx_255_frames); 9688c2ecf20Sopenharmony_ci ncs->hnc_tx_511_frames = ntohl(rsp->tx_511_frames); 9698c2ecf20Sopenharmony_ci ncs->hnc_tx_1023_frames = ntohl(rsp->tx_1023_frames); 9708c2ecf20Sopenharmony_ci ncs->hnc_tx_1522_frames = ntohl(rsp->tx_1522_frames); 9718c2ecf20Sopenharmony_ci ncs->hnc_tx_9022_frames = ntohl(rsp->tx_9022_frames); 9728c2ecf20Sopenharmony_ci ncs->hnc_rx_valid_bytes = ntohl(rsp->rx_valid_bytes); 9738c2ecf20Sopenharmony_ci ncs->hnc_rx_runt_pkts = ntohl(rsp->rx_runt_pkts); 9748c2ecf20Sopenharmony_ci ncs->hnc_rx_jabber_pkts = ntohl(rsp->rx_jabber_pkts); 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci return 0; 9778c2ecf20Sopenharmony_ci} 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_cistatic int ncsi_rsp_handler_gns(struct ncsi_request *nr) 9808c2ecf20Sopenharmony_ci{ 9818c2ecf20Sopenharmony_ci struct ncsi_rsp_gns_pkt *rsp; 9828c2ecf20Sopenharmony_ci struct ncsi_dev_priv *ndp = nr->ndp; 9838c2ecf20Sopenharmony_ci struct ncsi_channel *nc; 9848c2ecf20Sopenharmony_ci struct ncsi_channel_stats *ncs; 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci /* Find the channel */ 9878c2ecf20Sopenharmony_ci rsp = (struct ncsi_rsp_gns_pkt *)skb_network_header(nr->rsp); 9888c2ecf20Sopenharmony_ci ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, 9898c2ecf20Sopenharmony_ci NULL, &nc); 9908c2ecf20Sopenharmony_ci if (!nc) 9918c2ecf20Sopenharmony_ci return -ENODEV; 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci /* Update HNC's statistics */ 9948c2ecf20Sopenharmony_ci ncs = &nc->stats; 9958c2ecf20Sopenharmony_ci ncs->ncsi_rx_cmds = ntohl(rsp->rx_cmds); 9968c2ecf20Sopenharmony_ci ncs->ncsi_dropped_cmds = ntohl(rsp->dropped_cmds); 9978c2ecf20Sopenharmony_ci ncs->ncsi_cmd_type_errs = ntohl(rsp->cmd_type_errs); 9988c2ecf20Sopenharmony_ci ncs->ncsi_cmd_csum_errs = ntohl(rsp->cmd_csum_errs); 9998c2ecf20Sopenharmony_ci ncs->ncsi_rx_pkts = ntohl(rsp->rx_pkts); 10008c2ecf20Sopenharmony_ci ncs->ncsi_tx_pkts = ntohl(rsp->tx_pkts); 10018c2ecf20Sopenharmony_ci ncs->ncsi_tx_aen_pkts = ntohl(rsp->tx_aen_pkts); 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci return 0; 10048c2ecf20Sopenharmony_ci} 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_cistatic int ncsi_rsp_handler_gnpts(struct ncsi_request *nr) 10078c2ecf20Sopenharmony_ci{ 10088c2ecf20Sopenharmony_ci struct ncsi_rsp_gnpts_pkt *rsp; 10098c2ecf20Sopenharmony_ci struct ncsi_dev_priv *ndp = nr->ndp; 10108c2ecf20Sopenharmony_ci struct ncsi_channel *nc; 10118c2ecf20Sopenharmony_ci struct ncsi_channel_stats *ncs; 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_ci /* Find the channel */ 10148c2ecf20Sopenharmony_ci rsp = (struct ncsi_rsp_gnpts_pkt *)skb_network_header(nr->rsp); 10158c2ecf20Sopenharmony_ci ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, 10168c2ecf20Sopenharmony_ci NULL, &nc); 10178c2ecf20Sopenharmony_ci if (!nc) 10188c2ecf20Sopenharmony_ci return -ENODEV; 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci /* Update HNC's statistics */ 10218c2ecf20Sopenharmony_ci ncs = &nc->stats; 10228c2ecf20Sopenharmony_ci ncs->pt_tx_pkts = ntohl(rsp->tx_pkts); 10238c2ecf20Sopenharmony_ci ncs->pt_tx_dropped = ntohl(rsp->tx_dropped); 10248c2ecf20Sopenharmony_ci ncs->pt_tx_channel_err = ntohl(rsp->tx_channel_err); 10258c2ecf20Sopenharmony_ci ncs->pt_tx_us_err = ntohl(rsp->tx_us_err); 10268c2ecf20Sopenharmony_ci ncs->pt_rx_pkts = ntohl(rsp->rx_pkts); 10278c2ecf20Sopenharmony_ci ncs->pt_rx_dropped = ntohl(rsp->rx_dropped); 10288c2ecf20Sopenharmony_ci ncs->pt_rx_channel_err = ntohl(rsp->rx_channel_err); 10298c2ecf20Sopenharmony_ci ncs->pt_rx_us_err = ntohl(rsp->rx_us_err); 10308c2ecf20Sopenharmony_ci ncs->pt_rx_os_err = ntohl(rsp->rx_os_err); 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_ci return 0; 10338c2ecf20Sopenharmony_ci} 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_cistatic int ncsi_rsp_handler_gps(struct ncsi_request *nr) 10368c2ecf20Sopenharmony_ci{ 10378c2ecf20Sopenharmony_ci struct ncsi_rsp_gps_pkt *rsp; 10388c2ecf20Sopenharmony_ci struct ncsi_dev_priv *ndp = nr->ndp; 10398c2ecf20Sopenharmony_ci struct ncsi_package *np; 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci /* Find the package */ 10428c2ecf20Sopenharmony_ci rsp = (struct ncsi_rsp_gps_pkt *)skb_network_header(nr->rsp); 10438c2ecf20Sopenharmony_ci ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, 10448c2ecf20Sopenharmony_ci &np, NULL); 10458c2ecf20Sopenharmony_ci if (!np) 10468c2ecf20Sopenharmony_ci return -ENODEV; 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_ci return 0; 10498c2ecf20Sopenharmony_ci} 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_cistatic int ncsi_rsp_handler_gpuuid(struct ncsi_request *nr) 10528c2ecf20Sopenharmony_ci{ 10538c2ecf20Sopenharmony_ci struct ncsi_rsp_gpuuid_pkt *rsp; 10548c2ecf20Sopenharmony_ci struct ncsi_dev_priv *ndp = nr->ndp; 10558c2ecf20Sopenharmony_ci struct ncsi_package *np; 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ci /* Find the package */ 10588c2ecf20Sopenharmony_ci rsp = (struct ncsi_rsp_gpuuid_pkt *)skb_network_header(nr->rsp); 10598c2ecf20Sopenharmony_ci ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, 10608c2ecf20Sopenharmony_ci &np, NULL); 10618c2ecf20Sopenharmony_ci if (!np) 10628c2ecf20Sopenharmony_ci return -ENODEV; 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci memcpy(np->uuid, rsp->uuid, sizeof(rsp->uuid)); 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci return 0; 10678c2ecf20Sopenharmony_ci} 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_cistatic int ncsi_rsp_handler_pldm(struct ncsi_request *nr) 10708c2ecf20Sopenharmony_ci{ 10718c2ecf20Sopenharmony_ci return 0; 10728c2ecf20Sopenharmony_ci} 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_cistatic int ncsi_rsp_handler_netlink(struct ncsi_request *nr) 10758c2ecf20Sopenharmony_ci{ 10768c2ecf20Sopenharmony_ci struct ncsi_dev_priv *ndp = nr->ndp; 10778c2ecf20Sopenharmony_ci struct ncsi_rsp_pkt *rsp; 10788c2ecf20Sopenharmony_ci struct ncsi_package *np; 10798c2ecf20Sopenharmony_ci struct ncsi_channel *nc; 10808c2ecf20Sopenharmony_ci int ret; 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci /* Find the package */ 10838c2ecf20Sopenharmony_ci rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp); 10848c2ecf20Sopenharmony_ci ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, 10858c2ecf20Sopenharmony_ci &np, &nc); 10868c2ecf20Sopenharmony_ci if (!np) 10878c2ecf20Sopenharmony_ci return -ENODEV; 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci ret = ncsi_send_netlink_rsp(nr, np, nc); 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci return ret; 10928c2ecf20Sopenharmony_ci} 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_cistatic struct ncsi_rsp_handler { 10958c2ecf20Sopenharmony_ci unsigned char type; 10968c2ecf20Sopenharmony_ci int payload; 10978c2ecf20Sopenharmony_ci int (*handler)(struct ncsi_request *nr); 10988c2ecf20Sopenharmony_ci} ncsi_rsp_handlers[] = { 10998c2ecf20Sopenharmony_ci { NCSI_PKT_RSP_CIS, 4, ncsi_rsp_handler_cis }, 11008c2ecf20Sopenharmony_ci { NCSI_PKT_RSP_SP, 4, ncsi_rsp_handler_sp }, 11018c2ecf20Sopenharmony_ci { NCSI_PKT_RSP_DP, 4, ncsi_rsp_handler_dp }, 11028c2ecf20Sopenharmony_ci { NCSI_PKT_RSP_EC, 4, ncsi_rsp_handler_ec }, 11038c2ecf20Sopenharmony_ci { NCSI_PKT_RSP_DC, 4, ncsi_rsp_handler_dc }, 11048c2ecf20Sopenharmony_ci { NCSI_PKT_RSP_RC, 4, ncsi_rsp_handler_rc }, 11058c2ecf20Sopenharmony_ci { NCSI_PKT_RSP_ECNT, 4, ncsi_rsp_handler_ecnt }, 11068c2ecf20Sopenharmony_ci { NCSI_PKT_RSP_DCNT, 4, ncsi_rsp_handler_dcnt }, 11078c2ecf20Sopenharmony_ci { NCSI_PKT_RSP_AE, 4, ncsi_rsp_handler_ae }, 11088c2ecf20Sopenharmony_ci { NCSI_PKT_RSP_SL, 4, ncsi_rsp_handler_sl }, 11098c2ecf20Sopenharmony_ci { NCSI_PKT_RSP_GLS, 16, ncsi_rsp_handler_gls }, 11108c2ecf20Sopenharmony_ci { NCSI_PKT_RSP_SVF, 4, ncsi_rsp_handler_svf }, 11118c2ecf20Sopenharmony_ci { NCSI_PKT_RSP_EV, 4, ncsi_rsp_handler_ev }, 11128c2ecf20Sopenharmony_ci { NCSI_PKT_RSP_DV, 4, ncsi_rsp_handler_dv }, 11138c2ecf20Sopenharmony_ci { NCSI_PKT_RSP_SMA, 4, ncsi_rsp_handler_sma }, 11148c2ecf20Sopenharmony_ci { NCSI_PKT_RSP_EBF, 4, ncsi_rsp_handler_ebf }, 11158c2ecf20Sopenharmony_ci { NCSI_PKT_RSP_DBF, 4, ncsi_rsp_handler_dbf }, 11168c2ecf20Sopenharmony_ci { NCSI_PKT_RSP_EGMF, 4, ncsi_rsp_handler_egmf }, 11178c2ecf20Sopenharmony_ci { NCSI_PKT_RSP_DGMF, 4, ncsi_rsp_handler_dgmf }, 11188c2ecf20Sopenharmony_ci { NCSI_PKT_RSP_SNFC, 4, ncsi_rsp_handler_snfc }, 11198c2ecf20Sopenharmony_ci { NCSI_PKT_RSP_GVI, 40, ncsi_rsp_handler_gvi }, 11208c2ecf20Sopenharmony_ci { NCSI_PKT_RSP_GC, 32, ncsi_rsp_handler_gc }, 11218c2ecf20Sopenharmony_ci { NCSI_PKT_RSP_GP, -1, ncsi_rsp_handler_gp }, 11228c2ecf20Sopenharmony_ci { NCSI_PKT_RSP_GCPS, 204, ncsi_rsp_handler_gcps }, 11238c2ecf20Sopenharmony_ci { NCSI_PKT_RSP_GNS, 32, ncsi_rsp_handler_gns }, 11248c2ecf20Sopenharmony_ci { NCSI_PKT_RSP_GNPTS, 48, ncsi_rsp_handler_gnpts }, 11258c2ecf20Sopenharmony_ci { NCSI_PKT_RSP_GPS, 8, ncsi_rsp_handler_gps }, 11268c2ecf20Sopenharmony_ci { NCSI_PKT_RSP_OEM, -1, ncsi_rsp_handler_oem }, 11278c2ecf20Sopenharmony_ci { NCSI_PKT_RSP_PLDM, -1, ncsi_rsp_handler_pldm }, 11288c2ecf20Sopenharmony_ci { NCSI_PKT_RSP_GPUUID, 20, ncsi_rsp_handler_gpuuid }, 11298c2ecf20Sopenharmony_ci { NCSI_PKT_RSP_QPNPR, -1, ncsi_rsp_handler_pldm }, 11308c2ecf20Sopenharmony_ci { NCSI_PKT_RSP_SNPR, -1, ncsi_rsp_handler_pldm } 11318c2ecf20Sopenharmony_ci}; 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_ciint ncsi_rcv_rsp(struct sk_buff *skb, struct net_device *dev, 11348c2ecf20Sopenharmony_ci struct packet_type *pt, struct net_device *orig_dev) 11358c2ecf20Sopenharmony_ci{ 11368c2ecf20Sopenharmony_ci struct ncsi_rsp_handler *nrh = NULL; 11378c2ecf20Sopenharmony_ci struct ncsi_dev *nd; 11388c2ecf20Sopenharmony_ci struct ncsi_dev_priv *ndp; 11398c2ecf20Sopenharmony_ci struct ncsi_request *nr; 11408c2ecf20Sopenharmony_ci struct ncsi_pkt_hdr *hdr; 11418c2ecf20Sopenharmony_ci unsigned long flags; 11428c2ecf20Sopenharmony_ci int payload, i, ret; 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_ci /* Find the NCSI device */ 11458c2ecf20Sopenharmony_ci nd = ncsi_find_dev(orig_dev); 11468c2ecf20Sopenharmony_ci ndp = nd ? TO_NCSI_DEV_PRIV(nd) : NULL; 11478c2ecf20Sopenharmony_ci if (!ndp) 11488c2ecf20Sopenharmony_ci return -ENODEV; 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci /* Check if it is AEN packet */ 11518c2ecf20Sopenharmony_ci hdr = (struct ncsi_pkt_hdr *)skb_network_header(skb); 11528c2ecf20Sopenharmony_ci if (hdr->type == NCSI_PKT_AEN) 11538c2ecf20Sopenharmony_ci return ncsi_aen_handler(ndp, skb); 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci /* Find the handler */ 11568c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ncsi_rsp_handlers); i++) { 11578c2ecf20Sopenharmony_ci if (ncsi_rsp_handlers[i].type == hdr->type) { 11588c2ecf20Sopenharmony_ci if (ncsi_rsp_handlers[i].handler) 11598c2ecf20Sopenharmony_ci nrh = &ncsi_rsp_handlers[i]; 11608c2ecf20Sopenharmony_ci else 11618c2ecf20Sopenharmony_ci nrh = NULL; 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_ci break; 11648c2ecf20Sopenharmony_ci } 11658c2ecf20Sopenharmony_ci } 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci if (!nrh) { 11688c2ecf20Sopenharmony_ci netdev_err(nd->dev, "Received unrecognized packet (0x%x)\n", 11698c2ecf20Sopenharmony_ci hdr->type); 11708c2ecf20Sopenharmony_ci return -ENOENT; 11718c2ecf20Sopenharmony_ci } 11728c2ecf20Sopenharmony_ci 11738c2ecf20Sopenharmony_ci /* Associate with the request */ 11748c2ecf20Sopenharmony_ci spin_lock_irqsave(&ndp->lock, flags); 11758c2ecf20Sopenharmony_ci nr = &ndp->requests[hdr->id]; 11768c2ecf20Sopenharmony_ci if (!nr->used) { 11778c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ndp->lock, flags); 11788c2ecf20Sopenharmony_ci return -ENODEV; 11798c2ecf20Sopenharmony_ci } 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_ci nr->rsp = skb; 11828c2ecf20Sopenharmony_ci if (!nr->enabled) { 11838c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ndp->lock, flags); 11848c2ecf20Sopenharmony_ci ret = -ENOENT; 11858c2ecf20Sopenharmony_ci goto out; 11868c2ecf20Sopenharmony_ci } 11878c2ecf20Sopenharmony_ci 11888c2ecf20Sopenharmony_ci /* Validate the packet */ 11898c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ndp->lock, flags); 11908c2ecf20Sopenharmony_ci payload = nrh->payload; 11918c2ecf20Sopenharmony_ci if (payload < 0) 11928c2ecf20Sopenharmony_ci payload = ntohs(hdr->length); 11938c2ecf20Sopenharmony_ci ret = ncsi_validate_rsp_pkt(nr, payload); 11948c2ecf20Sopenharmony_ci if (ret) { 11958c2ecf20Sopenharmony_ci netdev_warn(ndp->ndev.dev, 11968c2ecf20Sopenharmony_ci "NCSI: 'bad' packet ignored for type 0x%x\n", 11978c2ecf20Sopenharmony_ci hdr->type); 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_ci if (nr->flags == NCSI_REQ_FLAG_NETLINK_DRIVEN) { 12008c2ecf20Sopenharmony_ci if (ret == -EPERM) 12018c2ecf20Sopenharmony_ci goto out_netlink; 12028c2ecf20Sopenharmony_ci else 12038c2ecf20Sopenharmony_ci ncsi_send_netlink_err(ndp->ndev.dev, 12048c2ecf20Sopenharmony_ci nr->snd_seq, 12058c2ecf20Sopenharmony_ci nr->snd_portid, 12068c2ecf20Sopenharmony_ci &nr->nlhdr, 12078c2ecf20Sopenharmony_ci ret); 12088c2ecf20Sopenharmony_ci } 12098c2ecf20Sopenharmony_ci goto out; 12108c2ecf20Sopenharmony_ci } 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_ci /* Process the packet */ 12138c2ecf20Sopenharmony_ci ret = nrh->handler(nr); 12148c2ecf20Sopenharmony_ci if (ret) 12158c2ecf20Sopenharmony_ci netdev_err(ndp->ndev.dev, 12168c2ecf20Sopenharmony_ci "NCSI: Handler for packet type 0x%x returned %d\n", 12178c2ecf20Sopenharmony_ci hdr->type, ret); 12188c2ecf20Sopenharmony_ci 12198c2ecf20Sopenharmony_ciout_netlink: 12208c2ecf20Sopenharmony_ci if (nr->flags == NCSI_REQ_FLAG_NETLINK_DRIVEN) { 12218c2ecf20Sopenharmony_ci ret = ncsi_rsp_handler_netlink(nr); 12228c2ecf20Sopenharmony_ci if (ret) { 12238c2ecf20Sopenharmony_ci netdev_err(ndp->ndev.dev, 12248c2ecf20Sopenharmony_ci "NCSI: Netlink handler for packet type 0x%x returned %d\n", 12258c2ecf20Sopenharmony_ci hdr->type, ret); 12268c2ecf20Sopenharmony_ci } 12278c2ecf20Sopenharmony_ci } 12288c2ecf20Sopenharmony_ci 12298c2ecf20Sopenharmony_ciout: 12308c2ecf20Sopenharmony_ci ncsi_free_request(nr); 12318c2ecf20Sopenharmony_ci return ret; 12328c2ecf20Sopenharmony_ci} 1233