Annotation of cf/dev_nm_16esw.c, revision 1.1

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

unix.superglobalmegacorp.com

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