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 printf("%s\n", __func__); 397 398 /* No action needed */ 399 400 np = NCSI_PACKAGE_INDEX(rsp->common.channel); 401 if (np >= ncsi_priv->n_packages) 402 debug("NCSI: DP response from unknown package %d\n", np); 403 } 404 405 static void ncsi_rsp_sp(struct ncsi_rsp_pkt *pkt) 406 { 407 struct ncsi_rsp_pkt_hdr *rsp = (struct ncsi_rsp_pkt_hdr *)pkt; 408 unsigned int np; 409 410 printf("%s\n", __func__); 411 412 np = NCSI_PACKAGE_INDEX(rsp->common.channel); 413 414 if (np < ncsi_priv->n_packages) { 415 /* Already know about this package */ 416 debug("NCSI: package 0x%02x selected\n", np); 417 return; 418 } 419 420 debug("NCSI: adding new package %d\n", np); 421 422 ncsi_priv->packages = realloc(ncsi_priv->packages, 423 sizeof(struct ncsi_package) * 424 (ncsi_priv->n_packages + 1)); 425 if (!ncsi_priv->packages) { 426 printf("NCSI: could not allocate memory for new package\n"); 427 return; 428 } 429 430 ncsi_priv->packages[np].id = np; 431 ncsi_priv->packages[np].n_channels = 0; 432 ncsi_priv->packages[np].channels = NULL; 433 ncsi_priv->n_packages++; 434 } 435 436 static void ncsi_update_state(struct ncsi_rsp_pkt_hdr *nh) 437 { 438 bool timeout = !nh; 439 int np, nc; 440 441 switch (ncsi_priv->state) { 442 case NCSI_PROBE_PACKAGE_SP: 443 if (!timeout && 444 ncsi_priv->current_package + 1 < NCSI_PACKAGE_MAX) { 445 ncsi_priv->current_package++; 446 } else { 447 ncsi_priv->state = NCSI_PROBE_PACKAGE_DP; 448 ncsi_priv->current_package = 0; 449 } 450 return ncsi_probe_packages(); 451 case NCSI_PROBE_PACKAGE_DP: 452 if (ncsi_priv->current_package + 1 < ncsi_priv->n_packages && 453 !timeout) { 454 ncsi_priv->current_package++; 455 } else { 456 if (!ncsi_priv->n_packages) { 457 printf("NCSI: no packages found\n"); 458 net_set_state(NETLOOP_FAIL); 459 return; 460 } 461 printf("NCSI: probing channels\n"); 462 ncsi_priv->state = NCSI_PROBE_CHANNEL_SP; 463 ncsi_priv->current_package = 0; 464 ncsi_priv->current_channel = 0; 465 } 466 return ncsi_probe_packages(); 467 case NCSI_PROBE_CHANNEL_SP: 468 if (!timeout && nh->common.type == NCSI_PKT_RSP_SP) { 469 ncsi_priv->state = NCSI_PROBE_CHANNEL; 470 return ncsi_probe_packages(); 471 } 472 printf("NCSI: failed to select package 0x%0x2 or timeout\n", 473 ncsi_priv->current_package); 474 net_set_state(NETLOOP_FAIL); 475 break; 476 case NCSI_PROBE_CHANNEL: 477 // TODO only does package 0 for now 478 if (ncsi_priv->pending_requests == 0) { 479 np = ncsi_priv->current_package; 480 nc = ncsi_priv->current_channel; 481 482 /* Configure first channel that has link */ 483 if (ncsi_priv->packages[np].channels[nc].has_link) { 484 ncsi_priv->state = NCSI_CONFIG; 485 } else if (ncsi_priv->current_channel + 1 < 486 NCSI_CHANNEL_MAX) { 487 ncsi_priv->current_channel++; 488 } else { 489 // XXX As above only package 0 490 printf("NCSI: no channel found with link\n"); 491 net_set_state(NETLOOP_FAIL); 492 return; 493 } 494 return ncsi_probe_packages(); 495 } 496 break; 497 case NCSI_CONFIG: 498 if (ncsi_priv->pending_requests == 0) { 499 printf("NCSI: configuration done!\n"); 500 net_set_state(NETLOOP_SUCCESS); 501 } else if (timeout) { 502 printf("NCSI: timeout during configure\n"); 503 net_set_state(NETLOOP_FAIL); 504 } 505 break; 506 default: 507 printf("NCSI: something went very wrong, nevermind\n"); 508 net_set_state(NETLOOP_FAIL); 509 break; 510 } 511 } 512 513 static void ncsi_timeout_handler(void) 514 { 515 if (ncsi_priv->pending_requests) 516 ncsi_priv->pending_requests--; 517 518 ncsi_update_state(NULL); 519 } 520 521 static int ncsi_send_command(unsigned int np, unsigned int nc, unsigned int cmd, 522 uchar *payload, int len, bool wait) 523 { 524 struct ncsi_pkt_hdr *hdr; 525 __be32 *pchecksum; 526 int eth_hdr_size; 527 u32 checksum; 528 uchar *pkt, *start; 529 int final_len; 530 531 pkt = calloc(1, PKTSIZE_ALIGN + PKTALIGN); 532 if (!pkt) 533 return -ENOMEM; 534 start = pkt; 535 536 eth_hdr_size = net_set_ether(pkt, net_bcast_ethaddr, PROT_NCSI); 537 pkt += eth_hdr_size; 538 539 /* Set NCSI command header fields */ 540 hdr = (struct ncsi_pkt_hdr *)pkt; 541 hdr->mc_id = 0; 542 hdr->revision = NCSI_PKT_REVISION; 543 hdr->id = ++ncsi_priv->last_request; 544 ncsi_priv->requests[ncsi_priv->last_request] = 1; 545 hdr->type = cmd; 546 hdr->channel = NCSI_TO_CHANNEL(np, nc); 547 hdr->length = htons(len); 548 549 if (payload && len) 550 memcpy(pkt + sizeof(struct ncsi_pkt_hdr), payload, len); 551 552 /* Calculate checksum */ 553 checksum = ncsi_calculate_checksum((unsigned char *)hdr, 554 sizeof(*hdr) + len); 555 pchecksum = (__be32 *)((void *)(hdr + 1) + len); 556 put_unaligned_be32(checksum, pchecksum); 557 558 if (wait) { 559 net_set_timeout_handler(1000UL, ncsi_timeout_handler); 560 ncsi_priv->pending_requests++; 561 } 562 563 if (len < 26) 564 len = 26; 565 /* frame header, packet header, payload, checksum */ 566 final_len = eth_hdr_size + sizeof(struct ncsi_cmd_pkt_hdr) + len + 4; 567 568 net_send_packet(start, final_len); 569 free(start); 570 return 0; 571 } 572 573 static void ncsi_handle_aen(struct ip_udp_hdr *ip, unsigned int len) 574 { 575 struct ncsi_aen_pkt_hdr *hdr = (struct ncsi_aen_pkt_hdr *)ip; 576 int payload, i; 577 __be32 pchecksum; 578 u32 checksum; 579 580 switch (hdr->type) { 581 case NCSI_PKT_AEN_LSC: 582 printf("NCSI: link state changed\n"); 583 payload = 12; 584 break; 585 case NCSI_PKT_AEN_CR: 586 printf("NCSI: re-configuration required\n"); 587 payload = 4; 588 break; 589 case NCSI_PKT_AEN_HNCDSC: 590 /* Host notifcation - N/A but weird */ 591 debug("NCSI: HNCDSC AEN received\n"); 592 return; 593 default: 594 printf("%s: Invalid type 0x%02x\n", __func__, hdr->type); 595 return; 596 } 597 598 /* Validate packet */ 599 if (hdr->common.revision != 1) { 600 printf("NCSI: 0x%02x response has unsupported revision 0x%x\n", 601 hdr->common.type, hdr->common.revision); 602 return; 603 } 604 605 if (ntohs(hdr->common.length) != payload) { 606 printf("NCSI: 0x%02x response has incorrect length %d\n", 607 hdr->common.type, hdr->common.length); 608 return; 609 } 610 611 pchecksum = get_unaligned_be32((void *)(hdr + 1) + payload - 4); 612 if (pchecksum != 0) { 613 checksum = ncsi_calculate_checksum((unsigned char *)hdr, 614 sizeof(*hdr) + payload - 4); 615 if (pchecksum != checksum) { 616 printf("NCSI: 0x%02x response has invalid checksum\n", 617 hdr->common.type); 618 return; 619 } 620 } 621 622 /* Link or configuration lost - just redo the discovery process */ 623 ncsi_priv->state = NCSI_PROBE_PACKAGE_SP; 624 for (i = 0; i < ncsi_priv->n_packages; i++) 625 free(ncsi_priv->packages[i].channels); 626 free(ncsi_priv->packages); 627 ncsi_priv->n_packages = 0; 628 629 ncsi_priv->current_package = NCSI_PACKAGE_MAX; 630 ncsi_priv->current_channel = NCSI_CHANNEL_MAX; 631 632 ncsi_probe_packages(); 633 } 634 635 void ncsi_receive(struct ethernet_hdr *et, struct ip_udp_hdr *ip, 636 unsigned int len) 637 { 638 struct ncsi_rsp_pkt *pkt = (struct ncsi_rsp_pkt *)ip; 639 struct ncsi_rsp_pkt_hdr *nh = (struct ncsi_rsp_pkt_hdr *)&pkt->rsp; 640 void (*handler)(struct ncsi_rsp_pkt *pkt) = NULL; 641 unsigned short payload; 642 643 if (ncsi_priv->pending_requests) 644 ncsi_priv->pending_requests--; 645 646 if (len < sizeof(struct ncsi_rsp_pkt_hdr)) { 647 printf("NCSI: undersized packet: %u bytes\n", len); 648 goto out; 649 } 650 651 if (nh->common.type == NCSI_PKT_AEN) 652 return ncsi_handle_aen(ip, len); 653 654 switch (nh->common.type) { 655 case NCSI_PKT_RSP_SP: 656 payload = 4; 657 handler = ncsi_rsp_sp; 658 break; 659 case NCSI_PKT_RSP_DP: 660 payload = 4; 661 handler = ncsi_rsp_dp; 662 break; 663 case NCSI_PKT_RSP_CIS: 664 payload = 4; 665 handler = ncsi_rsp_cis; 666 break; 667 case NCSI_PKT_RSP_GLS: 668 payload = 16; 669 handler = ncsi_rsp_gls; 670 break; 671 case NCSI_PKT_RSP_GVI: 672 payload = 40; 673 handler = ncsi_rsp_gvi; 674 break; 675 case NCSI_PKT_RSP_GC: 676 payload = 32; 677 handler = ncsi_rsp_gc; 678 break; 679 case NCSI_PKT_RSP_SMA: 680 payload = 4; 681 handler = ncsi_rsp_sma; 682 break; 683 case NCSI_PKT_RSP_EBF: 684 payload = 4; 685 handler = ncsi_rsp_ebf; 686 break; 687 case NCSI_PKT_RSP_ECNT: 688 payload = 4; 689 handler = ncsi_rsp_ecnt; 690 break; 691 case NCSI_PKT_RSP_EC: 692 payload = 4; 693 handler = ncsi_rsp_ec; 694 break; 695 case NCSI_PKT_RSP_AE: 696 payload = 4; 697 handler = NULL; 698 break; 699 default: 700 printf("NCSI: unsupported packet type 0x%02x\n", 701 nh->common.type); 702 goto out; 703 } 704 705 if (ncsi_validate_rsp(pkt, payload) != 0) { 706 printf("NCSI: discarding invalid packet of type 0x%02x\n", 707 nh->common.type); 708 goto out; 709 } 710 711 if (handler) 712 handler(pkt); 713 out: 714 ncsi_update_state(nh); 715 } 716 717 static void ncsi_send_sp(unsigned int np) 718 { 719 uchar payload[4] = {0}; 720 721 printf("%s\n", __func__); 722 723 ncsi_send_command(np, NCSI_RESERVED_CHANNEL, NCSI_PKT_CMD_SP, 724 (unsigned char *)&payload, 725 cmd_payload(NCSI_PKT_CMD_SP), true); 726 } 727 728 static void ncsi_send_dp(unsigned int np) 729 { 730 ncsi_send_command(np, NCSI_RESERVED_CHANNEL, NCSI_PKT_CMD_DP, NULL, 0, 731 true); 732 } 733 734 static void ncsi_send_gls(unsigned int np, unsigned int nc) 735 { 736 ncsi_send_command(np, nc, NCSI_PKT_CMD_GLS, NULL, 0, true); 737 } 738 739 static void ncsi_send_cis(unsigned int np, unsigned int nc) 740 { 741 ncsi_send_command(np, nc, NCSI_PKT_CMD_CIS, NULL, 0, true); 742 } 743 744 static void ncsi_send_ae(unsigned int np, unsigned int nc) 745 { 746 struct ncsi_cmd_ae_pkt cmd; 747 748 memset(&cmd, 0, sizeof(cmd)); 749 cmd.mode = htonl(ncsi_priv->packages[np].channels[nc].cap_aen); 750 751 ncsi_send_command(np, nc, NCSI_PKT_CMD_AE, 752 ((unsigned char *)&cmd) 753 + sizeof(struct ncsi_cmd_pkt_hdr), 754 cmd_payload(NCSI_PKT_CMD_AE), true); 755 } 756 757 static void ncsi_send_ebf(unsigned int np, unsigned int nc) 758 { 759 struct ncsi_cmd_ebf_pkt cmd; 760 761 memset(&cmd, 0, sizeof(cmd)); 762 cmd.mode = htonl(ncsi_priv->packages[np].channels[nc].cap_bc); 763 764 ncsi_send_command(np, nc, NCSI_PKT_CMD_EBF, 765 ((unsigned char *)&cmd) 766 + sizeof(struct ncsi_cmd_pkt_hdr), 767 cmd_payload(NCSI_PKT_CMD_EBF), true); 768 } 769 770 static void ncsi_send_sma(unsigned int np, unsigned int nc) 771 { 772 struct ncsi_cmd_sma_pkt cmd; 773 unsigned char *addr, i; 774 775 addr = eth_get_ethaddr(); 776 if (!addr) { 777 printf("NCSI: no MAC address configured\n"); 778 return; 779 } 780 781 memset(&cmd, 0, sizeof(cmd)); 782 for (i = 0; i < ARP_HLEN; i++) 783 cmd.mac[i] = addr[i]; 784 cmd.index = 1; 785 cmd.at_e = 1; 786 787 ncsi_send_command(np, nc, NCSI_PKT_CMD_SMA, 788 ((unsigned char *)&cmd) 789 + sizeof(struct ncsi_cmd_pkt_hdr), 790 cmd_payload(NCSI_PKT_CMD_SMA), true); 791 } 792 793 void ncsi_probe_packages(void) 794 { 795 struct ncsi_package *package; 796 unsigned int np, nc; 797 798 switch (ncsi_priv->state) { 799 case NCSI_PROBE_PACKAGE_SP: 800 if (ncsi_priv->current_package == NCSI_PACKAGE_MAX) 801 ncsi_priv->current_package = 0; 802 printf("%s: NCSI_PROBE_PACKAGE_SP current_package %d\n", 803 __func__, ncsi_priv->current_package); 804 ncsi_send_sp(ncsi_priv->current_package); 805 break; 806 case NCSI_PROBE_PACKAGE_DP: 807 printf("%s: NCSI_PROBE_PACKAGE_DP current_package %d\n", 808 __func__, ncsi_priv->current_package); 809 ncsi_send_dp(ncsi_priv->current_package); 810 break; 811 case NCSI_PROBE_CHANNEL_SP: 812 printf("%s: NCSI_PROBE_CHANNEL_SP\n", __func__); 813 if (ncsi_priv->n_packages > 0) 814 ncsi_send_sp(ncsi_priv->current_package); 815 else 816 printf("NCSI: no packages discovered, configuration not possible\n"); 817 break; 818 case NCSI_PROBE_CHANNEL: 819 printf("%s NCSI_PROBE_CHANNEL package %d channel %d\n", 820 __func__, 821 ncsi_priv->current_package, 822 ncsi_priv->current_channel); 823 /* Kicks off chain of channel discovery */ 824 ncsi_send_cis(ncsi_priv->current_package, 825 ncsi_priv->current_channel); 826 break; 827 case NCSI_CONFIG: 828 for (np = 0; np < ncsi_priv->n_packages; np++) { 829 package = &ncsi_priv->packages[np]; 830 for (nc = 0; nc < package->n_channels; nc++) 831 if (package->channels[nc].has_link) 832 break; 833 if (nc < package->n_channels) 834 break; 835 } 836 if (np == ncsi_priv->n_packages) { 837 printf("NCSI: no link available\n"); 838 return; 839 } 840 841 printf("NCSI: configuring channel %d\n", nc); 842 ncsi_priv->current_package = np; 843 ncsi_priv->current_channel = nc; 844 /* Kicks off rest of configure chain */ 845 ncsi_send_sma(np, nc); 846 break; 847 default: 848 printf("NCSI: unknown state 0x%x\n", ncsi_priv->state); 849 } 850 } 851 852 int ncsi_probe(struct phy_device *phydev) 853 { 854 if (!phydev->priv) { 855 phydev->priv = malloc(sizeof(struct ncsi)); 856 if (!phydev->priv) 857 return -ENOMEM; 858 memset(phydev->priv, 0, sizeof(struct ncsi)); 859 } 860 861 ncsi_priv = phydev->priv; 862 863 return 0; 864 } 865 866 int ncsi_startup(struct phy_device *phydev) 867 { 868 /* Set phydev parameters */ 869 phydev->speed = SPEED_100; 870 phydev->duplex = DUPLEX_FULL; 871 /* Normal phy reset is N/A */ 872 phydev->flags |= PHY_FLAG_BROKEN_RESET; 873 874 /* Set initial probe state */ 875 ncsi_priv->state = NCSI_PROBE_PACKAGE_SP; 876 877 /* No active package/channel yet */ 878 ncsi_priv->current_package = NCSI_PACKAGE_MAX; 879 ncsi_priv->current_channel = NCSI_CHANNEL_MAX; 880 881 /* Pretend link works so the MAC driver sets final bits up */ 882 phydev->link = true; 883 884 /* Set ncsi_priv so we can use it when called from net_loop() */ 885 ncsi_priv = phydev->priv; 886 887 return 0; 888 } 889 890 int ncsi_shutdown(struct phy_device *phydev) 891 { 892 printf("NCSI: Disabling package %d\n", ncsi_priv->current_package); 893 ncsi_send_dp(ncsi_priv->current_package); 894 return 0; 895 } 896 897 static struct phy_driver ncsi_driver = { 898 .uid = PHY_NCSI_ID, 899 .mask = 0xffffffff, 900 .name = "NC-SI", 901 .features = PHY_100BT_FEATURES | PHY_DEFAULT_FEATURES | SUPPORTED_100baseT_Full | SUPPORTED_MII, 902 .probe = ncsi_probe, 903 .startup = ncsi_startup, 904 .shutdown = ncsi_shutdown, 905 }; 906 907 int phy_ncsi_init(void) 908 { 909 phy_register(&ncsi_driver); 910 return 0; 911 } 912