openbcm

Git mirror of https://github.com/Broadcom-Network-Switching-Software/OpenBCM
git clone git://git.finwo.net/mirror/broadcom/openbcm
Log | Files | Refs | README

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 }