Annotation of cf/dev_nm_16esw.c, revision 1.1.1.3

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);
1.1.1.3 ! root     1398:          d->schan_cmd_res = 0x00008002;
1.1       root     1399:          break;
                   1400: 
                   1401:       case BCM5600_SCHAN_CMD_READ_MII:
                   1402:          bcm5600_mii_read(d);
1.1.1.3 ! root     1403:          d->schan_cmd_res = 0x00048000;
1.1       root     1404:          break;
                   1405: 
                   1406:       case BCM5600_SCHAN_CMD_WRITE_MII:
                   1407:          bcm5600_mii_write(d);
1.1.1.3 ! root     1408:          d->schan_cmd_res = 0x00048000;
1.1       root     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:  */
1.1.1.3 ! root     1426: void *dev_bcm5605_access(cpu_gen_t *cpu,struct vdevice *dev,m_uint32_t offset,
1.1       root     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) {
1.1.1.3 ! root     1437:       BCM_LOG(d,"read  access to offset=0x%x, pc=0x%llx\n",
        !          1438:               offset,cpu_get_pc(cpu));
1.1       root     1439:    } else {
                   1440:       BCM_LOG(d,"write access to offset=0x%x, pc=0x%llx, val=0x%llx\n",
1.1.1.3 ! root     1441:               offset,cpu_get_pc(cpu),*data);
1.1       root     1442:    }
                   1443: #endif
                   1444: 
                   1445:    BCM_LOCK(d);
                   1446: 
                   1447:    switch(offset) {
                   1448:       case 0x50:
                   1449:          if (op_type == MTS_WRITE) {
                   1450:             bcm5600_handle_schan_cmd(d,*data);
                   1451:          } else {
                   1452:             *data = d->schan_cmd_res;
                   1453:          }
                   1454:          break;
                   1455: 
                   1456:       case 0x140:
                   1457:          if (op_type == MTS_READ)
                   1458:             *data = bcm5600_mii_port_status_bmp(d);
                   1459:          break;
                   1460: 
                   1461:       /* MII input register */
                   1462:       case 0x158:
                   1463:          if (op_type == MTS_WRITE)
                   1464:             d->mii_input = *data;
                   1465:          break;
                   1466: 
                   1467:       /* MII output register */
                   1468:       case 0x15c:
                   1469:          if (op_type == MTS_READ)
                   1470:             *data = d->mii_output;
                   1471:          break;         
                   1472: 
                   1473:       /* Unknown (related to RX/TX rings ?) */
                   1474:       case 0x104:
                   1475:          break;
                   1476: 
                   1477:       /* TX ring address */
                   1478:       case 0x110:
                   1479:          if (op_type == MTS_READ)
                   1480:             *data = d->tx_ring_addr;
                   1481:          else {
                   1482:             d->tx_ring_addr = d->tx_current = *data;   
                   1483:             d->tx_end_scan = 0;
                   1484: #if DEBUG_TRANSMIT
                   1485:             BCM_LOG(d,"tx_ring_addr = 0x%8.8x\n",d->tx_ring_addr);
                   1486: #endif
                   1487:          }
                   1488:          break;
                   1489: 
                   1490:       /* RX ring address */
                   1491:       case 0x114:
                   1492:          if (op_type == MTS_READ)
                   1493:             *data = d->rx_ring_addr;
                   1494:          else {
                   1495:             d->rx_ring_addr = d->rx_current = *data;
                   1496:             d->rx_end_scan = 0;
                   1497: #if DEBUG_RECEIVE
                   1498:             BCM_LOG(d,"rx_ring_addr = 0x%8.8x\n",d->rx_ring_addr);
                   1499: #endif
                   1500:          }
                   1501:          break;
                   1502: 
                   1503:       /* Interrupt status */
                   1504:       case 0x144:
                   1505:          if (op_type == MTS_READ) {
                   1506:             *data = 0;
                   1507: 
                   1508:             /* RX/TX underrun (end of rings reached) */
                   1509:             if (d->tx_end_scan)
                   1510:                *data |= BCM5600_INTR_TX_UNDERRUN;
                   1511: 
                   1512:             if (d->rx_end_scan)
                   1513:                *data |= BCM5600_INTR_RX_UNDERRUN;
                   1514: 
                   1515:             /* RX packet available */
                   1516:             *data |= BCM5600_INTR_RX_AVAIL;
                   1517: 
                   1518:             /* Link status changed */
                   1519:             if (d->mii_intr) {
                   1520:                *data |= BCM5600_INTR_LINKSTAT_MOD;
                   1521:                d->mii_intr = FALSE;
                   1522:             }
                   1523:          }
                   1524:          break;
                   1525: 
                   1526:       /* Interrupt mask */
                   1527:       case 0x148:
                   1528:          if (op_type == MTS_READ)
                   1529:             *data = d->intr_mask;
                   1530:          else
                   1531:             d->intr_mask = *data;
                   1532:          break;
                   1533: 
                   1534:       /* Data Words */
                   1535:       case 0x800 ... 0x850:
                   1536:          reg = (offset - 0x800) >> 2;
                   1537: 
                   1538:          if (op_type == MTS_READ)
                   1539:             *data = d->dw[reg];
                   1540:          else
                   1541:             d->dw[reg] = *data;
                   1542:          break;
                   1543: 
                   1544: #if DEBUG_UNKNOWN
                   1545:       /* Unknown offset */
                   1546:       default:
                   1547:          if (op_type == MTS_READ) {
                   1548:             BCM_LOG(d,"read from unknown addr 0x%x, pc=0x%llx (size=%u)\n",
1.1.1.3 ! root     1549:                     offset,cpu_get_pc(cpu),op_size);
1.1       root     1550:          } else {
                   1551:             BCM_LOG(d,"write to unknown addr 0x%x, value=0x%llx, "
1.1.1.3 ! root     1552:                     "pc=0x%llx (size=%u)\n",
        !          1553:                     offset,*data,cpu_get_pc(cpu),op_size);
1.1       root     1554:          }
                   1555: #endif
                   1556:    }
                   1557: 
                   1558:    BCM_UNLOCK(d);
                   1559:    return NULL;
                   1560: }
                   1561: 
                   1562: /* Show mirroring status */
                   1563: static int bcm5600_mirror_show_status(struct nm_16esw_data *d)
                   1564: {
                   1565:    m_uint32_t *port,dst_port;
                   1566:    int i;
                   1567: 
                   1568:    printf("Mirroring status: "); 
                   1569: 
                   1570:    if (!(d->mirror_dst_port & BCM5600_MIRROR_ENABLE)) {
                   1571:       printf("disabled.\n\n");
                   1572:       return(FALSE);
                   1573:    }
                   1574: 
                   1575:    printf("enabled. Dest port: ");
                   1576: 
                   1577:    dst_port = d->mirror_dst_port & BCM5600_MIRROR_PORT_MASK;
                   1578: 
                   1579:    if (dst_port < 32)
                   1580:       printf("%s\n",d->ports[dst_port].name);
                   1581:    else
                   1582:       printf("none set.\n");
                   1583: 
                   1584:    /* Ingress info */
                   1585:    printf("  Ingress Ports: ");
                   1586: 
                   1587:    for(i=0;i<d->nr_port;i++) {
                   1588:       port = bcm5600_table_get_entry(d,d->t_ptable,i);
                   1589:       if (port[1] & BCM5600_PTABLE_MI_FLAG)
                   1590:          printf("%s ",d->ports[i].name);
                   1591:    }
                   1592: 
                   1593:    printf("\n");
                   1594: 
                   1595:    /* Egress info */
                   1596:    printf("  Egress Ports: ");
                   1597:   
                   1598:    for(i=0;i<d->nr_port;i++)
                   1599:       if (d->mirror_egress_ports & (1 << i))
                   1600:          printf("%s ",d->ports[i].name);
                   1601: 
                   1602:    printf("\n\n");
                   1603:    return(TRUE);
                   1604: }
                   1605: 
                   1606: /* Mirror a packet */
                   1607: static int bcm5600_mirror_pkt(struct nm_16esw_data *d,struct bcm5600_pkt *p,
                   1608:                               int reason)
                   1609: {
                   1610:    u_int mport;
                   1611: 
                   1612:    if (!(d->mirror_dst_port & BCM5600_MIRROR_ENABLE))
                   1613:       return(FALSE);
                   1614: 
                   1615: #if DEBUG_MIRROR
                   1616:    if (reason == 0) {
                   1617:       BCM_LOG(d,"mirroring packet on ingress port %s\n",
                   1618:               d->ports[p->ingress_port]);
                   1619:    } else {
                   1620:       BCM_LOG(d,"mirroring packet on egress port (input port %s)\n",
                   1621:               d->ports[p->ingress_port]);
                   1622:    }
                   1623:    mem_dump(d->vm->log_fd,pkt,pkt_len);
                   1624: #endif
                   1625: 
                   1626:    mport = d->mirror_dst_port & BCM5600_MIRROR_PORT_MASK;
                   1627:    if (mport < 32)
                   1628:       netio_send(d->ports[mport].nio,p->pkt,p->pkt_len);
                   1629:    return(TRUE);
                   1630: }
                   1631: 
                   1632: /* Put a packet into the RX ring (tag it if necessary) */
                   1633: static int bcm5600_send_pkt_to_cpu(struct nm_16esw_data *d,
                   1634:                                    struct bcm5600_pkt *p)
                   1635: {
                   1636:    m_uint32_t pkt_addr,pkt_len,dot1q_data;
                   1637: 
                   1638:    /* If the packet was already sent to CPU, don't send it again */
                   1639:    if (p->sent_to_cpu)
                   1640:       return(FALSE);
                   1641: 
                   1642:    pkt_addr = p->rdes[0];
                   1643:    pkt_len  = p->pkt_len;
                   1644: 
                   1645:    if (p->orig_vlan != -1) {
                   1646:       /* 802.1Q packet: copy it directly */
                   1647:       physmem_copy_to_vm(d->vm,p->pkt,pkt_addr,pkt_len);
                   1648:    } else {
                   1649:       /* untagged packet: copy the dst and src addresses first */
                   1650:       physmem_copy_to_vm(d->vm,p->pkt,pkt_addr,N_ETH_HLEN - 2);
                   1651: 
                   1652:       /* add the 802.1Q protocol field (0x8100) + VLAN info */
                   1653:       dot1q_data = (N_ETH_PROTO_DOT1Q << 16) | p->real_vlan;
                   1654:       physmem_copy_u32_to_vm(d->vm,pkt_addr+N_ETH_HLEN-2,dot1q_data);
                   1655: 
                   1656:       /* copy the payload */
                   1657:       physmem_copy_to_vm(d->vm,p->pkt+N_ETH_HLEN-2,
                   1658:                          pkt_addr+sizeof(n_eth_dot1q_hdr_t),
                   1659:                          pkt_len - (N_ETH_HLEN - 2));
                   1660:       pkt_len += 4;
                   1661:    }
                   1662: 
                   1663:    physmem_copy_u32_to_vm(d->vm,d->rx_current+0x14,0x40000000 + (pkt_len+4));
                   1664:    physmem_copy_u32_to_vm(d->vm,d->rx_current+0x18,0x100 + p->ingress_port);
                   1665:    p->sent_to_cpu = TRUE;
                   1666: 
                   1667: #if DEBUG_RECEIVE
                   1668:    BCM_LOG(d,"sending packet to CPU (orig_vlan=%d).\n",p->orig_vlan);
                   1669: #endif
                   1670:    return(TRUE);
                   1671: }
                   1672: 
                   1673: /* Source MAC address learning */
                   1674: static int bcm5600_src_mac_learning(struct nm_16esw_data *d,
                   1675:                                     struct bcm5600_pkt *p)
                   1676: {  
                   1677:    n_eth_hdr_t *eth_hdr = (n_eth_hdr_t *)p->pkt;
                   1678:    n_eth_addr_t *src_mac = &eth_hdr->saddr;
                   1679:    m_uint32_t *arl_entry,*src_port,*trunk;
                   1680:    u_int trunk_id,old_ingress_port;
                   1681:    int src_mac_index;
                   1682: 
                   1683:    trunk = NULL;
                   1684:    trunk_id = 0;
                   1685: 
                   1686:    /* Skip multicast sources */
                   1687:    if (eth_addr_is_mcast(src_mac))
                   1688:       return(FALSE);
                   1689: 
                   1690:    src_port = bcm5600_table_get_entry(d,d->t_ptable,p->ingress_port);
                   1691:    assert(src_port != NULL);
                   1692: 
                   1693:    /* 
                   1694:     * The packet comes from a trunk port. Prevent sending the packet
                   1695:     * to the other ports of the trunk.
                   1696:     */
                   1697:    if (src_port[0] & BCM5600_PTABLE_TRUNK_FLAG) {
                   1698:       trunk_id = src_port[0] & BCM5600_PTABLE_TGID_MASK;
                   1699:       trunk_id >>= BCM5600_PTABLE_TGID_SHIFT;
                   1700: 
                   1701:       trunk = bcm5600_table_get_entry(d,d->t_tbmap,trunk_id);
                   1702:       assert(trunk != NULL);
                   1703: 
                   1704:       p->egress_filter_bitmap |= trunk[0] & BCM5600_TBMAP_MASK;
                   1705:    }
                   1706: 
                   1707:    /* Source MAC address learning */
                   1708:    src_mac_index = bcm5600_arl_lookup(d,src_mac,p->real_vlan);
                   1709: 
                   1710:    if (src_mac_index != -1) {
                   1711:       arl_entry = bcm5600_table_get_entry(d,d->t_arl,src_mac_index);
                   1712:       assert(arl_entry != NULL);
                   1713: 
                   1714:       old_ingress_port = arl_entry[2] & BCM5600_ARL_PORT_MASK;
                   1715:       old_ingress_port >>= BCM5600_ARL_PORT_SHIFT;
                   1716: 
                   1717:       if (old_ingress_port != p->ingress_port) 
                   1718:       {
                   1719:          /*
                   1720:           * Determine if we have a station movement.
                   1721:           * If we have a trunk, check if the old ingress port is member
                   1722:           * of this trunk, in this case this is not a movement.
                   1723:           */
                   1724:          if (trunk != NULL) {
                   1725:             if (trunk[0] & (1 << old_ingress_port))
                   1726:                arl_entry[2] |= BCM5600_ARL_HIT_FLAG;
                   1727:             else 
                   1728:                arl_entry[2] &= ~BCM5600_ARL_HIT_FLAG;
                   1729:          } else {
                   1730:             arl_entry[2] &= ~(BCM5600_ARL_TRUNK_FLAG|BCM5600_ARL_HIT_FLAG);
                   1731:             arl_entry[2] &= ~BCM5600_ARL_TGID_MASK;
                   1732:          }
                   1733: 
                   1734:          /* Change the ingress port */
                   1735:          arl_entry[2] &= ~BCM5600_ARL_PORT_MASK;
                   1736:          arl_entry[2] |= p->ingress_port << BCM5600_ARL_PORT_SHIFT;
                   1737:          return(TRUE);
                   1738:       }
                   1739: 
                   1740:       arl_entry[2] |= BCM5600_ARL_HIT_FLAG;
                   1741:       return(TRUE);
                   1742:    }
                   1743: 
                   1744: #if DEBUG_FORWARD
                   1745:       BCM_LOG(d,"source MAC address unknown, learning it.\n");
                   1746: #endif
                   1747: 
                   1748:    /* Add the new learned MAC address */
                   1749:    src_mac_index = bcm5600_find_free_arl_entry(d);
                   1750: 
                   1751:    if (src_mac_index == -1) {
                   1752:       BCM_LOG(d,"no free entries in ARL table!\n");
                   1753:       return(FALSE);
                   1754:    }
                   1755: 
                   1756:    arl_entry = bcm5600_table_get_entry(d,d->t_arl,src_mac_index);
                   1757:    assert(arl_entry != NULL);
                   1758:     
                   1759:    /* Fill the new ARL entry */
                   1760:    arl_entry[0]  = src_mac->eth_addr_byte[2] << 24;
                   1761:    arl_entry[0] |= src_mac->eth_addr_byte[3] << 16;
                   1762:    arl_entry[0] |= src_mac->eth_addr_byte[4] << 8;
                   1763:    arl_entry[0] |= src_mac->eth_addr_byte[5];
                   1764: 
                   1765:    arl_entry[1]  = src_mac->eth_addr_byte[0] << 8;
                   1766:    arl_entry[1] |= src_mac->eth_addr_byte[1];
                   1767:    arl_entry[1] |= p->real_vlan << BCM5600_ARL_VLAN_TAG_SHIFT;
                   1768: 
                   1769:    arl_entry[2]  = BCM5600_ARL_HIT_FLAG;
                   1770:    arl_entry[2] |= p->ingress_port << BCM5600_ARL_PORT_SHIFT;
                   1771: 
                   1772:    if (trunk != NULL) {
                   1773:       arl_entry[2] |= BCM5600_ARL_TRUNK_FLAG;
                   1774:       arl_entry[2] |= (trunk_id << BCM5600_ARL_TGID_SHIFT);
                   1775:    }
                   1776: 
                   1777:    d->arl_cnt[0]++;
                   1778:    return(TRUE);
                   1779: }
                   1780: 
                   1781: /* Select an egress port the specified trunk */
                   1782: static int bcm5600_trunk_egress_port(struct nm_16esw_data *d,
                   1783:                                      struct bcm5600_pkt *p,
                   1784:                                      u_int trunk_id)
                   1785: {   
                   1786:    n_eth_hdr_t *eth_hdr = (n_eth_hdr_t *)p->pkt;
                   1787:    struct bcm5600_tg_info *tgi;
                   1788:    m_uint32_t *ttr_entry;
                   1789:    u_int i,nr_links;
                   1790:    u_int hash,port_id;
                   1791: 
                   1792:    ttr_entry = bcm5600_table_get_entry(d,d->t_ttr,trunk_id);
                   1793:    assert(ttr_entry != NULL);
                   1794: 
                   1795:    nr_links = ttr_entry[1] & BCM5600_TTR_TG_SIZE_MASK;
                   1796:    nr_links >>= BCM5600_TTR_TG_SIZE_SHIFT;
                   1797: 
                   1798: #if 0
                   1799:    /* Hash on source and destination MAC addresses */
                   1800:    for(i=0,hash=0;i<N_ETH_ALEN;i++) {
                   1801:       hash ^= eth_hdr->saddr.eth_addr_byte[i];
                   1802:       hash ^= eth_hdr->daddr.eth_addr_byte[i];
                   1803:    }
                   1804: 
                   1805:    hash ^= (hash >> 4);
                   1806:    port_id = hash % nr_links;
                   1807: 
                   1808:    /* Maximum of 8 ports per trunk */
                   1809:    assert(hash < BCM5600_MAX_PORTS_PER_TRUNK);
                   1810: #else
                   1811:    port_id = d->trunk_last_egress_port[trunk_id] + 1;
                   1812:    port_id %= nr_links;   
                   1813: #endif
                   1814: 
                   1815:    /* Save the latest port used for this trunk */
                   1816:    d->trunk_last_egress_port[trunk_id] = port_id;
                   1817: 
                   1818:    /* Select the egress port */
                   1819:    tgi = &tg_info[port_id];
                   1820:    return((ttr_entry[tgi->index] & tgi->mask) >> tgi->shift);
                   1821: }
                   1822: 
                   1823: /* Destination address lookup (take the forwarding decision) */
                   1824: static int bcm5600_dst_mac_lookup(struct nm_16esw_data *d,
                   1825:                                   struct bcm5600_pkt *p)
                   1826: {
                   1827:    n_eth_hdr_t *eth_hdr = (n_eth_hdr_t *)p->pkt;
                   1828:    n_eth_addr_t *dst_mac = &eth_hdr->daddr;
                   1829:    struct bcm5600_table *arl_table;
                   1830:    m_uint32_t *arl_entry;
                   1831:    u_int egress_port;
                   1832:    u_int trunk_id;
                   1833:    int dst_mac_index;
                   1834:    int is_mcast;
                   1835: 
                   1836:    /* Select the appropriate ARL table and do the lookup on dst MAC + VLAN */
                   1837:    if (eth_addr_is_mcast(dst_mac)) {
                   1838:       is_mcast = TRUE;
                   1839:       arl_table = d->t_marl;
                   1840:       dst_mac_index = bcm5600_marl_lookup(d,dst_mac,p->real_vlan);
                   1841:    } else {
                   1842:       is_mcast = FALSE;
                   1843:       arl_table = d->t_arl;
                   1844:       dst_mac_index = bcm5600_arl_lookup(d,dst_mac,p->real_vlan);
                   1845:    }
                   1846: 
                   1847:    /*
                   1848:     * Destination Lookup Failure (DLF).
                   1849:     * 
                   1850:     * Use the VLAN bitmap to compute the Egress port bitmap.
                   1851:     * Remove the ingress port from it.
                   1852:     */
                   1853:    if (dst_mac_index == -1) {
                   1854: #if DEBUG_FORWARD
                   1855:       BCM_LOG(d,"Destination MAC address unknown, flooding.\n");
                   1856: #endif
                   1857:       p->egress_bitmap = p->vlan_entry[1] & BCM5600_VTABLE_PORT_BMAP_MASK;
                   1858: 
                   1859:       /* Add the CPU to the egress ports */
                   1860:       p->egress_bitmap |= 1 << d->cpu_port;
                   1861: 
                   1862:       p->egress_ut_bitmap = p->vlan_entry[2];
                   1863:       p->egress_ut_bitmap &= BCM5600_VTABLE_UT_PORT_BMAP_MASK;
                   1864:       return(TRUE);
                   1865:    }
                   1866: 
                   1867:    /* The MAC address was found in the ARL/MARL table */
                   1868:    arl_entry = bcm5600_table_get_entry(d,arl_table,dst_mac_index);
                   1869:    assert(arl_entry != NULL);
                   1870: 
                   1871:    /* If the CPU bit is set, send a copy of the packet to the CPU */
                   1872:    if (arl_entry[1] & BCM5600_ARL_CPU_FLAG)
                   1873:       bcm5600_send_pkt_to_cpu(d,p);
                   1874: 
                   1875:    if (!is_mcast) {
                   1876:       /* Unicast: send the packet to the port or trunk found in ARL table */
                   1877:       if (arl_entry[2] & BCM5600_ARL_TRUNK_FLAG) {
                   1878:          trunk_id = arl_entry[2] & BCM5600_ARL_TGID_MASK;
                   1879:          trunk_id >>= BCM5600_ARL_TGID_SHIFT;
                   1880: 
                   1881:          /* Select an output port for this trunk */
                   1882:          egress_port = bcm5600_trunk_egress_port(d,p,trunk_id);
                   1883: 
                   1884: #if DEBUG_FORWARD
                   1885:          BCM_LOG(d,"Sending packet to trunk port %u, egress port %u\n",
                   1886:                  trunk_id,egress_port);
                   1887: #endif
                   1888:       } else {
                   1889:          egress_port = arl_entry[2] & BCM5600_ARL_PORT_MASK;
                   1890:          egress_port >>= BCM5600_ARL_PORT_SHIFT;
                   1891:       }
                   1892: 
                   1893:       p->egress_bitmap = 1 << egress_port;
                   1894:       p->egress_ut_bitmap = p->vlan_entry[2] & 
                   1895:          BCM5600_VTABLE_UT_PORT_BMAP_MASK;
                   1896:    } else {
                   1897:       /* Multicast: send the packet to the egress ports found in MARL table */
                   1898:       p->egress_bitmap = arl_entry[2] & BCM5600_MARL_PORT_BMAP_MASK;
                   1899:       p->egress_ut_bitmap = arl_entry[3] & BCM5600_MARL_UT_PORT_BMAP_MASK;
                   1900:    }
                   1901: 
                   1902: #if DEBUG_FORWARD
                   1903:    {
                   1904:       char buffer[1024];
                   1905: 
                   1906:       BCM_LOG(d,"bitmap: 0x%8.8x, filter: 0x%8.8x\n",
                   1907:               p->egress_bitmap,p->egress_filter_bitmap);
                   1908: 
                   1909:       bcm5600_port_bitmap_str(d,buffer,p->egress_bitmap);
                   1910: 
                   1911:       /* without egress port filtering */
                   1912:       if (*buffer)
                   1913:          BCM_LOG(d,"forwarding to egress port list w/o filter: %s\n",buffer);
                   1914:       else
                   1915:          BCM_LOG(d,"w/o filter: empty egress port list.\n");
                   1916: 
                   1917:       /* with egress port filtering */
                   1918:       bcm5600_port_bitmap_str(d,buffer,
                   1919:                               p->egress_bitmap & ~p->egress_filter_bitmap);
                   1920: 
                   1921:       if (*buffer)
                   1922:          BCM_LOG(d,"forwarding to egress port list w/ filter: %s\n",buffer);
                   1923:    }
                   1924: #endif
                   1925: 
                   1926:    return(p->egress_bitmap != 0);
                   1927: }
                   1928: 
                   1929: /* Prototype for a packet sending function */
                   1930: typedef void (*bcm5600_send_pkt_t)(struct nm_16esw_data *d,
                   1931:                                    struct bcm5600_pkt *p,
                   1932:                                    netio_desc_t *nio);
                   1933: 
                   1934: /* Directly forward a packet (not rewritten) */
                   1935: static void bcm5600_send_pkt_direct(struct nm_16esw_data *d,
                   1936:                                     struct bcm5600_pkt *p,
                   1937:                                     netio_desc_t *nio)
                   1938: {
                   1939:    netio_send(nio,p->pkt,p->pkt_len);
                   1940: }
                   1941: 
                   1942: /* Send a packet with a 802.1Q tag */
                   1943: static void bcm5600_send_pkt_push_dot1q(struct nm_16esw_data *d,
                   1944:                                         struct bcm5600_pkt *p,
                   1945:                                         netio_desc_t *nio)
                   1946: {
                   1947:    n_eth_dot1q_hdr_t *hdr;
                   1948: 
                   1949:    if (!p->rewrite_done) {
                   1950:       memcpy(p->rewr_pkt,p->pkt,(N_ETH_HLEN - 2));
                   1951: 
                   1952:       hdr = (n_eth_dot1q_hdr_t *)p->rewr_pkt;
                   1953:       hdr->type    = htons(N_ETH_PROTO_DOT1Q);
                   1954:       hdr->vlan_id = htons(p->real_vlan);
                   1955: 
                   1956:       memcpy(p->rewr_pkt + sizeof(n_eth_dot1q_hdr_t),
                   1957:              p->pkt + (N_ETH_HLEN - 2),
                   1958:              p->pkt_len - (N_ETH_HLEN - 2));
                   1959: 
                   1960:       p->rewrite_done = TRUE;
                   1961:    }
                   1962:    
                   1963:    netio_send(nio,p->rewr_pkt,p->pkt_len+4);
                   1964: }
                   1965: 
                   1966: /* Send a packet deleting its 802.1Q tag */
                   1967: static void bcm5600_send_pkt_pop_dot1q(struct nm_16esw_data *d,
                   1968:                                        struct bcm5600_pkt *p,
                   1969:                                        netio_desc_t *nio)
                   1970: {
                   1971:    if (!p->rewrite_done) {
                   1972:       memcpy(p->rewr_pkt,p->pkt,(N_ETH_HLEN - 2));
                   1973: 
                   1974:       memcpy(p->rewr_pkt + (N_ETH_HLEN - 2),
                   1975:              p->pkt + sizeof(n_eth_dot1q_hdr_t),
                   1976:              p->pkt_len - sizeof(n_eth_dot1q_hdr_t));
                   1977: 
                   1978:       p->rewrite_done = TRUE;
                   1979:    }
                   1980:    
                   1981:    netio_send(nio,p->rewr_pkt,p->pkt_len-4);
                   1982: }
                   1983: 
                   1984: /* Forward a packet on physical ports (egress bitmap must be defined) */
                   1985: static int bcm5600_forward_pkt(struct nm_16esw_data *d,struct bcm5600_pkt *p)
                   1986: {
                   1987:    u_char rewr_pkt[BCM5600_MAX_PKT_SIZE];
                   1988:    bcm5600_send_pkt_t send_pkt;
                   1989:    u_int egress_untagged,trunk_id;
                   1990:    m_uint32_t *dst_port,*trunk;
                   1991:    int i;
                   1992: 
                   1993:    p->egress_bitmap &= ~p->egress_filter_bitmap;
                   1994:    
                   1995:    if (!p->egress_bitmap)
                   1996:       return(FALSE);
                   1997: 
                   1998:    /* Process egress mirroring (if enabled) */
                   1999:    if (p->egress_bitmap & d->mirror_egress_ports)      
                   2000:       bcm5600_mirror_pkt(d,p,1);
                   2001: 
                   2002:    /* No rewrite done at this time */
                   2003:    p->rewr_pkt = rewr_pkt;
                   2004:    p->rewrite_done = FALSE;
                   2005: 
                   2006:    /* Forward to CPU port ? */
                   2007:    if (p->egress_bitmap & (1 << d->cpu_port))
                   2008:       bcm5600_send_pkt_to_cpu(d,p);
                   2009: 
                   2010:    for(i=0;i<d->nr_port;i++) {
                   2011:       if (!(p->egress_bitmap & (1 << i)))
                   2012:          continue;
                   2013: 
                   2014:       /* 
                   2015:        * If this port is a member of a trunk, remove all other ports to avoid
                   2016:        * duplicate frames (typically, when a dest MAC address is unknown
                   2017:        * or for a broadcast/multicast).
                   2018:        */
                   2019:       dst_port = bcm5600_table_get_entry(d,d->t_ptable,i);
                   2020:       assert(dst_port != NULL);
                   2021: 
                   2022:       if (dst_port[0] & BCM5600_PTABLE_TRUNK_FLAG) {
                   2023:          trunk_id = dst_port[0] & BCM5600_PTABLE_TGID_MASK;
                   2024:          trunk_id >>= BCM5600_PTABLE_TGID_SHIFT;
                   2025: 
                   2026:          trunk = bcm5600_table_get_entry(d,d->t_tbmap,trunk_id);
                   2027:          assert(trunk != NULL);
                   2028:          
                   2029:          p->egress_bitmap &= ~trunk[0];
                   2030:       }
                   2031: 
                   2032:       /* select the appropriate output vector */
                   2033:       if (p->orig_vlan == 0)
                   2034:          send_pkt = bcm5600_send_pkt_direct;
                   2035:       else {
                   2036:          egress_untagged = p->egress_ut_bitmap & (1 << i);
                   2037: 
                   2038:          if (p->orig_vlan == -1) {
                   2039:             /* Untagged packet */
                   2040:             if (egress_untagged)
                   2041:                send_pkt = bcm5600_send_pkt_direct;
                   2042:             else
                   2043:                send_pkt = bcm5600_send_pkt_push_dot1q;
                   2044:          } else {
                   2045:             /* Tagged packet */
                   2046:             if (egress_untagged)
                   2047:                send_pkt = bcm5600_send_pkt_pop_dot1q;
                   2048:             else
                   2049:                send_pkt = bcm5600_send_pkt_direct;
                   2050:          }
                   2051:       }
                   2052: 
                   2053: #if DEBUG_FORWARD > 1
                   2054:       BCM_LOG(d,"forwarding on port %s (vector=%p)\n",
                   2055:               d->ports[i].name,send_pkt);
                   2056: #endif
                   2057:       send_pkt(d,p,d->ports[i].nio);
                   2058:    }
                   2059: 
                   2060:    return(TRUE);
                   2061: }
                   2062: 
