Annotation of cf/dev_nm_16esw.c, revision 1.1.1.2

1.1       root        1: /*
                      2:  * Cisco C3600 simulation platform.
                      3:  * Copyright (c) 2006 Christophe Fillot ([email protected])
                      4:  *
                      5:  * NM-16ESW ethernet switch module (experimental!)
                      6:  *
                      7:  * It's an attempt of proof of concept, so not optimized at all at this time.
                      8:  * Only L2 switching will be managed (no L3 at all).
                      9:  *
                     10:  * To do next: QoS features (CoS/DSCP handling).
                     11:  */
                     12: 
                     13: #include <stdio.h>
                     14: #include <stdlib.h>
                     15: #include <string.h>
                     16: #include <stdarg.h>
                     17: #include <unistd.h>
                     18: #include <time.h>
                     19: #include <errno.h>
                     20: #include <assert.h>
                     21: 
                     22: #include "utils.h"
                     23: #include "timer.h"
                     24: #include "net.h"
                     25: #include "net_io.h"
                     26: #include "ptask.h"
                     27: #include "dev_nm_16esw.h"
                     28: 
                     29: /* Debugging flags */
                     30: #define DEBUG_ACCESS     0
                     31: #define DEBUG_UNKNOWN    0
                     32: #define DEBUG_MII        0
                     33: #define DEBUG_MEM        0
