1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * NC-SI protocol configuration 4 * 5 * Copyright (C) 2019, IBM Corporation. 6 */ 7 8 #include <common.h> 9 #include <malloc.h> 10 #include <phy.h> 11 #include <net/ncsi.h> 12 #include <net/ncsi-pkt.h> 13 #include <asm/unaligned.h> 14 15 #define NCSI_PACKAGE_MAX 8 16 #define NCSI_CHANNEL_MAX 31 17 18 #define NCSI_PACKAGE_SHIFT 5 19 #define NCSI_PACKAGE_INDEX(c) (((c) >> NCSI_PACKAGE_SHIFT) & 0x7) 20 #define NCSI_RESERVED_CHANNEL 0x1f 21 #define NCSI_CHANNEL_INDEX(c) ((c) & ((1 << NCSI_PACKAGE_SHIFT) - 1)) 22 #define NCSI_TO_CHANNEL(p, c) (((p) << NCSI_PACKAGE_SHIFT) | (c)) 23 24 #define NCSI_PKT_REVISION 0x01 25 26 #define NCSI_CAP_GENERIC_MASK 0x7f 27 #define NCSI_CAP_BC_MASK 0x0f 28 #define NCSI_CAP_MC_MASK 0x3f 29 #define NCSI_CAP_AEN_MASK 0x07 30 #define NCSI_CAP_VLAN_MASK 0x07 31 32 static void ncsi_send_ebf(unsigned int np, unsigned int nc); 33 static void ncsi_send_ae(unsigned int np, unsigned int nc); 34 static void ncsi_send_gls(unsigned int np, unsigned int nc); 35 static int ncsi_send_command(unsigned int np, unsigned int nc, unsigned int cmd, 36 uchar *payload, int len, bool wait); 37 38 struct ncsi_channel { 39 unsigned int id; 40 bool has_link; 41 42 /* capabilities */ 43 u32 cap_generic; 44 u32 cap_bc; 45 u32 cap_mc; 46 u32 cap_buffer; 47 u32 cap_aen; 48 u32 cap_vlan; 49 50 /* version information */ 51 struct { 52 u32 version; /* Supported BCD encoded NCSI version */ 53 u32 alpha2; /* Supported BCD encoded NCSI version */ 54 u8 fw_name[12]; /* Firmware name string */ 55 u32 fw_version; /* Firmware version */ 56 u16 pci_ids[4]; /* PCI identification */ 57 u32 mf_id; /* Manufacture ID */ 58 } version; 59 60 }; 61 62 struct ncsi_package { 63 unsigned int id; 64 unsigned int n_channels; 65 struct ncsi_channel *channels; 66 }; 67 68 struct ncsi { 69 enum { 70 NCSI_PROBE_PACKAGE_SP, 71 NCSI_PROBE_PACKAGE_DP, 72 NCSI_PROBE_CHANNEL_SP, 73 NCSI_PROBE_CHANNEL, 74 NCSI_CONFIG, 75 } state; 76 77 unsigned int pending_requests; 78 unsigned int requests[256]; 79 unsigned int last_request; 80 81 unsigned int current_package; 82 unsigned int current_channel; 83 84 unsigned int n_packages; 85 struct ncsi_package *packages; 86 }; 87 88 struct ncsi *ncsi_priv; 89 90 bool ncsi_active(void) 91 { 92 unsigned int np, nc; 93 94 if (!ncsi_priv) 95 return false; 96 97 np = ncsi_priv->current_package; 98 nc = ncsi_priv->current_channel; 99 100 if (ncsi_priv->state != NCSI_CONFIG) 101 return false; 102 103 return np < NCSI_PACKAGE_MAX && nc < NCSI_CHANNEL_MAX && 104 ncsi_priv->packages[np].channels[nc].has_link; 105 } 106 107 static unsigned int cmd_payload(int cmd) 108 { 109 switch (cmd) { 110 case NCSI_PKT_CMD_CIS: 111 return 0; 112 case NCSI_PKT_CMD_SP: 113 return 4; 114 case NCSI_PKT_CMD_DP: 115 return 0; 116 case NCSI_PKT_CMD_EC: 117 return 0; 118 case NCSI_PKT_CMD_DC: 119 return 4; 120 case NCSI_PKT_CMD_RC: 121 return 4; 122 case NCSI_PKT_CMD_ECNT: 123 return 0; 124 case NCSI_PKT_CMD_DCNT: 125 return 0; 126 case NCSI_PKT_CMD_AE: 127 return 8; 128 case NCSI_PKT_CMD_SL: 129 return 8; 130 case NCSI_PKT_CMD_GLS: 131 return 0; 132 case NCSI_PKT_CMD_SVF: 133 return 8; 134 case NCSI_PKT_CMD_EV: 135 return 4; 136 case NCSI_PKT_CMD_DV: 137 return 0; 138 case NCSI_PKT_CMD_SMA: 139 return 8; 140 case NCSI_PKT_CMD_EBF: 141 return 4; 142 case NCSI_PKT_CMD_DBF: 143 return 0; 144 case NCSI_PKT_CMD_EGMF: 145 return 4; 146 case NCSI_PKT_CMD_DGMF: 147 return 0; 148 case NCSI_PKT_CMD_SNFC: 149 return 4; 150 case NCSI_PKT_CMD_GVI: 151 return 0; 152 case NCSI_PKT_CMD_GC: 153 return 0; 154 case NCSI_PKT_CMD_GP: 155 return 0; 156 case NCSI_PKT_CMD_GCPS: 157 return 0; 158 case NCSI_PKT_CMD_GNS: 159 return 0; 160 case NCSI_PKT_CMD_GNPTS: 161 return 0; 162 case NCSI_PKT_CMD_GPS: 163 return 0; 164 default: 165 printf("NCSI: Unknown command 0x%02x\n", cmd); 166 return 0; 167 } 168 } 169 170 static u32 ncsi_calculate_checksum(unsigned char *data, int len) 171 { 172 u32 checksum = 0; 173 int i; 174 175 for (i = 0; i < len; i += 2) 176 checksum += (((u32)data[i] << 8) | data[i + 1]); 177 178 checksum = (~checksum + 1); 179 return checksum; 180 } 181 182 static int ncsi_validate_rsp(struct ncsi_rsp_pkt *pkt, int payload) 183 { 184 struct ncsi_rsp_pkt_hdr *hdr = &pkt->rsp; 185 u32 checksum, c_offset; 186 __be32 pchecksum; 187 188 if (hdr->common.revision != 1) { 189 printf("NCSI: 0x%02x response has unsupported revision 0x%x\n", 190 hdr->common.type, hdr->common.revision); 191 return -1; 192 } 193 194 if (hdr->code != 0) { 195 printf("NCSI: 0x%02x response returns error %d\n", 196 hdr->common.type, __be16_to_cpu(hdr->code)); 197 if (ntohs(hdr->reason) == 0x05) 198 printf("(Invalid command length)\n"); 199 return -1; 200 } 201 202 if (ntohs(hdr->common.length) != payload) { 203 printf("NCSI: 0x%02x response has incorrect length %d\n", 204 hdr->common.type, hdr->common.length); 205 return -1; 206 } 207 208 c_offset = sizeof(struct ncsi_rsp_pkt_hdr) + payload - sizeof(checksum); 209 pchecksum = get_unaligned_be32((void *)hdr + c_offset); 210 if (pchecksum != 0) { 211 checksum = ncsi_calculate_checksum((unsigned char *)hdr, 212 c_offset); 213 if (pchecksum != checksum) { 214 printf("NCSI: 0x%02x response has invalid checksum\n", 215 hdr->common.type); 216 return -1; 217 } 218 } 219 220 return 0; 221 } 222 223 static void ncsi_rsp_ec(struct ncsi_rsp_pkt *pkt) 224 { 225 struct ncsi_rsp_pkt_hdr *rsp = (struct ncsi_rsp_pkt_hdr *)&pkt->rsp; 226 unsigned int np, nc; 227 228 np = NCSI_PACKAGE_INDEX(rsp->common.channel); 229 nc = NCSI_CHANNEL_INDEX(rsp->common.channel); 230 231 if (ncsi_priv->packages[np].channels[nc].cap_aen != 0) 232 ncsi_send_ae(np, nc); 233 /* else, done */ 234 } 235 236 static void ncsi_rsp_ecnt(struct ncsi_rsp_pkt *pkt) 237 { 238 struct ncsi_rsp_pkt_hdr *rsp = (struct ncsi_rsp_pkt_hdr *)&pkt->rsp; 239 unsigned int np, nc; 240 241 np = NCSI_PACKAGE_INDEX(rsp->common.channel); 242 nc = NCSI_CHANNEL_INDEX(rsp->common.channel); 243 244 ncsi_send_command(np, nc, NCSI_PKT_CMD_EC, NULL, 0, true); 245 } 246 247 static void ncsi_rsp_ebf(struct ncsi_rsp_pkt *pkt) 248 { 249 struct ncsi_rsp_pkt_hdr *rsp = (struct ncsi_rsp_pkt_hdr *)&pkt->rsp; 250 unsigned int np, nc; 251 252 np = NCSI_PACKAGE_INDEX(rsp->common.channel); 253 nc = NCSI_CHANNEL_INDEX(rsp->common.channel); 254 255 ncsi_send_command(np, nc, NCSI_PKT_CMD_ECNT, NULL, 0, true); 256 } 257 258 static void ncsi_rsp_sma(struct ncsi_rsp_pkt *pkt) 259 { 260 struct ncsi_rsp_pkt_hdr *rsp = (struct ncsi_rsp_pkt_hdr *)&pkt->rsp; 261 unsigned int np, nc; 262 263 np = NCSI_PACKAGE_INDEX(rsp->common.channel); 264 nc = NCSI_CHANNEL_INDEX(rsp->common.channel); 265 266 ncsi_send_ebf(np, nc); 267 } 268 269 static void ncsi_rsp_gc(struct ncsi_rsp_pkt *pkt) 270 { 271 struct ncsi_rsp_gc_pkt *gc = (struct ncsi_rsp_gc_pkt *)pkt; 272 struct ncsi_rsp_pkt_hdr *rsp = (struct ncsi_rsp_pkt_hdr *)&gc->rsp; 273 struct ncsi_channel *c; 274 unsigned int np, nc; 275 276 np = NCSI_PACKAGE_INDEX(rsp->common.channel); 277 nc = NCSI_CHANNEL_INDEX(rsp->common.channel); 278 279 if (np >= ncsi_priv->n_packages || 280 nc >= ncsi_priv->packages[np].n_channels) { 281 printf("NCSI: Invalid package / channel (0x%02x, 0x%02x)\n", 282 np, nc); 283 return; 284 } 285 286 c = &ncsi_priv->packages[np].channels[nc]; 287 c->cap_generic = ntohl(gc->cap) & NCSI_CAP_GENERIC_MASK; 288 c->cap_bc = ntohl(gc->bc_cap) & NCSI_CAP_BC_MASK; 289 c->cap_mc = ntohl(gc->mc_cap) & NCSI_CAP_MC_MASK; 290 c->cap_aen = ntohl(gc->aen_cap) & NCSI_CAP_AEN_MASK; 291 c->cap_vlan = ntohl(gc->vlan_mode) & NCSI_CAP_VLAN_MASK; 292 293 /* End of probe for this channel */ 294 } 295 296 static void ncsi_rsp_gvi(struct ncsi_rsp_pkt *pkt) 297 { 298 struct ncsi_rsp_gvi_pkt *gvi = (struct ncsi_rsp_gvi_pkt *)pkt; 299 struct ncsi_rsp_pkt_hdr *rsp = (struct ncsi_rsp_pkt_hdr *)&gvi->rsp; 300 struct ncsi_channel *c; 301 unsigned int np, nc, i; 302 303 np = NCSI_PACKAGE_INDEX(rsp->common.channel); 304 nc = NCSI_CHANNEL_INDEX(rsp->common.channel); 305 306 if (np >= ncsi_priv->n_packages || 307 nc >= ncsi_priv->packages[np].n_channels) { 308 printf("NCSI: Invalid package / channel (0x%02x, 0x%02x)\n", 309 np, nc); 310 return; 311 } 312 313 c = &ncsi_priv->packages[np].channels[nc]; 314 c->version.version = get_unaligned_be32(&gvi->ncsi_version); 315 c->version.alpha2 = gvi->alpha2; 316 memcpy(c->version.fw_name, gvi->fw_name, sizeof(c->version.fw_name)); 317 c->version.fw_version = get_unaligned_be32(&gvi->fw_version); 318 for (i = 0; i < ARRAY_SIZE(c->version.pci_ids); i++) 319 c->version.pci_ids[i] = get_unaligned_be16(gvi->pci_ids + i); 320 c->version.mf_id = get_unaligned_be32(&gvi->mf_id); 321 322 if (ncsi_priv->state == NCSI_PROBE_CHANNEL) 323 ncsi_send_command(np, nc, NCSI_PKT_CMD_GC, NULL, 0, true); 324 } 325 326 static void ncsi_rsp_gls(struct ncsi_rsp_pkt *pkt) 327 { 328 struct ncsi_rsp_gls_pkt *gls = (struct ncsi_rsp_gls_pkt *)pkt; 329 struct ncsi_rsp_pkt_hdr *rsp = (struct ncsi_rsp_pkt_hdr *)&gls->rsp; 330 unsigned int np, nc; 331 332 np = NCSI_PACKAGE_INDEX(rsp->common.channel); 333 nc = NCSI_CHANNEL_INDEX(rsp->common.channel); 334 335 if (np >= ncsi_priv->n_packages || 336 nc >= ncsi_priv->packages[np].n_channels) { 337 printf("NCSI: Invalid package / channel (0x%02x, 0x%02x)\n", 338 np, nc); 339 return; 340 } 341 342 ncsi_priv->packages[np].channels[nc].has_link = 343 !!(get_unaligned_be32(&gls->status)); 344 345 if (ncsi_priv->state == NCSI_PROBE_CHANNEL) 346 ncsi_send_command(np, nc, NCSI_PKT_CMD_GVI, NULL, 0, true); 347 } 348 349 static void ncsi_rsp_cis(struct ncsi_rsp_pkt *pkt) 350 { 351 struct ncsi_rsp_pkt_hdr *rsp = (struct ncsi_rsp_pkt_hdr *)pkt; 352 struct ncsi_package *package; 353 unsigned int np, nc; 354 355 np = NCSI_PACKAGE_INDEX(rsp->common.channel); 356 nc = NCSI_CHANNEL_INDEX(rsp->common.channel); 357 358 if (np >= ncsi_priv->n_packages) { 359 printf("NCSI: Mystery package 0x%02x from CIS\n", np); 360 return; 361 } 362 363 package = &ncsi_priv->packages[np]; 364 365 if (nc < package->n_channels) { 366 /* 367 * This is fine in general but in the current design we 368 * don't send CIS commands to known channels. 369 */ 370 debug("NCSI: Duplicate channel 0x%02x\n", nc); 371 return; 372 } 373 374 package->channels = realloc(package->channels, 375 sizeof(struct ncsi_channel) * 376 (package->n_channels + 1)); 377 if (!package->channels) { 378 printf("NCSI: Could not allocate memory for new channel\n"); 379 return; 380 } 381 382 debug("NCSI: New channel 0x%02x\n", nc); 383 384 package->channels[nc].id = nc; 385 package->channels[nc].has_link = false; 386 package->n_channels++; 387 388 ncsi_send_gls(np, nc); 389 } 390 391 static void ncsi_rsp_dp(struct ncsi_rsp_pkt *pkt) 392 { 393 struct ncsi_rsp_pkt_hdr *rsp = (struct ncsi_rsp_pkt_hdr *)pkt; 394 unsigned int np; 395 396 /* No action needed */ 397 398 np = NCSI_PACKAGE_INDEX(rsp->common.channel); 399 if (np >= ncsi_priv->n_packages) 400 debug("NCSI: DP response from unknown package %d\n", np); 401 } 402 403 static void ncsi_rsp_sp(struct ncsi_rsp_pkt *pkt) 404 { 405 struct ncsi_rsp_pkt_hdr *rsp = (struct ncsi_rsp_pkt_hdr *)pkt; 406 unsigned int np; 407 408 np = NCSI_PACKAGE_INDEX(rsp->common.channel); 409 410 if (np < ncsi_priv->n_packages) { 411 /* Already know about this package */ 412 debug("NCSI: package 0x%02x selected\n", np); 413 return; 414 } 415 416 debug("NCSI: adding new package %d\n", np); 417 418 ncsi_priv->packages = realloc(ncsi_priv->packages, 419 sizeof(struct ncsi_package) * 420 (ncsi_priv->n_packages + 1)); 421 if (!ncsi_priv->packages) { 422 printf("NCSI: could not allocate memory for new package\n"); 423 return; 424 } 425 426 ncsi_priv->packages[np].id = np; 427 ncsi_priv->packages[np].n_channels = 0; 428 ncsi_priv->packages[np].channels = NULL; 429 ncsi_priv->n_packages++; 430 } 431 432 static void ncsi_update_state(struct ncsi_rsp_pkt_hdr *nh) 433 { 434 bool timeout = !nh; 435 int np, nc; 436 437 switch (ncsi_priv->state) { 438 case NCSI_PROBE_PACKAGE_SP: 439 if (!timeout && 440 ncsi_priv->current_package + 1 < NCSI_PACKAGE_MAX) { 441 ncsi_priv->current_package++; 442 } else { 443 ncsi_priv->state = NCSI_PROBE_PACKAGE_DP; 444 ncsi_priv->current_package = 0; 445 } 446 return ncsi_probe_packages(); 447 case NCSI_PROBE_PACKAGE_DP: 448 if (ncsi_priv->current_package + 1 < ncsi_priv->n_packages && 449 !timeout) { 450 ncsi_priv->current_package++; 451 } else { 452 if (!ncsi_priv->n_packages) { 453 printf("NCSI: no packages found\n"); 454 net_set_state(NETLOOP_FAIL); 455 return; 456 } 457 debug("NCSI: probing channels\n"); 458 ncsi_priv->state = NCSI_PROBE_CHANNEL_SP; 459 ncsi_priv->current_package = 0; 460 ncsi_priv->current_channel = 0; 461 } 462 return ncsi_probe_packages(); 463 case NCSI_PROBE_CHANNEL_SP: 464 if (!timeout && nh->common.type == NCSI_PKT_RSP_SP) { 465 ncsi_priv->state = NCSI_PROBE_CHANNEL; 466 return ncsi_probe_packages(); 467 } 468 printf("NCSI: failed to select package 0x%0x2 or timeout\n", 469 ncsi_priv->current_package); 470 net_set_state(NETLOOP_FAIL); 471 break; 472 case NCSI_PROBE_CHANNEL: 473 // TODO only does package 0 for now 474 if (ncsi_priv->pending_requests == 0) { 475 np = ncsi_priv->current_package; 476 nc = ncsi_priv->current_channel; 477 478 /* Configure first channel that has link */ 479 if (ncsi_priv->packages[np].channels[nc].has_link) { 480 ncsi_priv->state = NCSI_CONFIG; 481 } else if (ncsi_priv->current_channel + 1 < 482 NCSI_CHANNEL_MAX) { 483 ncsi_priv->current_channel++; 484 } else { 485 // XXX As above only package 0 486 printf("NCSI: no channel found with link\n"); 487 net_set_state(NETLOOP_FAIL); 488 return; 489 } 490 return ncsi_probe_packages(); 491 } 492 break; 493 case NCSI_CONFIG: 494 if (ncsi_priv->pending_requests == 0) { 495 debug("NCSI: configuration done!\n"); 496 net_set_state(NETLOOP_SUCCESS); 497 } else if (timeout) { 498 printf("NCSI: timeout during configure\n"); 499 net_set_state(NETLOOP_FAIL); 500 } 501 break; 502 default: 503 printf("NCSI: something went very wrong, nevermind\n"); 504 net_set_state(NETLOOP_FAIL); 505 break; 506 } 507 } 508 509 static void ncsi_timeout_handler(void) 510 { 511 if (ncsi_priv->pending_requests) 512 ncsi_priv->pending_requests--; 513 514 ncsi_update_state(NULL); 515 } 516 517 static int ncsi_send_command(unsigned int np, unsigned int nc, unsigned int cmd, 518 uchar *payload, int len, bool wait) 519 { 520 struct ncsi_pkt_hdr *hdr; 521 __be32 *pchecksum; 522 int eth_hdr_size; 523 u32 checksum; 524 uchar *pkt, *start; 525 int final_len; 526 527 pkt = calloc(1, PKTSIZE_ALIGN + PKTALIGN); 528 if (!pkt) 529 return -ENOMEM; 530 start = pkt; 531 532 eth_hdr_size = net_set_ether(pkt, net_bcast_ethaddr, PROT_NCSI); 533 pkt += eth_hdr_size; 534 535 /* Set NCSI command header fields */ 536 hdr = (struct ncsi_pkt_hdr *)pkt; 537 hdr->mc_id = 0; 538 hdr->revision = NCSI_PKT_REVISION; 539 hdr->id = ++ncsi_priv->last_request; 540 ncsi_priv->requests[ncsi_priv->last_request] = 1; 541 hdr->type = cmd; 542 hdr->channel = NCSI_TO_CHANNEL(np, nc); 543 hdr->length = htons(len); 544 545 if (payload && len) 546 memcpy(pkt + sizeof(struct ncsi_pkt_hdr), payload, len); 547 548 /* Calculate checksum */ 549 checksum = ncsi_calculate_checksum((unsigned char *)hdr, 550 sizeof(*hdr) + len); 551 pchecksum = (__be32 *)((void *)(hdr + 1) + len); 552 put_unaligned_be32(checksum, pchecksum); 553 554 if (wait) { 555 net_set_timeout_handler(1000UL, ncsi_timeout_handler); 556 ncsi_priv->pending_requests++; 557 } 558 559 if (len < 26) 560 len = 26; 561 /* frame header, packet header, payload, checksum */ 562 final_len = eth_hdr_size + sizeof(struct ncsi_cmd_pkt_hdr) + len + 4; 563 564 net_send_packet(start, final_len); 565 free(start); 566 return 0; 567 } 568 569 static void ncsi_handle_aen(struct ip_udp_hdr *ip, unsigned int len) 570 { 571 struct ncsi_aen_pkt_hdr *hdr = (struct ncsi_aen_pkt_hdr *)ip; 572 int payload, i; 573 __be32 pchecksum; 574 u32 checksum; 575 576 switch (hdr->type) { 577 case NCSI_PKT_AEN_LSC: 578 printf("NCSI: link state changed\n"); 579 payload = 12; 580 break; 581 case NCSI_PKT_AEN_CR: 582 printf("NCSI: re-configuration required\n"); 583 payload = 4; 584 break; 585 case NCSI_PKT_AEN_HNCDSC: 586 /* Host notifcation - N/A but weird */ 587 debug("NCSI: HNCDSC AEN received\n"); 588 return; 589 default: 590 printf("%s: Invalid type 0x%02x\n", __func__, hdr->type); 591 return; 592 } 593 594 /* Validate packet */ 595 if (hdr->common.revision != 1) { 596 printf("NCSI: 0x%02x response has unsupported revision 0x%x\n", 597 hdr->common.type, hdr->common.revision); 598 return; 599 } 600 601 if (ntohs(hdr->common.length) != payload) { 602 printf("NCSI: 0x%02x response has incorrect length %d\n", 603 hdr->common.type, hdr->common.length); 604 return; 605 } 606 607 pchecksum = get_unaligned_be32((void *)(hdr + 1) + payload - 4); 608 if (pchecksum != 0) { 609 checksum = ncsi_calculate_checksum((unsigned char *)hdr, 610 sizeof(*hdr) + payload - 4); 611 if (pchecksum != checksum) { 612 printf("NCSI: 0x%02x response has invalid checksum\n", 613 hdr->common.type); 614 return; 615 } 616 } 617 618 /* Link or configuration lost - just redo the discovery process */ 619 ncsi_priv->state = NCSI_PROBE_PACKAGE_SP; 620 for (i = 0; i < ncsi_priv->n_packages; i++) 621 free(ncsi_priv->packages[i].channels); 622 free(ncsi_priv->packages); 623 ncsi_priv->n_packages = 0; 624 625 ncsi_priv->current_package = NCSI_PACKAGE_MAX; 626 ncsi_priv->current_channel = NCSI_CHANNEL_MAX; 627 628 ncsi_probe_packages(); 629 } 630 631 void ncsi_receive(struct ethernet_hdr *et, struct ip_udp_hdr *ip, 632 unsigned int len) 633 { 634 struct ncsi_rsp_pkt *pkt = (struct ncsi_rsp_pkt *)ip; 635 struct ncsi_rsp_pkt_hdr *nh = (struct ncsi_rsp_pkt_hdr *)&pkt->rsp; 636 void (*handler)(struct ncsi_rsp_pkt *pkt) = NULL; 637 unsigned short payload; 638 639 if (ncsi_priv->pending_requests) 640 ncsi_priv->pending_requests--; 641 642 if (len < sizeof(struct ncsi_rsp_pkt_hdr)) { 643 printf("NCSI: undersized packet: %u bytes\n", len); 644 goto out; 645 } 646 647 if (nh->common.type == NCSI_PKT_AEN) 648 return ncsi_handle_aen(ip, len); 649 650 switch (nh->common.type) { 651 case NCSI_PKT_RSP_SP: 652 payload = 4; 653 handler = ncsi_rsp_sp; 654 break; 655 case NCSI_PKT_RSP_DP: 656 payload = 4; 657 handler = ncsi_rsp_dp; 658 break; 659 case NCSI_PKT_RSP_CIS: 660 payload = 4; 661 handler = ncsi_rsp_cis; 662 break; 663 case NCSI_PKT_RSP_GLS: 664 payload = 16; 665 handler = ncsi_rsp_gls; 666 break; 667 case NCSI_PKT_RSP_GVI: 668 payload = 40; 669 handler = ncsi_rsp_gvi; 670 break; 671 case NCSI_PKT_RSP_GC: 672 payload = 32; 673 handler = ncsi_rsp_gc; 674 break; 675 case NCSI_PKT_RSP_SMA: 676 payload = 4; 677 handler = ncsi_rsp_sma; 678 break; 679 case NCSI_PKT_RSP_EBF: 680 payload = 4; 681 handler = ncsi_rsp_ebf; 682 break; 683 case NCSI_PKT_RSP_ECNT: 684 payload = 4; 685 handler = ncsi_rsp_ecnt; 686 break; 687 case NCSI_PKT_RSP_EC: 688 payload = 4; 689 handler = ncsi_rsp_ec; 690 break; 691 case NCSI_PKT_RSP_AE: 692 payload = 4; 693 handler = NULL; 694 break; 695 default: 696 printf("NCSI: unsupported packet type 0x%02x\n", 697 nh->common.type); 698 goto out; 699 } 700 701 if (ncsi_validate_rsp(pkt, payload) != 0) { 702 printf("NCSI: discarding invalid packet of type 0x%02x\n", 703 nh->common.type); 704 goto out; 705 } 706 707 if (handler) 708 handler(pkt); 709 out: 710 ncsi_update_state(nh); 711 } 712 713 static void ncsi_send_sp(unsigned int np) 714 { 715 uchar payload[4] = {0}; 716 717 ncsi_send_command(np, NCSI_RESERVED_CHANNEL, NCSI_PKT_CMD_SP, 718 (unsigned char *)&payload, 719 cmd_payload(NCSI_PKT_CMD_SP), true); 720 } 721 722 static void ncsi_send_dp(unsigned int np) 723 { 724 ncsi_send_command(np, NCSI_RESERVED_CHANNEL, NCSI_PKT_CMD_DP, NULL, 0, 725 true); 726 } 727 728 static void ncsi_send_gls(unsigned int np, unsigned int nc) 729 { 730 ncsi_send_command(np, nc, NCSI_PKT_CMD_GLS, NULL, 0, true); 731 } 732 733 static void ncsi_send_cis(unsigned int np, unsigned int nc) 734 { 735 ncsi_send_command(np, nc, NCSI_PKT_CMD_CIS, NULL, 0, true); 736 } 737 738 static void ncsi_send_ae(unsigned int np, unsigned int nc) 739 { 740 struct ncsi_cmd_ae_pkt cmd; 741 742 memset(&cmd, 0, sizeof(cmd)); 743 cmd.mode = htonl(ncsi_priv->packages[np].channels[nc].cap_aen); 744 745 ncsi_send_command(np, nc, NCSI_PKT_CMD_AE, 746 ((unsigned char *)&cmd) 747 + sizeof(struct ncsi_cmd_pkt_hdr), 748 cmd_payload(NCSI_PKT_CMD_AE), true); 749 } 750 751 static void ncsi_send_ebf(unsigned int np, unsigned int nc) 752 { 753 struct ncsi_cmd_ebf_pkt cmd; 754 755 memset(&cmd, 0, sizeof(cmd)); 756 cmd.mode = htonl(ncsi_priv->packages[np].channels[nc].cap_bc); 757 758 ncsi_send_command(np, nc, NCSI_PKT_CMD_EBF, 759 ((unsigned char *)&cmd) 760 + sizeof(struct ncsi_cmd_pkt_hdr), 761 cmd_payload(NCSI_PKT_CMD_EBF), true); 762 } 763 764 static void ncsi_send_sma(unsigned int np, unsigned int nc) 765 { 766 struct ncsi_cmd_sma_pkt cmd; 767 unsigned char *addr, i; 768 769 addr = eth_get_ethaddr(); 770 if (!addr) { 771 printf("NCSI: no MAC address configured\n"); 772 return; 773 } 774 775 memset(&cmd, 0, sizeof(cmd)); 776 for (i = 0; i < ARP_HLEN; i++) 777 cmd.mac[i] = addr[i]; 778 cmd.index = 1; 779 cmd.at_e = 1; 780 781 ncsi_send_command(np, nc, NCSI_PKT_CMD_SMA, 782 ((unsigned char *)&cmd) 783 + sizeof(struct ncsi_cmd_pkt_hdr), 784 cmd_payload(NCSI_PKT_CMD_SMA), true); 785 } 786 787 void ncsi_probe_packages(void) 788 { 789 struct ncsi_package *package; 790 unsigned int np, nc; 791 792 switch (ncsi_priv->state) { 793 case NCSI_PROBE_PACKAGE_SP: 794 if (ncsi_priv->current_package == NCSI_PACKAGE_MAX) 795 ncsi_priv->current_package = 0; 796 debug("%s: NCSI_PROBE_PACKAGE_SP current_package %d\n", 797 __func__, ncsi_priv->current_package); 798 ncsi_send_sp(ncsi_priv->current_package); 799 break; 800 case NCSI_PROBE_PACKAGE_DP: 801 debug("%s: NCSI_PROBE_PACKAGE_DP current_package %d\n", 802 __func__, ncsi_priv->current_package); 803 ncsi_send_dp(ncsi_priv->current_package); 804 break; 805 case NCSI_PROBE_CHANNEL_SP: 806 debug("%s: NCSI_PROBE_CHANNEL_SP\n", __func__); 807 if (ncsi_priv->n_packages > 0) 808 ncsi_send_sp(ncsi_priv->current_package); 809 else 810 printf("NCSI: no packages discovered, configuration not possible\n"); 811 break; 812 case NCSI_PROBE_CHANNEL: 813 debug("%s NCSI_PROBE_CHANNEL package %d channel %d\n", 814 __func__, 815 ncsi_priv->current_package, 816 ncsi_priv->current_channel); 817 /* Kicks off chain of channel discovery */ 818 ncsi_send_cis(ncsi_priv->current_package, 819 ncsi_priv->current_channel); 820 break; 821 case NCSI_CONFIG: 822 for (np = 0; np < ncsi_priv->n_packages; np++) { 823 package = &ncsi_priv->packages[np]; 824 for (nc = 0; nc < package->n_channels; nc++) 825 if (package->channels[nc].has_link) 826 break; 827 if (nc < package->n_channels) 828 break; 829 } 830 if (np == ncsi_priv->n_packages) { 831 printf("NCSI: no link available\n"); 832 return; 833 } 834 835 debug("NCSI: configuring channel %d\n", nc); 836 ncsi_priv->current_package = np; 837 ncsi_priv->current_channel = nc; 838 /* Kicks off rest of configure chain */ 839 ncsi_send_sma(np, nc); 840 break; 841 default: 842 printf("NCSI: unknown state 0x%x\n", ncsi_priv->state); 843 } 844 } 845 846 int ncsi_probe(struct phy_device *phydev) 847 { 848 if (!phydev->priv) { 849 phydev->priv = malloc(sizeof(struct ncsi)); 850 if (!phydev->priv) 851 return -ENOMEM; 852 memset(phydev->priv, 0, sizeof(struct ncsi)); 853 } 854 855 ncsi_priv = phydev->priv; 856 857 return 0; 858 } 859 860 int ncsi_startup(struct phy_device *phydev) 861 { 862 /* Set phydev parameters */ 863 phydev->speed = SPEED_100; 864 phydev->duplex = DUPLEX_FULL; 865 /* Normal phy reset is N/A */ 866 phydev->flags |= PHY_FLAG_BROKEN_RESET; 867 868 /* Set initial probe state */ 869 ncsi_priv->state = NCSI_PROBE_PACKAGE_SP; 870 871 /* No active package/channel yet */ 872 ncsi_priv->current_package = NCSI_PACKAGE_MAX; 873 ncsi_priv->current_channel = NCSI_CHANNEL_MAX; 874 875 /* Pretend link works so the MAC driver sets final bits up */ 876 phydev->link = true; 877 878 /* Set ncsi_priv so we can use it when called from net_loop() */ 879 ncsi_priv = phydev->priv; 880 881 return 0; 882 } 883 884 int ncsi_shutdown(struct phy_device *phydev) 885 { 886 printf("NCSI: Disabling package %d\n", ncsi_priv->current_package); 887 ncsi_send_dp(ncsi_priv->current_package); 888 return 0; 889 } 890 891 static struct phy_driver ncsi_driver = { 892 .uid = PHY_NCSI_ID, 893 .mask = 0xffffffff, 894 .name = "NC-SI", 895 .features = PHY_100BT_FEATURES | PHY_DEFAULT_FEATURES | SUPPORTED_100baseT_Full | SUPPORTED_MII, 896 .probe = ncsi_probe, 897 .startup = ncsi_startup, 898 .shutdown = ncsi_shutdown, 899 }; 900 901 int phy_ncsi_init(void) 902 { 903 phy_register(&ncsi_driver); 904 return 0; 905 } 906