📄 dev_nm_16esw.c
字号:
};/* Return port status (up or down), based on the MII register */static int bcm5600_mii_port_status(struct nm_16esw_data *d,u_int port){ u_int mii_ctrl; mii_ctrl = d->mii_regs[port][0x00]; /* Isolate bit */ return(!(mii_ctrl & 0x400));}/* Build port status bitmap */static m_uint32_t bcm5600_mii_port_status_bmp(struct nm_16esw_data *d){ m_uint32_t bmp; int i; for(i=0,bmp=0;i<d->nr_port;i++) if (bcm5600_mii_port_status(d,i)) bmp |= 1 << i; return(bmp);}/* Read a MII register */static void bcm5600_mii_read(struct nm_16esw_data *d){ m_uint8_t port,reg; port = (d->mii_input >> 16) & 0xFF; reg = (d->mii_input >> 24) & 0xFF; if ((port < 32) && (reg < 32)) { d->mii_output = d->mii_regs[port][reg]; switch(reg) { case 0x00: d->mii_output &= ~0x8200; break; case 0x01: if (d->ports[port].nio && bcm5600_mii_port_status(d,port)) d->mii_output = 0x782C; else d->mii_output = 0; break; case 0x02: d->mii_output = 0x40; break; case 0x03: d->mii_output = 0x61d4; break; case 0x04: d->mii_output = 0x1E1; break; case 0x05: d->mii_output = 0x41E1; break; default: d->mii_output = 0; } }}/* Write a MII register */static void bcm5600_mii_write(struct nm_16esw_data *d){ m_uint8_t port,reg; m_uint16_t isolation; port = (d->mii_input >> 16) & 0xFF; reg = (d->mii_input >> 24) & 0xFF; if ((port < 32) && (reg < 32)) {#if DEBUG_MII BCM_LOG(d,"MII: port 0x%4.4x, reg 0x%2.2x: writing 0x%4.4x\n", port,reg,d->mii_input & 0xFFFF);#endif /* Check if PHY isolation status is changing */ if (reg == 0) { isolation = (d->mii_input ^ d->mii_regs[port][reg]) & 0x400; if (isolation) {#if DEBUG_MII BCM_LOG(d,"MII: port 0x%4.4x: generating IRQ\n",port);#endif d->mii_intr = TRUE; pci_dev_trigger_irq(d->vm,d->pci_dev); } } d->mii_regs[port][reg] = d->mii_input & 0xFFFF; }}/* Hash function for register */static u_int bcm5600_reg_get_hash(m_uint32_t addr){ return((addr ^ (addr >> 16)) & (BCM5600_REG_HASH_SIZE - 1));}/* Find a register entry */static struct bcm5600_reg *bcm5600_reg_find(struct nm_16esw_data *d, m_uint32_t addr){ struct bcm5600_reg *reg; u_int h_index; h_index = bcm5600_reg_get_hash(addr); for(reg=d->reg_hash_table[h_index];reg;reg=reg->next) if (reg->addr == addr) return reg; return NULL;}/* Read a register */static m_uint32_t bcm5600_reg_read(struct nm_16esw_data *d,m_uint32_t addr){ struct bcm5600_reg *reg; if (!(reg = bcm5600_reg_find(d,addr))) return(0); return(reg->value);}/* Write a register */static int bcm5600_reg_write(struct nm_16esw_data *d,m_uint32_t addr, m_uint32_t value){ struct bcm5600_reg *reg; u_int h_index; if ((reg = bcm5600_reg_find(d,addr))) { reg->value = value; return(0); } /* create a new register */ if (!(reg = malloc(sizeof(*reg)))) return(-1); reg->addr = addr; reg->value = value; /* insert new register in hash table */ h_index = bcm5600_reg_get_hash(addr); reg->next = d->reg_hash_table[h_index]; d->reg_hash_table[h_index] = reg; return(0);}/* Register special handling */static void bcm5600_reg_write_special(struct nm_16esw_data *d, m_uint32_t addr,m_uint32_t value){ switch(addr) { case 0x80006: d->mirror_dst_port = value; break; case 0x8000d: d->mirror_egress_ports = value; break; case 0x80009: /* age timer */ break; }}/* Free memory used to store register info */static void bcm5600_reg_free(struct nm_16esw_data *d){ struct bcm5600_reg *reg,*next; int i; for(i=0;i<BCM5600_REG_HASH_SIZE;i++) for(reg=d->reg_hash_table[i];reg;reg=next) { next = reg->next; free(reg); }}/* Dump all known registers */static void bcm5600_reg_dump(struct nm_16esw_data *d,int show_null){ struct bcm5600_reg *reg; int i; printf("%s: dumping registers:\n",d->name); for(i=0;i<BCM5600_REG_HASH_SIZE;i++) for(reg=d->reg_hash_table[i];reg;reg=reg->next) { if (reg->value || show_null) printf(" 0x%8.8x: 0x%8.8x\n",reg->addr,reg->value); }}/* Fill a string buffer with all ports of the specified bitmap */static char *bcm5600_port_bitmap_str(struct nm_16esw_data *d, char *buffer,m_uint32_t bitmap){ char *ptr = buffer; int i; *ptr = 0; for(i=0;i<d->nr_port;i++) if (bitmap & (1 << i)) { ptr += sprintf(ptr,"%s ",d->ports[i].name); } return buffer;}/* BCM5600 tables */#define BCM_OFFSET(x) (OFFSET(struct nm_16esw_data,x))static struct bcm5600_table bcm5600_tables[] = { /* ARL tables */ { "arlcnt0", BCM_OFFSET(arl_cnt), BCM5600_ADDR_ARLCNT0, 0, 0, 1 }, { "arlcnt1", BCM_OFFSET(arl_cnt), BCM5600_ADDR_ARLCNT1, 0, 0, 1 }, { "arlcnt2", BCM_OFFSET(arl_cnt), BCM5600_ADDR_ARLCNT2, 0, 0, 1 }, /* ARL tables */ { "arl0", BCM_OFFSET(arl_table), BCM5600_ADDR_ARL0, 0, 8191, 3 }, { "arl1", BCM_OFFSET(arl_table), BCM5600_ADDR_ARL1, 0, 8191, 3 }, { "arl2", BCM_OFFSET(arl_table), BCM5600_ADDR_ARL2, 0, 8191, 3 }, /* Multicast ARL tables */ { "marl0", BCM_OFFSET(marl_table), BCM5600_ADDR_MARL0, 1, 255, 5 }, { "marl1", BCM_OFFSET(marl_table), BCM5600_ADDR_MARL1, 1, 255, 5 }, { "marl2", BCM_OFFSET(marl_table), BCM5600_ADDR_MARL2, 1, 255, 5 }, /* PTABLE - Physical Ports */ { "ptable0", BCM_OFFSET(ptable), BCM5600_ADDR_PTABLE0, 0, 31, 6 }, { "ptable1", BCM_OFFSET(ptable), BCM5600_ADDR_PTABLE1, 0, 31, 6 }, { "ptable2", BCM_OFFSET(ptable), BCM5600_ADDR_PTABLE2, 0, 31, 6 }, /* VTABLE - VLANs */ { "vtable0", BCM_OFFSET(vtable), BCM5600_ADDR_VTABLE0, 1, 255, 4 }, { "vtable1", BCM_OFFSET(vtable), BCM5600_ADDR_VTABLE1, 1, 255, 4 }, { "vtable2", BCM_OFFSET(vtable), BCM5600_ADDR_VTABLE2, 1, 255, 4 }, /* TTR */ { "ttr0", BCM_OFFSET(ttr), BCM5600_ADDR_TTR0, 0, 5, 3 }, { "ttr1", BCM_OFFSET(ttr), BCM5600_ADDR_TTR1, 0, 5, 3 }, { "ttr2", BCM_OFFSET(ttr), BCM5600_ADDR_TTR2, 0, 5, 3 }, /* TBMAP */ { "tbmap0", BCM_OFFSET(tbmap), BCM5600_ADDR_TBMAP0, 0, 5, 1 }, { "tbmap1", BCM_OFFSET(tbmap), BCM5600_ADDR_TBMAP1, 0, 5, 1 }, { "tbmap2", BCM_OFFSET(tbmap), BCM5600_ADDR_TBMAP2, 0, 5, 1 }, { NULL, -1, 0, 0, 0 },};/* Get table size (in number of words) */static inline u_int bcm5600_table_get_size(struct bcm5600_table *table){ return(table->nr_words * (table->max_index + 1));}/* Create automatically tables */static int bcm5600_table_create(struct nm_16esw_data *d){ struct bcm5600_table *table; m_uint32_t *array; size_t nr_words; int i; for(i=0;bcm5600_tables[i].name;i++) { table = &bcm5600_tables[i]; nr_words = bcm5600_table_get_size(table); if (!(array = calloc(nr_words,sizeof(m_uint32_t)))) { fprintf(stderr,"BCM5600: unable to create table '%s'\n",table->name); return(-1); } *(PTR_ADJUST(m_uint32_t **,d,table->offset)) = array; } return(0);}/* Free tables */static void bcm5600_table_free(struct nm_16esw_data *d){ struct bcm5600_table *table; m_uint32_t **array; int i; for(i=0;bcm5600_tables[i].name;i++) { table = &bcm5600_tables[i]; array = (PTR_ADJUST(m_uint32_t **,d,table->offset)); free(*array); /* avoid freeing the same table multiple times */ *array = NULL; }}/* Find a table given its address */static struct bcm5600_table *bcm5600_table_find(struct nm_16esw_data *d, m_uint32_t addr){ int i; for(i=0;bcm5600_tables[i].name;i++) if (bcm5600_tables[i].addr == addr) return(&bcm5600_tables[i]);#if DEBUG_UNKNOWN BCM_LOG(d,"unknown table at address 0x%8.8x\n",addr);#endif return NULL;}/* Get a table entry */static inline m_uint32_t *bcm5600_table_get_entry(struct nm_16esw_data *d, struct bcm5600_table *table, m_uint32_t index){ m_uint32_t *array; if ((index < table->min_index) || (index > table->max_index)) return NULL; array = *(PTR_ADJUST(m_uint32_t **,d,table->offset)); return(&array[index*table->nr_words]);}/* Read a table entry */static int bcm5600_table_read_entry(struct nm_16esw_data *d){ struct bcm5600_table *table; m_uint32_t addr,index,*entry; int i; addr = d->dw[1] & 0xFFFF0000; index = d->dw[1] & 0x0000FFFF; if (!(table = bcm5600_table_find(d,addr))) {#if DEBUG_UNKNOWN BCM_LOG(d,"unknown mem address at address 0x%8.8x\n",d->dw[1]);#endif return(-1); } if (!(entry = bcm5600_table_get_entry(d,table,index))) return(-1);#if DEBUG_MEM BCM_LOG(d,"READ_MEM: addr=0x%8.8x (table %s)\n",d->dw[1],table->name);#endif for(i=0;i<table->nr_words;i++) d->dw[i+1] = entry[i]; return(0);}/* Write a table entry */static int bcm5600_table_write_entry(struct nm_16esw_data *d){ struct bcm5600_table *table; m_uint32_t addr,index,*entry; int i; addr = d->dw[1] & 0xFFFF0000; index = d->dw[1] & 0x0000FFFF; if (!(table = bcm5600_table_find(d,addr))) return(-1); if (!(entry = bcm5600_table_get_entry(d,table,index))) return(-1); for(i=0;i<table->nr_words;i++) entry[i] = d->dw[i+2];#if DEBUG_MEM { char buffer[512],*ptr = buffer; for(i=0;i<table->nr_words;i++) ptr += sprintf(ptr,"data[%d]=0x%8.8x ",i,entry[i]); BCM_LOG(d,"WRITE_MEM: addr=0x%8.8x (table %s) %s\n", d->dw[1],table->name,buffer); }#endif return(0);}/* Dump a table (for debugging) */static int bcm5600_table_dump(struct nm_16esw_data *d,m_uint32_t addr){ struct bcm5600_table *table; m_uint32_t *entry; int i,j; if (!(table = bcm5600_table_find(d,addr))) return(-1); printf("%s: dumping table \"%s\":\n",d->name,table->name); for(i=table->min_index;i<=table->max_index;i++) { if (!(entry = bcm5600_table_get_entry(d,table,i))) break; printf(" %4d:",i); for(j=0;j<table->nr_words;j++) printf("0x%8.8x ",entry[j]); printf("\n"); } printf("\n"); return(0);}/* Dump the VLAN table */static int bcm5600_dump_vtable(struct nm_16esw_data *d){ struct bcm5600_table *table; struct bcm5600_port *port; m_uint32_t *entry,tbmp,ubmp; u_int vlan; int i,j; if (!(table = bcm5600_table_find(d,BCM5600_ADDR_VTABLE0))) return(-1); printf("%s: dumping VLAN table:\n",d->name); for(i=table->min_index;i<=table->max_index;i++) { if (!(entry = bcm5600_table_get_entry(d,table,i))) break; /* Extract the VLAN info */ vlan = entry[0] & BCM5600_VTABLE_VLAN_TAG_MASK; if (vlan == VLAN_INVALID) continue; printf(" VLAN %4u: ",vlan); for(j=0;j<d->nr_port;j++) { tbmp = entry[1] & (1 << j); ubmp = entry[2] & (1 << j); if (tbmp || ubmp) { port = &d->ports[j]; printf("%s (",port->name); if (tbmp) printf("T%s",ubmp ? "/" : ") "); if (ubmp) printf("UT) "); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -