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