1.1.1.2   root     2063: /* Determine if the specified MAC address matches a BPDU */
                   2064: static inline int bcm5600_is_bpdu(n_eth_addr_t *m)
                   2065: {
                   2066:    /* PVST+ */
                   2067:    if (!memcmp(m,"\x01\x00\x0c\xcc\xcc\xcd",6))
                   2068:       return(TRUE);
                   2069: 
                   2070:    /* Classical 802.1D */
                   2071:    if (!memcmp(m,"\x01\x80\xc2\x00\x00",5) && !(m->eth_addr_byte[5] & 0xF0))
                   2072:       return(TRUE);
                   2073: 
                   2074:    return(FALSE);
                   2075: }
                   2076: 
1.1       root     2077: /* Handle a received packet */
                   2078: static int bcm5600_handle_rx_pkt(struct nm_16esw_data *d,struct bcm5600_pkt *p)
                   2079: {
                   2080:    m_uint32_t *port_entry;
                   2081:    n_eth_dot1q_hdr_t *eth_hdr;
                   2082:    u_int discard;
                   2083: 
                   2084:    /* No egress port at this time */
                   2085:    p->egress_bitmap = 0;
                   2086: 
                   2087:    /* Never send back frames to the source port */
                   2088:    p->egress_filter_bitmap = 1 << p->ingress_port;
                   2089: 
                   2090:    if (!(port_entry = bcm5600_table_get_entry(d,d->t_ptable,p->ingress_port)))
                   2091:       return(FALSE);
                   2092: 
                   2093:    /* Analyze the Ethernet header */
                   2094:    eth_hdr = (n_eth_dot1q_hdr_t *)p->pkt;
                   2095: 
1.1.1.2   root     2096:    /* Determine VLAN */
                   2097:    if (ntohs(eth_hdr->type) != N_ETH_PROTO_DOT1Q) {
                   2098:       p->orig_vlan = -1;
                   2099:       p->real_vlan = port_entry[0] & BCM5600_PTABLE_VLAN_TAG_MASK;
                   2100: 
                   2101:      /* TODO: 802.1p/CoS remarking */
                   2102:      if (port_entry[4] & BCM5600_PTABLE_RPE_FLAG) {
                   2103:      }
                   2104:    } else {
                   2105:       p->orig_vlan = p->real_vlan = ntohs(eth_hdr->vlan_id) & 0xFFF;
                   2106:    }
                   2107: 
                   2108:    /* Check that this VLAN exists */
                   2109:    if (!(p->vlan_entry = bcm5600_vtable_get_entry_by_vlan(d,p->real_vlan)))
                   2110:       return(FALSE);
                   2111: 
1.1       root     2112:    /* Check for the reserved addresses (BPDU for spanning-tree) */
1.1.1.2   root     2113:    if (bcm5600_is_bpdu(&eth_hdr->daddr)) {
1.1       root     2114: #if DEBUG_RECEIVE
                   2115:       BCM_LOG(d,"Received a BPDU packet:\n");
                   2116:       mem_dump(d->vm->log_fd,p->pkt,p->pkt_len);
                   2117: #endif
                   2118:       p->egress_bitmap |= 1 << d->cpu_port;
                   2119:       return(bcm5600_forward_pkt(d,p));
                   2120:    }
                   2121: 
1.1.1.2   root     2122:    /* Check that this port is a member of this VLAN */
                   2123:    if (!(p->vlan_entry[1] & (1 << p->ingress_port)))
                   2124:       return(FALSE);
                   2125: 
1.1       root     2126:    /* Discard packet ? */
                   2127:    discard = port_entry[0] & BCM5600_PTABLE_PRT_DIS_MASK;
                   2128:    discard >>= BCM5600_PTABLE_PRT_DIS_SHIFT;
                   2129: 
1.1.1.3 ! root     2130:    if ((p->orig_vlan == -1) && discard) {
1.1       root     2131:       if (discard != 0x20) {
                   2132:          printf("\n\n\n"
                   2133:                 "-----------------------------------------------------------"
                   2134:                 "---------------------------------\n"
                   2135:                 "Unspported feature: please post your current configuration "
                   2136:                 "on http://www.ipflow.utc.fr/blog/\n"
                   2137:                 "-----------------------------------------------------------"
                   2138:                 "---------------------------------\n");
                   2139:       }
                   2140: 
                   2141:       /* Drop the packet */
                   2142:       return(FALSE);
                   2143:    }
                   2144: 
                   2145:    /* Mirroring on Ingress ? */
                   2146:    if (port_entry[1] & BCM5600_PTABLE_MI_FLAG)
                   2147:       bcm5600_mirror_pkt(d,p,0);
                   2148: 
                   2149: #if DEBUG_RECEIVE
                   2150:    BCM_LOG(d,"%s: received a packet on VLAN %u\n",
                   2151:            d->ports[p->ingress_port].name,p->real_vlan);
                   2152: #endif
                   2153: 
                   2154:    /* Source MAC address learning */
                   2155:    if (!bcm5600_src_mac_learning(d,p))
                   2156:       return(FALSE);
                   2157: 
                   2158:    /* Take forwarding decision based on destination MAC address */
                   2159:    if (!bcm5600_dst_mac_lookup(d,p))
                   2160:       return(FALSE);
                   2161: 
                   2162:    /* Send the packet to the egress ports */
                   2163:    return(bcm5600_forward_pkt(d,p));
                   2164: }
                   2165: 
                   2166: /* Handle a packet to transmit */
                   2167: static int bcm5600_handle_tx_pkt(struct nm_16esw_data *d,
                   2168:                                  struct bcm5600_pkt *p,
                   2169:                                  u_int egress_bitmap)
                   2170: {   
                   2171:    n_eth_dot1q_hdr_t *eth_hdr;
                   2172:    
                   2173:    /* Never send back frames to the source port */
                   2174:    p->egress_filter_bitmap = 1 << p->ingress_port;
                   2175: 
                   2176:    /* We take the complete forwarding decision if bit 23 is set */
                   2177:    if (egress_bitmap & (1 << 23)) {
                   2178:       /* No egress port at this time */
                   2179:       p->egress_bitmap = 0;
                   2180: 
                   2181:       /* The packet must be tagged so that we can determine the VLAN */
                   2182:       eth_hdr = (n_eth_dot1q_hdr_t *)p->pkt;
                   2183: 
                   2184:       if (ntohs(eth_hdr->type) != N_ETH_PROTO_DOT1Q) {
                   2185:          BCM_LOG(d,"bcm5600_handle_tx_pkt: untagged packet ?\n");
                   2186:          return(FALSE);
                   2187:       }
                   2188: 
                   2189:       /* Find the appropriate, check it exists (just in case) */
                   2190:       p->orig_vlan = p->real_vlan = ntohs(eth_hdr->vlan_id) & 0xFFF;
                   2191: 
                   2192:       if (!(p->vlan_entry = bcm5600_vtable_get_entry_by_vlan(d,p->real_vlan)))
                   2193:         return(FALSE);
                   2194: 
                   2195: #if DEBUG_TRANSMIT
                   2196:       BCM_LOG(d,"Transmitting a packet from TX ring to VLAN %u\n",
                   2197:               p->real_vlan);
                   2198: #endif
                   2199: 
                   2200:       /* Take forwarding decision based on destination MAC address */
                   2201:       if (!bcm5600_dst_mac_lookup(d,p))
                   2202:          return(FALSE);
                   2203:    } else {
                   2204: #if DEBUG_TRANSMIT
                   2205:       BCM_LOG(d,"Transmitting natively a packet from TX ring.\n");
                   2206: #endif
                   2207:       /* The egress ports are specified, send the packet natively */
                   2208:       p->orig_vlan = 0;
                   2209:       p->egress_bitmap = egress_bitmap;
                   2210:    }
                   2211: 
                   2212:    /* Send the packet to the egress ports */
                   2213:    return(bcm5600_forward_pkt(d,p));
                   2214: }
                   2215: 
                   2216: /* Handle the TX ring */
                   2217: static int dev_bcm5600_handle_txring(struct nm_16esw_data *d)
                   2218: {
                   2219:    struct bcm5600_pkt pkt_data;
                   2220:    m_uint32_t tdes[4],txd_len;
                   2221: 
                   2222:    BCM_LOCK(d);
                   2223: 
                   2224:    if (!d->tx_current || d->tx_end_scan) {
                   2225:       BCM_UNLOCK(d);
                   2226:       return(FALSE);
                   2227:    }
                   2228: 
                   2229:    /* Read the current TX descriptor */
                   2230:    physmem_copy_from_vm(d->vm,tdes,d->tx_current,4*sizeof(m_uint32_t));
                   2231:    tdes[0] = vmtoh32(tdes[0]);
                   2232:    tdes[1] = vmtoh32(tdes[1]);
                   2233:    tdes[2] = vmtoh32(tdes[2]);
                   2234:    tdes[3] = vmtoh32(tdes[3]);
                   2235:    
                   2236: #if DEBUG_TRANSMIT
                   2237:    BCM_LOG(d,"=== TRANSMIT PATH ===\n");
                   2238: 
                   2239:    BCM_LOG(d,"tx_current=0x%8.8x, "
                   2240:            "tdes[0]=0x%8.8x, tdes[1]=0x%8.8x, tdes[2]=0x%8.8x\n",
                   2241:            d->tx_current,tdes[0],tdes[1],tdes[2]);
                   2242: #endif
                   2243: 
                   2244:    /* Get the buffer size */
                   2245:    txd_len = tdes[1] & 0x7FF;
                   2246: 
                   2247:    /* Check buffer size */
                   2248:    if ((d->tx_bufsize + txd_len) >= sizeof(d->tx_buffer))
                   2249:       goto done;
                   2250: 
                   2251:    /* Copy the packet from memory */
                   2252:    physmem_copy_from_vm(d->vm,d->tx_buffer+d->tx_bufsize,tdes[0],txd_len);
                   2253:    d->tx_bufsize += txd_len;
                   2254: 
                   2255:    /* Packet not complete: handle it later */
                   2256:    if (tdes[1] & BCM5600_TXD_NEOP)
                   2257:       goto done;
                   2258: 
                   2259: #if DEBUG_TRANSMIT
                   2260:    mem_dump(d->vm->log_fd,d->tx_buffer,d->tx_bufsize);
                   2261: #endif
                   2262: 
                   2263:    /* Transmit the packet */
                   2264:    pkt_data.ingress_port = d->cpu_port;
                   2265:    pkt_data.pkt = d->tx_buffer;
                   2266:    pkt_data.pkt_len = d->tx_bufsize - 4;
                   2267:    pkt_data.sent_to_cpu = TRUE;
                   2268:    bcm5600_handle_tx_pkt(d,&pkt_data,tdes[2]);
                   2269: 
                   2270:    /* Reset the TX buffer (packet fully transmitted) */
                   2271:    d->tx_bufsize = 0;
                   2272: 
                   2273:  done:
                   2274:    /* We have reached end of ring: trigger the TX underrun interrupt */
                   2275:    if (!(tdes[1] & BCM5600_TXD_RING_CONT)) {
                   2276:       d->tx_end_scan = 1;
                   2277:       pci_dev_trigger_irq(d->vm,d->pci_dev);
                   2278:       BCM_UNLOCK(d);
                   2279:       return(TRUE);
                   2280:    } 
                   2281: 
                   2282:    /* Go to the next descriptor */
                   2283:    d->tx_current += BCM5600_TXD_SIZE;
                   2284:    BCM_UNLOCK(d);   
                   2285:    return(TRUE);
                   2286: }
                   2287: 
                   2288: /* Handle the RX ring */
                   2289: static int dev_bcm5600_handle_rxring(netio_desc_t *nio,
                   2290:                                      u_char *pkt,ssize_t pkt_len,
                   2291:                                      struct nm_16esw_data *d,  
                   2292:                                      struct bcm5600_port *port)
                   2293: {  
                   2294:    struct bcm5600_pkt pkt_data;
                   2295:    m_uint32_t rxd_len;
                   2296: 
                   2297: #if DEBUG_RECEIVE
                   2298:    BCM_LOG(d,"=== RECEIVE PATH ===\n");
                   2299: 
                   2300:    BCM_LOG(d,"%s: received a packet of %ld bytes.\n",
                   2301:            port->name,(u_long)pkt_len);
                   2302:    mem_dump(d->vm->log_fd,pkt,pkt_len);
                   2303: #endif
                   2304: 
                   2305:    BCM_LOCK(d);
                   2306: 
                   2307:    if (!d->rx_current || d->rx_end_scan) {
                   2308:       BCM_UNLOCK(d);
                   2309:       return(FALSE);
                   2310:    }
                   2311:    
                   2312:    /* Read the current TX descriptor */
                   2313:    physmem_copy_from_vm(d->vm,pkt_data.rdes,d->rx_current,
                   2314:                         (4 * sizeof(m_uint32_t)));
                   2315: 
                   2316:    pkt_data.rdes[0] = vmtoh32(pkt_data.rdes[0]);
                   2317:    pkt_data.rdes[1] = vmtoh32(pkt_data.rdes[1]);
                   2318:    pkt_data.rdes[2] = vmtoh32(pkt_data.rdes[2]);
                   2319:    pkt_data.rdes[3] = vmtoh32(pkt_data.rdes[3]);
                   2320: 
                   2321: #if DEBUG_RECEIVE
                   2322:    BCM_LOG(d,"rx_current=0x%8.8x, "
                   2323:            "rdes[0]=0x%8.8x, rdes[1]=0x%8.8x, rdes[2]=0x%8.8x\n",
                   2324:            d->rx_current,pkt_data.rdes[0],pkt_data.rdes[1],pkt_data.rdes[2]);
                   2325: #endif
                   2326: 
                   2327:    /* Get the buffer size */
                   2328:    rxd_len = pkt_data.rdes[1] & 0x7FF;
                   2329: 
                   2330:    if (pkt_len > rxd_len) {
                   2331:       BCM_UNLOCK(d);
                   2332:       return(FALSE);
                   2333:    }
                   2334: 
                   2335:    /* Fill the packet info */
                   2336:    pkt_data.ingress_port = port->id;
                   2337:    pkt_data.pkt = pkt;
                   2338:    pkt_data.pkt_len = pkt_len;
                   2339:    pkt_data.sent_to_cpu = FALSE;
                   2340: 
                   2341:    /* Handle the packet */
                   2342:    bcm5600_handle_rx_pkt(d,&pkt_data);
                   2343:   
                   2344:    /* Signal only an interrupt when a packet has been sent to the CPU */
                   2345:    if (pkt_data.sent_to_cpu) {
                   2346:       /* We have reached end of ring: trigger the RX underrun interrupt */
                   2347:       if (!(pkt_data.rdes[1] & BCM5600_RXD_RING_CONT)) {
                   2348:          d->rx_end_scan = 1;
                   2349:          pci_dev_trigger_irq(d->vm,d->pci_dev);
                   2350:          BCM_UNLOCK(d);
                   2351:          return(TRUE);
                   2352:       }
                   2353: 
                   2354:       /* A packet was received */
                   2355:       pci_dev_trigger_irq(d->vm,d->pci_dev);
                   2356: 
                   2357:       /* Go to the next descriptor */
                   2358:       d->rx_current += BCM5600_RXD_SIZE;
                   2359:    }
                   2360: 
                   2361:    BCM_UNLOCK(d);
                   2362:    return(TRUE);
                   2363: }
                   2364: 
                   2365: /* pci_bcm5605_read() */
