/[dynamips]/upstream/dynamips-0.2.6-RC1/dev_c3600_esw.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /upstream/dynamips-0.2.6-RC1/dev_c3600_esw.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2 - (show annotations)
Sat Oct 6 16:03:58 2007 UTC (11 years, 11 months ago) by dpavlin
File MIME type: text/plain
File size: 69179 byte(s)
import dynamips-0.2.6-RC1

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

  ViewVC Help
Powered by ViewVC 1.1.26