/[dynamips]/upstream/dynamips-0.2.6-RC5/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

Annotation of /upstream/dynamips-0.2.6-RC5/dev_c3600_esw.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2 - (hide annotations)
Sat Oct 6 16:03:58 2007 UTC (16 years, 5 months ago) by dpavlin
Original Path: upstream/dynamips-0.2.6-RC1/dev_c3600_esw.c
File MIME type: text/plain
File size: 69179 byte(s)
import dynamips-0.2.6-RC1

1 dpavlin 2 /*
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