1138635ccSGavin Shan /* 2138635ccSGavin Shan * Copyright Gavin Shan, IBM Corporation 2016. 3138635ccSGavin Shan * 4138635ccSGavin Shan * This program is free software; you can redistribute it and/or modify 5138635ccSGavin Shan * it under the terms of the GNU General Public License as published by 6138635ccSGavin Shan * the Free Software Foundation; either version 2 of the License, or 7138635ccSGavin Shan * (at your option) any later version. 8138635ccSGavin Shan */ 9138635ccSGavin Shan 10138635ccSGavin Shan #include <linux/module.h> 11138635ccSGavin Shan #include <linux/kernel.h> 12138635ccSGavin Shan #include <linux/init.h> 13138635ccSGavin Shan #include <linux/netdevice.h> 14138635ccSGavin Shan #include <linux/skbuff.h> 15138635ccSGavin Shan 16138635ccSGavin Shan #include <net/ncsi.h> 17138635ccSGavin Shan #include <net/net_namespace.h> 18138635ccSGavin Shan #include <net/sock.h> 19138635ccSGavin Shan 20138635ccSGavin Shan #include "internal.h" 21138635ccSGavin Shan #include "ncsi-pkt.h" 22138635ccSGavin Shan 23138635ccSGavin Shan static int ncsi_validate_rsp_pkt(struct ncsi_request *nr, 24138635ccSGavin Shan unsigned short payload) 25138635ccSGavin Shan { 26138635ccSGavin Shan struct ncsi_rsp_pkt_hdr *h; 27138635ccSGavin Shan u32 checksum; 28138635ccSGavin Shan __be32 *pchecksum; 29138635ccSGavin Shan 30138635ccSGavin Shan /* Check NCSI packet header. We don't need validate 31138635ccSGavin Shan * the packet type, which should have been checked 32138635ccSGavin Shan * before calling this function. 33138635ccSGavin Shan */ 34138635ccSGavin Shan h = (struct ncsi_rsp_pkt_hdr *)skb_network_header(nr->rsp); 35138635ccSGavin Shan if (h->common.revision != NCSI_PKT_REVISION) 36138635ccSGavin Shan return -EINVAL; 37138635ccSGavin Shan if (ntohs(h->common.length) != payload) 38138635ccSGavin Shan return -EINVAL; 39138635ccSGavin Shan 40138635ccSGavin Shan /* Check on code and reason */ 41138635ccSGavin Shan if (ntohs(h->code) != NCSI_PKT_RSP_C_COMPLETED || 42138635ccSGavin Shan ntohs(h->reason) != NCSI_PKT_RSP_R_NO_ERROR) 43138635ccSGavin Shan return -EINVAL; 44138635ccSGavin Shan 45138635ccSGavin Shan /* Validate checksum, which might be zeroes if the 46138635ccSGavin Shan * sender doesn't support checksum according to NCSI 47138635ccSGavin Shan * specification. 48138635ccSGavin Shan */ 49138635ccSGavin Shan pchecksum = (__be32 *)((void *)(h + 1) + payload - 4); 50138635ccSGavin Shan if (ntohl(*pchecksum) == 0) 51138635ccSGavin Shan return 0; 52138635ccSGavin Shan 53138635ccSGavin Shan checksum = ncsi_calculate_checksum((unsigned char *)h, 54138635ccSGavin Shan sizeof(*h) + payload - 4); 55138635ccSGavin Shan if (*pchecksum != htonl(checksum)) 56138635ccSGavin Shan return -EINVAL; 57138635ccSGavin Shan 58138635ccSGavin Shan return 0; 59138635ccSGavin Shan } 60138635ccSGavin Shan 61138635ccSGavin Shan static int ncsi_rsp_handler_cis(struct ncsi_request *nr) 62138635ccSGavin Shan { 63138635ccSGavin Shan struct ncsi_rsp_pkt *rsp; 64138635ccSGavin Shan struct ncsi_dev_priv *ndp = nr->ndp; 65138635ccSGavin Shan struct ncsi_package *np; 66138635ccSGavin Shan struct ncsi_channel *nc; 67138635ccSGavin Shan unsigned char id; 68138635ccSGavin Shan 69138635ccSGavin Shan rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp); 70138635ccSGavin Shan ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, &np, &nc); 71138635ccSGavin Shan if (!nc) { 72e6f44ed6SGavin Shan if (ndp->flags & NCSI_DEV_PROBED) 73e6f44ed6SGavin Shan return -ENXIO; 74e6f44ed6SGavin Shan 75138635ccSGavin Shan id = NCSI_CHANNEL_INDEX(rsp->rsp.common.channel); 76138635ccSGavin Shan nc = ncsi_add_channel(np, id); 77138635ccSGavin Shan } 78138635ccSGavin Shan 79138635ccSGavin Shan return nc ? 0 : -ENODEV; 80138635ccSGavin Shan } 81138635ccSGavin Shan 82138635ccSGavin Shan static int ncsi_rsp_handler_sp(struct ncsi_request *nr) 83138635ccSGavin Shan { 84138635ccSGavin Shan struct ncsi_rsp_pkt *rsp; 85138635ccSGavin Shan struct ncsi_dev_priv *ndp = nr->ndp; 86138635ccSGavin Shan struct ncsi_package *np; 87138635ccSGavin Shan unsigned char id; 88138635ccSGavin Shan 89138635ccSGavin Shan /* Add the package if it's not existing. Otherwise, 90138635ccSGavin Shan * to change the state of its child channels. 91138635ccSGavin Shan */ 92138635ccSGavin Shan rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp); 93138635ccSGavin Shan ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, 94138635ccSGavin Shan &np, NULL); 95138635ccSGavin Shan if (!np) { 96e6f44ed6SGavin Shan if (ndp->flags & NCSI_DEV_PROBED) 97e6f44ed6SGavin Shan return -ENXIO; 98e6f44ed6SGavin Shan 99138635ccSGavin Shan id = NCSI_PACKAGE_INDEX(rsp->rsp.common.channel); 100138635ccSGavin Shan np = ncsi_add_package(ndp, id); 101138635ccSGavin Shan if (!np) 102138635ccSGavin Shan return -ENODEV; 103138635ccSGavin Shan } 104138635ccSGavin Shan 105138635ccSGavin Shan return 0; 106138635ccSGavin Shan } 107138635ccSGavin Shan 108138635ccSGavin Shan static int ncsi_rsp_handler_dp(struct ncsi_request *nr) 109138635ccSGavin Shan { 110138635ccSGavin Shan struct ncsi_rsp_pkt *rsp; 111138635ccSGavin Shan struct ncsi_dev_priv *ndp = nr->ndp; 112138635ccSGavin Shan struct ncsi_package *np; 113138635ccSGavin Shan struct ncsi_channel *nc; 114138635ccSGavin Shan unsigned long flags; 115138635ccSGavin Shan 116138635ccSGavin Shan /* Find the package */ 117138635ccSGavin Shan rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp); 118138635ccSGavin Shan ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, 119138635ccSGavin Shan &np, NULL); 120138635ccSGavin Shan if (!np) 121138635ccSGavin Shan return -ENODEV; 122138635ccSGavin Shan 123138635ccSGavin Shan /* Change state of all channels attached to the package */ 124138635ccSGavin Shan NCSI_FOR_EACH_CHANNEL(np, nc) { 125138635ccSGavin Shan spin_lock_irqsave(&nc->lock, flags); 126138635ccSGavin Shan nc->state = NCSI_CHANNEL_INACTIVE; 127138635ccSGavin Shan spin_unlock_irqrestore(&nc->lock, flags); 128138635ccSGavin Shan } 129138635ccSGavin Shan 130138635ccSGavin Shan return 0; 131138635ccSGavin Shan } 132138635ccSGavin Shan 133138635ccSGavin Shan static int ncsi_rsp_handler_ec(struct ncsi_request *nr) 134138635ccSGavin Shan { 135138635ccSGavin Shan struct ncsi_rsp_pkt *rsp; 136138635ccSGavin Shan struct ncsi_dev_priv *ndp = nr->ndp; 137138635ccSGavin Shan struct ncsi_channel *nc; 138138635ccSGavin Shan struct ncsi_channel_mode *ncm; 139138635ccSGavin Shan 140138635ccSGavin Shan /* Find the package and channel */ 141138635ccSGavin Shan rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp); 142138635ccSGavin Shan ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, 143138635ccSGavin Shan NULL, &nc); 144138635ccSGavin Shan if (!nc) 145138635ccSGavin Shan return -ENODEV; 146138635ccSGavin Shan 147138635ccSGavin Shan ncm = &nc->modes[NCSI_MODE_ENABLE]; 148138635ccSGavin Shan if (ncm->enable) 149138635ccSGavin Shan return -EBUSY; 150138635ccSGavin Shan 151138635ccSGavin Shan ncm->enable = 1; 152138635ccSGavin Shan return 0; 153138635ccSGavin Shan } 154138635ccSGavin Shan 155138635ccSGavin Shan static int ncsi_rsp_handler_dc(struct ncsi_request *nr) 156138635ccSGavin Shan { 157138635ccSGavin Shan struct ncsi_rsp_pkt *rsp; 158138635ccSGavin Shan struct ncsi_dev_priv *ndp = nr->ndp; 159138635ccSGavin Shan struct ncsi_channel *nc; 160138635ccSGavin Shan struct ncsi_channel_mode *ncm; 161138635ccSGavin Shan int ret; 162138635ccSGavin Shan 163138635ccSGavin Shan ret = ncsi_validate_rsp_pkt(nr, 4); 164138635ccSGavin Shan if (ret) 165138635ccSGavin Shan return ret; 166138635ccSGavin Shan 167138635ccSGavin Shan /* Find the package and channel */ 168138635ccSGavin Shan rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp); 169138635ccSGavin Shan ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, 170138635ccSGavin Shan NULL, &nc); 171138635ccSGavin Shan if (!nc) 172138635ccSGavin Shan return -ENODEV; 173138635ccSGavin Shan 174138635ccSGavin Shan ncm = &nc->modes[NCSI_MODE_ENABLE]; 175138635ccSGavin Shan if (!ncm->enable) 176138635ccSGavin Shan return -EBUSY; 177138635ccSGavin Shan 178138635ccSGavin Shan ncm->enable = 0; 179138635ccSGavin Shan return 0; 180138635ccSGavin Shan } 181138635ccSGavin Shan 182138635ccSGavin Shan static int ncsi_rsp_handler_rc(struct ncsi_request *nr) 183138635ccSGavin Shan { 184138635ccSGavin Shan struct ncsi_rsp_pkt *rsp; 185138635ccSGavin Shan struct ncsi_dev_priv *ndp = nr->ndp; 186138635ccSGavin Shan struct ncsi_channel *nc; 187138635ccSGavin Shan unsigned long flags; 188138635ccSGavin Shan 189138635ccSGavin Shan /* Find the package and channel */ 190138635ccSGavin Shan rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp); 191138635ccSGavin Shan ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, 192138635ccSGavin Shan NULL, &nc); 193138635ccSGavin Shan if (!nc) 194138635ccSGavin Shan return -ENODEV; 195138635ccSGavin Shan 196138635ccSGavin Shan /* Update state for the specified channel */ 197138635ccSGavin Shan spin_lock_irqsave(&nc->lock, flags); 198138635ccSGavin Shan nc->state = NCSI_CHANNEL_INACTIVE; 199138635ccSGavin Shan spin_unlock_irqrestore(&nc->lock, flags); 200138635ccSGavin Shan 201138635ccSGavin Shan return 0; 202138635ccSGavin Shan } 203138635ccSGavin Shan 204138635ccSGavin Shan static int ncsi_rsp_handler_ecnt(struct ncsi_request *nr) 205138635ccSGavin Shan { 206138635ccSGavin Shan struct ncsi_rsp_pkt *rsp; 207138635ccSGavin Shan struct ncsi_dev_priv *ndp = nr->ndp; 208138635ccSGavin Shan struct ncsi_channel *nc; 209138635ccSGavin Shan struct ncsi_channel_mode *ncm; 210138635ccSGavin Shan 211138635ccSGavin Shan /* Find the package and channel */ 212138635ccSGavin Shan rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp); 213138635ccSGavin Shan ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, 214138635ccSGavin Shan NULL, &nc); 215138635ccSGavin Shan if (!nc) 216138635ccSGavin Shan return -ENODEV; 217138635ccSGavin Shan 218138635ccSGavin Shan ncm = &nc->modes[NCSI_MODE_TX_ENABLE]; 219138635ccSGavin Shan if (ncm->enable) 220138635ccSGavin Shan return -EBUSY; 221138635ccSGavin Shan 222138635ccSGavin Shan ncm->enable = 1; 223138635ccSGavin Shan return 0; 224138635ccSGavin Shan } 225138635ccSGavin Shan 226138635ccSGavin Shan static int ncsi_rsp_handler_dcnt(struct ncsi_request *nr) 227138635ccSGavin Shan { 228138635ccSGavin Shan struct ncsi_rsp_pkt *rsp; 229138635ccSGavin Shan struct ncsi_dev_priv *ndp = nr->ndp; 230138635ccSGavin Shan struct ncsi_channel *nc; 231138635ccSGavin Shan struct ncsi_channel_mode *ncm; 232138635ccSGavin Shan 233138635ccSGavin Shan /* Find the package and channel */ 234138635ccSGavin Shan rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp); 235138635ccSGavin Shan ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, 236138635ccSGavin Shan NULL, &nc); 237138635ccSGavin Shan if (!nc) 238138635ccSGavin Shan return -ENODEV; 239138635ccSGavin Shan 240138635ccSGavin Shan ncm = &nc->modes[NCSI_MODE_TX_ENABLE]; 241138635ccSGavin Shan if (!ncm->enable) 242138635ccSGavin Shan return -EBUSY; 243138635ccSGavin Shan 244138635ccSGavin Shan ncm->enable = 1; 245138635ccSGavin Shan return 0; 246138635ccSGavin Shan } 247138635ccSGavin Shan 248138635ccSGavin Shan static int ncsi_rsp_handler_ae(struct ncsi_request *nr) 249138635ccSGavin Shan { 250138635ccSGavin Shan struct ncsi_cmd_ae_pkt *cmd; 251138635ccSGavin Shan struct ncsi_rsp_pkt *rsp; 252138635ccSGavin Shan struct ncsi_dev_priv *ndp = nr->ndp; 253138635ccSGavin Shan struct ncsi_channel *nc; 254138635ccSGavin Shan struct ncsi_channel_mode *ncm; 255138635ccSGavin Shan 256138635ccSGavin Shan /* Find the package and channel */ 257138635ccSGavin Shan rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp); 258138635ccSGavin Shan ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, 259138635ccSGavin Shan NULL, &nc); 260138635ccSGavin Shan if (!nc) 261138635ccSGavin Shan return -ENODEV; 262138635ccSGavin Shan 263138635ccSGavin Shan /* Check if the AEN has been enabled */ 264138635ccSGavin Shan ncm = &nc->modes[NCSI_MODE_AEN]; 265138635ccSGavin Shan if (ncm->enable) 266138635ccSGavin Shan return -EBUSY; 267138635ccSGavin Shan 268138635ccSGavin Shan /* Update to AEN configuration */ 269138635ccSGavin Shan cmd = (struct ncsi_cmd_ae_pkt *)skb_network_header(nr->cmd); 270138635ccSGavin Shan ncm->enable = 1; 271138635ccSGavin Shan ncm->data[0] = cmd->mc_id; 272138635ccSGavin Shan ncm->data[1] = ntohl(cmd->mode); 273138635ccSGavin Shan 274138635ccSGavin Shan return 0; 275138635ccSGavin Shan } 276138635ccSGavin Shan 277138635ccSGavin Shan static int ncsi_rsp_handler_sl(struct ncsi_request *nr) 278138635ccSGavin Shan { 279138635ccSGavin Shan struct ncsi_cmd_sl_pkt *cmd; 280138635ccSGavin Shan struct ncsi_rsp_pkt *rsp; 281138635ccSGavin Shan struct ncsi_dev_priv *ndp = nr->ndp; 282138635ccSGavin Shan struct ncsi_channel *nc; 283138635ccSGavin Shan struct ncsi_channel_mode *ncm; 284138635ccSGavin Shan 285138635ccSGavin Shan /* Find the package and channel */ 286138635ccSGavin Shan rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp); 287138635ccSGavin Shan ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, 288138635ccSGavin Shan NULL, &nc); 289138635ccSGavin Shan if (!nc) 290138635ccSGavin Shan return -ENODEV; 291138635ccSGavin Shan 292138635ccSGavin Shan cmd = (struct ncsi_cmd_sl_pkt *)skb_network_header(nr->cmd); 293138635ccSGavin Shan ncm = &nc->modes[NCSI_MODE_LINK]; 294138635ccSGavin Shan ncm->data[0] = ntohl(cmd->mode); 295138635ccSGavin Shan ncm->data[1] = ntohl(cmd->oem_mode); 296138635ccSGavin Shan 297138635ccSGavin Shan return 0; 298138635ccSGavin Shan } 299138635ccSGavin Shan 300138635ccSGavin Shan static int ncsi_rsp_handler_gls(struct ncsi_request *nr) 301138635ccSGavin Shan { 302138635ccSGavin Shan struct ncsi_rsp_gls_pkt *rsp; 303138635ccSGavin Shan struct ncsi_dev_priv *ndp = nr->ndp; 304138635ccSGavin Shan struct ncsi_channel *nc; 305138635ccSGavin Shan struct ncsi_channel_mode *ncm; 306e6f44ed6SGavin Shan unsigned long flags; 307138635ccSGavin Shan 308138635ccSGavin Shan /* Find the package and channel */ 309138635ccSGavin Shan rsp = (struct ncsi_rsp_gls_pkt *)skb_network_header(nr->rsp); 310138635ccSGavin Shan ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, 311138635ccSGavin Shan NULL, &nc); 312138635ccSGavin Shan if (!nc) 313138635ccSGavin Shan return -ENODEV; 314138635ccSGavin Shan 315138635ccSGavin Shan ncm = &nc->modes[NCSI_MODE_LINK]; 316138635ccSGavin Shan ncm->data[2] = ntohl(rsp->status); 317138635ccSGavin Shan ncm->data[3] = ntohl(rsp->other); 318138635ccSGavin Shan ncm->data[4] = ntohl(rsp->oem_status); 319138635ccSGavin Shan 320a0509cbeSGavin Shan if (nr->flags & NCSI_REQ_FLAG_EVENT_DRIVEN) 321e6f44ed6SGavin Shan return 0; 322e6f44ed6SGavin Shan 323e6f44ed6SGavin Shan /* Reset the channel monitor if it has been enabled */ 324e6f44ed6SGavin Shan spin_lock_irqsave(&nc->lock, flags); 32583afdc6aSGavin Shan nc->monitor.state = NCSI_CHANNEL_MONITOR_START; 326e6f44ed6SGavin Shan spin_unlock_irqrestore(&nc->lock, flags); 327e6f44ed6SGavin Shan 328138635ccSGavin Shan return 0; 329138635ccSGavin Shan } 330138635ccSGavin Shan 331138635ccSGavin Shan static int ncsi_rsp_handler_svf(struct ncsi_request *nr) 332138635ccSGavin Shan { 333138635ccSGavin Shan struct ncsi_cmd_svf_pkt *cmd; 334138635ccSGavin Shan struct ncsi_rsp_pkt *rsp; 335138635ccSGavin Shan struct ncsi_dev_priv *ndp = nr->ndp; 336138635ccSGavin Shan struct ncsi_channel *nc; 337138635ccSGavin Shan struct ncsi_channel_filter *ncf; 338138635ccSGavin Shan unsigned short vlan; 339138635ccSGavin Shan int ret; 340138635ccSGavin Shan 341138635ccSGavin Shan /* Find the package and channel */ 342138635ccSGavin Shan rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp); 343138635ccSGavin Shan ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, 344138635ccSGavin Shan NULL, &nc); 345138635ccSGavin Shan if (!nc) 346138635ccSGavin Shan return -ENODEV; 347138635ccSGavin Shan 348138635ccSGavin Shan cmd = (struct ncsi_cmd_svf_pkt *)skb_network_header(nr->cmd); 349138635ccSGavin Shan ncf = nc->filters[NCSI_FILTER_VLAN]; 350138635ccSGavin Shan if (!ncf) 351138635ccSGavin Shan return -ENOENT; 352138635ccSGavin Shan if (cmd->index >= ncf->total) 353138635ccSGavin Shan return -ERANGE; 354138635ccSGavin Shan 355138635ccSGavin Shan /* Add or remove the VLAN filter */ 356138635ccSGavin Shan if (!(cmd->enable & 0x1)) { 3578579a67eSSamuel Mendoza-Jonas /* HW indexes from 1 */ 3588579a67eSSamuel Mendoza-Jonas ret = ncsi_remove_filter(nc, NCSI_FILTER_VLAN, cmd->index - 1); 359138635ccSGavin Shan } else { 360138635ccSGavin Shan vlan = ntohs(cmd->vlan); 361138635ccSGavin Shan ret = ncsi_add_filter(nc, NCSI_FILTER_VLAN, &vlan); 362138635ccSGavin Shan } 363138635ccSGavin Shan 364138635ccSGavin Shan return ret; 365138635ccSGavin Shan } 366138635ccSGavin Shan 367138635ccSGavin Shan static int ncsi_rsp_handler_ev(struct ncsi_request *nr) 368138635ccSGavin Shan { 369138635ccSGavin Shan struct ncsi_cmd_ev_pkt *cmd; 370138635ccSGavin Shan struct ncsi_rsp_pkt *rsp; 371138635ccSGavin Shan struct ncsi_dev_priv *ndp = nr->ndp; 372138635ccSGavin Shan struct ncsi_channel *nc; 373138635ccSGavin Shan struct ncsi_channel_mode *ncm; 374138635ccSGavin Shan 375138635ccSGavin Shan /* Find the package and channel */ 376138635ccSGavin Shan rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp); 377138635ccSGavin Shan ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, 378138635ccSGavin Shan NULL, &nc); 379138635ccSGavin Shan if (!nc) 380138635ccSGavin Shan return -ENODEV; 381138635ccSGavin Shan 382138635ccSGavin Shan /* Check if VLAN mode has been enabled */ 383138635ccSGavin Shan ncm = &nc->modes[NCSI_MODE_VLAN]; 384138635ccSGavin Shan if (ncm->enable) 385138635ccSGavin Shan return -EBUSY; 386138635ccSGavin Shan 387138635ccSGavin Shan /* Update to VLAN mode */ 388138635ccSGavin Shan cmd = (struct ncsi_cmd_ev_pkt *)skb_network_header(nr->cmd); 389138635ccSGavin Shan ncm->enable = 1; 390138635ccSGavin Shan ncm->data[0] = ntohl(cmd->mode); 391138635ccSGavin Shan 392138635ccSGavin Shan return 0; 393138635ccSGavin Shan } 394138635ccSGavin Shan 395138635ccSGavin Shan static int ncsi_rsp_handler_dv(struct ncsi_request *nr) 396138635ccSGavin Shan { 397138635ccSGavin Shan struct ncsi_rsp_pkt *rsp; 398138635ccSGavin Shan struct ncsi_dev_priv *ndp = nr->ndp; 399138635ccSGavin Shan struct ncsi_channel *nc; 400138635ccSGavin Shan struct ncsi_channel_mode *ncm; 401138635ccSGavin Shan 402138635ccSGavin Shan /* Find the package and channel */ 403138635ccSGavin Shan rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp); 404138635ccSGavin Shan ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, 405138635ccSGavin Shan NULL, &nc); 406138635ccSGavin Shan if (!nc) 407138635ccSGavin Shan return -ENODEV; 408138635ccSGavin Shan 409138635ccSGavin Shan /* Check if VLAN mode has been enabled */ 410138635ccSGavin Shan ncm = &nc->modes[NCSI_MODE_VLAN]; 411138635ccSGavin Shan if (!ncm->enable) 412138635ccSGavin Shan return -EBUSY; 413138635ccSGavin Shan 414138635ccSGavin Shan /* Update to VLAN mode */ 415138635ccSGavin Shan ncm->enable = 0; 416138635ccSGavin Shan return 0; 417138635ccSGavin Shan } 418138635ccSGavin Shan 419138635ccSGavin Shan static int ncsi_rsp_handler_sma(struct ncsi_request *nr) 420138635ccSGavin Shan { 421138635ccSGavin Shan struct ncsi_cmd_sma_pkt *cmd; 422138635ccSGavin Shan struct ncsi_rsp_pkt *rsp; 423138635ccSGavin Shan struct ncsi_dev_priv *ndp = nr->ndp; 424138635ccSGavin Shan struct ncsi_channel *nc; 425138635ccSGavin Shan struct ncsi_channel_filter *ncf; 426138635ccSGavin Shan void *bitmap; 427138635ccSGavin Shan 428138635ccSGavin Shan /* Find the package and channel */ 429138635ccSGavin Shan rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp); 430138635ccSGavin Shan ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, 431138635ccSGavin Shan NULL, &nc); 432138635ccSGavin Shan if (!nc) 433138635ccSGavin Shan return -ENODEV; 434138635ccSGavin Shan 435138635ccSGavin Shan /* According to NCSI spec 1.01, the mixed filter table 436138635ccSGavin Shan * isn't supported yet. 437138635ccSGavin Shan */ 438138635ccSGavin Shan cmd = (struct ncsi_cmd_sma_pkt *)skb_network_header(nr->cmd); 439138635ccSGavin Shan switch (cmd->at_e >> 5) { 440138635ccSGavin Shan case 0x0: /* UC address */ 441138635ccSGavin Shan ncf = nc->filters[NCSI_FILTER_UC]; 442138635ccSGavin Shan break; 443138635ccSGavin Shan case 0x1: /* MC address */ 444138635ccSGavin Shan ncf = nc->filters[NCSI_FILTER_MC]; 445138635ccSGavin Shan break; 446138635ccSGavin Shan default: 447138635ccSGavin Shan return -EINVAL; 448138635ccSGavin Shan } 449138635ccSGavin Shan 450138635ccSGavin Shan /* Sanity check on the filter */ 451138635ccSGavin Shan if (!ncf) 452138635ccSGavin Shan return -ENOENT; 453138635ccSGavin Shan else if (cmd->index >= ncf->total) 454138635ccSGavin Shan return -ERANGE; 455138635ccSGavin Shan 456138635ccSGavin Shan bitmap = &ncf->bitmap; 457138635ccSGavin Shan if (cmd->at_e & 0x1) { 458138635ccSGavin Shan if (test_and_set_bit(cmd->index, bitmap)) 459138635ccSGavin Shan return -EBUSY; 460138635ccSGavin Shan memcpy(ncf->data + 6 * cmd->index, cmd->mac, 6); 461138635ccSGavin Shan } else { 462138635ccSGavin Shan if (!test_and_clear_bit(cmd->index, bitmap)) 463138635ccSGavin Shan return -EBUSY; 464138635ccSGavin Shan 465138635ccSGavin Shan memset(ncf->data + 6 * cmd->index, 0, 6); 466138635ccSGavin Shan } 467138635ccSGavin Shan 468138635ccSGavin Shan return 0; 469138635ccSGavin Shan } 470138635ccSGavin Shan 471138635ccSGavin Shan static int ncsi_rsp_handler_ebf(struct ncsi_request *nr) 472138635ccSGavin Shan { 473138635ccSGavin Shan struct ncsi_cmd_ebf_pkt *cmd; 474138635ccSGavin Shan struct ncsi_rsp_pkt *rsp; 475138635ccSGavin Shan struct ncsi_dev_priv *ndp = nr->ndp; 476138635ccSGavin Shan struct ncsi_channel *nc; 477138635ccSGavin Shan struct ncsi_channel_mode *ncm; 478138635ccSGavin Shan 479138635ccSGavin Shan /* Find the package and channel */ 480138635ccSGavin Shan rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp); 481138635ccSGavin Shan ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, NULL, &nc); 482138635ccSGavin Shan if (!nc) 483138635ccSGavin Shan return -ENODEV; 484138635ccSGavin Shan 485138635ccSGavin Shan /* Check if broadcast filter has been enabled */ 486138635ccSGavin Shan ncm = &nc->modes[NCSI_MODE_BC]; 487138635ccSGavin Shan if (ncm->enable) 488138635ccSGavin Shan return -EBUSY; 489138635ccSGavin Shan 490138635ccSGavin Shan /* Update to broadcast filter mode */ 491138635ccSGavin Shan cmd = (struct ncsi_cmd_ebf_pkt *)skb_network_header(nr->cmd); 492138635ccSGavin Shan ncm->enable = 1; 493138635ccSGavin Shan ncm->data[0] = ntohl(cmd->mode); 494138635ccSGavin Shan 495138635ccSGavin Shan return 0; 496138635ccSGavin Shan } 497138635ccSGavin Shan 498138635ccSGavin Shan static int ncsi_rsp_handler_dbf(struct ncsi_request *nr) 499138635ccSGavin Shan { 500138635ccSGavin Shan struct ncsi_rsp_pkt *rsp; 501138635ccSGavin Shan struct ncsi_dev_priv *ndp = nr->ndp; 502138635ccSGavin Shan struct ncsi_channel *nc; 503138635ccSGavin Shan struct ncsi_channel_mode *ncm; 504138635ccSGavin Shan 505138635ccSGavin Shan rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp); 506138635ccSGavin Shan ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, 507138635ccSGavin Shan NULL, &nc); 508138635ccSGavin Shan if (!nc) 509138635ccSGavin Shan return -ENODEV; 510138635ccSGavin Shan 511138635ccSGavin Shan /* Check if broadcast filter isn't enabled */ 512138635ccSGavin Shan ncm = &nc->modes[NCSI_MODE_BC]; 513138635ccSGavin Shan if (!ncm->enable) 514138635ccSGavin Shan return -EBUSY; 515138635ccSGavin Shan 516138635ccSGavin Shan /* Update to broadcast filter mode */ 517138635ccSGavin Shan ncm->enable = 0; 518138635ccSGavin Shan ncm->data[0] = 0; 519138635ccSGavin Shan 520138635ccSGavin Shan return 0; 521138635ccSGavin Shan } 522138635ccSGavin Shan 523138635ccSGavin Shan static int ncsi_rsp_handler_egmf(struct ncsi_request *nr) 524138635ccSGavin Shan { 525138635ccSGavin Shan struct ncsi_cmd_egmf_pkt *cmd; 526138635ccSGavin Shan struct ncsi_rsp_pkt *rsp; 527138635ccSGavin Shan struct ncsi_dev_priv *ndp = nr->ndp; 528138635ccSGavin Shan struct ncsi_channel *nc; 529138635ccSGavin Shan struct ncsi_channel_mode *ncm; 530138635ccSGavin Shan 531138635ccSGavin Shan /* Find the channel */ 532138635ccSGavin Shan rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp); 533138635ccSGavin Shan ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, 534138635ccSGavin Shan NULL, &nc); 535138635ccSGavin Shan if (!nc) 536138635ccSGavin Shan return -ENODEV; 537138635ccSGavin Shan 538138635ccSGavin Shan /* Check if multicast filter has been enabled */ 539138635ccSGavin Shan ncm = &nc->modes[NCSI_MODE_MC]; 540138635ccSGavin Shan if (ncm->enable) 541138635ccSGavin Shan return -EBUSY; 542138635ccSGavin Shan 543138635ccSGavin Shan /* Update to multicast filter mode */ 544138635ccSGavin Shan cmd = (struct ncsi_cmd_egmf_pkt *)skb_network_header(nr->cmd); 545138635ccSGavin Shan ncm->enable = 1; 546138635ccSGavin Shan ncm->data[0] = ntohl(cmd->mode); 547138635ccSGavin Shan 548138635ccSGavin Shan return 0; 549138635ccSGavin Shan } 550138635ccSGavin Shan 551138635ccSGavin Shan static int ncsi_rsp_handler_dgmf(struct ncsi_request *nr) 552138635ccSGavin Shan { 553138635ccSGavin Shan struct ncsi_rsp_pkt *rsp; 554138635ccSGavin Shan struct ncsi_dev_priv *ndp = nr->ndp; 555138635ccSGavin Shan struct ncsi_channel *nc; 556138635ccSGavin Shan struct ncsi_channel_mode *ncm; 557138635ccSGavin Shan 558138635ccSGavin Shan rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp); 559138635ccSGavin Shan ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, 560138635ccSGavin Shan NULL, &nc); 561138635ccSGavin Shan if (!nc) 562138635ccSGavin Shan return -ENODEV; 563138635ccSGavin Shan 564138635ccSGavin Shan /* Check if multicast filter has been enabled */ 565138635ccSGavin Shan ncm = &nc->modes[NCSI_MODE_MC]; 566138635ccSGavin Shan if (!ncm->enable) 567138635ccSGavin Shan return -EBUSY; 568138635ccSGavin Shan 569138635ccSGavin Shan /* Update to multicast filter mode */ 570138635ccSGavin Shan ncm->enable = 0; 571138635ccSGavin Shan ncm->data[0] = 0; 572138635ccSGavin Shan 573138635ccSGavin Shan return 0; 574138635ccSGavin Shan } 575138635ccSGavin Shan 576138635ccSGavin Shan static int ncsi_rsp_handler_snfc(struct ncsi_request *nr) 577138635ccSGavin Shan { 578138635ccSGavin Shan struct ncsi_cmd_snfc_pkt *cmd; 579138635ccSGavin Shan struct ncsi_rsp_pkt *rsp; 580138635ccSGavin Shan struct ncsi_dev_priv *ndp = nr->ndp; 581138635ccSGavin Shan struct ncsi_channel *nc; 582138635ccSGavin Shan struct ncsi_channel_mode *ncm; 583138635ccSGavin Shan 584138635ccSGavin Shan /* Find the channel */ 585138635ccSGavin Shan rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp); 586138635ccSGavin Shan ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, 587138635ccSGavin Shan NULL, &nc); 588138635ccSGavin Shan if (!nc) 589138635ccSGavin Shan return -ENODEV; 590138635ccSGavin Shan 591138635ccSGavin Shan /* Check if flow control has been enabled */ 592138635ccSGavin Shan ncm = &nc->modes[NCSI_MODE_FC]; 593138635ccSGavin Shan if (ncm->enable) 594138635ccSGavin Shan return -EBUSY; 595138635ccSGavin Shan 596138635ccSGavin Shan /* Update to flow control mode */ 597138635ccSGavin Shan cmd = (struct ncsi_cmd_snfc_pkt *)skb_network_header(nr->cmd); 598138635ccSGavin Shan ncm->enable = 1; 599138635ccSGavin Shan ncm->data[0] = cmd->mode; 600138635ccSGavin Shan 601138635ccSGavin Shan return 0; 602138635ccSGavin Shan } 603138635ccSGavin Shan 604138635ccSGavin Shan static int ncsi_rsp_handler_gvi(struct ncsi_request *nr) 605138635ccSGavin Shan { 606138635ccSGavin Shan struct ncsi_rsp_gvi_pkt *rsp; 607138635ccSGavin Shan struct ncsi_dev_priv *ndp = nr->ndp; 608138635ccSGavin Shan struct ncsi_channel *nc; 609138635ccSGavin Shan struct ncsi_channel_version *ncv; 610138635ccSGavin Shan int i; 611138635ccSGavin Shan 612138635ccSGavin Shan /* Find the channel */ 613138635ccSGavin Shan rsp = (struct ncsi_rsp_gvi_pkt *)skb_network_header(nr->rsp); 614138635ccSGavin Shan ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, 615138635ccSGavin Shan NULL, &nc); 616138635ccSGavin Shan if (!nc) 617138635ccSGavin Shan return -ENODEV; 618138635ccSGavin Shan 619138635ccSGavin Shan /* Update to channel's version info */ 620138635ccSGavin Shan ncv = &nc->version; 621138635ccSGavin Shan ncv->version = ntohl(rsp->ncsi_version); 622138635ccSGavin Shan ncv->alpha2 = rsp->alpha2; 623138635ccSGavin Shan memcpy(ncv->fw_name, rsp->fw_name, 12); 624138635ccSGavin Shan ncv->fw_version = ntohl(rsp->fw_version); 625138635ccSGavin Shan for (i = 0; i < ARRAY_SIZE(ncv->pci_ids); i++) 626138635ccSGavin Shan ncv->pci_ids[i] = ntohs(rsp->pci_ids[i]); 627138635ccSGavin Shan ncv->mf_id = ntohl(rsp->mf_id); 628138635ccSGavin Shan 629138635ccSGavin Shan return 0; 630138635ccSGavin Shan } 631138635ccSGavin Shan 632138635ccSGavin Shan static int ncsi_rsp_handler_gc(struct ncsi_request *nr) 633138635ccSGavin Shan { 634138635ccSGavin Shan struct ncsi_rsp_gc_pkt *rsp; 635138635ccSGavin Shan struct ncsi_dev_priv *ndp = nr->ndp; 636138635ccSGavin Shan struct ncsi_channel *nc; 637138635ccSGavin Shan struct ncsi_channel_filter *ncf; 638138635ccSGavin Shan size_t size, entry_size; 639138635ccSGavin Shan int cnt, i; 640138635ccSGavin Shan 641138635ccSGavin Shan /* Find the channel */ 642138635ccSGavin Shan rsp = (struct ncsi_rsp_gc_pkt *)skb_network_header(nr->rsp); 643138635ccSGavin Shan ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, 644138635ccSGavin Shan NULL, &nc); 645138635ccSGavin Shan if (!nc) 646138635ccSGavin Shan return -ENODEV; 647138635ccSGavin Shan 648138635ccSGavin Shan /* Update channel's capabilities */ 649138635ccSGavin Shan nc->caps[NCSI_CAP_GENERIC].cap = ntohl(rsp->cap) & 650138635ccSGavin Shan NCSI_CAP_GENERIC_MASK; 651138635ccSGavin Shan nc->caps[NCSI_CAP_BC].cap = ntohl(rsp->bc_cap) & 652138635ccSGavin Shan NCSI_CAP_BC_MASK; 653138635ccSGavin Shan nc->caps[NCSI_CAP_MC].cap = ntohl(rsp->mc_cap) & 654138635ccSGavin Shan NCSI_CAP_MC_MASK; 655138635ccSGavin Shan nc->caps[NCSI_CAP_BUFFER].cap = ntohl(rsp->buf_cap); 656138635ccSGavin Shan nc->caps[NCSI_CAP_AEN].cap = ntohl(rsp->aen_cap) & 657138635ccSGavin Shan NCSI_CAP_AEN_MASK; 658138635ccSGavin Shan nc->caps[NCSI_CAP_VLAN].cap = rsp->vlan_mode & 659138635ccSGavin Shan NCSI_CAP_VLAN_MASK; 660138635ccSGavin Shan 661138635ccSGavin Shan /* Build filters */ 662138635ccSGavin Shan for (i = 0; i < NCSI_FILTER_MAX; i++) { 663138635ccSGavin Shan switch (i) { 664138635ccSGavin Shan case NCSI_FILTER_VLAN: 665138635ccSGavin Shan cnt = rsp->vlan_cnt; 666138635ccSGavin Shan entry_size = 2; 667138635ccSGavin Shan break; 668138635ccSGavin Shan case NCSI_FILTER_MIXED: 669138635ccSGavin Shan cnt = rsp->mixed_cnt; 670138635ccSGavin Shan entry_size = 6; 671138635ccSGavin Shan break; 672138635ccSGavin Shan case NCSI_FILTER_MC: 673138635ccSGavin Shan cnt = rsp->mc_cnt; 674138635ccSGavin Shan entry_size = 6; 675138635ccSGavin Shan break; 676138635ccSGavin Shan case NCSI_FILTER_UC: 677138635ccSGavin Shan cnt = rsp->uc_cnt; 678138635ccSGavin Shan entry_size = 6; 679138635ccSGavin Shan break; 680138635ccSGavin Shan default: 681138635ccSGavin Shan continue; 682138635ccSGavin Shan } 683138635ccSGavin Shan 684138635ccSGavin Shan if (!cnt || nc->filters[i]) 685138635ccSGavin Shan continue; 686138635ccSGavin Shan 687138635ccSGavin Shan size = sizeof(*ncf) + cnt * entry_size; 688138635ccSGavin Shan ncf = kzalloc(size, GFP_ATOMIC); 689138635ccSGavin Shan if (!ncf) { 690138635ccSGavin Shan pr_warn("%s: Cannot alloc filter table (%d)\n", 691138635ccSGavin Shan __func__, i); 692138635ccSGavin Shan return -ENOMEM; 693138635ccSGavin Shan } 694138635ccSGavin Shan 695138635ccSGavin Shan ncf->index = i; 696138635ccSGavin Shan ncf->total = cnt; 69721acf630SSamuel Mendoza-Jonas if (i == NCSI_FILTER_VLAN) { 69821acf630SSamuel Mendoza-Jonas /* Set VLAN filters active so they are cleared in 69921acf630SSamuel Mendoza-Jonas * first configuration state 70021acf630SSamuel Mendoza-Jonas */ 70121acf630SSamuel Mendoza-Jonas ncf->bitmap = U64_MAX; 70221acf630SSamuel Mendoza-Jonas } else { 703138635ccSGavin Shan ncf->bitmap = 0x0ul; 70421acf630SSamuel Mendoza-Jonas } 705138635ccSGavin Shan nc->filters[i] = ncf; 706138635ccSGavin Shan } 707138635ccSGavin Shan 708138635ccSGavin Shan return 0; 709138635ccSGavin Shan } 710138635ccSGavin Shan 711138635ccSGavin Shan static int ncsi_rsp_handler_gp(struct ncsi_request *nr) 712138635ccSGavin Shan { 713138635ccSGavin Shan struct ncsi_rsp_gp_pkt *rsp; 714138635ccSGavin Shan struct ncsi_dev_priv *ndp = nr->ndp; 715138635ccSGavin Shan struct ncsi_channel *nc; 716138635ccSGavin Shan unsigned short enable, vlan; 717138635ccSGavin Shan unsigned char *pdata; 718138635ccSGavin Shan int table, i; 719138635ccSGavin Shan 720138635ccSGavin Shan /* Find the channel */ 721138635ccSGavin Shan rsp = (struct ncsi_rsp_gp_pkt *)skb_network_header(nr->rsp); 722138635ccSGavin Shan ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, 723138635ccSGavin Shan NULL, &nc); 724138635ccSGavin Shan if (!nc) 725138635ccSGavin Shan return -ENODEV; 726138635ccSGavin Shan 727138635ccSGavin Shan /* Modes with explicit enabled indications */ 728138635ccSGavin Shan if (ntohl(rsp->valid_modes) & 0x1) { /* BC filter mode */ 729138635ccSGavin Shan nc->modes[NCSI_MODE_BC].enable = 1; 730138635ccSGavin Shan nc->modes[NCSI_MODE_BC].data[0] = ntohl(rsp->bc_mode); 731138635ccSGavin Shan } 732138635ccSGavin Shan if (ntohl(rsp->valid_modes) & 0x2) /* Channel enabled */ 733138635ccSGavin Shan nc->modes[NCSI_MODE_ENABLE].enable = 1; 734138635ccSGavin Shan if (ntohl(rsp->valid_modes) & 0x4) /* Channel Tx enabled */ 735138635ccSGavin Shan nc->modes[NCSI_MODE_TX_ENABLE].enable = 1; 736138635ccSGavin Shan if (ntohl(rsp->valid_modes) & 0x8) /* MC filter mode */ 737138635ccSGavin Shan nc->modes[NCSI_MODE_MC].enable = 1; 738138635ccSGavin Shan 739138635ccSGavin Shan /* Modes without explicit enabled indications */ 740138635ccSGavin Shan nc->modes[NCSI_MODE_LINK].enable = 1; 741138635ccSGavin Shan nc->modes[NCSI_MODE_LINK].data[0] = ntohl(rsp->link_mode); 742138635ccSGavin Shan nc->modes[NCSI_MODE_VLAN].enable = 1; 743138635ccSGavin Shan nc->modes[NCSI_MODE_VLAN].data[0] = rsp->vlan_mode; 744138635ccSGavin Shan nc->modes[NCSI_MODE_FC].enable = 1; 745138635ccSGavin Shan nc->modes[NCSI_MODE_FC].data[0] = rsp->fc_mode; 746138635ccSGavin Shan nc->modes[NCSI_MODE_AEN].enable = 1; 747138635ccSGavin Shan nc->modes[NCSI_MODE_AEN].data[0] = ntohl(rsp->aen_mode); 748138635ccSGavin Shan 749138635ccSGavin Shan /* MAC addresses filter table */ 750138635ccSGavin Shan pdata = (unsigned char *)rsp + 48; 751138635ccSGavin Shan enable = rsp->mac_enable; 752138635ccSGavin Shan for (i = 0; i < rsp->mac_cnt; i++, pdata += 6) { 753138635ccSGavin Shan if (i >= (nc->filters[NCSI_FILTER_UC]->total + 754138635ccSGavin Shan nc->filters[NCSI_FILTER_MC]->total)) 755138635ccSGavin Shan table = NCSI_FILTER_MIXED; 756138635ccSGavin Shan else if (i >= nc->filters[NCSI_FILTER_UC]->total) 757138635ccSGavin Shan table = NCSI_FILTER_MC; 758138635ccSGavin Shan else 759138635ccSGavin Shan table = NCSI_FILTER_UC; 760138635ccSGavin Shan 761138635ccSGavin Shan if (!(enable & (0x1 << i))) 762138635ccSGavin Shan continue; 763138635ccSGavin Shan 764138635ccSGavin Shan if (ncsi_find_filter(nc, table, pdata) >= 0) 765138635ccSGavin Shan continue; 766138635ccSGavin Shan 767138635ccSGavin Shan ncsi_add_filter(nc, table, pdata); 768138635ccSGavin Shan } 769138635ccSGavin Shan 770138635ccSGavin Shan /* VLAN filter table */ 771138635ccSGavin Shan enable = ntohs(rsp->vlan_enable); 772138635ccSGavin Shan for (i = 0; i < rsp->vlan_cnt; i++, pdata += 2) { 773138635ccSGavin Shan if (!(enable & (0x1 << i))) 774138635ccSGavin Shan continue; 775138635ccSGavin Shan 776138635ccSGavin Shan vlan = ntohs(*(__be16 *)pdata); 777138635ccSGavin Shan if (ncsi_find_filter(nc, NCSI_FILTER_VLAN, &vlan) >= 0) 778138635ccSGavin Shan continue; 779138635ccSGavin Shan 780138635ccSGavin Shan ncsi_add_filter(nc, NCSI_FILTER_VLAN, &vlan); 781138635ccSGavin Shan } 782138635ccSGavin Shan 783138635ccSGavin Shan return 0; 784138635ccSGavin Shan } 785138635ccSGavin Shan 786138635ccSGavin Shan static int ncsi_rsp_handler_gcps(struct ncsi_request *nr) 787138635ccSGavin Shan { 788138635ccSGavin Shan struct ncsi_rsp_gcps_pkt *rsp; 789138635ccSGavin Shan struct ncsi_dev_priv *ndp = nr->ndp; 790138635ccSGavin Shan struct ncsi_channel *nc; 791138635ccSGavin Shan struct ncsi_channel_stats *ncs; 792138635ccSGavin Shan 793138635ccSGavin Shan /* Find the channel */ 794138635ccSGavin Shan rsp = (struct ncsi_rsp_gcps_pkt *)skb_network_header(nr->rsp); 795138635ccSGavin Shan ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, 796138635ccSGavin Shan NULL, &nc); 797138635ccSGavin Shan if (!nc) 798138635ccSGavin Shan return -ENODEV; 799138635ccSGavin Shan 800138635ccSGavin Shan /* Update HNC's statistics */ 801138635ccSGavin Shan ncs = &nc->stats; 802138635ccSGavin Shan ncs->hnc_cnt_hi = ntohl(rsp->cnt_hi); 803138635ccSGavin Shan ncs->hnc_cnt_lo = ntohl(rsp->cnt_lo); 804138635ccSGavin Shan ncs->hnc_rx_bytes = ntohl(rsp->rx_bytes); 805138635ccSGavin Shan ncs->hnc_tx_bytes = ntohl(rsp->tx_bytes); 806138635ccSGavin Shan ncs->hnc_rx_uc_pkts = ntohl(rsp->rx_uc_pkts); 807138635ccSGavin Shan ncs->hnc_rx_mc_pkts = ntohl(rsp->rx_mc_pkts); 808138635ccSGavin Shan ncs->hnc_rx_bc_pkts = ntohl(rsp->rx_bc_pkts); 809138635ccSGavin Shan ncs->hnc_tx_uc_pkts = ntohl(rsp->tx_uc_pkts); 810138635ccSGavin Shan ncs->hnc_tx_mc_pkts = ntohl(rsp->tx_mc_pkts); 811138635ccSGavin Shan ncs->hnc_tx_bc_pkts = ntohl(rsp->tx_bc_pkts); 812138635ccSGavin Shan ncs->hnc_fcs_err = ntohl(rsp->fcs_err); 813138635ccSGavin Shan ncs->hnc_align_err = ntohl(rsp->align_err); 814138635ccSGavin Shan ncs->hnc_false_carrier = ntohl(rsp->false_carrier); 815138635ccSGavin Shan ncs->hnc_runt_pkts = ntohl(rsp->runt_pkts); 816138635ccSGavin Shan ncs->hnc_jabber_pkts = ntohl(rsp->jabber_pkts); 817138635ccSGavin Shan ncs->hnc_rx_pause_xon = ntohl(rsp->rx_pause_xon); 818138635ccSGavin Shan ncs->hnc_rx_pause_xoff = ntohl(rsp->rx_pause_xoff); 819138635ccSGavin Shan ncs->hnc_tx_pause_xon = ntohl(rsp->tx_pause_xon); 820138635ccSGavin Shan ncs->hnc_tx_pause_xoff = ntohl(rsp->tx_pause_xoff); 821138635ccSGavin Shan ncs->hnc_tx_s_collision = ntohl(rsp->tx_s_collision); 822138635ccSGavin Shan ncs->hnc_tx_m_collision = ntohl(rsp->tx_m_collision); 823138635ccSGavin Shan ncs->hnc_l_collision = ntohl(rsp->l_collision); 824138635ccSGavin Shan ncs->hnc_e_collision = ntohl(rsp->e_collision); 825138635ccSGavin Shan ncs->hnc_rx_ctl_frames = ntohl(rsp->rx_ctl_frames); 826138635ccSGavin Shan ncs->hnc_rx_64_frames = ntohl(rsp->rx_64_frames); 827138635ccSGavin Shan ncs->hnc_rx_127_frames = ntohl(rsp->rx_127_frames); 828138635ccSGavin Shan ncs->hnc_rx_255_frames = ntohl(rsp->rx_255_frames); 829138635ccSGavin Shan ncs->hnc_rx_511_frames = ntohl(rsp->rx_511_frames); 830138635ccSGavin Shan ncs->hnc_rx_1023_frames = ntohl(rsp->rx_1023_frames); 831138635ccSGavin Shan ncs->hnc_rx_1522_frames = ntohl(rsp->rx_1522_frames); 832138635ccSGavin Shan ncs->hnc_rx_9022_frames = ntohl(rsp->rx_9022_frames); 833138635ccSGavin Shan ncs->hnc_tx_64_frames = ntohl(rsp->tx_64_frames); 834138635ccSGavin Shan ncs->hnc_tx_127_frames = ntohl(rsp->tx_127_frames); 835138635ccSGavin Shan ncs->hnc_tx_255_frames = ntohl(rsp->tx_255_frames); 836138635ccSGavin Shan ncs->hnc_tx_511_frames = ntohl(rsp->tx_511_frames); 837138635ccSGavin Shan ncs->hnc_tx_1023_frames = ntohl(rsp->tx_1023_frames); 838138635ccSGavin Shan ncs->hnc_tx_1522_frames = ntohl(rsp->tx_1522_frames); 839138635ccSGavin Shan ncs->hnc_tx_9022_frames = ntohl(rsp->tx_9022_frames); 840138635ccSGavin Shan ncs->hnc_rx_valid_bytes = ntohl(rsp->rx_valid_bytes); 841138635ccSGavin Shan ncs->hnc_rx_runt_pkts = ntohl(rsp->rx_runt_pkts); 842138635ccSGavin Shan ncs->hnc_rx_jabber_pkts = ntohl(rsp->rx_jabber_pkts); 843138635ccSGavin Shan 844138635ccSGavin Shan return 0; 845138635ccSGavin Shan } 846138635ccSGavin Shan 847138635ccSGavin Shan static int ncsi_rsp_handler_gns(struct ncsi_request *nr) 848138635ccSGavin Shan { 849138635ccSGavin Shan struct ncsi_rsp_gns_pkt *rsp; 850138635ccSGavin Shan struct ncsi_dev_priv *ndp = nr->ndp; 851138635ccSGavin Shan struct ncsi_channel *nc; 852138635ccSGavin Shan struct ncsi_channel_stats *ncs; 853138635ccSGavin Shan 854138635ccSGavin Shan /* Find the channel */ 855138635ccSGavin Shan rsp = (struct ncsi_rsp_gns_pkt *)skb_network_header(nr->rsp); 856138635ccSGavin Shan ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, 857138635ccSGavin Shan NULL, &nc); 858138635ccSGavin Shan if (!nc) 859138635ccSGavin Shan return -ENODEV; 860138635ccSGavin Shan 861138635ccSGavin Shan /* Update HNC's statistics */ 862138635ccSGavin Shan ncs = &nc->stats; 863138635ccSGavin Shan ncs->ncsi_rx_cmds = ntohl(rsp->rx_cmds); 864138635ccSGavin Shan ncs->ncsi_dropped_cmds = ntohl(rsp->dropped_cmds); 865138635ccSGavin Shan ncs->ncsi_cmd_type_errs = ntohl(rsp->cmd_type_errs); 866138635ccSGavin Shan ncs->ncsi_cmd_csum_errs = ntohl(rsp->cmd_csum_errs); 867138635ccSGavin Shan ncs->ncsi_rx_pkts = ntohl(rsp->rx_pkts); 868138635ccSGavin Shan ncs->ncsi_tx_pkts = ntohl(rsp->tx_pkts); 869138635ccSGavin Shan ncs->ncsi_tx_aen_pkts = ntohl(rsp->tx_aen_pkts); 870138635ccSGavin Shan 871138635ccSGavin Shan return 0; 872138635ccSGavin Shan } 873138635ccSGavin Shan 874138635ccSGavin Shan static int ncsi_rsp_handler_gnpts(struct ncsi_request *nr) 875138635ccSGavin Shan { 876138635ccSGavin Shan struct ncsi_rsp_gnpts_pkt *rsp; 877138635ccSGavin Shan struct ncsi_dev_priv *ndp = nr->ndp; 878138635ccSGavin Shan struct ncsi_channel *nc; 879138635ccSGavin Shan struct ncsi_channel_stats *ncs; 880138635ccSGavin Shan 881138635ccSGavin Shan /* Find the channel */ 882138635ccSGavin Shan rsp = (struct ncsi_rsp_gnpts_pkt *)skb_network_header(nr->rsp); 883138635ccSGavin Shan ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, 884138635ccSGavin Shan NULL, &nc); 885138635ccSGavin Shan if (!nc) 886138635ccSGavin Shan return -ENODEV; 887138635ccSGavin Shan 888138635ccSGavin Shan /* Update HNC's statistics */ 889138635ccSGavin Shan ncs = &nc->stats; 890138635ccSGavin Shan ncs->pt_tx_pkts = ntohl(rsp->tx_pkts); 891138635ccSGavin Shan ncs->pt_tx_dropped = ntohl(rsp->tx_dropped); 892138635ccSGavin Shan ncs->pt_tx_channel_err = ntohl(rsp->tx_channel_err); 893138635ccSGavin Shan ncs->pt_tx_us_err = ntohl(rsp->tx_us_err); 894138635ccSGavin Shan ncs->pt_rx_pkts = ntohl(rsp->rx_pkts); 895138635ccSGavin Shan ncs->pt_rx_dropped = ntohl(rsp->rx_dropped); 896138635ccSGavin Shan ncs->pt_rx_channel_err = ntohl(rsp->rx_channel_err); 897138635ccSGavin Shan ncs->pt_rx_us_err = ntohl(rsp->rx_us_err); 898138635ccSGavin Shan ncs->pt_rx_os_err = ntohl(rsp->rx_os_err); 899138635ccSGavin Shan 900138635ccSGavin Shan return 0; 901138635ccSGavin Shan } 902138635ccSGavin Shan 903138635ccSGavin Shan static int ncsi_rsp_handler_gps(struct ncsi_request *nr) 904138635ccSGavin Shan { 905138635ccSGavin Shan struct ncsi_rsp_gps_pkt *rsp; 906138635ccSGavin Shan struct ncsi_dev_priv *ndp = nr->ndp; 907138635ccSGavin Shan struct ncsi_package *np; 908138635ccSGavin Shan 909138635ccSGavin Shan /* Find the package */ 910138635ccSGavin Shan rsp = (struct ncsi_rsp_gps_pkt *)skb_network_header(nr->rsp); 911138635ccSGavin Shan ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, 912138635ccSGavin Shan &np, NULL); 913138635ccSGavin Shan if (!np) 914138635ccSGavin Shan return -ENODEV; 915138635ccSGavin Shan 916138635ccSGavin Shan return 0; 917138635ccSGavin Shan } 918138635ccSGavin Shan 919138635ccSGavin Shan static int ncsi_rsp_handler_gpuuid(struct ncsi_request *nr) 920138635ccSGavin Shan { 921138635ccSGavin Shan struct ncsi_rsp_gpuuid_pkt *rsp; 922138635ccSGavin Shan struct ncsi_dev_priv *ndp = nr->ndp; 923138635ccSGavin Shan struct ncsi_package *np; 924138635ccSGavin Shan 925138635ccSGavin Shan /* Find the package */ 926138635ccSGavin Shan rsp = (struct ncsi_rsp_gpuuid_pkt *)skb_network_header(nr->rsp); 927138635ccSGavin Shan ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, 928138635ccSGavin Shan &np, NULL); 929138635ccSGavin Shan if (!np) 930138635ccSGavin Shan return -ENODEV; 931138635ccSGavin Shan 932138635ccSGavin Shan memcpy(np->uuid, rsp->uuid, sizeof(rsp->uuid)); 933138635ccSGavin Shan 934138635ccSGavin Shan return 0; 935138635ccSGavin Shan } 936138635ccSGavin Shan 937138635ccSGavin Shan static struct ncsi_rsp_handler { 938138635ccSGavin Shan unsigned char type; 939138635ccSGavin Shan int payload; 940138635ccSGavin Shan int (*handler)(struct ncsi_request *nr); 941138635ccSGavin Shan } ncsi_rsp_handlers[] = { 942138635ccSGavin Shan { NCSI_PKT_RSP_CIS, 4, ncsi_rsp_handler_cis }, 943138635ccSGavin Shan { NCSI_PKT_RSP_SP, 4, ncsi_rsp_handler_sp }, 944138635ccSGavin Shan { NCSI_PKT_RSP_DP, 4, ncsi_rsp_handler_dp }, 945138635ccSGavin Shan { NCSI_PKT_RSP_EC, 4, ncsi_rsp_handler_ec }, 946138635ccSGavin Shan { NCSI_PKT_RSP_DC, 4, ncsi_rsp_handler_dc }, 947138635ccSGavin Shan { NCSI_PKT_RSP_RC, 4, ncsi_rsp_handler_rc }, 948138635ccSGavin Shan { NCSI_PKT_RSP_ECNT, 4, ncsi_rsp_handler_ecnt }, 949138635ccSGavin Shan { NCSI_PKT_RSP_DCNT, 4, ncsi_rsp_handler_dcnt }, 950138635ccSGavin Shan { NCSI_PKT_RSP_AE, 4, ncsi_rsp_handler_ae }, 951138635ccSGavin Shan { NCSI_PKT_RSP_SL, 4, ncsi_rsp_handler_sl }, 952138635ccSGavin Shan { NCSI_PKT_RSP_GLS, 16, ncsi_rsp_handler_gls }, 953138635ccSGavin Shan { NCSI_PKT_RSP_SVF, 4, ncsi_rsp_handler_svf }, 954138635ccSGavin Shan { NCSI_PKT_RSP_EV, 4, ncsi_rsp_handler_ev }, 955138635ccSGavin Shan { NCSI_PKT_RSP_DV, 4, ncsi_rsp_handler_dv }, 956138635ccSGavin Shan { NCSI_PKT_RSP_SMA, 4, ncsi_rsp_handler_sma }, 957138635ccSGavin Shan { NCSI_PKT_RSP_EBF, 4, ncsi_rsp_handler_ebf }, 958138635ccSGavin Shan { NCSI_PKT_RSP_DBF, 4, ncsi_rsp_handler_dbf }, 959138635ccSGavin Shan { NCSI_PKT_RSP_EGMF, 4, ncsi_rsp_handler_egmf }, 960138635ccSGavin Shan { NCSI_PKT_RSP_DGMF, 4, ncsi_rsp_handler_dgmf }, 961138635ccSGavin Shan { NCSI_PKT_RSP_SNFC, 4, ncsi_rsp_handler_snfc }, 9620a90e251SGavin Shan { NCSI_PKT_RSP_GVI, 40, ncsi_rsp_handler_gvi }, 963138635ccSGavin Shan { NCSI_PKT_RSP_GC, 32, ncsi_rsp_handler_gc }, 964138635ccSGavin Shan { NCSI_PKT_RSP_GP, -1, ncsi_rsp_handler_gp }, 965138635ccSGavin Shan { NCSI_PKT_RSP_GCPS, 172, ncsi_rsp_handler_gcps }, 966138635ccSGavin Shan { NCSI_PKT_RSP_GNS, 172, ncsi_rsp_handler_gns }, 967138635ccSGavin Shan { NCSI_PKT_RSP_GNPTS, 172, ncsi_rsp_handler_gnpts }, 968138635ccSGavin Shan { NCSI_PKT_RSP_GPS, 8, ncsi_rsp_handler_gps }, 969138635ccSGavin Shan { NCSI_PKT_RSP_OEM, 0, NULL }, 970138635ccSGavin Shan { NCSI_PKT_RSP_PLDM, 0, NULL }, 971138635ccSGavin Shan { NCSI_PKT_RSP_GPUUID, 20, ncsi_rsp_handler_gpuuid } 972138635ccSGavin Shan }; 973138635ccSGavin Shan 974138635ccSGavin Shan int ncsi_rcv_rsp(struct sk_buff *skb, struct net_device *dev, 975138635ccSGavin Shan struct packet_type *pt, struct net_device *orig_dev) 976138635ccSGavin Shan { 977138635ccSGavin Shan struct ncsi_rsp_handler *nrh = NULL; 978138635ccSGavin Shan struct ncsi_dev *nd; 979138635ccSGavin Shan struct ncsi_dev_priv *ndp; 980138635ccSGavin Shan struct ncsi_request *nr; 981138635ccSGavin Shan struct ncsi_pkt_hdr *hdr; 982138635ccSGavin Shan unsigned long flags; 983138635ccSGavin Shan int payload, i, ret; 984138635ccSGavin Shan 985138635ccSGavin Shan /* Find the NCSI device */ 986138635ccSGavin Shan nd = ncsi_find_dev(dev); 987138635ccSGavin Shan ndp = nd ? TO_NCSI_DEV_PRIV(nd) : NULL; 988138635ccSGavin Shan if (!ndp) 989138635ccSGavin Shan return -ENODEV; 990138635ccSGavin Shan 9917a82ecf4SGavin Shan /* Check if it is AEN packet */ 992138635ccSGavin Shan hdr = (struct ncsi_pkt_hdr *)skb_network_header(skb); 9937a82ecf4SGavin Shan if (hdr->type == NCSI_PKT_AEN) 9947a82ecf4SGavin Shan return ncsi_aen_handler(ndp, skb); 9957a82ecf4SGavin Shan 9967a82ecf4SGavin Shan /* Find the handler */ 997138635ccSGavin Shan for (i = 0; i < ARRAY_SIZE(ncsi_rsp_handlers); i++) { 998138635ccSGavin Shan if (ncsi_rsp_handlers[i].type == hdr->type) { 999138635ccSGavin Shan if (ncsi_rsp_handlers[i].handler) 1000138635ccSGavin Shan nrh = &ncsi_rsp_handlers[i]; 1001138635ccSGavin Shan else 1002138635ccSGavin Shan nrh = NULL; 1003138635ccSGavin Shan 1004138635ccSGavin Shan break; 1005138635ccSGavin Shan } 1006138635ccSGavin Shan } 1007138635ccSGavin Shan 1008138635ccSGavin Shan if (!nrh) { 1009138635ccSGavin Shan netdev_err(nd->dev, "Received unrecognized packet (0x%x)\n", 1010138635ccSGavin Shan hdr->type); 1011138635ccSGavin Shan return -ENOENT; 1012138635ccSGavin Shan } 1013138635ccSGavin Shan 1014138635ccSGavin Shan /* Associate with the request */ 1015138635ccSGavin Shan spin_lock_irqsave(&ndp->lock, flags); 1016138635ccSGavin Shan nr = &ndp->requests[hdr->id]; 1017138635ccSGavin Shan if (!nr->used) { 1018138635ccSGavin Shan spin_unlock_irqrestore(&ndp->lock, flags); 1019138635ccSGavin Shan return -ENODEV; 1020138635ccSGavin Shan } 1021138635ccSGavin Shan 1022138635ccSGavin Shan nr->rsp = skb; 1023138635ccSGavin Shan if (!nr->enabled) { 1024138635ccSGavin Shan spin_unlock_irqrestore(&ndp->lock, flags); 1025138635ccSGavin Shan ret = -ENOENT; 1026138635ccSGavin Shan goto out; 1027138635ccSGavin Shan } 1028138635ccSGavin Shan 1029138635ccSGavin Shan /* Validate the packet */ 1030138635ccSGavin Shan spin_unlock_irqrestore(&ndp->lock, flags); 1031138635ccSGavin Shan payload = nrh->payload; 1032138635ccSGavin Shan if (payload < 0) 1033138635ccSGavin Shan payload = ntohs(hdr->length); 1034138635ccSGavin Shan ret = ncsi_validate_rsp_pkt(nr, payload); 1035*9ef8690bSSamuel Mendoza-Jonas if (ret) { 1036*9ef8690bSSamuel Mendoza-Jonas netdev_warn(ndp->ndev.dev, 1037*9ef8690bSSamuel Mendoza-Jonas "NCSI: 'bad' packet ignored for type 0x%x\n", 1038*9ef8690bSSamuel Mendoza-Jonas hdr->type); 1039138635ccSGavin Shan goto out; 1040*9ef8690bSSamuel Mendoza-Jonas } 1041138635ccSGavin Shan 1042138635ccSGavin Shan /* Process the packet */ 1043138635ccSGavin Shan ret = nrh->handler(nr); 1044*9ef8690bSSamuel Mendoza-Jonas if (ret) 1045*9ef8690bSSamuel Mendoza-Jonas netdev_err(ndp->ndev.dev, 1046*9ef8690bSSamuel Mendoza-Jonas "NCSI: Handler for packet type 0x%x returned %d\n", 1047*9ef8690bSSamuel Mendoza-Jonas hdr->type, ret); 1048138635ccSGavin Shan out: 1049138635ccSGavin Shan ncsi_free_request(nr); 1050138635ccSGavin Shan return ret; 1051138635ccSGavin Shan } 1052