|
|
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 = ð_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 = ð_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(ð_hdr->daddr,"\x01\x80\xc2\x00\x00",5) ||
2082: !memcmp(ð_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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.