/[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 6 - (hide annotations)
Sat Oct 6 16:09:07 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 72069 byte(s)
dynamips-0.2.6-RC5

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

  ViewVC Help
Powered by ViewVC 1.1.26