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