1.1.1.3 ! root     2366: static m_uint32_t pci_bcm5605_read(cpu_gen_t *cpu,struct pci_device *dev,
1.1       root     2367:                                    int reg)
                   2368: {
                   2369:    struct nm_16esw_data *d = dev->priv_data;
                   2370: 
                   2371:    switch(reg) {
                   2372:       case PCI_REG_BAR0:
                   2373:          return(d->dev->phys_addr);
                   2374:       default:
                   2375:          return(0);
                   2376:    }
                   2377: }
                   2378: 
                   2379: /* pci_bcm5605_write() */
1.1.1.3 ! root     2380: static void pci_bcm5605_write(cpu_gen_t *cpu,struct pci_device *dev,
1.1       root     2381:                               int reg,m_uint32_t value)
                   2382: {
                   2383:    struct nm_16esw_data *d = dev->priv_data;
                   2384: 
                   2385:    switch(reg) {
                   2386:       case PCI_REG_BAR0:
                   2387:          vm_map_device(cpu->vm,d->dev,(m_uint64_t)value);
                   2388:          BCM_LOG(d,"BCM5600 registers are mapped at 0x%x\n",value);
                   2389:          break;
                   2390:    }
                   2391: }
                   2392: 
                   2393: /* Rewrite the base MAC address */
                   2394: int dev_nm_16esw_burn_mac_addr(vm_instance_t *vm,u_int nm_bay,
                   2395:                                struct cisco_eeprom *eeprom)
                   2396: {
                   2397:    m_uint8_t eeprom_ver;
                   2398:    size_t offset;
                   2399:    n_eth_addr_t addr;
                   2400:    m_uint16_t pid;
                   2401: 
                   2402:    pid = (m_uint16_t)getpid();
                   2403: 
                   2404:    /* Generate automatically the MAC address */
                   2405:    addr.eth_addr_byte[0] = vm_get_mac_addr_msb(vm);
                   2406:    addr.eth_addr_byte[1] = vm->instance_id & 0xFF;
                   2407:    addr.eth_addr_byte[2] = pid >> 8;
                   2408:    addr.eth_addr_byte[3] = pid & 0xFF;
                   2409:    addr.eth_addr_byte[4] = 0xF0 + nm_bay;
                   2410:    addr.eth_addr_byte[5] = 0x00;
                   2411: 
                   2412:    /* Read EEPROM format version */
                   2413:    cisco_eeprom_get_byte(eeprom,0,&eeprom_ver);
                   2414: 
                   2415:    if (eeprom_ver != 4)
                   2416:       return(-1);
                   2417: 
                   2418:    if (cisco_eeprom_v4_find_field(eeprom,0xCF,&offset) == -1)
                   2419:       return(-1);
                   2420: 
                   2421:    cisco_eeprom_set_region(eeprom,offset,addr.eth_addr_byte,6);
                   2422:    return(0);
                   2423: }
                   2424: 
                   2425: /* Initialize a NM-16ESW module */
                   2426: struct nm_16esw_data *
                   2427: dev_nm_16esw_init(vm_instance_t *vm,char *name,u_int nm_bay,
                   2428:                   struct pci_bus *pci_bus,int pci_device,int irq)
                   2429: {
                   2430:    struct nm_16esw_data *data;
                   2431:    struct bcm5600_port *port;
                   2432:    struct vdevice *dev;
                   2433:    int i,port_id;
                   2434: 
                   2435:    /* Allocate the private data structure */
                   2436:    if (!(data = malloc(sizeof(*data)))) {
                   2437:       fprintf(stderr,"%s: out of memory\n",name);
                   2438:       return NULL;
                   2439:    }
                   2440: 
                   2441:    memset(data,0,sizeof(*data));
                   2442:    pthread_mutex_init(&data->lock,NULL);
                   2443:    data->name = name;
                   2444:    data->nr_port = 16;
                   2445:    data->vm = vm;
                   2446: 
                   2447:    /* Create the BCM5600 tables */
                   2448:    if (bcm5600_table_create(data) == -1)
                   2449:       return NULL;
                   2450: 
                   2451:    /* Clear the various tables */
                   2452:    bcm5600_reset_arl(data);
                   2453:    data->arl_cnt[0] = 1;
                   2454:    data->t_ptable = bcm5600_table_find(data,BCM5600_ADDR_PTABLE0);
                   2455:    data->t_vtable = bcm5600_table_find(data,BCM5600_ADDR_VTABLE0);
                   2456:    data->t_arl    = bcm5600_table_find(data,BCM5600_ADDR_ARL0);
                   2457:    data->t_marl   = bcm5600_table_find(data,BCM5600_ADDR_MARL0);
                   2458:    data->t_tbmap  = bcm5600_table_find(data,BCM5600_ADDR_TBMAP0);
                   2459:    data->t_ttr    = bcm5600_table_find(data,BCM5600_ADDR_TTR0);
                   2460: 
                   2461:    /* Initialize ports */
                   2462:    data->cpu_port = 27;
                   2463: 
                   2464:    for(i=0;i<data->nr_port;i++) {
                   2465:       port_id = nm16esw_port_mapping[i];
                   2466: 
                   2467:       port = &data->ports[port_id];
                   2468:       port->id = port_id;
                   2469:       snprintf(port->name,sizeof(port->name),"Fa%u/%d",nm_bay,i);
                   2470:    }
                   2471: 
                   2472:    /* Create the BCM5605 PCI device */
                   2473:    data->pci_dev = pci_dev_add(pci_bus,name,
                   2474:                                BCM5605_PCI_VENDOR_ID,BCM5605_PCI_PRODUCT_ID,
                   2475:                                pci_device,0,irq,data,
                   2476:                                NULL,pci_bcm5605_read,pci_bcm5605_write);
                   2477: 
                   2478:    if (!data->pci_dev) {
                   2479:       fprintf(stderr,"%s: unable to create PCI device.\n",name);
                   2480:       return NULL;
                   2481:    }
                   2482: 
                   2483:    /* Create the BCM5605 device itself */
                   2484:    if (!(dev = dev_create(name))) {
                   2485:       fprintf(stderr,"%s: unable to create device.\n",name);
                   2486:       return NULL;
                   2487:    }
                   2488: 
                   2489:    dev->phys_addr = 0;
                   2490:    dev->phys_len  = 0x200000;
                   2491:    dev->handler   = dev_bcm5605_access;
                   2492: 
                   2493:    /* Store device info */
                   2494:    dev->priv_data = data;
                   2495:    data->dev = dev;
                   2496: 
                   2497:    /* Create the TX ring scanner */
                   2498:    data->tx_tid = ptask_add((ptask_callback)dev_bcm5600_handle_txring,
                   2499:                             data,NULL);
                   2500: 
                   2501:    /* Start the MAC address ager */
                   2502:    data->ager_tid = timer_create_entry(15000,FALSE,10,
                   2503:                                        (timer_proc)bcm5600_arl_ager,data);
                   2504:    return data;
                   2505: }
                   2506: 
                   2507: /* Remove a NM-16ESW from the specified slot */
                   2508: int dev_nm_16esw_remove(struct nm_16esw_data *data)
                   2509: {
                   2510:    /* Stop the Ager */
                   2511:    timer_remove(data->ager_tid);
                   2512: 
                   2513:    /* Stop the TX ring task */
                   2514:    ptask_remove(data->tx_tid);
                   2515: 
                   2516:    /* Remove device + PCI stuff */
                   2517:    pci_dev_remove(data->pci_dev);
                   2518:    vm_unbind_device(data->vm,data->dev);
                   2519:    cpu_group_rebuild_mts(data->vm->cpu_group);
                   2520:    free(data->dev);
                   2521: 
                   2522:    /* Free all tables and registers */
                   2523:    bcm5600_table_free(data);
                   2524:    bcm5600_reg_free(data);
                   2525:    free(data);
                   2526:    return(0);
                   2527: }
                   2528: 
                   2529: /* Bind a Network IO descriptor */
                   2530: int dev_nm_16esw_set_nio(struct nm_16esw_data *d,u_int port_id,
                   2531:                          netio_desc_t *nio)
                   2532: {
                   2533:    struct bcm5600_port *port;
                   2534: 
                   2535:    if (!d || (port_id >= d->nr_port))
                   2536:       return(-1);
                   2537: 
                   2538:    /* define the new NIO */
                   2539:    port = &d->ports[nm16esw_port_mapping[port_id]];
                   2540:    port->nio = nio;
                   2541:    netio_rxl_add(nio,(netio_rx_handler_t)dev_bcm5600_handle_rxring,d,port);
                   2542:    return(0);
                   2543: }
                   2544: 
                   2545: /* Unbind a Network IO descriptor */
                   2546: int dev_nm_16esw_unset_nio(struct nm_16esw_data *d,u_int port_id)
                   2547: {
                   2548:    struct bcm5600_port *port;
                   2549: 
                   2550:    if (!d || (port_id >= d->nr_port))
                   2551:       return(-1);
                   2552: 
                   2553:    port = &d->ports[nm16esw_port_mapping[port_id]];
                   2554: 
                   2555:    if (port->nio) {
                   2556:       netio_rxl_remove(port->nio);
                   2557:       port->nio = NULL;
                   2558:    }
                   2559: 
                   2560:    return(0);
                   2561: }
                   2562: 
                   2563: /* Show debugging information */
                   2564: int dev_nm_16esw_show_info(struct nm_16esw_data *d)
                   2565: {   
                   2566:    BCM_LOCK(d);
                   2567:    printf("ARL count = %u\n\n",d->arl_cnt[0]);
                   2568:    bcm5600_dump_main_tables(d);
                   2569:    bcm5600_mirror_show_status(d);
                   2570:    bcm5600_reg_dump(d,FALSE);
                   2571:    BCM_UNLOCK(d);
                   2572:    return(0);
                   2573: }

unix.superglobalmegacorp.com

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