l2switch.c (14439B)
1 /* 2 * 3 * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file. 4 * 5 * Copyright 2007-2019 Broadcom Inc. All rights reserved. 6 * 7 * l2switch.c: Example L2 Switching Application 8 */ 9 10 #include <shared/bsl.h> 11 12 #include <sal/core/boot.h> 13 #include <sal/appl/sal.h> 14 #include <sal/appl/io.h> 15 #include <sal/appl/pci.h> 16 #include <sal/appl/config.h> 17 18 #include <soc/drv.h> 19 #include <soc/mem.h> 20 #include <soc/debug.h> 21 #include <soc/cmext.h> 22 23 #include <bcm/init.h> 24 #include <bcm/rx.h> 25 #include <bcm/error.h> 26 27 #include <stdlib.h> 28 29 30 #include <appl/diag/system.h> /* system_init */ 31 32 /* Build Information */ 33 34 extern char *_build_release; 35 extern char *_build_user; 36 extern char *_build_host; 37 extern char *_build_date; 38 extern char *_build_tree; 39 extern char *_build_arch; 40 extern char *_build_os; 41 42 /* 43 * System Configuration (Config Manager and PCI Device Config) 44 */ 45 46 typedef struct sysconf_pci_dev_s { 47 int cm_dev; 48 49 pci_dev_t pciDevice; /* Bus, device, function */ 50 uint32 pciMemBaseAddr; /* PCI base memory address of SOC */ 51 uint16 pciDevID; /* PCI device ID (0x5600, 0x5800, etc) */ 52 uint8 pciRevID; /* PCI revision ID (chip rev) */ 53 uint8 pciIntPin; 54 uint8 pciIntLine; 55 } sysconf_pci_dev_t; 56 57 static sysconf_pci_dev_t _devices[SOC_MAX_NUM_DEVICES]; 58 static int _ndevices = 0; 59 60 char * 61 sysconf_get_property(const char *property) 62 { 63 return sal_config_get(property); 64 } 65 66 static char * 67 _config_var_get(soc_cm_dev_t *dev, const char *property) 68 { 69 return sysconf_get_property(property); 70 } 71 72 static void 73 _write(soc_cm_dev_t *dev, uint32 addr, uint32 data) 74 { 75 #if defined(PLISIM) 76 sysconf_pci_dev_t *soc = &_devices[dev->dev]; 77 pci_memory_putw(&soc->pciDevice, addr, data); 78 #else 79 *((uint32*)addr) = data; 80 #endif 81 } 82 83 static uint32 84 _read(soc_cm_dev_t *dev, uint32 addr) 85 { 86 #if defined(PLISIM) 87 sysconf_pci_dev_t *soc = &_devices[dev->dev]; 88 return pci_memory_getw(&soc->pciDevice, addr); 89 #else 90 return *((uint32*)addr); 91 #endif 92 } 93 94 static void * 95 _salloc(soc_cm_dev_t *dev, int size, const char *name) 96 { 97 return sal_dma_alloc(size, (char *)name); 98 } 99 100 static void 101 _sfree(soc_cm_dev_t *dev, void *ptr) 102 { 103 sal_dma_free(ptr); 104 } 105 106 static int 107 _sflush(soc_cm_dev_t *dev, void *addr, int length) 108 { 109 return sal_dma_flush(addr, length), 0; 110 } 111 112 static int 113 _sinval(soc_cm_dev_t *dev, void *addr, int length) 114 { 115 return sal_dma_inval(addr, length), 0; 116 } 117 118 static int 119 _interrupt_connect(soc_cm_dev_t *dev, soc_cm_isr_func_t handler, void *data) 120 { 121 sysconf_pci_dev_t *pci_dev = (sysconf_pci_dev_t *)dev->cookie; 122 123 LOG_INFO(BSL_LS_SOC_PCI, 124 (BSL_META("sysconf_probe: connecting INT%c# to IRQ %d\n"), 125 'A' + pci_dev->pciIntPin - 1, pci_dev->pciIntLine)); 126 127 return pci_int_connect(pci_dev->pciIntLine, (pci_isr_t) handler, data); 128 } 129 130 static int 131 _interrupt_disconnect(soc_cm_dev_t *dev) 132 { 133 return 1; 134 } 135 136 /* 137 * Function: 138 * sysconf_chip_override 139 * Purpose: 140 * For driver testing only, allow properties to override the PCI 141 * device ID/rev ID for a particular unit to specified values. 142 * Parameters: 143 * unit - Unit number 144 * devID, revID - (IN, OUT) original PCI ID info 145 */ 146 147 void 148 sysconf_chip_override(int unit, uint16 *devID, uint8 *revID) 149 { 150 char prop[64], *s; 151 152 sprintf(prop, "pci_override_dev.%d", unit); 153 154 if ((s = sysconf_get_property(prop)) == NULL) { 155 s = sysconf_get_property("pci_override_dev"); 156 } 157 158 if (s != NULL) { 159 *devID = sal_ctoi(s, 0); 160 } 161 162 sprintf(prop, "pci_override_rev.%d", unit); 163 164 if ((s = sysconf_get_property(prop)) == NULL) { 165 s = sysconf_get_property("pci_override_rev"); 166 } 167 168 if (s != NULL) { 169 *revID = sal_ctoi(s, 0); 170 } 171 } 172 173 /* 174 * _setup_pci 175 * 176 * Utility routine used by sysconf_probe 177 */ 178 179 static int 180 _setup_pci(int unit) 181 { 182 sysconf_pci_dev_t *soc = &_devices[unit]; 183 pci_dev_t *dev = &soc->pciDevice; 184 uint16 driverDevID; 185 uint8 driverRevID; 186 187 soc_cm_get_id_driver(soc->pciDevID, soc->pciRevID, 188 &driverDevID, &driverRevID); 189 190 LOG_CLI((BSL_META_U(unit, 191 "PCI Discovery: found unit %d: %s " 192 "on bus %d, dev 0x%x, fn %d\n" 193 "Using driver: %s\n"), 194 unit, 195 soc_cm_get_device_name(soc->pciDevID, soc->pciRevID), 196 dev->busNo, dev->devNo, dev->funcNo, 197 soc_cm_get_device_name(driverDevID, driverRevID))); 198 199 /* Write control word (turns on parity detect) */ 200 201 pci_config_putw(dev, PCI_CONF_COMM, (PCI_COMM_ME | 202 PCI_COMM_MAE | 203 PCI_COMM_PARITY_DETECT)); 204 205 /* 206 * On platforms where the underlying OS or BIOS has not 207 * automatically assigned a value to the StrataSwitch MBAR and/or 208 * intLine, we need to write them here. PCI_SOC_MBAR(unit) and 209 * PCI_SOC_INTLINE(unit) are defined in <sal/appl/pci.h> for these 210 * platforms, which include PLISIM, Sandpoint, Mousse, and IDT. 211 */ 212 213 #ifdef PCI_SOC_MBAR 214 pci_config_putw(dev, PCI_CONF_BASE0, PCI_SOC_MBAR(unit)); 215 LOG_INFO(BSL_LS_SOC_PCI, 216 (BSL_META_U(unit, 217 "Set PCI MBAR 0x%x\n"), PCI_SOC_MBAR(unit))); 218 #endif 219 220 #ifdef PCI_SOC_INTLINE 221 { 222 uint32 tmp = pci_config_getw(dev, PCI_CONF_ILINE); 223 tmp = (tmp & ~0xff) | PCI_SOC_INTLINE(unit); 224 pci_config_putw(dev, PCI_CONF_ILINE, tmp); 225 } 226 #endif 227 228 soc->pciMemBaseAddr = 229 pci_config_getw(dev, PCI_CONF_BASE0) & PCI_MBASE_MASK; 230 231 LOG_INFO(BSL_LS_SOC_PCI, 232 (BSL_META_U(unit, 233 "Read back PCI MBAR 0x%x\n"), soc->pciMemBaseAddr)); 234 235 /* 236 * Set # retries to infinite. Otherwise other devices using the bus 237 * may monopolize it long enough for us to time out. 238 */ 239 240 pci_config_putw(dev, PCI_CONF_TRDY_TO, 0x0080); 241 242 /* 243 * Sanity check to ensure first CMIC register is accessible. 244 */ 245 246 if (sal_memory_check(soc->pciMemBaseAddr) < 0) { 247 LOG_CLI((BSL_META_U(unit, 248 "sysconf_probe: unable to probe address 0x%x\n"), 249 soc->pciMemBaseAddr)); 250 return -1; 251 } 252 253 /* 254 * Hook up PCI device interrupt to our ISR. The interrupt number is 255 * determined by reading the value configured by the BIOS from PCI 256 * config space. The SOC uses PCI pin INTA#. 257 */ 258 259 soc->pciIntLine = pci_config_getw(dev, PCI_CONF_ILINE) >> 0 & 0xff; 260 soc->pciIntPin = pci_config_getw(dev, PCI_CONF_ILINE) >> 8 & 0xff; 261 262 return 0; 263 } 264 265 STATIC int 266 _sysconf_probe_dev(pci_dev_t *dev, 267 uint16 venID, uint16 devID, uint8 revID) 268 { 269 sysconf_pci_dev_t *cookie; 270 int device_handle; 271 int unit; 272 273 unit = _ndevices; 274 275 sysconf_chip_override(unit, &devID, &revID); 276 277 if (venID != BROADCOM_VENDOR_ID || 278 soc_cm_device_supported(devID, revID) < 0) { 279 /* Not a switch chip; continue probing other devices */ 280 return 0; 281 } 282 283 if (unit == SOC_MAX_NUM_DEVICES) { 284 /* Already found max chips; stop probing */ 285 return -1; 286 } 287 288 cookie = &_devices[unit]; 289 290 sal_memcpy(&cookie->pciDevice, dev, sizeof (pci_dev_t)); 291 292 cookie->pciDevID = devID; 293 cookie->pciRevID = revID; 294 295 if (_setup_pci(unit) < 0) { 296 /* Error message already printed; continue probing other devices */ 297 return 0; 298 } 299 300 /* Create a device handle, but don't initialize yet */ 301 302 device_handle = soc_cm_device_create(cookie->pciDevID, 303 cookie->pciRevID, 304 cookie); 305 assert(device_handle >= 0); 306 cookie->cm_dev = device_handle; 307 308 _ndevices++; 309 310 return 0; 311 } 312 313 /* 314 * sysconf_probe 315 * 316 * Probes PCI bus for available units (devices), sets soc_ndev to the 317 * number of units found, and fills in the following components of the 318 * sysconf_pci_dev_t driver structure for each unit: 319 * 320 * pciDevice (bus, device, function) 321 * pciMemBaseAddr 322 * pciIntLine 323 * pciIntPin 324 * 325 * Each device's PCI memory space is mapped and interrupts are enabled. 326 * No chip initialization is performed (see soc_attach and soc_init). 327 */ 328 329 int 330 sysconf_probe(void) 331 { 332 int rv = -1; 333 334 LOG_INFO(BSL_LS_SOC_PCI, 335 (BSL_META("sysconf_probe: checking for SOC devices\n"))); 336 337 if (_ndevices > 0) { 338 LOG_ERROR(BSL_LS_SOC_COMMON, 339 (BSL_META("sysconf_probe: probe already done\n"))); 340 goto done; /* Should never probe more than once */ 341 } 342 343 pci_device_iter(_sysconf_probe_dev); 344 345 if (_ndevices == 0) { 346 LOG_ERROR(BSL_LS_SOC_COMMON, 347 (BSL_META("WARNING: No StrataSwitch unit found.\n"))); 348 goto done; 349 } 350 351 rv = 0; 352 353 done: 354 LOG_INFO(BSL_LS_SOC_PCI, 355 (BSL_META("soc_probe: rv=%d\n"), rv)); 356 return rv; 357 } 358 359 int 360 sysconf_attach(int unit) 361 { 362 /* Ready to install into configuration manager */ 363 364 soc_cm_device_vectors_t vectors; 365 sysconf_pci_dev_t* cookie; 366 367 assert(unit >= 0 && unit < _ndevices); 368 369 cookie = &_devices[unit]; 370 371 vectors.big_endian_pio = 0; 372 vectors.big_endian_packet = 0; 373 vectors.big_endian_other = 0; 374 375 #if !defined(IDTRP334) 376 # if !defined(LE_HOST) 377 vectors.big_endian_other = 1; 378 # ifdef COLDFIRE_NATIVE_INTERFACE 379 vectors.big_endian_packet = 1; 380 # endif 381 # endif /* !defined(LE_HOST) */ 382 #endif 383 384 #if defined(IDTRP334) 385 vectors.big_endian_packet = 1; 386 #endif 387 388 vectors.config_var_get = _config_var_get; 389 vectors.interrupt_connect = _interrupt_connect; 390 vectors.interrupt_disconnect= _interrupt_disconnect; 391 vectors.base_address = cookie->pciMemBaseAddr; 392 vectors.read = _read; 393 vectors.write = _write; 394 vectors.salloc = _salloc; 395 vectors.sfree = _sfree; 396 vectors.sinval = _sinval; 397 vectors.sflush = _sflush; 398 vectors.l2p = NULL; 399 vectors.p2l = NULL; 400 401 if (soc_cm_device_init(cookie->cm_dev, &vectors) < 0) { 402 LOG_CLI((BSL_META_U(unit, 403 "sysconf_attach: bcm device init failed\n"))); 404 return -1; 405 } 406 407 return 0; 408 } 409 410 int 411 sysconf_detach(int unit) 412 { 413 assert(unit >= 0 && unit < _ndevices); 414 return soc_cm_device_destroy(unit); 415 } 416 417 pci_dev_t * 418 sysconf_get_pci_device(int unit) 419 { 420 return &_devices[unit].pciDevice; 421 } 422 423 static int 424 _sysconf_debug_out(uint32 flags, const char *format, va_list args) 425 { 426 return (flags) ? vdebugk(flags, format, args) : vprintk(format, args); 427 } 428 429 static int 430 _sysconf_dump(soc_cm_dev_t *cookie) 431 { 432 sysconf_pci_dev_t *dev = (sysconf_pci_dev_t *)cookie->cookie; 433 434 LOG_CLI((BSL_META("PCI: Base=0x%x Bus=%d Dev=0x%x iPin=%d iLine=%d\n"), 435 dev->pciMemBaseAddr, 436 dev->pciDevice.busNo, dev->pciDevice.devNo, 437 dev->pciIntPin, dev->pciIntLine)); 438 439 return 0; 440 } 441 442 int 443 sysconf_init(void) 444 { 445 soc_cm_init_t init_data; 446 447 _ndevices = 0; 448 449 init_data.debug_out = _sysconf_debug_out; 450 init_data.debug_check = debugk_check; 451 init_data.debug_dump = _sysconf_dump; 452 453 return soc_cm_init(&init_data); 454 } 455 456 #if 0 457 /* 458 * Custom handler for assertion failures in the driver 459 */ 460 461 void _diag_assert(const char *expr, const char *file, int line) 462 { 463 #ifdef VXWORKS 464 extern void sysReboot(void); 465 # if defined(MOUSSE) || defined(BMW) 466 extern void sysBacktracePpc(char *pfx, char *sfx, int direct); 467 # endif 468 #endif 469 int int_ctxt; 470 471 #ifdef UNIX 472 /* 473 * You can have assertion failures call abort() when you're in GDB 474 * by adding the following to your ~/.gdbinit: set environment GDB 1 475 */ 476 477 if (getenv("GDB")) 478 abort(); 479 #endif 480 481 LOG_CLI((BSL_META("ERROR: Assertion failed: (%s) at %s:%d\n"), expr, file, line)); 482 483 int_ctxt = sal_int_context(); 484 485 #ifdef VXWORKS 486 # if defined(MOUSSE) || defined(BMW) 487 sysBacktracePpc("ERROR: Stack trace follows\n", "", int_ctxt); 488 # endif 489 if (int_ctxt) 490 sysReboot(); 491 #endif /* VXWORKS */ 492 493 /* 494 * Allow user to continue or return to command prompt. 495 */ 496 497 LOG_CLI((BSL_META("WARNING: continuing: correct behavior no longer guaranteed!\n"))); 498 } 499 #endif 500 501 bcm_rx_t 502 packet_process(int unit, bcm_pkt_t *pkt, void *cookie) 503 { 504 int i; 505 uint8 *p; 506 507 LOG_CLI((BSL_META_U(unit, 508 "=== Packet received: port %d length %d ===\n"), 509 pkt->rx_port, pkt->tot_len)); 510 511 p = BCM_PKT_IEEE(pkt); 512 for (i = 0; i < pkt->tot_len; i++) { 513 LOG_CLI((BSL_META_U(unit, 514 "%02x%s"), p[i], (i % 16) == 15 ? "\n" : " ")); 515 } 516 if ((pkt->tot_len % 16) != 0) { 517 LOG_CLI((BSL_META_U(unit, 518 "\n"))); 519 } 520 return BCM_RX_HANDLED; 521 } 522 523 /* 524 * Example L2 Switching Application 525 * Main entry point 526 */ 527 528 int main(int argc, char *argv[]) 529 { 530 int unit = 0; 531 int rv; 532 533 if (sal_core_init() < 0 || sal_appl_init() < 0) { 534 LOG_CLI((BSL_META_U(unit, 535 "SAL Initialization failed\n"))); 536 exit(1); 537 } 538 539 #if 0 540 sal_assert_set(_diag_assert); 541 #endif 542 543 #ifdef UNIX 544 if (getenv("DK")) 545 debugk_enable(sal_ctoi(getenv("DK"), 0)); 546 #endif 547 548 LOG_CLI((BSL_META_U(unit, 549 "Example L2 Switching Application\n"))); 550 LOG_CLI((BSL_META_U(unit, 551 "Version %s built %s\n"), _build_release, _build_date)); 552 553 sysconf_init(); 554 555 if ((rv = sysconf_probe()) < 0) { 556 LOG_CLI((BSL_META_U(unit, 557 "ERROR: PCI device probe failed\n"))); 558 return -1; 559 } 560 561 unit = 0; 562 563 LOG_CLI((BSL_META_U(unit, 564 "Attaching unit %d...\n"), unit)); 565 566 if (sysconf_attach(unit) < 0) { 567 LOG_CLI((BSL_META_U(unit, 568 "ERROR: PCI device attach failed\n"))); 569 return -1; 570 } 571 572 LOG_CLI((BSL_META_U(unit, 573 "Initializing unit %d...\n"), unit)); 574 575 if ((rv = system_init(unit)) < 0) { 576 LOG_CLI((BSL_META_U(unit, 577 "ERROR: Driver initialization failed: %s\n"), bcm_errmsg(rv))); 578 return -1; 579 } 580 581 LOG_CLI((BSL_META_U(unit, 582 "Initializing packet receiver...\n"))); 583 584 rv = bcm_rx_start(unit, NULL); 585 if (rv < 0) { 586 LOG_CLI((BSL_META_U(unit, 587 "ERROR: Packet receiver not started: %s\n"), bcm_errmsg(rv))); 588 } 589 590 rv = bcm_rx_register(unit, "l2switch", packet_process, 591 BCM_RX_PRIO_MAX, (void *)0, BCM_RCO_F_ALL_COS); 592 if (rv < 0) { 593 LOG_CLI((BSL_META_U(unit, 594 "ERROR: Packet monitor registration failed: %s\n"), 595 bcm_errmsg(rv))); 596 } 597 598 LOG_CLI((BSL_META_U(unit, 599 "Switching started.\n"))); 600 601 for (;;) { 602 /* Process packets and stuff */ 603 sal_usleep(250000); 604 } 605 606 /* NOTREACHED */ 607 return 0; 608 }