1.1.1.2 ! root       34: #define DEBUG_REG        0
1.1       root       35: #define DEBUG_TRANSMIT   0
                     36: #define DEBUG_RECEIVE    0
                     37: #define DEBUG_FORWARD    0
                     38: #define DEBUG_MIRROR     0
                     39: #define DEBUG_ARL        0
                     40: 
                     41: /* Invalid VLAN value */
                     42: #define VLAN_INVALID   0xFFF
                     43: 
                     44: /* Maximum packet size */
                     45: #define BCM5600_MAX_PKT_SIZE  2048
                     46: 
                     47: /* PCI vendor/product codes */
                     48: #define BCM5605_PCI_VENDOR_ID   0x14e4
                     49: #define BCM5605_PCI_PRODUCT_ID  0x5605
                     50: 
                     51: /* "S-channel" commands */
                     52: #define BCM5600_SCHAN_CMD_LINKSCAN    0x13
                     53: #define BCM5600_SCHAN_CMD_EXEC        0x80
                     54: #define BCM5600_SCHAN_CMD_READ_MII    0x90
                     55: #define BCM5600_SCHAN_CMD_WRITE_MII   0x91
                     56: 
                     57: /* Opcodes */
                     58: #define BCM5600_OP_BP_WARN_STATUS     0x01
                     59: #define BCM5600_OP_BP_DISCARD_STATUS  0x02
                     60: #define BCM5600_OP_COS_QSTAT_NOTIFY   0x03
                     61: #define BCM5600_OP_HOL_STAT_NOTIFY    0x04
                     62: #define BCM5600_OP_GBP_FULL_NOTIFY    0x05
                     63: #define BCM5600_OP_GBP_AVAIL_NOTIFY   0x06
                     64: #define BCM5600_OP_READ_MEM_CMD       0x07
                     65: #define BCM5600_OP_READ_MEM_ACK       0x08
                     66: #define BCM5600_OP_WRITE_MEM_CMD      0x09
                     67: #define BCM5600_OP_WRITE_MEM_ACK      0x0A
                     68: #define BCM5600_OP_READ_REG_CMD       0x0B
                     69: #define BCM5600_OP_READ_REG_ACK       0x0C
                     70: #define BCM5600_OP_WRITE_REG_CMD      0x0D
                     71: #define BCM5600_OP_WRITE_REG_ACK      0x0E
                     72: #define BCM5600_OP_ARL_INSERT_CMD     0x0F
                     73: #define BCM5600_OP_ARL_INSERT_DONE    0x10
                     74: #define BCM5600_OP_ARL_DELETE_CMD     0x11
                     75: #define BCM5600_OP_ARL_DELETE_DONE    0x12
                     76: #define BCM5600_OP_LINKSTAT_NOTIFY    0x13
                     77: #define BCM5600_OP_MEM_FAIL_NOTIFY    0x14
                     78: #define BCM5600_OP_INIT_CFAP          0x15
                     79: #define BCM5600_OP_INIT_SFAP          0x16
                     80: #define BCM5600_OP_ENTER_DEBUG_MODE   0x17
                     81: #define BCM5600_OP_EXIT_DEBUG_MODE    0x18
                     82: #define BCM5600_OP_ARL_LOOKUP_CMD     0x19
                     83: 
                     84: /* Command details */
                     85: #define BCM5600_CMD_OP_MASK      0xFC000000
                     86: #define BCM5600_CMD_OP_SHIFT     26
                     87: #define BCM5600_CMD_DST_MASK     0x03F00000
                     88: #define BCM5600_CMD_DST_SHIFT    20
                     89: #define BCM5600_CMD_SRC_MASK     0x000FC000
                     90: #define BCM5600_CMD_SRC_SHIFT    14
                     91: #define BCM5600_CMD_LEN_MASK     0x00003F80
                     92: #define BCM5600_CMD_LEN_SHIFT    7
                     93: #define BCM5600_CMD_EBIT_MASK    0x00000040
                     94: #define BCM5600_CMD_EBIT_SHIFT   6
                     95: #define BCM5600_CMD_ECODE_MASK   0x00000030
                     96: #define BCM5600_CMD_ECODE_SHIFT  4
                     97: #define BCM5600_CMD_COS_MASK     0x0000000E
                     98: #define BCM5600_CMD_COS_SHIFT    1
                     99: #define BCM5600_CMD_CPU_MASK     0x00000001
                    100: #define BCM5600_CMD_CPU_SHIFT    0
                    101: 
                    102: /* Memory zones */
                    103: #define BCM5600_ADDR_ARLCNT0     0x01000000
                    104: #define BCM5600_ADDR_ARLCNT1     0x01100000
                    105: #define BCM5600_ADDR_ARLCNT2     0x01200000
                    106: #define BCM5600_ADDR_ARL0        0x02000000
                    107: #define BCM5600_ADDR_ARL1        0x02100000
                    108: #define BCM5600_ADDR_ARL2        0x02200000
                    109: #define BCM5600_ADDR_PTABLE0     0x03000000
                    110: #define BCM5600_ADDR_PTABLE1     0x03100000
                    111: #define BCM5600_ADDR_PTABLE2     0x03200000
                    112: #define BCM5600_ADDR_VTABLE0     0x05000000
                    113: #define BCM5600_ADDR_VTABLE1     0x05100000
                    114: #define BCM5600_ADDR_VTABLE2     0x05200000
                    115: #define BCM5600_ADDR_TTR0        0x06000000
                    116: #define BCM5600_ADDR_TBMAP0      0x06010000
                    117: #define BCM5600_ADDR_TTR1        0x06100000
                    118: #define BCM5600_ADDR_TBMAP1      0x06110000
                    119: #define BCM5600_ADDR_TTR2        0x06200000
                    120: #define BCM5600_ADDR_TBMAP2      0x06210000
                    121: #define BCM5600_ADDR_IMASK0      0x07000000
                    122: #define BCM5600_ADDR_IRULE0      0x07020000
                    123: #define BCM5600_ADDR_IMASK1      0x07100000
                    124: #define BCM5600_ADDR_IRULE1      0x07120000
                    125: #define BCM5600_ADDR_IMASK2      0x07200000
                    126: #define BCM5600_ADDR_IRULE2      0x07220000
                    127: #define BCM5600_ADDR_GIMASK      0x07300000
                    128: #define BCM5600_ADDR_GIRULE      0x07320000
                    129: #define BCM5600_ADDR_MARL0       0x08000000
                    130: #define BCM5600_ADDR_MARL1       0x08100000
                    131: #define BCM5600_ADDR_MARL2       0x08200000
                    132: #define BCM5600_ADDR_L3          0x09000000
                    133: #define BCM5600_ADDR_DEFIP       0x09010000
                    134: #define BCM5600_ADDR_L3INTF      0x09020000
                    135: #define BCM5600_ADDR_IPMC        0x09030000
                    136: #define BCM5600_ADDR_CBPHDR      0x0A600000
                    137: #define BCM5600_ADDR_CAB0        0x0A610000
                    138: #define BCM5600_ADDR_CAB1        0x0A620000
                    139: #define BCM5600_ADDR_CAB2        0x0A630000
                    140: #define BCM5600_ADDR_CAB3        0x0A640000
                    141: #define BCM5600_ADDR_CCP         0x0A650000
                    142: #define BCM5600_ADDR_PPP         0x0A660000
                    143: #define BCM5600_ADDR_CFAP        0x0A670000
                    144: #define BCM5600_ADDR_SFAP        0x0A680000
                    145: #define BCM5600_ADDR_CBPDATA0    0x0A6A0000
                    146: #define BCM5600_ADDR_CBPDATA1    0x0A6B0000
                    147: #define BCM5600_ADDR_CBPDATA2    0x0A6C0000
                    148: #define BCM5600_ADDR_CBPDATA3    0x0A6D0000
                    149: #define BCM5600_ADDR_PID         0x0A900000
                    150: #define BCM5600_ADDR_XQ_BASE     0x0B600000
                    151: #define BCM5600_ADDR_GBP         0x12000000
                    152: 
                    153: /* Number of "Data Words" */
                    154: #define BCM5600_DW_MAX  32
                    155: 
                    156: /* === VTABLE definitions === */
                    157: /* Word 0 */
                    158: #define BCM5600_VTABLE_VLAN_TAG_MASK      0x00000FFF
                    159: 
                    160: /* Word 1: Port bitmap */
                    161: #define BCM5600_VTABLE_PORT_BMAP_MASK     0x1FFFFFFF
                    162: 
                    163: /* Word 2: Untagged port bitmap */
                    164: #define BCM5600_VTABLE_UT_PORT_BMAP_MASK  0x1FFFFFFF
                    165: 
                    166: /* Word 3: Module bitmap */
                    167: #define BCM5600_VTABLE_MOD_BMAP_MASK      0xFFFFFFFF
                    168: 
                    169: /* === PTABLE definitions === */
                    170: /* Word 0 */
                    171: #define BCM5600_PTABLE_VLAN_TAG_MASK    0x00000FFF
                    172: #define BCM5600_PTABLE_SP_ST_MASK       0x00003000
                    173: #define BCM5600_PTABLE_SP_ST_SHIFT      12
                    174: #define BCM5600_PTABLE_PRT_DIS_MASK     0x000FC000
                    175: #define BCM5600_PTABLE_PRT_DIS_SHIFT    14
                    176: #define BCM5600_PTABLE_JUMBO_FLAG       0x00100000
                    177: #define BCM5600_PTABLE_RTAG_MASK        0x00E00000
                    178: #define BCM5600_PTABLE_RTAG_SHIFT       21
                    179: #define BCM5600_PTABLE_TGID_MASK        0x07000000
                    180: #define BCM5600_PTABLE_TGID_SHIFT       24
                    181: #define BCM5600_PTABLE_TRUNK_FLAG       0x08000000
                    182: #define BCM5600_PTABLE_CPU_FLAG         0x10000000
                    183: #define BCM5600_PTABLE_PTYPE_MASK       0x60000000
                    184: #define BCM5600_PTABLE_PTYPE_SHIFT      29
                    185: #define BCM5600_PTABLE_BPDU_FLAG        0x80000000
                    186: 
                    187: /* Word 1 */
                    188: #define BCM5600_PTABLE_PORT_BMAP_MASK   0x1FFFFFFF
                    189: #define BCM5600_PTABLE_MI_FLAG          0x20000000
                    190: #define BCM5600_PTABLE_CML_MASK         0xC0000000
                    191: #define BCM5600_PTABLE_CML_SHIFT        30
                    192: 
                    193: /* Word 2 */
                    194: #define BCM5600_PTABLE_UT_PORT_BMAP_MASK  0x1FFFFFFF
                    195: 
                    196: /* Word 4 */
                    197: #define BCM5600_PTABLE_DSCP_MASK        0x0000003F
                    198: #define BCM5600_PTABLE_DSCP_SHIFT       0
                    199: #define BCM5600_PTABLE_DSE_MODE_MASK    0x000000C0
                    200: #define BCM5600_PTABLE_DSE_MODE_SHIFT   6
                    201: #define BCM5600_PTABLE_RPE_FLAG         0x00000100
                    202: #define BCM5600_PTABLE_PRI_MASK         0x00000E00
                    203: #define BCM5600_PTABLE_PRI_SHIFT        9
                    204: #define BCM5600_PTABLE_L3_DIS_FLAG      0x00001000
                    205: 
                    206: 
                    207: /* === ARL (Addess Resolution Logic) definitions === */
                    208: /* Word 0: MAC address LSB */
                    209: 
                    210: /* Word 1 */
                    211: #define BCM5600_ARL_MAC_MSB_MASK        0x0000FFFF
                    212: #define BCM5600_ARL_VLAN_TAG_MASK       0x0FFF0000
                    213: #define BCM5600_ARL_VLAN_TAG_SHIFT      16
                    214: #define BCM5600_ARL_COS_DST_MASK        0x70000000
                    215: #define BCM5600_ARL_COS_DST_SHIFT       28
                    216: #define BCM5600_ARL_CPU_FLAG            0x80000000
                    217: 
                    218: /* Word 2 */
                    219: #define BCM5600_ARL_L3_FLAG             0x00000001
                    220: #define BCM5600_ARL_SD_DIS_MASK         0x00000006
                    221: #define BCM5600_ARL_SD_DIS_SHIFT        1
                    222: #define BCM5600_ARL_ST_FLAG             0x00000008
                    223: #define BCM5600_ARL_HIT_FLAG            0x00000010
                    224: #define BCM5600_ARL_COS_SRC_MASK        0x000000E0
                    225: #define BCM5600_ARL_COS_SRC_SHIFT       5
                    226: #define BCM5600_ARL_TRUNK_FLAG          0x00000100
                    227: #define BCM5600_ARL_TGID_MASK           0x00000E00
                    228: #define BCM5600_ARL_TGID_SHIFT          9
                    229: #define BCM5600_ARL_RTAG_MASK           0x00007000
                    230: #define BCM5600_ARL_RTAG_SHIFT          12
                    231: #define BCM5600_ARL_PORT_MASK           0x001F8000
                    232: #define BCM5600_ARL_PORT_SHIFT          15
                    233: #define BCM5600_ARL_SCP_FLAG            0x00200000
                    234: #define BCM5600_ARL_MOD_ID_MASK         0x07C00000
                    235: #define BCM5600_ARL_MOD_ID_SHIFT        22
                    236: 
                    237: /* === Multicast ARL definitions === */
                    238: /* Word 0: MAC address LSB */
                    239: 
                    240: /* Word 1 */
                    241: #define BCM5600_MARL_MAC_MSB_MASK       0x0000FFFF
                    242: #define BCM5600_MARL_VLAN_TAG_MASK      0x0FFF0000
                    243: #define BCM5600_MARL_VLAN_TAG_SHIFT     16
                    244: #define BCM5600_MARL_COS_DST_MASK       0x70000000
                    245: #define BCM5600_MARL_COS_DST_SHIFT      28
                    246: 
                    247: /* Word 2 */
                    248: #define BCM5600_MARL_PORT_BMAP_MASK     0x1FFFFFFF
                    249: 
                    250: /* Word 3 */
                    251: #define BCM5600_MARL_UT_PORT_BMAP_MASK  0x1FFFFFFF
                    252: 
                    253: /* Word 4 */
                    254: #define BCM5600_MARL_MOD_BMAP_MASK      0xFFFFFFFF
                    255: 
                    256: /* === Trunk bitmap === */
                    257: #define BCM5600_TBMAP_MASK     0x0FFFFFFF
                    258: 
                    259: /* === Trunk table === */
                    260: /* Word 0 */
                    261: #define BCM5600_TTR_TP0_MASK   0x0000003F
                    262: #define BCM5600_TTR_TP0_SHIFT  0
                    263: #define BCM5600_TTR_TP1_MASK   0x00000FC0
                    264: #define BCM5600_TTR_TP1_SHIFT  6
                    265: #define BCM5600_TTR_TP2_MASK   0x0003F000
                    266: #define BCM5600_TTR_TP2_SHIFT  12
                    267: #define BCM5600_TTR_TP3_MASK   0x00FC0000
                    268: #define BCM5600_TTR_TP3_SHIFT  18
                    269: #define BCM5600_TTR_TP4_MASK   0x3F000000
                    270: #define BCM5600_TTR_TP4_SHIFT  24
                    271: 
                    272: /* Word 1 */
                    273: #define BCM5600_TTR_TP5_MASK   0x0000003F
                    274: #define BCM5600_TTR_TP5_SHIFT  0
                    275: #define BCM5600_TTR_TP6_MASK   0x00000FC0
                    276: #define BCM5600_TTR_TP6_SHIFT  6
                    277: #define BCM5600_TTR_TP7_MASK   0x0003F000
                    278: #define BCM5600_TTR_TP7_SHIFT  12
                    279: 
                    280: #define BCM5600_TTR_TG_SIZE_MASK    0x003C0000
                    281: #define BCM5600_TTR_TG_SIZE_SHIFT   18
                    282: 
                    283: /* Trunks (port aggregation) */
                    284: #define BCM5600_MAX_TRUNKS  6
                    285: #define BCM5600_MAX_PORTS_PER_TRUNK  8
                    286: 
                    287: /* ======================================================================= */
                    288: 
                    289: /* Transmit descriptor size */
                    290: #define BCM5600_TXD_SIZE       32
                    291: #define BCM5600_TXD_RING_CONT  0x80000000   /* ring is continuing */
                    292: #define BCM5600_TXD_UNKNOWN    0x04000000   /* valid packet (?) */
                    293: #define BCM5600_TXD_NEOP       0x00040000   /* end of packet if not set */
                    294: 
                    295: /* Receive descriptor size */
                    296: #define BCM5600_RXD_SIZE       32
                    297: #define BCM5600_RXD_RING_CONT  0x80000000   /* ring is continuing */
                    298: #define BCM5600_RXD_UNKNOWN    0x00040000   /* unknown */
                    299: 
                    300: /* Interrupt sources */
                    301: #define BCM5600_INTR_STAT_ITER_DONE  0x00100000  /* Unknown */
                    302: #define BCM5600_INTR_RX_UNDERRUN     0x00000400  /* RX ring underrun */
                    303: #define BCM5600_INTR_RX_AVAIL        0x00000200  /* packet available */
                    304: #define BCM5600_INTR_TX_UNDERRUN     0x00000100  /* TX ring underrun */
                    305: #define BCM5600_INTR_LINKSTAT_MOD    0x00000010  /* Link status modified */
                    306: 
                    307: /* ======================================================================= */
                    308: 
                    309: /* Port Mirroring */
                    310: #define BCM5600_MIRROR_ENABLE     0x40
                    311: #define BCM5600_MIRROR_PORT_MASK  0x3F
                    312: 
                    313: /* ======================================================================= */
                    314: 
                    315: #define BCM5600_REG_HASH_SIZE  8192
                    316: 
                    317: /* BCM5600 register */
                    318: struct bcm5600_reg {
                    319:    m_uint32_t addr;
                    320:    m_uint32_t value;
                    321:    struct bcm5600_reg *next;
                    322: };
                    323: 
                    324: /* BCM5600 table */
                    325: struct bcm5600_table {
                    326:    char *name; 
                    327:    long offset;
                    328:    m_uint32_t addr;
                    329:    u_int min_index,max_index;
                    330:    u_int nr_words;
                    331: };
                    332: 
                    333: /* BCM5600 in-transit packet */
                    334: struct bcm5600_pkt {
                    335:    /* Received packet data */
                    336:    u_char *pkt;
                    337:    ssize_t pkt_len;
                    338: 
                    339:    /* Rewritten packet (802.1Q tag pushed or poped) */
                    340:    u_char *rewr_pkt;
                    341:    int rewrite_done;
                    342: 
                    343:    /* Original VLAN (-1 for untagged packet) and Real VLAN */
                    344:    int orig_vlan,real_vlan;
                    345: 
                    346:    /* VLAN entry */
                    347:    m_uint32_t *vlan_entry;
                    348: 
                    349:    /* Ingress Port and Egress Port bitmap */
                    350:    u_int ingress_port,egress_bitmap,egress_ut_bitmap;
                    351:    u_int egress_filter_bitmap;
                    352: 
                    353:    /* RX descriptor */
                    354:    m_uint32_t rdes[4];
                    355: 
                    356:    /* Packet sent to CPU */
                    357:    u_int sent_to_cpu;
                    358: };
                    359: 
                    360: /* BCM5600 physical port */
                    361: struct bcm5600_port {
                    362:    netio_desc_t *nio;
                    363:    u_int id;
                    364:    char name[32];
                    365: };
                    366: 
                    367: /* NM-16ESW private data */
                    368: struct nm_16esw_data {
                    369:    char *name;
                    370:    u_int nr_port;
                    371: 
                    372:    vm_instance_t *vm;
                    373:    struct vdevice *dev;
                    374:    struct pci_device *pci_dev;
                    375: 
                    376:    pthread_mutex_t lock;
                    377: 
                    378:    /* Ager task */
                    379:    timer_id ager_tid;
                    380: 
                    381:    /* S-channel command and command result */
                    382:    m_uint32_t schan_cmd,schan_cmd_res;
                    383:    
                    384:    /* Data Words */
                    385:    m_uint32_t dw[BCM5600_DW_MAX];
                    386: 
                    387:    /* Interrupt mask */
                    388:    m_uint32_t intr_mask;
                    389: 
                    390:    /* MII registers */
                    391:    m_uint16_t mii_regs[64][32];
                    392:    m_uint32_t mii_input,mii_output;
                    393:    u_int mii_intr;
                    394: 
                    395:    /* RX/TX rings addresses */
                    396:    m_uint32_t rx_ring_addr,tx_ring_addr;
                    397:    m_uint32_t tx_current,tx_end_scan;
                    398:    m_uint32_t rx_current,rx_end_scan;
                    399: 
                    400:    /* TX ring scanner task id */
                    401:    ptask_id_t tx_tid;
                    402: 
                    403:    /* TX buffer */
                    404:    u_char tx_buffer[BCM5600_MAX_PKT_SIZE];
                    405:    u_int tx_bufsize;
                    406:    
                    407:    /* Port Mirroring */
                    408:    u_int mirror_dst_port;
                    409:    u_int mirror_egress_ports;
                    410: 
                    411:    /* Registers hash table */
                    412:    struct bcm5600_reg *reg_hash_table[BCM5600_REG_HASH_SIZE];
                    413:    
                    414:    /* Most used tables... */
                    415:    struct bcm5600_table *t_ptable,*t_vtable;
                    416:    struct bcm5600_table *t_arl,*t_marl;
                    417:    struct bcm5600_table *t_tbmap,*t_ttr;
                    418: 
                    419:    /* Ports (only 16 are "real" and usable) */
                    420:    struct bcm5600_port ports[32];
                    421:    
                    422:    /* CPU port */
                    423:    u_int cpu_port;
                    424: 
                    425:    /* Current egress port of all trunks */
                    426:    u_int trunk_last_egress_port[BCM5600_MAX_TRUNKS];
                    427: 
                    428:    /* ARL count table */
                    429:    m_uint32_t *arl_cnt;
                    430: 
                    431:    /* ARL (Address Resolution Logic) Table */
                    432:    m_uint32_t *arl_table;
                    433: 
                    434:    /* Multicast ARL Table */
                    435:    m_uint32_t *marl_table;
                    436: 
                    437:    /* VTABLE (VLAN Table) */
                    438:    m_uint32_t *vtable;
                    439: 
                    440:    /* Trunks */
                    441:    m_uint32_t *ttr,*tbmap;
                    442: 
                    443:    /* PTABLE (Port Table) */
                    444:    m_uint32_t *ptable;
                    445: };
                    446: 
                    447: /* NM-16ESW Port physical port mapping table (Cisco => BCM) */
                    448: static int nm16esw_port_mapping[] = {
                    449:    2, 0, 6, 4, 10, 8, 14, 12, 3, 1, 7, 5, 11, 9, 15, 13,
                    450: };
                    451: 
                    452: /* Log a BCM message */
                    453: #define BCM_LOG(d,msg...) vm_log((d)->vm,(d)->name,msg)
                    454: 
                    455: /* Lock/Unlock primitives */
                    456: #define BCM_LOCK(d)    pthread_mutex_lock(&(d)->lock)
                    457: #define BCM_UNLOCK(d)  pthread_mutex_unlock(&(d)->lock)
                    458: 
                    459: /* Trunk group info */
                    460: struct bcm5600_tg_info {
                    461:    u_int index,mask,shift;
                    462: };
                    463: 
                    464: static struct bcm5600_tg_info tg_info[8] = {
                    465:    { 0, BCM5600_TTR_TP0_MASK, BCM5600_TTR_TP0_SHIFT },
                    466:    { 0, BCM5600_TTR_TP1_MASK, BCM5600_TTR_TP1_SHIFT },
                    467:    { 0, BCM5600_TTR_TP2_MASK, BCM5600_TTR_TP2_SHIFT },
                    468:    { 0, BCM5600_TTR_TP3_MASK, BCM5600_TTR_TP3_SHIFT },
                    469:    { 0, BCM5600_TTR_TP4_MASK, BCM5600_TTR_TP4_SHIFT },
                    470:    { 1, BCM5600_TTR_TP5_MASK, BCM5600_TTR_TP5_SHIFT },
                    471:    { 1, BCM5600_TTR_TP6_MASK, BCM5600_TTR_TP6_SHIFT },
                    472:    { 1, BCM5600_TTR_TP7_MASK, BCM5600_TTR_TP7_SHIFT },
                    473: };
                    474: 
                    475: /* Return port status (up or down), based on the MII register */
                    476: static int bcm5600_mii_port_status(struct nm_16esw_data *d,u_int port)
                    477: {
                    478:    u_int mii_ctrl;
                    479: 
                    480:    mii_ctrl = d->mii_regs[port][0x00];
                    481: 
                    482:    /* Isolate bit */
                    483:    return(!(mii_ctrl & 0x400));
                    484: }
                    485: 
                    486: /* Build port status bitmap */
                    487: static m_uint32_t bcm5600_mii_port_status_bmp(struct nm_16esw_data *d)
                    488: {
                    489:    m_uint32_t bmp;
                    490:    int i;
                    491:    
                    492:    for(i=0,bmp=0;i<d->nr_port;i++)
                    493:       if (bcm5600_mii_port_status(d,i))
                    494:          bmp |= 1 << i;
                    495: 
                    496:    return(bmp);
                    497: }
                    498: 
                    499: /* Read a MII register */
                    500: static void bcm5600_mii_read(struct nm_16esw_data *d)
                    501: {
                    502:    m_uint8_t port,reg;
                    503: 
                    504:    port = (d->mii_input >> 16) & 0xFF;
                    505:    reg  = (d->mii_input >> 24) & 0xFF;
                    506: 
                    507:    if ((port < 32) && (reg < 32)) {
                    508:       d->mii_output = d->mii_regs[port][reg];
                    509: 
                    510:       switch(reg) {
                    511:          case 0x00:
                    512:             d->mii_output &= ~0x8200;
                    513:             break;
                    514:          case 0x01:
                    515:             if (d->ports[port].nio && bcm5600_mii_port_status(d,port))
                    516:                d->mii_output = 0x782C;
                    517:             else
                    518:                d->mii_output = 0;
                    519:             break;
                    520:          case 0x02:
                    521:             d->mii_output = 0x40;
                    522:             break;
                    523:          case 0x03:
                    524:             d->mii_output = 0x61d4;
                    525:             break;
                    526:          case 0x04:
                    527:             d->mii_output = 0x1E1;
                    528:             break;
                    529:          case 0x05:
                    530:             d->mii_output = 0x41E1;
                    531:             break;
                    532:          default:
                    533:             d->mii_output = 0;
                    534:       }
                    535:    }
                    536: }
                    537: 
                    538: /* Write a MII register */
                    539: static void bcm5600_mii_write(struct nm_16esw_data *d)
                    540: {
                    541:    m_uint8_t port,reg;
                    542:    m_uint16_t isolation;
                    543: 
                    544:    port = (d->mii_input >> 16) & 0xFF;
                    545:    reg  = (d->mii_input >> 24) & 0xFF;
                    546: 
                    547:    if ((port < 32) && (reg < 32))
                    548:    {
                    549: #if DEBUG_MII
                    550:       BCM_LOG(d,"MII: port 0x%4.4x, reg 0x%2.2x: writing 0x%4.4x\n",
                    551:               port,reg,d->mii_input & 0xFFFF);
                    552: #endif
                    553: 
                    554:       /* Check if PHY isolation status is changing */
                    555:       if (reg == 0) {
                    556:          isolation = (d->mii_input ^ d->mii_regs[port][reg]) & 0x400;
                    557: 
                    558:          if (isolation) {
                    559: #if DEBUG_MII
                    560:             BCM_LOG(d,"MII: port 0x%4.4x: generating IRQ\n",port);
                    561: #endif
                    562:             d->mii_intr = TRUE;
                    563:             pci_dev_trigger_irq(d->vm,d->pci_dev);
                    564:          }
                    565:       }
                    566:       
                    567:       d->mii_regs[port][reg] = d->mii_input & 0xFFFF;
                    568:    }
                    569: }
                    570: 
                    571: /* Hash function for register */
                    572: static u_int bcm5600_reg_get_hash(m_uint32_t addr)
                    573: {
                    574:    return((addr ^ (addr >> 16)) & (BCM5600_REG_HASH_SIZE - 1));
                    575: }
                    576: 
                    577: /* Find a register entry */
                    578: static struct bcm5600_reg *bcm5600_reg_find(struct nm_16esw_data *d,
                    579:                                             m_uint32_t addr)
                    580: {   
                    581:    struct bcm5600_reg *reg;
                    582:    u_int h_index;
                    583: 
                    584:    h_index = bcm5600_reg_get_hash(addr);
                    585:    for(reg=d->reg_hash_table[h_index];reg;reg=reg->next)
                    586:       if (reg->addr == addr)
                    587:          return reg;
                    588: 
                    589:    return NULL;
                    590: }
                    591: 
                    592: /* Read a register */
                    593: static m_uint32_t bcm5600_reg_read(struct nm_16esw_data *d,m_uint32_t addr)
                    594: {
                    595:    struct bcm5600_reg *reg;
                    596: 
                    597:    if (!(reg = bcm5600_reg_find(d,addr)))
                    598:       return(0);
                    599: 
                    600:    return(reg->value);
                    601: }
                    602: 
                    603: /* Write a register */
                    604: static int bcm5600_reg_write(struct nm_16esw_data *d,m_uint32_t addr,
                    605:                              m_uint32_t value)
                    606: {
                    607:    struct bcm5600_reg *reg;
                    608:    u_int h_index;
                    609: 
                    610:    if ((reg = bcm5600_reg_find(d,addr))) {
                    611:       reg->value = value;
                    612:       return(0);
                    613:    }
                    614: 
                    615:    /* create a new register */
                    616:    if (!(reg = malloc(sizeof(*reg))))
                    617:       return(-1);
                    618: 
                    619:    reg->addr  = addr;
                    620:    reg->value = value;
                    621: 
                    622:    /* insert new register in hash table */
                    623:    h_index = bcm5600_reg_get_hash(addr);
                    624:    reg->next = d->reg_hash_table[h_index];
                    625:    d->reg_hash_table[h_index] = reg;
                    626: 
                    627:    return(0);
                    628: }
                    629: 
                    630: /* Register special handling */
                    631: static void bcm5600_reg_write_special(struct nm_16esw_data *d,
                    632:                                       m_uint32_t addr,m_uint32_t value)
                    633: {
                    634:    switch(addr) {
                    635:       case 0x80006:
                    636:          d->mirror_dst_port = value;
                    637:          break;
                    638: 
                    639:       case 0x8000d:
                    640:          d->mirror_egress_ports = value;
                    641:          break;
                    642: 
                    643:       case 0x80009:
                    644:          /* age timer */
                    645:          break;
                    646:    }
                    647: }
                    648: 
                    649: /* Free memory used to store register info */
                    650: static void bcm5600_reg_free(struct nm_16esw_data *d)
                    651: {  
                    652:    struct bcm5600_reg *reg,*next;
                    653:    int i;
                    654: 
                    655:    for(i=0;i<BCM5600_REG_HASH_SIZE;i++)
                    656:       for(reg=d->reg_hash_table[i];reg;reg=next) {
                    657:          next = reg->next;
                    658:          free(reg);
                    659:       }
                    660: }
                    661: 
                    662: /* Dump all known registers */
                    663: static void bcm5600_reg_dump(struct nm_16esw_data *d,int show_null)
                    664: {
                    665:    struct bcm5600_reg *reg;
                    666:    int i;
                    667: 
                    668:    printf("%s: dumping registers:\n",d->name);
                    669: 
                    670:    for(i=0;i<BCM5600_REG_HASH_SIZE;i++)
                    671:       for(reg=d->reg_hash_table[i];reg;reg=reg->next) {
                    672:          if (reg->value || show_null)
                    673:             printf("  0x%8.8x: 0x%8.8x\n",reg->addr,reg->value);
                    674:       }
                    675: }
                    676: 
                    677: /* Fill a string buffer with all ports of the specified bitmap */
                    678: static char *bcm5600_port_bitmap_str(struct nm_16esw_data *d,
                    679:                                      char *buffer,m_uint32_t bitmap)
                    680: {
                    681:    char *ptr = buffer;
                    682:    int i;
                    683: 
                    684:    *ptr = 0;
                    685: 
                    686:    for(i=0;i<d->nr_port;i++)
                    687:       if (bitmap & (1 << i)) {
                    688:          ptr += sprintf(ptr,"%s ",d->ports[i].name);
                    689:       }
                    690: 
                    691:    return buffer;
                    692: }
                    693: 
                    694: /* BCM5600 tables */
                    695: #define BCM_OFFSET(x) (OFFSET(struct nm_16esw_data,x))
                    696: 
                    697: static struct bcm5600_table bcm5600_tables[] = {
                    698:    /* ARL tables */
                    699:    { "arlcnt0", BCM_OFFSET(arl_cnt), BCM5600_ADDR_ARLCNT0, 0, 0, 1 },
                    700:    { "arlcnt1", BCM_OFFSET(arl_cnt), BCM5600_ADDR_ARLCNT1, 0, 0, 1 },
                    701:    { "arlcnt2", BCM_OFFSET(arl_cnt), BCM5600_ADDR_ARLCNT2, 0, 0, 1 },
                    702: 
                    703:    /* ARL tables */
                    704:    { "arl0", BCM_OFFSET(arl_table), BCM5600_ADDR_ARL0, 0, 8191, 3 },
                    705:    { "arl1", BCM_OFFSET(arl_table), BCM5600_ADDR_ARL1, 0, 8191, 3 },
                    706:    { "arl2", BCM_OFFSET(arl_table), BCM5600_ADDR_ARL2, 0, 8191, 3 },
                    707: 
                    708:    /* Multicast ARL tables */
                    709:    { "marl0", BCM_OFFSET(marl_table), BCM5600_ADDR_MARL0, 1, 255, 5 },
                    710:    { "marl1", BCM_OFFSET(marl_table), BCM5600_ADDR_MARL1, 1, 255, 5 },
                    711:    { "marl2", BCM_OFFSET(marl_table), BCM5600_ADDR_MARL2, 1, 255, 5 },
                    712: 
                    713:    /* PTABLE - Physical Ports */
                    714:    { "ptable0", BCM_OFFSET(ptable), BCM5600_ADDR_PTABLE0, 0, 31, 6 },
                    715:    { "ptable1", BCM_OFFSET(ptable), BCM5600_ADDR_PTABLE1, 0, 31, 6 },
                    716:    { "ptable2", BCM_OFFSET(ptable), BCM5600_ADDR_PTABLE2, 0, 31, 6 },
                    717: 
                    718:    /* VTABLE - VLANs */
                    719:    { "vtable0", BCM_OFFSET(vtable), BCM5600_ADDR_VTABLE0, 1, 255, 4 },
                    720:    { "vtable1", BCM_OFFSET(vtable), BCM5600_ADDR_VTABLE1, 1, 255, 4 },
                    721:    { "vtable2", BCM_OFFSET(vtable), BCM5600_ADDR_VTABLE2, 1, 255, 4 },
                    722: 
                    723:    /* TTR */
                    724:    { "ttr0", BCM_OFFSET(ttr), BCM5600_ADDR_TTR0, 0, 5, 3 },
                    725:    { "ttr1", BCM_OFFSET(ttr), BCM5600_ADDR_TTR1, 0, 5, 3 },
                    726:    { "ttr2", BCM_OFFSET(ttr), BCM5600_ADDR_TTR2, 0, 5, 3 },
                    727: 
                    728:    /* TBMAP */
                    729:    { "tbmap0", BCM_OFFSET(tbmap), BCM5600_ADDR_TBMAP0, 0, 5, 1 },
                    730:    { "tbmap1", BCM_OFFSET(tbmap), BCM5600_ADDR_TBMAP1, 0, 5, 1 },
                    731:    { "tbmap2", BCM_OFFSET(tbmap), BCM5600_ADDR_TBMAP2, 0, 5, 1 },
                    732: 
                    733:    { NULL, -1, 0, 0, 0 },
                    734: };
                    735: 
                    736: /* Get table size (in number of words) */
                    737: static inline u_int bcm5600_table_get_size(struct bcm5600_table *table)
                    738: {
                    739:    return(table->nr_words * (table->max_index + 1));
                    740: }
                    741: 
                    742: /* Create automatically tables */
                    743: static int bcm5600_table_create(struct nm_16esw_data *d)
                    744: {
                    745:    struct bcm5600_table *table;
                    746:    m_uint32_t *array;
                    747:    size_t nr_words;
                    748:    int i;
                    749: 
                    750:    for(i=0;bcm5600_tables[i].name;i++)
                    751:    {
                    752:       table = &bcm5600_tables[i];
                    753:       nr_words = bcm5600_table_get_size(table);
                    754: 
                    755:       if (!(array = calloc(nr_words,sizeof(m_uint32_t)))) {
                    756:          fprintf(stderr,"BCM5600: unable to create table '%s'\n",table->name);
                    757:          return(-1);
                    758:       }
                    759:          
                    760:       *(PTR_ADJUST(m_uint32_t **,d,table->offset)) = array;
                    761:    }
                    762: 
                    763:    return(0);
                    764: }
                    765: 
                    766: /* Free tables */
                    767: static void bcm5600_table_free(struct nm_16esw_data *d)
                    768: {
                    769:    struct bcm5600_table *table;
                    770:    m_uint32_t **array;
                    771:    int i;
                    772: 
                    773:    for(i=0;bcm5600_tables[i].name;i++) {
                    774:       table = &bcm5600_tables[i];
                    775:       array = (PTR_ADJUST(m_uint32_t **,d,table->offset));
                    776:       free(*array);
                    777:       
                    778:       /* avoid freeing the same table multiple times */
                    779:       *array = NULL;
                    780:    }
                    781: }
                    782: 
                    783: /* Find a table given its address */
                    784: static struct bcm5600_table *bcm5600_table_find(struct nm_16esw_data *d,
                    785:                                                 m_uint32_t addr)
                    786: {
                    787:    int i;
                    788: 
                    789:    for(i=0;bcm5600_tables[i].name;i++)
                    790:       if (bcm5600_tables[i].addr == addr)
                    791:          return(&bcm5600_tables[i]);
                    792: 
                    793: #if DEBUG_UNKNOWN
                    794:    BCM_LOG(d,"unknown table at address 0x%8.8x\n",addr);
                    795: #endif
                    796:    return NULL;
                    797: }
                    798: 
                    799: /* Get a table entry */
                    800: static inline m_uint32_t *bcm5600_table_get_entry(struct nm_16esw_data *d,
                    801:                                                   struct bcm5600_table *table,
                    802:                                                   m_uint32_t index)
                    803: {
                    804:    m_uint32_t *array;
                    805: 
                    806:    if ((index < table->min_index) || (index > table->max_index))
                    807:       return NULL;
                    808: 
                    809:    array = *(PTR_ADJUST(m_uint32_t **,d,table->offset));
                    810:    return(&array[index*table->nr_words]);
                    811: }
                    812: 
                    813: /* Read a table entry */
                    814: static int bcm5600_table_read_entry(struct nm_16esw_data *d)
                    815: {
                    816:    struct bcm5600_table *table;
                    817:    m_uint32_t addr,index,*entry;
                    818:    int i;
                    819: 
                    820:    addr  = d->dw[1] & 0xFFFF0000;
                    821:    index = d->dw[1] & 0x0000FFFF;
                    822: 
                    823:    if (!(table = bcm5600_table_find(d,addr))) {
                    824: #if DEBUG_UNKNOWN
                    825:       BCM_LOG(d,"unknown mem address at address 0x%8.8x\n",d->dw[1]);
                    826: #endif
                    827:       return(-1);
                    828:    }
                    829: 
                    830:    if (!(entry = bcm5600_table_get_entry(d,table,index)))
                    831:       return(-1);
                    832: 
                    833: #if DEBUG_MEM
                    834:    BCM_LOG(d,"READ_MEM: addr=0x%8.8x (table %s)\n",d->dw[1],table->name);
                    835: #endif
                    836: 
                    837:    for(i=0;i<table->nr_words;i++)
                    838:       d->dw[i+1] = entry[i];
                    839: 
                    840:    return(0);
                    841: }
                    842: 
                    843: /* Write a table entry */
                    844: static int bcm5600_table_write_entry(struct nm_16esw_data *d)
                    845: {
                    846:    struct bcm5600_table *table;
                    847:    m_uint32_t addr,index,*entry;
                    848:    int i;
                    849: 
                    850:    addr  = d->dw[1] & 0xFFFF0000;
                    851:    index = d->dw[1] & 0x0000FFFF;
                    852: 
                    853:    if (!(table = bcm5600_table_find(d,addr)))
                    854:       return(-1);
                    855: 
                    856:    if (!(entry = bcm5600_table_get_entry(d,table,index)))
                    857:       return(-1);
                    858: 
                    859:    for(i=0;i<table->nr_words;i++)
                    860:       entry[i] = d->dw[i+2];
                    861: 
                    862: #if DEBUG_MEM
                    863:    {
                    864:       char buffer[512],*ptr = buffer;
                    865: 
                    866:       for(i=0;i<table->nr_words;i++)
                    867:          ptr += sprintf(ptr,"data[%d]=0x%8.8x ",i,entry[i]);
                    868: 
                    869:       BCM_LOG(d,"WRITE_MEM: addr=0x%8.8x (table %s) %s\n",
                    870:               d->dw[1],table->name,buffer);
                    871:    }
                    872: #endif
                    873:    return(0);
                    874: }
                    875: 
                    876: /* Dump a table (for debugging) */
                    877: static int bcm5600_table_dump(struct nm_16esw_data *d,m_uint32_t addr)
                    878: {
                    879:    struct bcm5600_table *table;
                    880:    m_uint32_t *entry;
                    881:    int i,j;
                    882: 
                    883:    if (!(table = bcm5600_table_find(d,addr)))
                    884:       return(-1);
                    885: 
                    886:    printf("%s: dumping table \"%s\":\n",d->name,table->name);
                    887: 
                    888:    for(i=table->min_index;i<=table->max_index;i++) {
                    889:       if (!(entry = bcm5600_table_get_entry(d,table,i)))
                    890:          break;
                    891: 
                    892:       printf("  %4d:",i);
                    893: 
                    894:       for(j=0;j<table->nr_words;j++)
                    895:          printf("0x%8.8x ",entry[j]);
                    896: 
                    897:       printf("\n");
                    898:    }
                    899: 
                    900:    printf("\n");
                    901:    return(0);
                    902: }
                    903: 
                    904: /* Dump the VLAN table */
                    905: static int bcm5600_dump_vtable(struct nm_16esw_data *d)
                    906: {   
                    907:    struct bcm5600_table *table;
                    908:    struct bcm5600_port *port;
                    909:    m_uint32_t *entry,tbmp,ubmp;
                    910:    u_int vlan;
                    911:    int i,j;
                    912: 
                    913:    if (!(table = bcm5600_table_find(d,BCM5600_ADDR_VTABLE0)))
                    914:       return(-1);
                    915: 
                    916:    printf("%s: dumping VLAN table:\n",d->name);
                    917: 
                    918:    for(i=table->min_index;i<=table->max_index;i++) {
                    919:       if (!(entry = bcm5600_table_get_entry(d,table,i)))
                    920:          break;
                    921: 
                    922:       /* Extract the VLAN info */
                    923:       vlan = entry[0] & BCM5600_VTABLE_VLAN_TAG_MASK;
                    924: 
                    925:       if (vlan == VLAN_INVALID)
                    926:          continue;
                    927: 
                    928:       printf("  VLAN %4u: ",vlan);
                    929: 
                    930:       for(j=0;j<d->nr_port;j++) {
                    931:          tbmp = entry[1] & (1 << j);
                    932:          ubmp = entry[2] & (1 << j);
                    933: 
                    934:          if (tbmp || ubmp) {
                    935:             port = &d->ports[j];
                    936: 
                    937:             printf("%s (",port->name);
                    938: 
                    939:             if (tbmp) 
                    940:                printf("T%s",ubmp ? "/" : ") ");
                    941: 
                    942:             if (ubmp)
                    943:                printf("UT) ");
                    944:          }
                    945:       }
                    946: 
                    947:       printf("\n");
                    948:    }
                    949: 
                    950:    printf("\n");
                    951:    return(0);
                    952: }
                    953: 
                    954: /* Dump the "trunk" ports */
                    955: static int bcm5600_dump_trunks(struct nm_16esw_data *d)
                    956: {   
                    957:    struct bcm5600_table *table;
                    958:    struct bcm5600_port *port;
                    959:    m_uint32_t *entry;
                    960:    int i,j;
                    961: 
                    962:    if (!(table = bcm5600_table_find(d,BCM5600_ADDR_TBMAP0)))
                    963:       return(-1);
                    964: 
                    965:    printf("%s: trunk ports:\n",d->name);
                    966: 
                    967:    for(i=table->min_index;i<=table->max_index;i++) {
                    968:       if (!(entry = bcm5600_table_get_entry(d,table,i)))
                    969:          break;
                    970: 
                    971:       if (!entry[0])
                    972:          continue;
                    973: 
                    974:       printf("  Trunk %d: ",i);
                    975: 
                    976:       for(j=0;j<d->nr_port;j++) {
                    977:          if (entry[0] & (1 << j)) {
                    978:             port = &d->ports[j];
                    979:             printf("%s ",port->name);
                    980:          }
                    981:       }
                    982: 
                    983:       printf("\n");
                    984:    }
                    985: 
                    986:    printf("\n");
                    987:    return(0);
                    988: }
                    989: 
                    990: /* Dump the physical port info */
                    991: static int bcm5600_dump_ports(struct nm_16esw_data *d)
                    992: {   
                    993:    struct bcm5600_table *table;
                    994:    struct bcm5600_port *port;
                    995:    m_uint32_t *entry;
                    996:    u_int vlan,tgid;
                    997:    int i;
                    998: 
                    999:    if (!(table = bcm5600_table_find(d,BCM5600_ADDR_PTABLE0)))
                   1000:       return(-1);
                   1001: 
                   1002:    printf("%s: physical ports:\n",d->name);
                   1003: 
                   1004:    for(i=0;i<d->nr_port;i++) {
                   1005:       if (!(entry = bcm5600_table_get_entry(d,table,i)))
                   1006:          break;
                   1007: 
                   1008:       port = &d->ports[i];
                   1009:       vlan = entry[0] & BCM5600_PTABLE_VLAN_TAG_MASK;
                   1010:       
                   1011:       printf("  %-10s: VLAN %u",port->name,vlan);
                   1012: 
                   1013:       if (entry[0] & BCM5600_PTABLE_TRUNK_FLAG) {
                   1014:          tgid = entry[0] & BCM5600_PTABLE_TGID_MASK;
                   1015:          tgid >>= BCM5600_PTABLE_TGID_SHIFT;
                   1016: 
                   1017:          printf(", Trunk Group %u ",tgid);
                   1018:       }
                   1019: 
                   1020:       printf("\n");
                   1021:    }
                   1022: 
                   1023:    printf("\n");
                   1024:    return(0);
                   1025: }
                   1026: 
                   1027: /* Dump the physical port bitmaps */
                   1028: static int bcm5600_dump_port_bitmaps(struct nm_16esw_data *d)
                   1029: {   
                   1030:    struct bcm5600_table *table;
                   1031:    struct bcm5600_port *port;
                   1032:    m_uint32_t *entry,tbmp,ubmp;
                   1033:    int i,j;
                   1034: 
                   1035:    if (!(table = bcm5600_table_find(d,BCM5600_ADDR_PTABLE0)))
                   1036:       return(-1);
                   1037: 
                   1038:    printf("%s: dumping bitmaps of the port table:\n",d->name);
                   1039: 
                   1040:    for(i=0;i<d->nr_port;i++) {
                   1041:       if (!(entry = bcm5600_table_get_entry(d,table,i)))
                   1042:          break;
                   1043: 
                   1044:       port = &d->ports[i];
                   1045: 
                   1046:       printf("  %-10s: ",port->name);
                   1047: 
                   1048:       for(j=0;j<d->nr_port;j++) {
                   1049:          tbmp = entry[1] & (1 << j);
                   1050:          ubmp = entry[2] & (1 << j);
                   1051: 
                   1052:          if (tbmp || ubmp) {
                   1053:             printf("%s (",d->ports[j].name);
                   1054: 
                   1055:             if (tbmp) 
                   1056:                printf("T%s",ubmp ? "/" : ") ");
                   1057: 
                   1058:             if (ubmp)
                   1059:                printf("UT) ");
                   1060:          }
                   1061:       }
                   1062: 
                   1063:       printf("\n");
                   1064:    }
                   1065: 
                   1066:    printf("\n");
                   1067:    return(0);
                   1068: }
                   1069: 
                   1070: /* Dump main tables */
                   1071: static void bcm5600_dump_main_tables(struct nm_16esw_data *d)
                   1072: {
                   1073:    bcm5600_dump_ports(d);
                   1074:    bcm5600_dump_port_bitmaps(d);
                   1075:    bcm5600_dump_vtable(d);
                   1076:    bcm5600_dump_trunks(d);
                   1077: }
                   1078: 
                   1079: /* Find a free ARL entry */
                   1080: static int bcm5600_find_free_arl_entry(struct nm_16esw_data *d)
                   1081: {   
                   1082:    struct bcm5600_table *table = d->t_arl;
                   1083: 
                   1084:    if (d->arl_cnt[0] == table->max_index)
                   1085:       return(-1);
                   1086: 
                   1087:    return(d->arl_cnt[0] - 1);
                   1088: }
                   1089: 
                   1090: /* ARL Lookup. TODO: this must be optimized in the future. */
                   1091: static inline int bcm5600_gen_arl_lookup(struct nm_16esw_data *d,
                   1092:                                          struct bcm5600_table *table,
                   1093:                                          u_int index_start,u_int index_end,
                   1094:                                          n_eth_addr_t *mac_addr,
                   1095:                                          u_int vlan)
                   1096: {
                   1097:    m_uint32_t *entry,tmp[2],mask;
                   1098:    int i;
                   1099: 
                   1100:    tmp[0]  = mac_addr->eth_addr_byte[2] << 24;
                   1101:    tmp[0] |= mac_addr->eth_addr_byte[3] << 16;
                   1102:    tmp[0] |= mac_addr->eth_addr_byte[4] << 8;
                   1103:    tmp[0] |= mac_addr->eth_addr_byte[5];
                   1104: 
                   1105:    tmp[1] = (mac_addr->eth_addr_byte[0] << 8) | mac_addr->eth_addr_byte[1];
                   1106:    tmp[1] |= vlan << BCM5600_ARL_VLAN_TAG_SHIFT;
                   1107: 
                   1108:    mask = BCM5600_ARL_VLAN_TAG_MASK | BCM5600_ARL_MAC_MSB_MASK;
                   1109: 
                   1110:    for(i=index_start;i<index_end;i++) {
                   1111:       entry = bcm5600_table_get_entry(d,table,i);
                   1112: 
                   1113:       if ((entry[0] == tmp[0]) && ((entry[1] & mask) == tmp[1]))
                   1114:          return(i);
                   1115:    }
                   1116: 
                   1117:    return(-1);
                   1118: }
                   1119: 
                   1120: /* ARL Lookup */
                   1121: static inline int bcm5600_arl_lookup(struct nm_16esw_data *d,
                   1122:                                      n_eth_addr_t *mac_addr,
                   1123:                                      u_int vlan)
                   1124: {
                   1125:    struct bcm5600_table *table = d->t_arl;
                   1126:    return(bcm5600_gen_arl_lookup(d,table,1,d->arl_cnt[0]-1,mac_addr,vlan));
                   1127: }
                   1128: 
                   1129: /* MARL Lookup */
                   1130: static inline int bcm5600_marl_lookup(struct nm_16esw_data *d,
                   1131:                                       n_eth_addr_t *mac_addr,
                   1132:                                       u_int vlan)
                   1133: {
                   1134:    struct bcm5600_table *table = d->t_marl;
                   1135:    return(bcm5600_gen_arl_lookup(d,table,table->min_index,table->max_index+1,
                   1136:                                  mac_addr,vlan));
                   1137: }
                   1138: 
                   1139: /* Invalidate an ARL entry */
                   1140: static void bcm5600_invalidate_arl_entry(m_uint32_t *entry)
                   1141: {
                   1142:    entry[0] = entry[1] = entry[2] = 0;
                   1143: }
                   1144: 
                   1145: /* Insert an entry into the ARL table */
                   1146: static int bcm5600_insert_arl_entry(struct nm_16esw_data *d)
                   1147: {   
                   1148:    struct bcm5600_table *table = d->t_arl;
                   1149:    m_uint32_t *entry,mask;
                   1150:    int i,index;
                   1151: 
                   1152:    mask = BCM5600_ARL_VLAN_TAG_MASK | BCM5600_ARL_MAC_MSB_MASK;
                   1153: 
                   1154:    for(i=0;i<d->arl_cnt[0]-1;i++) {
                   1155:       entry = bcm5600_table_get_entry(d,table,i);
                   1156: 
                   1157:       /* If entry already exists, just modify it */
                   1158:       if ((entry[0] == d->dw[1]) && ((entry[1] & mask) == (d->dw[2] & mask))) {
                   1159:          entry[0] = d->dw[1];
                   1160:          entry[1] = d->dw[2];
                   1161:          entry[2] = d->dw[3];
                   1162:          d->dw[1] = i;
                   1163:          return(0);
                   1164:       }
                   1165:    }
                   1166: 
                   1167:    index = d->arl_cnt[0] - 1;
                   1168: 
                   1169:    entry = bcm5600_table_get_entry(d,table,index);
                   1170:    entry[0] = d->dw[1];
                   1171:    entry[1] = d->dw[2];
                   1172:    entry[2] = d->dw[3];
                   1173:    d->dw[1] = index;
                   1174:    
                   1175:    d->arl_cnt[0]++;
                   1176:    return(0);
                   1177: }
                   1178: 
                   1179: /* Delete an entry from the ARL table */
                   1180: static int bcm5600_delete_arl_entry(struct nm_16esw_data *d)
                   1181: {  
                   1182:    struct bcm5600_table *table;
                   1183:    m_uint32_t *entry,*last_entry,mac_msb;
                   1184:    u_int cvlan,vlan;
                   1185:    int i;
                   1186: 
                   1187:    if (!(table = bcm5600_table_find(d,BCM5600_ADDR_ARL0)))
                   1188:       return(-1);
                   1189: 
                   1190:    vlan = d->dw[2] & BCM5600_ARL_VLAN_TAG_MASK;
                   1191:    vlan >>= BCM5600_ARL_VLAN_TAG_SHIFT;
                   1192: 
                   1193:    mac_msb = d->dw[2] & BCM5600_ARL_MAC_MSB_MASK;
                   1194: 
                   1195:    for(i=table->min_index;i<=table->max_index;i++) {
                   1196:       entry = bcm5600_table_get_entry(d,table,i);
                   1197: 
                   1198:       /* compare VLANs and MAC addresses */
                   1199:       cvlan = (entry[1] & BCM5600_ARL_VLAN_TAG_MASK);
                   1200:       cvlan >>= BCM5600_ARL_VLAN_TAG_SHIFT;
                   1201: 
                   1202:       if ((cvlan == vlan) && (entry[0] == d->dw[1]) &&
                   1203:           ((entry[1] & BCM5600_ARL_MAC_MSB_MASK) == mac_msb))
                   1204:       {            
                   1205:          d->dw[1] = i;
                   1206: 
                   1207:          last_entry = bcm5600_table_get_entry(d,d->t_arl,d->arl_cnt[0]-2);
                   1208:             
                   1209:          entry[0] = last_entry[0];
                   1210:          entry[1] = last_entry[1];
                   1211:          entry[2] = last_entry[2];
                   1212: 
                   1213:          d->arl_cnt[0]--;
                   1214:          return(i);
                   1215:       }
                   1216:    }
                   1217: 
                   1218:    return(0);
                   1219: }
                   1220: 
                   1221: /* Reset the ARL tables */
                   1222: static int bcm5600_reset_arl(struct nm_16esw_data *d)
                   1223: {
                   1224:    struct bcm5600_table *table;
                   1225:    m_uint32_t *entry;
                   1226:    int i;
                   1227:    
                   1228:    if (!(table = bcm5600_table_find(d,BCM5600_ADDR_ARL0)))
                   1229:       return(-1);
                   1230: 
                   1231:    for(i=table->min_index;i<=table->max_index;i++) {
                   1232:       entry = bcm5600_table_get_entry(d,table,i);
                   1233:       bcm5600_invalidate_arl_entry(entry);
                   1234:    }
                   1235: 
                   1236:    return(0);
                   1237: }
                   1238: 
                   1239: /* MAC Address Ager */
                   1240: static int bcm5600_arl_ager(struct nm_16esw_data *d)
                   1241: {
                   1242:    m_uint32_t *entry,*last_entry;
                   1243:    int i;
                   1244: 
                   1245:    BCM_LOCK(d);
                   1246: 
                   1247:    for(i=1;i<d->arl_cnt[0]-1;i++) {
                   1248:       entry = bcm5600_table_get_entry(d,d->t_arl,i);
                   1249:       assert(entry);
                   1250: 
                   1251:       if (entry[2] & BCM5600_ARL_ST_FLAG)
                   1252:          continue;
                   1253: 
                   1254:       /* The entry has expired, purge it */
                   1255:       if (!(entry[2] & BCM5600_ARL_HIT_FLAG)) {
                   1256:          last_entry = bcm5600_table_get_entry(d,d->t_arl,d->arl_cnt[0]-2);
                   1257:         
                   1258:          entry[0] = last_entry[0];
                   1259:          entry[1] = last_entry[1];
                   1260:          entry[2] = last_entry[2];
                   1261: 
                   1262:          d->arl_cnt[0]--;
                   1263:          i--;
                   1264:       } else {
                   1265:          entry[2] &= ~BCM5600_ARL_HIT_FLAG;
                   1266:       }
                   1267:    }
                   1268: 
                   1269:    BCM_UNLOCK(d);
                   1270:    return(TRUE);
                   1271: }
                   1272: 
                   1273: /* Get the VTABLE entry matching the specified VLAN */
                   1274: static m_uint32_t *bcm5600_vtable_get_entry_by_vlan(struct nm_16esw_data *d,
                   1275:                                                     u_int vlan)
                   1276: {
                   1277:    struct bcm5600_table *table = d->t_vtable;
                   1278:    m_uint32_t *entry;
                   1279:    int i;
                   1280: 
                   1281:    for(i=table->min_index;i<=table->max_index;i++) {
                   1282:       if (!(entry = bcm5600_table_get_entry(d,table,i)))
                   1283:          break;
                   1284: 
                   1285:       if ((entry[0] & BCM5600_VTABLE_VLAN_TAG_MASK) == vlan)
                   1286:          return entry;
                   1287:    }
                   1288: 
                   1289:    return NULL;
                   1290: }
                   1291: 
                   1292: /* Read memory command */
                   1293: static void bcm5600_handle_read_mem_cmd(struct nm_16esw_data *d)
                   1294: {
                   1295:    int i;
                   1296: 
                   1297:    if (bcm5600_table_read_entry(d) != 0) {
                   1298:       for(i=1;i<BCM5600_DW_MAX;i++)
                   1299:          d->dw[i] = 0;
                   1300:    }
                   1301: 
                   1302:    d->dw[0] = BCM5600_OP_READ_MEM_ACK << BCM5600_CMD_OP_SHIFT;
                   1303: }
                   1304: 
                   1305: /* Write memory command */
                   1306: static void bcm5600_handle_write_mem_cmd(struct nm_16esw_data *d)
                   1307: {
                   1308:    bcm5600_table_write_entry(d);
                   1309:    d->dw[0] = BCM5600_OP_WRITE_MEM_ACK << BCM5600_CMD_OP_SHIFT;
                   1310: }
                   1311: 
                   1312: /* Handle a "general" command */
                   1313: static void bcm5600_handle_gen_cmd(struct nm_16esw_data *d)
                   1314: {
                   1315:    m_uint32_t op,src,dst,len;
                   1316: 
                   1317:    /* Extract the opcode */
                   1318:    op  = (d->dw[0] & BCM5600_CMD_OP_MASK) >> BCM5600_CMD_OP_SHIFT;
                   1319:    src = (d->dw[0] & BCM5600_CMD_SRC_MASK) >> BCM5600_CMD_SRC_SHIFT;
                   1320:    dst = (d->dw[0] & BCM5600_CMD_DST_MASK) >> BCM5600_CMD_DST_SHIFT;
                   1321:    len = (d->dw[0] & BCM5600_CMD_LEN_MASK) >> BCM5600_CMD_LEN_SHIFT;
                   1322: 
                   1323: #if DEBUG_ACCESS
                   1324:    BCM_LOG(d,"gen_cmd: opcode 0x%2.2x [src=0x%2.2x,dst=0x%2.2x,len=0x%2.2x] "
                   1325:            "(dw[0]=0x%8.8x, dw[1]=0x%8.8x, dw[2]=0x%8.8x, dw[3]=0x%8.8x)\n",
                   1326:            op,src,dst,len,d->dw[0],d->dw[1],d->dw[2],d->dw[3]);
                   1327: #endif
                   1328: 
                   1329:    switch(op) {
                   1330:       case BCM5600_OP_READ_MEM_CMD:
                   1331:          bcm5600_handle_read_mem_cmd(d);
                   1332:          break;
                   1333: 
                   1334:       case BCM5600_OP_WRITE_MEM_CMD:
                   1335:          bcm5600_handle_write_mem_cmd(d);
                   1336:          break;
                   1337: 
                   1338:       case BCM5600_OP_READ_REG_CMD:
                   1339:          d->dw[0] = BCM5600_OP_READ_REG_ACK << BCM5600_CMD_OP_SHIFT;
                   1340: #if DEBUG_REG
                   1341:          BCM_LOG(d,"READ_REG: reg_addr=0x%8.8x\n",d->dw[1]);
                   1342: #endif
                   1343:          d->dw[1] = bcm5600_reg_read(d,d->dw[1]);
                   1344:          break;
                   1345: 
                   1346:       case BCM5600_OP_WRITE_REG_CMD:
                   1347:          d->dw[0] = BCM5600_OP_WRITE_REG_ACK << BCM5600_CMD_OP_SHIFT;
                   1348: #if DEBUG_REG
                   1349:          BCM_LOG(d,"WRITE_REG: reg_addr=0x%8.8x val=0x%8.8x\n",
                   1350:                  d->dw[1],d->dw[2]);
                   1351: #endif
                   1352:          bcm5600_reg_write(d,d->dw[1],d->dw[2]);
                   1353:          bcm5600_reg_write_special(d,d->dw[1],d->dw[2]);
                   1354:          break;
                   1355: 
                   1356:       case BCM5600_OP_ARL_INSERT_CMD:
                   1357:          d->dw[0] = BCM5600_OP_ARL_INSERT_DONE << BCM5600_CMD_OP_SHIFT;
                   1358: 
                   1359: #if DEBUG_ARL
                   1360:          BCM_LOG(d,"ARL_INSERT_CMD "
                   1361:                  "(dw[1]=0x%8.8x,dw[2]=0x%8.8x,dw[3]=0x%8.8x)\n",
                   1362:                  d->dw[1],d->dw[2],d->dw[3]);
                   1363: #endif
                   1364:          bcm5600_insert_arl_entry(d);
                   1365:          break;
                   1366: 
                   1367:       case BCM5600_OP_ARL_DELETE_CMD:
                   1368:          d->dw[0] = BCM5600_OP_ARL_DELETE_DONE << BCM5600_CMD_OP_SHIFT;
                   1369: 
                   1370: #if DEBUG_ARL
                   1371:          BCM_LOG(d,"ARL_DELETE_CMD (dw[1]=0x%8.8x,dw[2]=0x%8.8x)\n",
                   1372:                  d->dw[1],d->dw[2]);
                   1373: #endif
                   1374:          bcm5600_delete_arl_entry(d);
                   1375:          break;
                   1376: 
                   1377:       case BCM5600_OP_ARL_LOOKUP_CMD:
                   1378:          d->dw[0] = BCM5600_OP_READ_MEM_ACK << BCM5600_CMD_OP_SHIFT;
                   1379:          break;
                   1380: 
                   1381:       default:
                   1382:          BCM_LOG(d,"unknown opcode 0x%8.8x (cmd=0x%8.8x)\n",op,d->dw[0]);
                   1383:    }
                   1384: }
                   1385: 
                   1386: /* Handle a s-channel command */
                   1387: static void bcm5600_handle_schan_cmd(struct nm_16esw_data *d,m_uint32_t cmd)
                   1388: {
                   1389:    d->schan_cmd = cmd;
                   1390: 
                   1391: #if DEBUG_ACCESS
                   1392:    BCM_LOG(d,"s-chan command 0x%8.8x\n",cmd);
                   1393: #endif
                   1394: 
                   1395:    switch(cmd) {
                   1396:       case BCM5600_SCHAN_CMD_EXEC:
                   1397:          bcm5600_handle_gen_cmd(d);
                   1398:          d->schan_cmd_res = 0xFFFFFFFF;
                   1399:          break;
                   1400: 
                   1401:       case BCM5600_SCHAN_CMD_READ_MII:
                   1402:          bcm5600_mii_read(d);
                   1403:          d->schan_cmd_res = 0xFFFFFFFF;
                   1404:          break;
                   1405: 
                   1406:       case BCM5600_SCHAN_CMD_WRITE_MII:
                   1407:          bcm5600_mii_write(d);
                   1408:          d->schan_cmd_res = 0xFFFFFFFF;
                   1409:          break;
                   1410: 
                   1411:       case BCM5600_SCHAN_CMD_LINKSCAN:
                   1412:          d->schan_cmd_res = 0x0;
                   1413:          break;
                   1414: 
                   1415:       default:
                   1416: #if DEBUG_UNKNOWN
                   1417:          BCM_LOG(d,"unknown s-chan command 0x%8.8x\n",cmd);
                   1418: #endif
                   1419:          d->schan_cmd_res = 0xFFFFFFFF;
                   1420:    }
                   1421: }
                   1422: 
                   1423: /*
                   1424:  * dev_bcm5605_access()
                   1425:  */
                   1426: void *dev_bcm5605_access(cpu_mips_t *cpu,struct vdevice *dev,m_uint32_t offset,
                   1427:                          u_int op_size,u_int op_type,m_uint64_t *data)
                   1428: {
                   1429:    struct nm_16esw_data *d = dev->priv_data;
                   1430:    u_int reg;
                   1431: 
                   1432:    if (op_type == MTS_READ)
                   1433:       *data = 0;
                   1434: 
                   1435: #if DEBUG_ACCESS
                   1436:    if (op_type == MTS_READ) {
                   1437:       BCM_LOG(d,"read  access to offset=0x%x, pc=0x%llx\n",offset,cpu->pc);
                   1438:    } else {
                   1439:       BCM_LOG(d,"write access to offset=0x%x, pc=0x%llx, val=0x%llx\n",
                   1440:               offset,cpu->pc,*data);
                   1441:    }
                   1442: #endif
                   1443: 
                   1444:    BCM_LOCK(d);
                   1445: 
                   1446:    switch(offset) {
                   1447:       case 0x50:
                   1448:          if (op_type == MTS_WRITE) {
                   1449:             bcm5600_handle_schan_cmd(d,*data);
                   1450:          } else {
                   1451:             *data = d->schan_cmd_res;
                   1452:          }
                   1453:          break;
                   1454: 
                   1455:       case 0x140:
                   1456:          if (op_type == MTS_READ)
                   1457:             *data = bcm5600_mii_port_status_bmp(d);
                   1458:          break;
                   1459: 
                   1460:       /* MII input register */
                   1461:       case 0x158:
                   1462:          if (op_type == MTS_WRITE)
                   1463:             d->mii_input = *data;
                   1464:          break;
                   1465: 
                   1466:       /* MII output register */
                   1467:       case 0x15c:
                   1468:          if (op_type == MTS_READ)
                   1469:             *data = d->mii_output;
                   1470:          break;         
                   1471: 
                   1472:       /* Unknown (related to RX/TX rings ?) */
                   1473:       case 0x104:
                   1474:          break;
                   1475: 
                   1476:       /* TX ring address */
                   1477:       case 0x110:
                   1478:          if (op_type == MTS_READ)
                   1479:             *data = d->tx_ring_addr;
                   1480:          else {
                   1481:             d->tx_ring_addr = d->tx_current = *data;   
                   1482:             d->tx_end_scan = 0;
                   1483: #if DEBUG_TRANSMIT
                   1484:             BCM_LOG(d,"tx_ring_addr = 0x%8.8x\n",d->tx_ring_addr);
                   1485: #endif
                   1486:          }
                   1487:          break;
                   1488: 
                   1489:       /* RX ring address */
                   1490:       case 0x114:
                   1491:          if (op_type == MTS_READ)
                   1492:             *data = d->rx_ring_addr;
                   1493:          else {
                   1494:             d->rx_ring_addr = d->rx_current = *data;
                   1495:             d->rx_end_scan = 0;
                   1496: #if DEBUG_RECEIVE
                   1497:             BCM_LOG(d,"rx_ring_addr = 0x%8.8x\n",d->rx_ring_addr);
                   1498: #endif
                   1499:          }
                   1500:          break;
                   1501: 
                   1502:       /* Interrupt status */
                   1503:       case 0x144:
                   1504:          if (op_type == MTS_READ) {
                   1505:             *data = 0;
                   1506: 
                   1507:             /* RX/TX underrun (end of rings reached) */
                   1508:             if (d->tx_end_scan)
                   1509:                *data |= BCM5600_INTR_TX_UNDERRUN;
                   1510: 
                   1511:             if (d->rx_end_scan)
                   1512:                *data |= BCM5600_INTR_RX_UNDERRUN;
                   1513: 
                   1514:             /* RX packet available */
                   1515:             *data |= BCM5600_INTR_RX_AVAIL;
                   1516: 
                   1517:             /* Link status changed */
                   1518:             if (d->mii_intr) {
                   1519:                *data |= BCM5600_INTR_LINKSTAT_MOD;
                   1520:                d->mii_intr = FALSE;
                   1521:             }
                   1522:          }
                   1523:          break;
                   1524: 
                   1525:       /* Interrupt mask */
                   1526:       case 0x148:
                   1527:          if (op_type == MTS_READ)
                   1528:             *data = d->intr_mask;
                   1529:          else
                   1530:             d->intr_mask = *data;
                   1531:          break;
                   1532: 
                   1533:       /* Data Words */
                   1534:       case 0x800 ... 0x850:
                   1535:          reg = (offset - 0x800) >> 2;
                   1536: 
                   1537:          if (op_type == MTS_READ)
                   1538:             *data = d->dw[reg];
                   1539:          else
                   1540:             d->dw[reg] = *data;
                   1541:          break;
                   1542: 
                   1543: #if DEBUG_UNKNOWN
                   1544:       /* Unknown offset */
                   1545:       default:
                   1546:          if (op_type == MTS_READ) {
                   1547:             BCM_LOG(d,"read from unknown addr 0x%x, pc=0x%llx (size=%u)\n",
                   1548:                     offset,cpu->pc,op_size);
                   1549:          } else {
                   1550:             BCM_LOG(d,"write to unknown addr 0x%x, value=0x%llx, "
                   1551:                     "pc=0x%llx (size=%u)\n",offset,*data,cpu->pc,op_size);
                   1552:          }
                   1553: #endif
                   1554:    }
                   1555: 
                   1556:    BCM_UNLOCK(d);
                   1557:    return NULL;
                   1558: }
                   1559: 
                   1560: /* Show mirroring status */
                   1561: static int bcm5600_mirror_show_status(struct nm_16esw_data *d)
                   1562: {
                   1563:    m_uint32_t *port,dst_port;
                   1564:    int i;
                   1565: 
                   1566:    printf("Mirroring status: "); 
                   1567: 
                   1568:    if (!(d->mirror_dst_port & BCM5600_MIRROR_ENABLE)) {
                   1569:       printf("disabled.\n\n");
                   1570:       return(FALSE);
                   1571:    }
                   1572: 
                   1573:    printf("enabled. Dest port: ");
                   1574: 
                   1575:    dst_port = d->mirror_dst_port & BCM5600_MIRROR_PORT_MASK;
                   1576: 
                   1577:    if (dst_port < 32)
                   1578:       printf("%s\n",d->ports[dst_port].name);
                   1579:    else
                   1580:       printf("none set.\n");
                   1581: 
                   1582:    /* Ingress info */
                   1583:    printf("  Ingress Ports: ");
                   1584: 
                   1585:    for(i=0;i<d->nr_port;i++) {
                   1586:       port = bcm5600_table_get_entry(d,d->t_ptable,i);
                   1587:       if (port[1] & BCM5600_PTABLE_MI_FLAG)
                   1588:          printf("%s ",d->ports[i].name);
                   1589:    }
                   1590: 
                   1591:    printf("\n");
                   1592: 
                   1593:    /* Egress info */
                   1594:    printf("  Egress Ports: ");
                   1595:   
                   1596:    for(i=0;i<d->nr_port;i++)
                   1597:       if (d->mirror_egress_ports & (1 << i))
                   1598:          printf("%s ",d->ports[i].name);
                   1599: 
                   1600:    printf("\n\n");
                   1601:    return(TRUE);
                   1602: }
                   1603: 
                   1604: /* Mirror a packet */
                   1605: static int bcm5600_mirror_pkt(struct nm_16esw_data *d,struct bcm5600_pkt *p,
                   1606:                               int reason)
                   1607: {
                   1608:    u_int mport;
                   1609: 
                   1610:    if (!(d->mirror_dst_port & BCM5600_MIRROR_ENABLE))
                   1611:       return(FALSE);
                   1612: 
                   1613: #if DEBUG_MIRROR
                   1614:    if (reason == 0) {
                   1615:       BCM_LOG(d,"mirroring packet on ingress port %s\n",
                   1616:               d->ports[p->ingress_port]);
                   1617:    } else {
                   1618:       BCM_LOG(d,"mirroring packet on egress port (input port %s)\n",
                   1619:               d->ports[p->ingress_port]);
                   1620:    }
                   1621:    mem_dump(d->vm->log_fd,pkt,pkt_len);
                   1622: #endif
                   1623: 
                   1624:    mport = d->mirror_dst_port & BCM5600_MIRROR_PORT_MASK;
                   1625:    if (mport < 32)
                   1626:       netio_send(d->ports[mport].nio,p->pkt,p->pkt_len);
                   1627:    return(TRUE);
                   1628: }
                   1629: 
                   1630: /* Put a packet into the RX ring (tag it if necessary) */
                   1631: static int bcm5600_send_pkt_to_cpu(struct nm_16esw_data *d,
                   1632:                                    struct bcm5600_pkt *p)
                   1633: {
                   1634:    m_uint32_t pkt_addr,pkt_len,dot1q_data;
                   1635: 
                   1636:    /* If the packet was already sent to CPU, don't send it again */
                   1637:    if (p->sent_to_cpu)
                   1638:       return(FALSE);
                   1639: 
                   1640:    pkt_addr = p->rdes[0];
                   1641:    pkt_len  = p->pkt_len;
                   1642: 
                   1643:    if (p->orig_vlan != -1) {
                   1644:       /* 802.1Q packet: copy it directly */
                   1645:       physmem_copy_to_vm(d->vm,p->pkt,pkt_addr,pkt_len);
                   1646:    } else {
                   1647:       /* untagged packet: copy the dst and src addresses first */
                   1648:       physmem_copy_to_vm(d->vm,p->pkt,pkt_addr,N_ETH_HLEN - 2);
                   1649: 
                   1650:       /* add the 802.1Q protocol field (0x8100) + VLAN info */
                   1651:       dot1q_data = (N_ETH_PROTO_DOT1Q << 16) | p->real_vlan;
                   1652:       physmem_copy_u32_to_vm(d->vm,pkt_addr+N_ETH_HLEN-2,dot1q_data);
                   1653: 
                   1654:       /* copy the payload */
                   1655:       physmem_copy_to_vm(d->vm,p->pkt+N_ETH_HLEN-2,
                   1656:                          pkt_addr+sizeof(n_eth_dot1q_hdr_t),
                   1657:                          pkt_len - (N_ETH_HLEN - 2));
                   1658:       pkt_len += 4;
                   1659:    }
                   1660: 
                   1661:    physmem_copy_u32_to_vm(d->vm,d->rx_current+0x14,0x40000000 + (pkt_len+4));
                   1662:    physmem_copy_u32_to_vm(d->vm,d->rx_current+0x18,0x100 + p->ingress_port);
                   1663:    p->sent_to_cpu = TRUE;
                   1664: 
                   1665: #if DEBUG_RECEIVE
                   1666:    BCM_LOG(d,"sending packet to CPU (orig_vlan=%d).\n",p->orig_vlan);
                   1667: #endif
                   1668:    return(TRUE);
                   1669: }
                   1670: 
                   1671: /* Source MAC address learning */
                   1672: static int bcm5600_src_mac_learning(struct nm_16esw_data *d,
                   1673:                                     struct bcm5600_pkt *p)
                   1674: {  
                   1675:    n_eth_hdr_t *eth_hdr = (n_eth_hdr_t *)p->pkt;
                   1676:    n_eth_addr_t *src_mac = &eth_hdr->saddr;
                   1677:    m_uint32_t *arl_entry,*src_port,*trunk;
                   1678:    u_int trunk_id,old_ingress_port;
                   1679:    int src_mac_index;
                   1680: 
                   1681:    trunk = NULL;
                   1682:    trunk_id = 0;
                   1683: 
                   1684:    /* Skip multicast sources */
                   1685:    if (eth_addr_is_mcast(src_mac))
                   1686:       return(FALSE);
                   1687: 
                   1688:    src_port = bcm5600_table_get_entry(d,d->t_ptable,p->ingress_port);
                   1689:    assert(src_port != NULL);
                   1690: 
                   1691:    /* 
                   1692:     * The packet comes from a trunk port. Prevent sending the packet
                   1693:     * to the other ports of the trunk.
                   1694:     */
                   1695:    if (src_port[0] & BCM5600_PTABLE_TRUNK_FLAG) {
                   1696:       trunk_id = src_port[0] & BCM5600_PTABLE_TGID_MASK;
                   1697:       trunk_id >>= BCM5600_PTABLE_TGID_SHIFT;
                   1698: 
                   1699:       trunk = bcm5600_table_get_entry(d,d->t_tbmap,trunk_id);
                   1700:       assert(trunk != NULL);
                   1701: 
                   1702:       p->egress_filter_bitmap |= trunk[0] & BCM5600_TBMAP_MASK;
                   1703:    }
                   1704: 
                   1705:    /* Source MAC address learning */
                   1706:    src_mac_index = bcm5600_arl_lookup(d,src_mac,p->real_vlan);
                   1707: 
                   1708:    if (src_mac_index != -1) {
                   1709:       arl_entry = bcm5600_table_get_entry(d,d->t_arl,src_mac_index);
                   1710:       assert(arl_entry != NULL);
                   1711: 
                   1712:       old_ingress_port = arl_entry[2] & BCM5600_ARL_PORT_MASK;
                   1713:       old_ingress_port >>= BCM5600_ARL_PORT_SHIFT;
                   1714: 
                   1715:       if (old_ingress_port != p->ingress_port) 
                   1716:       {
                   1717:          /*
                   1718:           * Determine if we have a station movement.
                   1719:           * If we have a trunk, check if the old ingress port is member
                   1720:           * of this trunk, in this case this is not a movement.
                   1721:           */
                   1722:          if (trunk != NULL) {
                   1723:             if (trunk[0] & (1 << old_ingress_port))
                   1724:                arl_entry[2] |= BCM5600_ARL_HIT_FLAG;
                   1725:             else 
                   1726:                arl_entry[2] &= ~BCM5600_ARL_HIT_FLAG;
                   1727:          } else {
                   1728:             arl_entry[2] &= ~(BCM5600_ARL_TRUNK_FLAG|BCM5600_ARL_HIT_FLAG);
                   1729:             arl_entry[2] &= ~BCM5600_ARL_TGID_MASK;
                   1730:          }
                   1731: 
                   1732:          /* Change the ingress port */
                   1733:          arl_entry[2] &= ~BCM5600_ARL_PORT_MASK;
                   1734:          arl_entry[2] |= p->ingress_port << BCM5600_ARL_PORT_SHIFT;
                   1735:          return(TRUE);
                   1736:       }
                   1737: 
                   1738:       arl_entry[2] |= BCM5600_ARL_HIT_FLAG;
                   1739:       return(TRUE);
                   1740:    }
                   1741: 
                   1742: #if DEBUG_FORWARD
                   1743:       BCM_LOG(d,"source MAC address unknown, learning it.\n");
                   1744: #endif
                   1745: 
                   1746:    /* Add the new learned MAC address */
                   1747:    src_mac_index = bcm5600_find_free_arl_entry(d);
                   1748: 
                   1749:    if (src_mac_index == -1) {
                   1750:       BCM_LOG(d,"no free entries in ARL table!\n");
                   1751:       return(FALSE);
                   1752:    }
                   1753: 
                   1754:    arl_entry = bcm5600_table_get_entry(d,d->t_arl,src_mac_index);
                   1755:    assert(arl_entry != NULL);
                   1756:     
                   1757:    /* Fill the new ARL entry */
                   1758:    arl_entry[0]  = src_mac->eth_addr_byte[2] << 24;
                   1759:    arl_entry[0] |= src_mac->eth_addr_byte[3] << 16;
                   1760:    arl_entry[0] |= src_mac->eth_addr_byte[4] << 8;
                   1761:    arl_entry[0] |= src_mac->eth_addr_byte[5];
                   1762: 
                   1763:    arl_entry[1]  = src_mac->eth_addr_byte[0] << 8;
                   1764:    arl_entry[1] |= src_mac->eth_addr_byte[1];
                   1765:    arl_entry[1] |= p->real_vlan << BCM5600_ARL_VLAN_TAG_SHIFT;
                   1766: 
                   1767:    arl_entry[2]  = BCM5600_ARL_HIT_FLAG;
                   1768:    arl_entry[2] |= p->ingress_port << BCM5600_ARL_PORT_SHIFT;
                   1769: 
                   1770:    if (trunk != NULL) {
                   1771:       arl_entry[2] |= BCM5600_ARL_TRUNK_FLAG;
                   1772:       arl_entry[2] |= (trunk_id << BCM5600_ARL_TGID_SHIFT);
                   1773:    }
                   1774: 
                   1775:    d->arl_cnt[0]++;
                   1776:    return(TRUE);
                   1777: }
                   1778: 
                   1779: /* Select an egress port the specified trunk */
                   1780: static int bcm5600_trunk_egress_port(struct nm_16esw_data *d,
                   1781:                                      struct bcm5600_pkt *p,
                   1782:                                      u_int trunk_id)
                   1783: {   
                   1784:    n_eth_hdr_t *eth_hdr = (n_eth_hdr_t *)p->pkt;
                   1785:    struct bcm5600_tg_info *tgi;
                   1786:    m_uint32_t *ttr_entry;
                   1787:    u_int i,nr_links;
                   1788:    u_int hash,port_id;
                   1789: 
                   1790:    ttr_entry = bcm5600_table_get_entry(d,d->t_ttr,trunk_id);
                   1791:    assert(ttr_entry != NULL);
                   1792: 
                   1793:    nr_links = ttr_entry[1] & BCM5600_TTR_TG_SIZE_MASK;
                   1794:    nr_links >>= BCM5600_TTR_TG_SIZE_SHIFT;
                   1795: 
                   1796: #if 0
                   1797:    /* Hash on source and destination MAC addresses */
                   1798:    for(i=0,hash=0;i<N_ETH_ALEN;i++) {
                   1799:       hash ^= eth_hdr->saddr.eth_addr_byte[i];
                   1800:       hash ^= eth_hdr->daddr.eth_addr_byte[i];
                   1801:    }
                   1802: 
                   1803:    hash ^= (hash >> 4);
                   1804:    port_id = hash % nr_links;
                   1805: 
                   1806:    /* Maximum of 8 ports per trunk */
                   1807:    assert(hash < BCM5600_MAX_PORTS_PER_TRUNK);
                   1808: #else
                   1809:    port_id = d->trunk_last_egress_port[trunk_id] + 1;
                   1810:    port_id %= nr_links;   
                   1811: #endif
                   1812: 
                   1813:    /* Save the latest port used for this trunk */
                   1814:    d->trunk_last_egress_port[trunk_id] = port_id;
                   1815: 
                   1816:    /* Select the egress port */
                   1817:    tgi = &tg_info[port_id];
                   1818:    return((ttr_entry[tgi->index] & tgi->mask) >> tgi->shift);
                   1819: }
                   1820: 
                   1821: /* Destination address lookup (take the forwarding decision) */
                   1822: static int bcm5600_dst_mac_lookup(struct nm_16esw_data *d,
                   1823:                                   struct bcm5600_pkt *p)
                   1824: {
                   1825:    n_eth_hdr_t *eth_hdr = (n_eth_hdr_t *)p->pkt;
                   1826:    n_eth_addr_t *dst_mac = &eth_hdr->daddr;
                   1827:    struct bcm5600_table *arl_table;
                   1828:    m_uint32_t *arl_entry;
                   1829:    u_int egress_port;
                   1830:    u_int trunk_id;
                   1831:    int dst_mac_index;
                   1832:    int is_mcast;
                   1833: 
                   1834:    /* Select the appropriate ARL table and do the lookup on dst MAC + VLAN */
                   1835:    if (eth_addr_is_mcast(dst_mac)) {
                   1836:       is_mcast = TRUE;
                   1837:       arl_table = d->t_marl;
                   1838:       dst_mac_index = bcm5600_marl_lookup(d,dst_mac,p->real_vlan);
                   1839:    } else {
                   1840:       is_mcast = FALSE;
                   1841:       arl_table = d->t_arl;
                   1842:       dst_mac_index = bcm5600_arl_lookup(d,dst_mac,p->real_vlan);
                   1843:    }
                   1844: 
                   1845:    /*
                   1846:     * Destination Lookup Failure (DLF).
                   1847:     * 
                   1848:     * Use the VLAN bitmap to compute the Egress port bitmap.
                   1849:     * Remove the ingress port from it.
                   1850:     */
                   1851:    if (dst_mac_index == -1) {
                   1852: #if DEBUG_FORWARD
                   1853:       BCM_LOG(d,"Destination MAC address unknown, flooding.\n");
                   1854: #endif
                   1855:       p->egress_bitmap = p->vlan_entry[1] & BCM5600_VTABLE_PORT_BMAP_MASK;
                   1856: 
                   1857:       /* Add the CPU to the egress ports */
                   1858:       p->egress_bitmap |= 1 << d->cpu_port;
                   1859: 
                   1860:       p->egress_ut_bitmap = p->vlan_entry[2];
                   1861:       p->egress_ut_bitmap &= BCM5600_VTABLE_UT_PORT_BMAP_MASK;
                   1862:       return(TRUE);
                   1863:    }
                   1864: 
                   1865:    /* The MAC address was found in the ARL/MARL table */
                   1866:    arl_entry = bcm5600_table_get_entry(d,arl_table,dst_mac_index);
                   1867:    assert(arl_entry != NULL);
                   1868: 
                   1869:    /* If the CPU bit is set, send a copy of the packet to the CPU */
                   1870:    if (arl_entry[1] & BCM5600_ARL_CPU_FLAG)
                   1871:       bcm5600_send_pkt_to_cpu(d,p);
                   1872: 
                   1873:    if (!is_mcast) {
                   1874:       /* Unicast: send the packet to the port or trunk found in ARL table */
                   1875:       if (arl_entry[2] & BCM5600_ARL_TRUNK_FLAG) {
                   1876:          trunk_id = arl_entry[2] & BCM5600_ARL_TGID_MASK;
                   1877:          trunk_id >>= BCM5600_ARL_TGID_SHIFT;
                   1878: 
                   1879:          /* Select an output port for this trunk */
                   1880:          egress_port = bcm5600_trunk_egress_port(d,p,trunk_id);
                   1881: 
                   1882: #if DEBUG_FORWARD
                   1883:          BCM_LOG(d,"Sending packet to trunk port %u, egress port %u\n",
                   1884:                  trunk_id,egress_port);
                   1885: #endif
                   1886:       } else {
                   1887:          egress_port = arl_entry[2] & BCM5600_ARL_PORT_MASK;
                   1888:          egress_port >>= BCM5600_ARL_PORT_SHIFT;
                   1889:       }
                   1890: 
                   1891:       p->egress_bitmap = 1 << egress_port;
                   1892:       p->egress_ut_bitmap = p->vlan_entry[2] & 
                   1893:          BCM5600_VTABLE_UT_PORT_BMAP_MASK;
                   1894:    } else {
                   1895:       /* Multicast: send the packet to the egress ports found in MARL table */
                   1896:       p->egress_bitmap = arl_entry[2] & BCM5600_MARL_PORT_BMAP_MASK;
                   1897:       p->egress_ut_bitmap = arl_entry[3] & BCM5600_MARL_UT_PORT_BMAP_MASK;
                   1898:    }
                   1899: 
                   1900: #if DEBUG_FORWARD
                   1901:    {
                   1902:       char buffer[1024];
                   1903: 
                   1904:       BCM_LOG(d,"bitmap: 0x%8.8x, filter: 0x%8.8x\n",
                   1905:               p->egress_bitmap,p->egress_filter_bitmap);
                   1906: 
                   1907:       bcm5600_port_bitmap_str(d,buffer,p->egress_bitmap);
                   1908: 
                   1909:       /* without egress port filtering */
                   1910:       if (*buffer)
                   1911:          BCM_LOG(d,"forwarding to egress port list w/o filter: %s\n",buffer);
                   1912:       else
                   1913:          BCM_LOG(d,"w/o filter: empty egress port list.\n");
                   1914: 
                   1915:       /* with egress port filtering */
                   1916:       bcm5600_port_bitmap_str(d,buffer,
                   1917:                               p->egress_bitmap & ~p->egress_filter_bitmap);
                   1918: 
                   1919:       if (*buffer)
                   1920:          BCM_LOG(d,"forwarding to egress port list w/ filter: %s\n",buffer);
                   1921:    }
                   1922: #endif
                   1923: 
                   1924:    return(p->egress_bitmap != 0);
                   1925: }
                   1926: 
                   1927: /* Prototype for a packet sending function */
                   1928: typedef void (*bcm5600_send_pkt_t)(struct nm_16esw_data *d,
                   1929:                                    struct bcm5600_pkt *p,
                   1930:                                    netio_desc_t *nio);
                   1931: 
                   1932: /* Directly forward a packet (not rewritten) */
                   1933: static void bcm5600_send_pkt_direct(struct nm_16esw_data *d,
                   1934:                                     struct bcm5600_pkt *p,
                   1935:                                     netio_desc_t *nio)
                   1936: {
                   1937:    netio_send(nio,p->pkt,p->pkt_len);
                   1938: }
                   1939: 
                   1940: /* Send a packet with a 802.1Q tag */
                   1941: static void bcm5600_send_pkt_push_dot1q(struct nm_16esw_data *d,
                   1942:                                         struct bcm5600_pkt *p,
                   1943:                                         netio_desc_t *nio)
                   1944: {
                   1945:    n_eth_dot1q_hdr_t *hdr;
                   1946: 
                   1947:    if (!p->rewrite_done) {
                   1948:       memcpy(p->rewr_pkt,p->pkt,(N_ETH_HLEN - 2));
                   1949: 
                   1950:       hdr = (n_eth_dot1q_hdr_t *)p->rewr_pkt;
                   1951:       hdr->type    = htons(N_ETH_PROTO_DOT1Q);
                   1952:       hdr->vlan_id = htons(p->real_vlan);
                   1953: 
                   1954:       memcpy(p->rewr_pkt + sizeof(n_eth_dot1q_hdr_t),
                   1955:              p->pkt + (N_ETH_HLEN - 2),
                   1956:              p->pkt_len - (N_ETH_HLEN - 2));
                   1957: 
                   1958:       p->rewrite_done = TRUE;
                   1959:    }
                   1960:    
                   1961:    netio_send(nio,p->rewr_pkt,p->pkt_len+4);
                   1962: }
                   1963: 
                   1964: /* Send a packet deleting its 802.1Q tag */
                   1965: static void bcm5600_send_pkt_pop_dot1q(struct nm_16esw_data *d,
                   1966:                                        struct bcm5600_pkt *p,
                   1967:                                        netio_desc_t *nio)
                   1968: {
                   1969:    if (!p->rewrite_done) {
                   1970:       memcpy(p->rewr_pkt,p->pkt,(N_ETH_HLEN - 2));
                   1971: 
                   1972:       memcpy(p->rewr_pkt + (N_ETH_HLEN - 2),
                   1973:              p->pkt + sizeof(n_eth_dot1q_hdr_t),
                   1974:              p->pkt_len - sizeof(n_eth_dot1q_hdr_t));
                   1975: 
                   1976:       p->rewrite_done = TRUE;
                   1977:    }
                   1978:    
                   1979:    netio_send(nio,p->rewr_pkt,p->pkt_len-4);
                   1980: }
                   1981: 
                   1982: /* Forward a packet on physical ports (egress bitmap must be defined) */
                   1983: static int bcm5600_forward_pkt(struct nm_16esw_data *d,struct bcm5600_pkt *p)
                   1984: {
                   1985:    u_char rewr_pkt[BCM5600_MAX_PKT_SIZE];
                   1986:    bcm5600_send_pkt_t send_pkt;
                   1987:    u_int egress_untagged,trunk_id;
                   1988:    m_uint32_t *dst_port,*trunk;
                   1989:    int i;
                   1990: 
                   1991:    p->egress_bitmap &= ~p->egress_filter_bitmap;
                   1992:    
                   1993:    if (!p->egress_bitmap)
                   1994:       return(FALSE);
                   1995: 
                   1996:    /* Process egress mirroring (if enabled) */
                   1997:    if (p->egress_bitmap & d->mirror_egress_ports)      
                   1998:       bcm5600_mirror_pkt(d,p,1);
                   1999: 
                   2000:    /* No rewrite done at this time */
                   2001:    p->rewr_pkt = rewr_pkt;
                   2002:    p->rewrite_done = FALSE;
                   2003: 
                   2004:    /* Forward to CPU port ? */
                   2005:    if (p->egress_bitmap & (1 << d->cpu_port))
                   2006:       bcm5600_send_pkt_to_cpu(d,p);
                   2007: 
                   2008:    for(i=0;i<d->nr_port;i++) {
                   2009:       if (!(p->egress_bitmap & (1 << i)))
                   2010:          continue;
                   2011: 
                   2012:       /* 
                   2013:        * If this port is a member of a trunk, remove all other ports to avoid
                   2014:        * duplicate frames (typically, when a dest MAC address is unknown
                   2015:        * or for a broadcast/multicast).
                   2016:        */
                   2017:       dst_port = bcm5600_table_get_entry(d,d->t_ptable,i);
                   2018:       assert(dst_port != NULL);
                   2019: 
                   2020:       if (dst_port[0] & BCM5600_PTABLE_TRUNK_FLAG) {
                   2021:          trunk_id = dst_port[0] & BCM5600_PTABLE_TGID_MASK;
                   2022:          trunk_id >>= BCM5600_PTABLE_TGID_SHIFT;
                   2023: 
                   2024:          trunk = bcm5600_table_get_entry(d,d->t_tbmap,trunk_id);
                   2025:          assert(trunk != NULL);
                   2026:          
                   2027:          p->egress_bitmap &= ~trunk[0];
                   2028:       }
                   2029: 
                   2030:       /* select the appropriate output vector */
                   2031:       if (p->orig_vlan == 0)
                   2032:          send_pkt = bcm5600_send_pkt_direct;
                   2033:       else {
                   2034:          egress_untagged = p->egress_ut_bitmap & (1 << i);
                   2035: 
                   2036:          if (p->orig_vlan == -1) {
                   2037:             /* Untagged packet */
                   2038:             if (egress_untagged)
                   2039:                send_pkt = bcm5600_send_pkt_direct;
                   2040:             else
                   2041:                send_pkt = bcm5600_send_pkt_push_dot1q;
                   2042:          } else {
                   2043:             /* Tagged packet */
                   2044:             if (egress_untagged)
                   2045:                send_pkt = bcm5600_send_pkt_pop_dot1q;
                   2046:             else
                   2047:                send_pkt = bcm5600_send_pkt_direct;
                   2048:          }
                   2049:       }
                   2050: 
                   2051: #if DEBUG_FORWARD > 1
                   2052:       BCM_LOG(d,"forwarding on port %s (vector=%p)\n",
                   2053:               d->ports[i].name,send_pkt);
                   2054: #endif
                   2055:       send_pkt(d,p,d->ports[i].nio);
                   2056:    }
                   2057: 
                   2058:    return(TRUE);
                   2059: }
                   2060: 
