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