1.1.1.2 ! root     2061: /* Determine if the specified MAC address matches a BPDU */
        !          2062: static inline int bcm5600_is_bpdu(n_eth_addr_t *m)
        !          2063: {
        !          2064:    /* PVST+ */
        !          2065:    if (!memcmp(m,"\x01\x00\x0c\xcc\xcc\xcd",6))
        !          2066:       return(TRUE);
        !          2067: 
        !          2068:    /* Classical 802.1D */
        !          2069:    if (!memcmp(m,"\x01\x80\xc2\x00\x00",5) && !(m->eth_addr_byte[5] & 0xF0))
        !          2070:       return(TRUE);
        !          2071: 
        !          2072:    return(FALSE);
        !          2073: }
        !          2074: 
1.1       root     2075: /* Handle a received packet */
                   2076: static int bcm5600_handle_rx_pkt(struct nm_16esw_data *d,struct bcm5600_pkt *p)
                   2077: {
                   2078:    m_uint32_t *port_entry;
                   2079:    n_eth_dot1q_hdr_t *eth_hdr;
                   2080:    u_int discard;
                   2081: 
                   2082:    /* No egress port at this time */
                   2083:    p->egress_bitmap = 0;
                   2084: 
                   2085:    /* Never send back frames to the source port */
                   2086:    p->egress_filter_bitmap = 1 << p->ingress_port;
                   2087: 
                   2088:    if (!(port_entry = bcm5600_table_get_entry(d,d->t_ptable,p->ingress_port)))
                   2089:       return(FALSE);
                   2090: 
                   2091:    /* Analyze the Ethernet header */
                   2092:    eth_hdr = (n_eth_dot1q_hdr_t *)p->pkt;
                   2093: 
1.1.1.2 ! root     2094:    /* Determine VLAN */
        !          2095:    if (ntohs(eth_hdr->type) != N_ETH_PROTO_DOT1Q) {
        !          2096:       p->orig_vlan = -1;
        !          2097:       p->real_vlan = port_entry[0] & BCM5600_PTABLE_VLAN_TAG_MASK;
        !          2098: 
        !          2099:      /* TODO: 802.1p/CoS remarking */
        !          2100:      if (port_entry[4] & BCM5600_PTABLE_RPE_FLAG) {
        !          2101:      }
        !          2102:    } else {
        !          2103:       p->orig_vlan = p->real_vlan = ntohs(eth_hdr->vlan_id) & 0xFFF;
        !          2104:    }
        !          2105: 
        !          2106:    /* Check that this VLAN exists */
        !          2107:    if (!(p->vlan_entry = bcm5600_vtable_get_entry_by_vlan(d,p->real_vlan)))
        !          2108:       return(FALSE);
        !          2109: 
1.1       root     2110:    /* Check for the reserved addresses (BPDU for spanning-tree) */
1.1.1.2 ! root     2111:    if (bcm5600_is_bpdu(&eth_hdr->daddr)) {
1.1       root     2112: #if DEBUG_RECEIVE
                   2113:       BCM_LOG(d,"Received a BPDU packet:\n");
                   2114:       mem_dump(d->vm->log_fd,p->pkt,p->pkt_len);
                   2115: #endif
                   2116:       p->egress_bitmap |= 1 << d->cpu_port;
                   2117:       return(bcm5600_forward_pkt(d,p));
                   2118:    }
                   2119: 
1.1.1.2 ! root     2120:    /* Check that this port is a member of this VLAN */
        !          2121:    if (!(p->vlan_entry[1] & (1 << p->ingress_port)))
        !          2122:       return(FALSE);
        !          2123: 
1.1       root     2124:    /* Discard packet ? */
                   2125:    discard = port_entry[0] & BCM5600_PTABLE_PRT_DIS_MASK;
                   2126:    discard >>= BCM5600_PTABLE_PRT_DIS_SHIFT;
                   2127: 
                   2128:    if (discard) {
                   2129:       if (discard != 0x20) {
                   2130:          printf("\n\n\n"
                   2131:                 "-----------------------------------------------------------"
                   2132:                 "---------------------------------\n"
                   2133:                 "Unspported feature: please post your current configuration "
                   2134:                 "on http://www.ipflow.utc.fr/blog/\n"
                   2135:                 "-----------------------------------------------------------"
                   2136:                 "---------------------------------\n");
                   2137:       }
                   2138: 
                   2139:       /* Drop the packet */
                   2140:       return(FALSE);
                   2141:    }
                   2142: 
                   2143:    /* Mirroring on Ingress ? */
                   2144:    if (port_entry[1] & BCM5600_PTABLE_MI_FLAG)
                   2145:       bcm5600_mirror_pkt(d,p,0);
                   2146: 
                   2147: #if DEBUG_RECEIVE
                   2148:    BCM_LOG(d,"%s: received a packet on VLAN %u\n",
                   2149:            d->ports[p->ingress_port].name,p->real_vlan);
                   2150: #endif
                   2151: 
                   2152:    /* Source MAC address learning */
                   2153:    if (!bcm5600_src_mac_learning(d,p))
                   2154:       return(FALSE);
                   2155: 
                   2156:    /* Take forwarding decision based on destination MAC address */
                   2157:    if (!bcm5600_dst_mac_lookup(d,p))
                   2158:       return(FALSE);
                   2159: 
                   2160:    /* Send the packet to the egress ports */
                   2161:    return(bcm5600_forward_pkt(d,p));
                   2162: }
                   2163: 
                   2164: /* Handle a packet to transmit */
                   2165: static int bcm5600_handle_tx_pkt(struct nm_16esw_data *d,
                   2166:                                  struct bcm5600_pkt *p,
                   2167:                                  u_int egress_bitmap)
                   2168: {   
                   2169:    n_eth_dot1q_hdr_t *eth_hdr;
                   2170:    
                   2171:    /* Never send back frames to the source port */
                   2172:    p->egress_filter_bitmap = 1 << p->ingress_port;
                   2173: 
                   2174:    /* We take the complete forwarding decision if bit 23 is set */
                   2175:    if (egress_bitmap & (1 << 23)) {
                   2176:       /* No egress port at this time */
                   2177:       p->egress_bitmap = 0;
                   2178: 
                   2179:       /* The packet must be tagged so that we can determine the VLAN */
                   2180:       eth_hdr = (n_eth_dot1q_hdr_t *)p->pkt;
                   2181: 
                   2182:       if (ntohs(eth_hdr->type) != N_ETH_PROTO_DOT1Q) {
                   2183:          BCM_LOG(d,"bcm5600_handle_tx_pkt: untagged packet ?\n");
                   2184:          return(FALSE);
                   2185:       }
                   2186: 
                   2187:       /* Find the appropriate, check it exists (just in case) */
                   2188:       p->orig_vlan = p->real_vlan = ntohs(eth_hdr->vlan_id) & 0xFFF;
                   2189: 
                   2190:       if (!(p->vlan_entry = bcm5600_vtable_get_entry_by_vlan(d,p->real_vlan)))
                   2191:         return(FALSE);
                   2192: 
                   2193: #if DEBUG_TRANSMIT
                   2194:       BCM_LOG(d,"Transmitting a packet from TX ring to VLAN %u\n",
                   2195:               p->real_vlan);
                   2196: #endif
                   2197: 
                   2198:       /* Take forwarding decision based on destination MAC address */
                   2199:       if (!bcm5600_dst_mac_lookup(d,p))
                   2200:          return(FALSE);
                   2201:    } else {
                   2202: #if DEBUG_TRANSMIT
                   2203:       BCM_LOG(d,"Transmitting natively a packet from TX ring.\n");
                   2204: #endif
                   2205:       /* The egress ports are specified, send the packet natively */
                   2206:       p->orig_vlan = 0;
                   2207:       p->egress_bitmap = egress_bitmap;
                   2208:    }
                   2209: 
                   2210:    /* Send the packet to the egress ports */
                   2211:    return(bcm5600_forward_pkt(d,p));
                   2212: }
                   2213: 
                   2214: /* Handle the TX ring */
                   2215: static int dev_bcm5600_handle_txring(struct nm_16esw_data *d)
                   2216: {
                   2217:    struct bcm5600_pkt pkt_data;
                   2218:    m_uint32_t tdes[4],txd_len;
                   2219: 
                   2220:    BCM_LOCK(d);
                   2221: 
                   2222:    if (!d->tx_current || d->tx_end_scan) {
                   2223:       BCM_UNLOCK(d);
                   2224:       return(FALSE);
                   2225:    }
                   2226: 
                   2227:    /* Read the current TX descriptor */
                   2228:    physmem_copy_from_vm(d->vm,tdes,d->tx_current,4*sizeof(m_uint32_t));
                   2229:    tdes[0] = vmtoh32(tdes[0]);
                   2230:    tdes[1] = vmtoh32(tdes[1]);
                   2231:    tdes[2] = vmtoh32(tdes[2]);
                   2232:    tdes[3] = vmtoh32(tdes[3]);
                   2233:    
                   2234: #if DEBUG_TRANSMIT
                   2235:    BCM_LOG(d,"=== TRANSMIT PATH ===\n");
                   2236: 
                   2237:    BCM_LOG(d,"tx_current=0x%8.8x, "
                   2238:            "tdes[0]=0x%8.8x, tdes[1]=0x%8.8x, tdes[2]=0x%8.8x\n",
                   2239:            d->tx_current,tdes[0],tdes[1],tdes[2]);
                   2240: #endif
                   2241: 
                   2242:    /* Get the buffer size */
                   2243:    txd_len = tdes[1] & 0x7FF;
                   2244: 
                   2245:    /* Check buffer size */
                   2246:    if ((d->tx_bufsize + txd_len) >= sizeof(d->tx_buffer))
                   2247:       goto done;
                   2248: 
                   2249:    /* Copy the packet from memory */
                   2250:    physmem_copy_from_vm(d->vm,d->tx_buffer+d->tx_bufsize,tdes[0],txd_len);
                   2251:    d->tx_bufsize += txd_len;
                   2252: 
                   2253:    /* Packet not complete: handle it later */
                   2254:    if (tdes[1] & BCM5600_TXD_NEOP)
                   2255:       goto done;
                   2256: 
                   2257: #if DEBUG_TRANSMIT
                   2258:    mem_dump(d->vm->log_fd,d->tx_buffer,d->tx_bufsize);
                   2259: #endif
                   2260: 
                   2261:    /* Transmit the packet */
                   2262:    pkt_data.ingress_port = d->cpu_port;
                   2263:    pkt_data.pkt = d->tx_buffer;
                   2264:    pkt_data.pkt_len = d->tx_bufsize - 4;
                   2265:    pkt_data.sent_to_cpu = TRUE;
                   2266:    bcm5600_handle_tx_pkt(d,&pkt_data,tdes[2]);
                   2267: 
                   2268:    /* Reset the TX buffer (packet fully transmitted) */
                   2269:    d->tx_bufsize = 0;
                   2270: 
                   2271:  done:
                   2272:    /* We have reached end of ring: trigger the TX underrun interrupt */
                   2273:    if (!(tdes[1] & BCM5600_TXD_RING_CONT)) {
                   2274:       d->tx_end_scan = 1;
                   2275:       pci_dev_trigger_irq(d->vm,d->pci_dev);
                   2276:       BCM_UNLOCK(d);
                   2277:       return(TRUE);
                   2278:    } 
                   2279: 
                   2280:    /* Go to the next descriptor */
                   2281:    d->tx_current += BCM5600_TXD_SIZE;
                   2282:    BCM_UNLOCK(d);   
                   2283:    return(TRUE);
                   2284: }
                   2285: 
                   2286: /* Handle the RX ring */
                   2287: static int dev_bcm5600_handle_rxring(netio_desc_t *nio,
                   2288:                                      u_char *pkt,ssize_t pkt_len,
                   2289:                                      struct nm_16esw_data *d,  
                   2290:                                      struct bcm5600_port *port)
                   2291: {  
                   2292:    struct bcm5600_pkt pkt_data;
                   2293:    m_uint32_t rxd_len;
                   2294: 
                   2295: #if DEBUG_RECEIVE
                   2296:    BCM_LOG(d,"=== RECEIVE PATH ===\n");
                   2297: 
                   2298:    BCM_LOG(d,"%s: received a packet of %ld bytes.\n",
                   2299:            port->name,(u_long)pkt_len);
                   2300:    mem_dump(d->vm->log_fd,pkt,pkt_len);
                   2301: #endif
                   2302: 
                   2303:    BCM_LOCK(d);
                   2304: 
                   2305:    if (!d->rx_current || d->rx_end_scan) {
                   2306:       BCM_UNLOCK(d);
                   2307:       return(FALSE);
                   2308:    }
                   2309:    
                   2310:    /* Read the current TX descriptor */
                   2311:    physmem_copy_from_vm(d->vm,pkt_data.rdes,d->rx_current,
                   2312:                         (4 * sizeof(m_uint32_t)));
                   2313: 
                   2314:    pkt_data.rdes[0] = vmtoh32(pkt_data.rdes[0]);
                   2315:    pkt_data.rdes[1] = vmtoh32(pkt_data.rdes[1]);
                   2316:    pkt_data.rdes[2] = vmtoh32(pkt_data.rdes[2]);
                   2317:    pkt_data.rdes[3] = vmtoh32(pkt_data.rdes[3]);
                   2318: 
                   2319: #if DEBUG_RECEIVE
                   2320:    BCM_LOG(d,"rx_current=0x%8.8x, "
                   2321:            "rdes[0]=0x%8.8x, rdes[1]=0x%8.8x, rdes[2]=0x%8.8x\n",
                   2322:            d->rx_current,pkt_data.rdes[0],pkt_data.rdes[1],pkt_data.rdes[2]);
                   2323: #endif
                   2324: 
                   2325:    /* Get the buffer size */
                   2326:    rxd_len = pkt_data.rdes[1] & 0x7FF;
                   2327: 
                   2328:    if (pkt_len > rxd_len) {
                   2329:       BCM_UNLOCK(d);
                   2330:       return(FALSE);
                   2331:    }
                   2332: 
                   2333:    /* Fill the packet info */
                   2334:    pkt_data.ingress_port = port->id;
                   2335:    pkt_data.pkt = pkt;
                   2336:    pkt_data.pkt_len = pkt_len;
                   2337:    pkt_data.sent_to_cpu = FALSE;
                   2338: 
                   2339:    /* Handle the packet */
                   2340:    bcm5600_handle_rx_pkt(d,&pkt_data);
                   2341:   
                   2342:    /* Signal only an interrupt when a packet has been sent to the CPU */
                   2343:    if (pkt_data.sent_to_cpu) {
                   2344:       /* We have reached end of ring: trigger the RX underrun interrupt */
                   2345:       if (!(pkt_data.rdes[1] & BCM5600_RXD_RING_CONT)) {
                   2346:          d->rx_end_scan = 1;
                   2347:          pci_dev_trigger_irq(d->vm,d->pci_dev);
                   2348:          BCM_UNLOCK(d);
                   2349:          return(TRUE);
                   2350:       }
                   2351: 
                   2352:       /* A packet was received */
                   2353:       pci_dev_trigger_irq(d->vm,d->pci_dev);
                   2354: 
                   2355:       /* Go to the next descriptor */
                   2356:       d->rx_current += BCM5600_RXD_SIZE;
                   2357:    }
                   2358: 
                   2359:    BCM_UNLOCK(d);
                   2360:    return(TRUE);
                   2361: }
                   2362: 
                   2363: /* pci_bcm5605_read() */
                   2364: static m_uint32_t pci_bcm5605_read(cpu_mips_t *cpu,struct pci_device *dev,
                   2365:                                    int reg)
                   2366: {
                   2367:    struct nm_16esw_data *d = dev->priv_data;
                   2368: 
                   2369:    switch(reg) {
                   2370:       case PCI_REG_BAR0:
                   2371:          return(d->dev->phys_addr);
                   2372:       default:
                   2373:          return(0);
                   2374:    }
                   2375: }
                   2376: 
                   2377: /* pci_bcm5605_write() */
                   2378: static void pci_bcm5605_write(cpu_mips_t *cpu,struct pci_device *dev,
                   2379:                               int reg,m_uint32_t value)
                   2380: {
                   2381:    struct nm_16esw_data *d = dev->priv_data;
                   2382: 
                   2383:    switch(reg) {
                   2384:       case PCI_REG_BAR0:
                   2385:          vm_map_device(cpu->vm,d->dev,(m_uint64_t)value);
                   2386:          BCM_LOG(d,"BCM5600 registers are mapped at 0x%x\n",value);
                   2387:          break;
                   2388:    }
                   2389: }
                   2390: 
                   2391: /* Rewrite the base MAC address */
                   2392: int dev_nm_16esw_burn_mac_addr(vm_instance_t *vm,u_int nm_bay,
                   2393:                                struct cisco_eeprom *eeprom)
                   2394: {
                   2395:    m_uint8_t eeprom_ver;
                   2396:    size_t offset;
                   2397:    n_eth_addr_t addr;
                   2398:    m_uint16_t pid;
                   2399: 
                   2400:    pid = (m_uint16_t)getpid();
                   2401: 
                   2402:    /* Generate automatically the MAC address */
                   2403:    addr.eth_addr_byte[0] = vm_get_mac_addr_msb(vm);
                   2404:    addr.eth_addr_byte[1] = vm->instance_id & 0xFF;
                   2405:    addr.eth_addr_byte[2] = pid >> 8;
                   2406:    addr.eth_addr_byte[3] = pid & 0xFF;
                   2407:    addr.eth_addr_byte[4] = 0xF0 + nm_bay;
                   2408:    addr.eth_addr_byte[5] = 0x00;
                   2409: 
                   2410:    /* Read EEPROM format version */
                   2411:    cisco_eeprom_get_byte(eeprom,0,&eeprom_ver);
                   2412: 
                   2413:    if (eeprom_ver != 4)
                   2414:       return(-1);
                   2415: 
                   2416:    if (cisco_eeprom_v4_find_field(eeprom,0xCF,&offset) == -1)
                   2417:       return(-1);
                   2418: 
                   2419:    cisco_eeprom_set_region(eeprom,offset,addr.eth_addr_byte,6);
                   2420:    return(0);
                   2421: }
                   2422: 
                   2423: /* Initialize a NM-16ESW module */
                   2424: struct nm_16esw_data *
                   2425: dev_nm_16esw_init(vm_instance_t *vm,char *name,u_int nm_bay,
                   2426:                   struct pci_bus *pci_bus,int pci_device,int irq)
                   2427: {
                   2428:    struct nm_16esw_data *data;
                   2429:    struct bcm5600_port *port;
                   2430:    struct vdevice *dev;
                   2431:    int i,port_id;
                   2432: 
                   2433:    /* Allocate the private data structure */
                   2434:    if (!(data = malloc(sizeof(*data)))) {
                   2435:       fprintf(stderr,"%s: out of memory\n",name);
                   2436:       return NULL;
                   2437:    }
                   2438: 
                   2439:    memset(data,0,sizeof(*data));
                   2440:    pthread_mutex_init(&data->lock,NULL);
                   2441:    data->name = name;
                   2442:    data->nr_port = 16;
                   2443:    data->vm = vm;
                   2444: 
                   2445:    /* Create the BCM5600 tables */
                   2446:    if (bcm5600_table_create(data) == -1)
                   2447:       return NULL;
                   2448: 
                   2449:    /* Clear the various tables */
                   2450:    bcm5600_reset_arl(data);
                   2451:    data->arl_cnt[0] = 1;
                   2452:    data->t_ptable = bcm5600_table_find(data,BCM5600_ADDR_PTABLE0);
                   2453:    data->t_vtable = bcm5600_table_find(data,BCM5600_ADDR_VTABLE0);
                   2454:    data->t_arl    = bcm5600_table_find(data,BCM5600_ADDR_ARL0);
                   2455:    data->t_marl   = bcm5600_table_find(data,BCM5600_ADDR_MARL0);
                   2456:    data->t_tbmap  = bcm5600_table_find(data,BCM5600_ADDR_TBMAP0);
                   2457:    data->t_ttr    = bcm5600_table_find(data,BCM5600_ADDR_TTR0);
                   2458: 
                   2459:    /* Initialize ports */
                   2460:    data->cpu_port = 27;
                   2461: 
                   2462:    for(i=0;i<data->nr_port;i++) {
                   2463:       port_id = nm16esw_port_mapping[i];
                   2464: 
                   2465:       port = &data->ports[port_id];
                   2466:       port->id = port_id;
                   2467:       snprintf(port->name,sizeof(port->name),"Fa%u/%d",nm_bay,i);
                   2468:    }
                   2469: 
                   2470:    /* Create the BCM5605 PCI device */
                   2471:    data->pci_dev = pci_dev_add(pci_bus,name,
                   2472:                                BCM5605_PCI_VENDOR_ID,BCM5605_PCI_PRODUCT_ID,
                   2473:                                pci_device,0,irq,data,
                   2474:                                NULL,pci_bcm5605_read,pci_bcm5605_write);
                   2475: 
                   2476:    if (!data->pci_dev) {
                   2477:       fprintf(stderr,"%s: unable to create PCI device.\n",name);
                   2478:       return NULL;
                   2479:    }
                   2480: 
                   2481:    /* Create the BCM5605 device itself */
                   2482:    if (!(dev = dev_create(name))) {
                   2483:       fprintf(stderr,"%s: unable to create device.\n",name);
                   2484:       return NULL;
                   2485:    }
                   2486: 
                   2487:    dev->phys_addr = 0;
                   2488:    dev->phys_len  = 0x200000;
                   2489:    dev->handler   = dev_bcm5605_access;
                   2490: 
                   2491:    /* Store device info */
                   2492:    dev->priv_data = data;
                   2493:    data->dev = dev;
                   2494: 
                   2495:    /* Create the TX ring scanner */
                   2496:    data->tx_tid = ptask_add((ptask_callback)dev_bcm5600_handle_txring,
                   2497:                             data,NULL);
                   2498: 
                   2499:    /* Start the MAC address ager */
                   2500:    data->ager_tid = timer_create_entry(15000,FALSE,10,
                   2501:                                        (timer_proc)bcm5600_arl_ager,data);
                   2502:    return data;
                   2503: }
                   2504: 
                   2505: /* Remove a NM-16ESW from the specified slot */
                   2506: int dev_nm_16esw_remove(struct nm_16esw_data *data)
                   2507: {
                   2508:    /* Stop the Ager */
                   2509:    timer_remove(data->ager_tid);
                   2510: 
                   2511:    /* Stop the TX ring task */
                   2512:    ptask_remove(data->tx_tid);
                   2513: 
                   2514:    /* Remove device + PCI stuff */
                   2515:    pci_dev_remove(data->pci_dev);
                   2516:    vm_unbind_device(data->vm,data->dev);
                   2517:    cpu_group_rebuild_mts(data->vm->cpu_group);
                   2518:    free(data->dev);
                   2519: 
                   2520:    /* Free all tables and registers */
                   2521:    bcm5600_table_free(data);
                   2522:    bcm5600_reg_free(data);
                   2523:    free(data);
                   2524:    return(0);
                   2525: }
                   2526: 
                   2527: /* Bind a Network IO descriptor */
                   2528: int dev_nm_16esw_set_nio(struct nm_16esw_data *d,u_int port_id,
                   2529:                          netio_desc_t *nio)
                   2530: {
                   2531:    struct bcm5600_port *port;
                   2532: 
                   2533:    if (!d || (port_id >= d->nr_port))
                   2534:       return(-1);
                   2535: 
                   2536:    /* define the new NIO */
                   2537:    port = &d->ports[nm16esw_port_mapping[port_id]];
                   2538:    port->nio = nio;
                   2539:    netio_rxl_add(nio,(netio_rx_handler_t)dev_bcm5600_handle_rxring,d,port);
                   2540:    return(0);
                   2541: }
                   2542: 
                   2543: /* Unbind a Network IO descriptor */
                   2544: int dev_nm_16esw_unset_nio(struct nm_16esw_data *d,u_int port_id)
                   2545: {
                   2546:    struct bcm5600_port *port;
                   2547: 
                   2548:    if (!d || (port_id >= d->nr_port))
                   2549:       return(-1);
                   2550: 
                   2551:    port = &d->ports[nm16esw_port_mapping[port_id]];
                   2552: 
                   2553:    if (port->nio) {
                   2554:       netio_rxl_remove(port->nio);
                   2555:       port->nio = NULL;
                   2556:    }
                   2557: 
                   2558:    return(0);
                   2559: }
                   2560: 
                   2561: /* Show debugging information */
                   2562: int dev_nm_16esw_show_info(struct nm_16esw_data *d)
                   2563: {   
                   2564:    BCM_LOCK(d);
                   2565:    printf("ARL count = %u\n\n",d->arl_cnt[0]);
                   2566:    bcm5600_dump_main_tables(d);
                   2567:    bcm5600_mirror_show_status(d);
                   2568:    bcm5600_reg_dump(d,FALSE);
                   2569:    BCM_UNLOCK(d);
                   2570:    return(0);
                   2571: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.