Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
W
White Rabbit Switch - Software
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
86
Issues
86
List
Board
Labels
Milestones
Merge Requests
4
Merge Requests
4
CI / CD
CI / CD
Pipelines
Schedules
Wiki
Wiki
image/svg+xml
Discourse
Discourse
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
Projects
White Rabbit Switch - Software
Commits
2e9542b1
Commit
2e9542b1
authored
Mar 09, 2012
by
Tomasz Wlostowski
Committed by
Alessandro Rubini
Mar 11, 2012
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
userspace/wrsw_rtud: re-done register layout for N-port generic RTU
parent
00ce398d
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
316 additions
and
798 deletions
+316
-798
rtu.h
userspace/wrsw_rtud/rtu.h
+31
-34
rtu_drv.c
userspace/wrsw_rtud/rtu_drv.c
+158
-328
rtu_drv.h
userspace/wrsw_rtud/rtu_drv.h
+0
-5
rtu_fd.c
userspace/wrsw_rtud/rtu_fd.c
+70
-375
rtu_fd.h
userspace/wrsw_rtud/rtu_fd.h
+7
-7
rtu_hash.c
userspace/wrsw_rtud/rtu_hash.c
+16
-14
rtu_hash.h
userspace/wrsw_rtud/rtu_hash.h
+6
-6
rtud.c
userspace/wrsw_rtud/rtud.c
+28
-29
No files found.
userspace/wrsw_rtud/rtu.h
View file @
2e9542b1
...
...
@@ -7,10 +7,10 @@
* Authors: Juan Luis Manas (juan.manas@integrasys.es)
* Maciej Lipinski (maciej.lipinski@cern.ch)
*
* Description: RTU data structures definition.
* Description: RTU data structures definition.
*
* Fixes:
* Tomasz Wlostowski
* Fixes:
* Tomasz Wlostowski
*
*
* This program is free software; you can redistribute it and/or
...
...
@@ -39,16 +39,13 @@
#include "mac.h"
#define RTU_
BANKS 2
#define RTU_
ENTRIES 2048
#define RTU_BUCKETS 4
#define LAST_RTU_BUCKET ((RTU_BUCKETS)-1)
#define RTU_ENTRIES (16384/(RTU_BANKS))
#define HTAB_ENTRIES ((RTU_ENTRIES)/(RTU_BUCKETS))
#define LAST_HTAB_ENTRY ((HTAB_ENTRIES)-1)
#define LAST_RTU_BUCKET (RTU_BUCKETS-1)
#define ENTRY_WORDS 8
#define CAM_ENTRIES (((RTU_HCAM_WORDS)/(ENTRY_WORDS))/(RTU_BANKS))
#define LAST_CAM_ENTRY ((CAM_ENTRIES)-1)
#define MIN_PORT 0
#define MAX_PORT 9
...
...
@@ -80,11 +77,11 @@
*/
struct
rtu_request
{
int
port_id
;
// physical port identifier
uint8_t
src
[
ETH_ALEN
];
// source MAC address
uint8_t
src
[
ETH_ALEN
];
// source MAC address
uint8_t
dst
[
ETH_ALEN
];
// destination MAC address
uint16_t
vid
;
// VLAN ID from the packet header
int
has_vid
;
// non-zero: VID is present,0:untagged packet (VID=0)
uint8_t
prio
;
// packet priority (either assigned by the port
uint8_t
prio
;
// packet priority (either assigned by the port
// or extracted from packet header)
int
has_prio
;
// non-zero: priority present, 0:no priority defined
};
...
...
@@ -93,36 +90,36 @@ struct rtu_request {
* \brief RTU Filtering Database Entry Object
*/
struct
filtering_entry
{
int
valid
;
// bit: 1 = entry is valid, 0: entry is
int
valid
;
// bit: 1 = entry is valid, 0: entry is
// invalid (empty)
int
end_of_bucket
;
// bit: 1 = last entry in current bucket, stop
// search at this point
int
is_bpdu
;
// bit: 1 = BPDU (or other non-STP-dependent
int
is_bpdu
;
// bit: 1 = BPDU (or other non-STP-dependent
// packet)
uint8_t
mac
[
ETH_ALEN
];
// MAC address (for searching the bucketed
uint8_t
mac
[
ETH_ALEN
];
// MAC address (for searching the bucketed
// hashtable)
uint8_t
fid
;
// Filtering database ID (for searching the
// bucketed hashtable)
uint32_t
port_mask_src
;
// port mask for source MAC addresses. Bits
// set to 1 indicate that packet having this
// MAC address can be forwarded from these
// corresponding ports. Ports having their
uint32_t
port_mask_src
;
// port mask for source MAC addresses. Bits
// set to 1 indicate that packet having this
// MAC address can be forwarded from these
// corresponding ports. Ports having their
// bits set to 0 shall drop the packet.
uint32_t
port_mask_dst
;
// port mask for destination MAC address. Bits
// set to 1 indicate to which physical ports
// the packet with matching destination MAC
// the packet with matching destination MAC
// address shall be routed
int
drop_when_source
;
// bit: 1 = drop the packet when source
int
drop_when_source
;
// bit: 1 = drop the packet when source
// address matches
int
drop_when_dest
;
// bit: 1 = drop the packet when destination
int
drop_when_dest
;
// bit: 1 = drop the packet when destination
// address matches
int
drop_unmatched_src_ports
;
// bit: 1 = drop the packet when it comes from
// source port different than specified in
// port_mask_src
// source port different than specified in
// port_mask_src
uint32_t
last_access_t
;
// time of last access to the rule (for aging)
...
...
@@ -134,10 +131,10 @@ struct filtering_entry {
int
has_prio_dst
;
// priority value valid
int
prio_override_dst
;
// priority override (force per-MAC priority)
int
go_to_cam
;
// 1 : there are more entries outside the
int
go_to_cam
;
// 1 : there are more entries outside the
// bucket
uint16_t
cam_addr
;
// address of the first entry in CAM memory
uint16_t
cam_addr
;
// address of the first entry in CAM memory
// (2 words)
int
dynamic
;
...
...
@@ -148,7 +145,7 @@ struct filtering_entry {
*/
struct
vlan_table_entry
{
uint32_t
port_mask
;
// VLAN port mask: 1 = ports assigned to this VLAN
uint8_t
fid
;
// Filtering Database Identifier
uint8_t
fid
;
// Filtering Database Identifier
uint8_t
prio
;
// VLAN priority
int
has_prio
;
// priority defined;
int
prio_override
;
// priority override (force per-VLAN priority)
...
...
@@ -159,9 +156,9 @@ struct vlan_table_entry {
* \brief Copies src filtering entry body into dst filtering entry body.
* @return pointer to dst filtering entry.
*/
static
inline
struct
filtering_entry
*
rtu_fe_copy
(
struct
filtering_entry
*
dst
,
struct
filtering_entry
*
src
)
static
inline
struct
filtering_entry
*
rtu_fe_copy
(
struct
filtering_entry
*
dst
,
struct
filtering_entry
*
src
)
{
return
memcpy
(
dst
,
src
,
sizeof
(
*
src
)
);
}
...
...
@@ -171,8 +168,8 @@ struct filtering_entry *rtu_fe_copy( struct filtering_entry *dst,
* @param ent pointer to entry to clean (either in HCAM or HTAB)
* @return pointer to filtering entry that was cleaned
*/
static
inline
struct
filtering_entry
*
rtu_fe_clean
(
struct
filtering_entry
*
ent
)
static
inline
struct
filtering_entry
*
rtu_fe_clean
(
struct
filtering_entry
*
ent
)
{
return
memset
(
ent
,
0
,
sizeof
(
*
ent
)
);
}
...
...
@@ -180,13 +177,13 @@ struct filtering_entry *rtu_fe_clean(struct filtering_entry *ent)
/**
* \brief Returns number of seconds since the epoch.
*/
static
inline
unsigned
long
now
()
static
inline
unsigned
long
now
()
{
return
(
unsigned
long
)
time
(
NULL
);
return
(
unsigned
long
)
time
(
NULL
);
}
int
rtud_init_exports
();
void
rtud_handle_wripc
();
#endif
/*__WHITERABBIT_RTU_H*/
userspace/wrsw_rtud/rtu_drv.c
View file @
2e9542b1
...
...
@@ -8,18 +8,16 @@
* Miguel Baizan (miguel.baizan@integrasys.es)
* Maciej Lipinski (maciej.lipinski@cern.ch)
*
* Description: RTU driver module in user space. Provides read/write access
* to RTU_at_HW components including:
* - UFIFO
* Description: RTU driver module in user space. Provides read/write access
* to RTU_at_HW components including:
* - UFIFO
* - MFIFO
* - HCAM
* - Aging RAM for Main Hashtable
* - Aging Register for HCAM
* - VLAN Table
* - RTU Global Control Register
* - RTU Port settings
*
* Fixes:
* Fixes:
* Alessandro Rubini
* Tomasz Wlostowski
*
...
...
@@ -43,7 +41,7 @@
#include <sys/ioctl.h>
#include <hw/switch_hw.h>
#include <hw/
wrsw_rtu_wb
.h>
#include <hw/
rtu_regs
.h>
#include <hal_client.h>
#include "rtu_drv.h"
...
...
@@ -68,7 +66,6 @@ static void mac_entry_word3_r(uint32_t word, struct filtering_entry *ent);
static
void
mac_entry_word4_r
(
uint32_t
word
,
struct
filtering_entry
*
ent
);
static
uint32_t
vlan_entry_word0_w
(
struct
vlan_table_entry
*
ent
);
static
uint32_t
fpga_rtu_pcr_addr
(
int
port
);
/*
* Used to communicate to RTU UFIFO IRQ handler device at kernel space
...
...
@@ -82,17 +79,19 @@ int rtu_init(void)
{
int
err
;
if
(
halexp_client_init
()
<
0
)
if
(
halexp_client_init
()
<
0
)
TRACE
(
TRACE_FATAL
,
"
WRSW_
HAL is not responding... Are you sure it's running on your switch?
\n
"
"
The
HAL is not responding... Are you sure it's running on your switch?
\n
"
);
// Used to 'get' RTU IRQs from kernel
fd
=
open
(
RTU_DEVNAME
,
O_RDWR
);
if
(
fd
<
0
)
return
errno
;
{
TRACE
(
TRACE_ERROR
,
"Can't open %s: is the RTU kernel driver loaded?"
,
RTU_DEVNAME
);
return
errno
;
}
// init IO memory map
err
=
shw_fpga_mmap_init
();
if
(
err
)
...
...
@@ -107,11 +106,33 @@ void rtu_exit(void)
{
if
(
fd
>=
0
)
close
(
fd
);
TRACE
(
TRACE_INFO
,
"module cleanup
\n
"
);
}
static
inline
uint32_t
rtu_rd
(
uint32_t
reg
)
{
return
_fpga_readl
(
FPGA_BASE_RTU
+
reg
);
}
static
inline
void
rtu_wr
(
uint32_t
reg
,
uint32_t
value
)
{
_fpga_writel
(
FPGA_BASE_RTU
+
reg
,
value
);
}
static
inline
void
write_pcr
(
int
port
,
uint32_t
pcr
)
{
rtu_wr
(
RTU_REG_PSR
,
RTU_PSR_PORT_SEL_W
(
port
));
rtu_wr
(
RTU_REG_PCR
,
pcr
);
}
static
inline
uint32_t
read_pcr
(
int
port
)
{
rtu_wr
(
RTU_REG_PSR
,
RTU_PSR_PORT_SEL_W
(
port
));
return
rtu_rd
(
RTU_REG_PCR
);
}
// UFIFO
/**
...
...
@@ -120,7 +141,7 @@ void rtu_exit(void)
*/
int
rtu_ufifo_is_empty
(
void
)
{
uint32_t
csr
=
_fpga_readl
(
FPGA_BASE_RTU
+
RTU_REG_UFIFO_CSR
);
uint32_t
csr
=
rtu_rd
(
RTU_REG_UFIFO_CSR
);
return
RTU_UFIFO_CSR_EMPTY
&
csr
;
}
...
...
@@ -132,7 +153,7 @@ int rtu_read_learning_queue_cnt(void)
{
// Get counter from UFIFO Control-Status Register
// Fixme: USEDW returns 0 (FIFO overflow?)
uint32_t
csr
=
_fpga_readl
(
FPGA_BASE_RTU
+
RTU_REG_UFIFO_CSR
);
uint32_t
csr
=
rtu_rd
(
RTU_REG_UFIFO_CSR
);
return
RTU_UFIFO_CSR_USEDW_R
(
csr
);
}
...
...
@@ -142,10 +163,19 @@ int rtu_read_learning_queue_cnt(void)
* @param req pointer to unrecognised request data. Memory handled by callee.
* @return error code
*/
static
int
irq_disabled
=
1
;
int
rtu_read_learning_queue
(
struct
rtu_request
*
req
)
{
int
err
;
if
(
irq_disabled
)
{
ioctl
(
fd
,
WR_RTU_IRQENA
);
irq_disabled
=
0
;
}
// If learning queue is empty, wait for UFIFO IRQ
if
(
rtu_ufifo_is_empty
())
{
err
=
ioctl
(
fd
,
WR_RTU_IRQWAIT
);
...
...
@@ -153,27 +183,25 @@ int rtu_read_learning_queue(struct rtu_request *req)
return
err
;
}
// read data from mapped IO memory
uint32_t
r0
=
_fpga_readl
(
FPGA_BASE_RTU
+
RTU_REG_UFIFO_R0
);
uint32_t
r1
=
_fpga_readl
(
FPGA_BASE_RTU
+
RTU_REG_UFIFO_R1
);
uint32_t
r2
=
_fpga_readl
(
FPGA_BASE_RTU
+
RTU_REG_UFIFO_R2
);
uint32_t
r3
=
_fpga_readl
(
FPGA_BASE_RTU
+
RTU_REG_UFIFO_R3
);
uint32_t
r4
=
_fpga_readl
(
FPGA_BASE_RTU
+
RTU_REG_UFIFO_R4
);
// read data from mapped IO memory
uint32_t
r0
=
rtu_rd
(
RTU_REG_UFIFO_R0
);
uint32_t
r1
=
rtu_rd
(
RTU_REG_UFIFO_R1
);
uint32_t
r2
=
rtu_rd
(
RTU_REG_UFIFO_R2
);
uint32_t
r3
=
rtu_rd
(
RTU_REG_UFIFO_R3
);
uint32_t
r4
=
rtu_rd
(
RTU_REG_UFIFO_R4
);
// Once read: if learning queue becomes empty again, enable UFIFO IRQ
if
(
rtu_ufifo_is_empty
())
ioctl
(
fd
,
WR_RTU_IRQENA
);
// unmarshall data and populate request
uint32_t
dmac_lo
=
RTU_UFIFO_R0_DMAC_LO_R
(
r0
);
uint32_t
dmac_hi
=
RTU_UFIFO_R1_DMAC_HI_R
(
r1
);
uint32_t
smac_lo
=
RTU_UFIFO_R2_SMAC_LO_R
(
r2
);
uint32_t
smac_hi
=
RTU_UFIFO_R3_SMAC_HI_R
(
r3
);
req
->
port_id
=
RTU_UFIFO_R4_PID_R
(
r4
);
req
->
has_prio
=
RTU_UFIFO_R4_HAS_PRIO
&
r4
;
req
->
prio
=
RTU_UFIFO_R4_PRIO_R
(
r4
);
req
->
has_vid
=
RTU_UFIFO_R4_HAS_VID
&
r4
;
uint32_t
smac_hi
=
RTU_UFIFO_R3_SMAC_HI_R
(
r3
);
req
->
port_id
=
RTU_UFIFO_R4_PID_R
(
r4
);
req
->
has_prio
=
RTU_UFIFO_R4_HAS_PRIO
&
r4
;
req
->
prio
=
RTU_UFIFO_R4_PRIO_R
(
r4
);
req
->
has_vid
=
RTU_UFIFO_R4_HAS_VID
&
r4
;
req
->
vid
=
RTU_UFIFO_R4_VID_R
(
r4
);
// destination mac
req
->
dst
[
5
]
=
0xFF
&
dmac_lo
;
...
...
@@ -189,6 +217,9 @@ int rtu_read_learning_queue(struct rtu_request *req)
req
->
src
[
2
]
=
0xFF
&
(
smac_lo
>>
24
);
req
->
src
[
1
]
=
0xFF
&
smac_hi
;
req
->
src
[
0
]
=
0xFF
&
(
smac_hi
>>
8
);
ioctl
(
fd
,
WR_RTU_IRQENA
);
return
0
;
}
...
...
@@ -202,7 +233,7 @@ int rtu_read_learning_queue(struct rtu_request *req)
int
rtu_read_mfifo_cnt
(
void
)
{
// Get counter from MFIFO Control-Status Register
uint32_t
csr
=
_fpga_readl
(
FPGA_BASE_RTU
+
RTU_REG_MFIFO_CSR
);
uint32_t
csr
=
rtu_rd
(
RTU_REG_MFIFO_CSR
);
return
RTU_MFIFO_CSR_USEDW_R
(
csr
);
}
...
...
@@ -212,7 +243,7 @@ int rtu_read_mfifo_cnt(void)
*/
int
rtu_mfifo_is_full
(
void
)
{
uint32_t
csr
=
_fpga_readl
(
FPGA_BASE_RTU
+
RTU_REG_MFIFO_CSR
);
uint32_t
csr
=
rtu_rd
(
RTU_REG_MFIFO_CSR
);
return
RTU_MFIFO_CSR_FULL
&
csr
;
}
...
...
@@ -222,20 +253,16 @@ int rtu_mfifo_is_full(void)
*/
int
rtu_mfifo_is_empty
(
void
)
{
uint32_t
csr
=
_fpga_readl
(
FPGA_BASE_RTU
+
RTU_REG_MFIFO_CSR
);
uint32_t
csr
=
rtu_rd
(
RTU_REG_MFIFO_CSR
);
return
RTU_MFIFO_CSR_EMPTY
&
csr
;
}
/**
* \brief Cleans MFIFO
*/
void
rtu_clean_mfifo
(
void
)
static
inline
void
flush_mfifo
()
{
while
(
!
rtu_mfifo_is_empty
())
{
_fpga_writel
(
FPGA_BASE_RTU
+
RTU_REG_MFIFO_R0
,
RTU_MFIFO_R0_AD_SEL
);
_fpga_writel
(
FPGA_BASE_RTU
+
RTU_REG_MFIFO_R1
,
0
);
usleep
(
10
);
}
uint32_t
gcr
=
rtu_rd
(
RTU_REG_GCR
);
rtu_wr
(
RTU_REG_GCR
,
gcr
|
RTU_GCR_MFIFOTRIG
);
while
(
!
rtu_rd
(
RTU_REG_GCR
)
&
RTU_GCR_MFIFOTRIG
);
/* wait while the RTU is busy flushing the MFIFO */
}
/**
...
...
@@ -251,11 +278,12 @@ void rtu_write_htab_entry(uint16_t zbt_addr, struct filtering_entry *ent)
write_mfifo_data
(
mac_entry_word2_w
(
ent
));
write_mfifo_data
(
mac_entry_word3_w
(
ent
));
write_mfifo_data
(
mac_entry_word4_w
(
ent
));
flush_mfifo
();
TRACE_DBG
(
TRACE_INFO
,
"write htab entry: addr %x ent %08x %08x %08x %08x %08x"
,
zbt_addr
,
"write htab entry
[with flush]
: addr %x ent %08x %08x %08x %08x %08x"
,
zbt_addr
,
mac_entry_word0_w
(
ent
),
mac_entry_word1_w
(
ent
),
mac_entry_word2_w
(
ent
),
...
...
@@ -287,105 +315,21 @@ void rtu_clean_htab(void)
write_mfifo_data
(
0x00000000
);
write_mfifo_data
(
0x00000000
);
write_mfifo_data
(
0x00000000
);
write_mfifo_data
(
0x00000000
);
write_mfifo_data
(
0x00000000
);
flush_mfifo
();
}
}
// HCAM
/**
* \brief Reads MAC entry from HCAM Hash collisions memory
* @param ent used to store the entry read. Memory should be handled by callee.
* @param cam_addr memory address which shoud be read.
*/
void
rtu_read_hcam_entry
(
uint16_t
cam_addr
,
struct
filtering_entry
*
ent
)
{
// read data from mapped IO memory
uint32_t
w0
=
_fpga_readl
(
FPGA_BASE_RTU
+
RTU_HCAM
+
4
*
cam_addr
);
uint32_t
w1
=
_fpga_readl
(
FPGA_BASE_RTU
+
RTU_HCAM
+
4
*
(
cam_addr
+
0x1
));
uint32_t
w2
=
_fpga_readl
(
FPGA_BASE_RTU
+
RTU_HCAM
+
4
*
(
cam_addr
+
0x2
));
uint32_t
w3
=
_fpga_readl
(
FPGA_BASE_RTU
+
RTU_HCAM
+
4
*
(
cam_addr
+
0x3
));
uint32_t
w4
=
_fpga_readl
(
FPGA_BASE_RTU
+
RTU_HCAM
+
4
*
(
cam_addr
+
0x4
));
TRACE_DBG
(
TRACE_INFO
,
"read hcam entry: addr %x ent %08x %08x %08x %08x %08x"
,
cam_addr
,
w0
,
w1
,
w2
,
w3
,
w4
);
// unmarshall data and populate entry
mac_entry_word0_r
(
w0
,
ent
);
mac_entry_word1_r
(
w1
,
ent
);
mac_entry_word2_r
(
w2
,
ent
);
mac_entry_word3_r
(
w3
,
ent
);
mac_entry_word4_r
(
w4
,
ent
);
}
/**
* \brief Writes MAC entry to HCAM Hash collisions memory
* @param ent MAC table entry to be written to HCAM.
* @param cam_addr memory address in which MAC entry shoud be added.
*/
void
rtu_write_hcam_entry
(
uint16_t
cam_addr
,
struct
filtering_entry
*
ent
)
{
_fpga_writel
(
FPGA_BASE_RTU
+
RTU_HCAM
+
4
*
cam_addr
,
mac_entry_word0_w
(
ent
));
_fpga_writel
(
FPGA_BASE_RTU
+
RTU_HCAM
+
4
*
(
cam_addr
+
0x1
),
mac_entry_word1_w
(
ent
));
_fpga_writel
(
FPGA_BASE_RTU
+
RTU_HCAM
+
4
*
(
cam_addr
+
0x2
),
mac_entry_word2_w
(
ent
));
_fpga_writel
(
FPGA_BASE_RTU
+
RTU_HCAM
+
4
*
(
cam_addr
+
0x3
),
mac_entry_word3_w
(
ent
));
_fpga_writel
(
FPGA_BASE_RTU
+
RTU_HCAM
+
4
*
(
cam_addr
+
0x4
),
mac_entry_word4_w
(
ent
));
TRACE_DBG
(
TRACE_INFO
,
"write hcam entry: addr %x ent %08x %08x %08x %08x %08x"
,
cam_addr
,
mac_entry_word0_w
(
ent
),
mac_entry_word1_w
(
ent
),
mac_entry_word2_w
(
ent
),
mac_entry_word3_w
(
ent
),
mac_entry_word4_w
(
ent
)
);
}
/**
* \brief Cleans MAC entry in HCAM Hash collisions memory
* @param addr memory address which shoud be cleaned.
*/
void
rtu_clean_hcam_entry
(
uint8_t
cam_addr
)
{
_fpga_writel
(
FPGA_BASE_RTU
+
RTU_HCAM
+
4
*
cam_addr
,
0x00000000
);
_fpga_writel
(
FPGA_BASE_RTU
+
RTU_HCAM
+
4
*
(
cam_addr
+
0x1
),
0x00000000
);
_fpga_writel
(
FPGA_BASE_RTU
+
RTU_HCAM
+
4
*
(
cam_addr
+
0x2
),
0x00000000
);
_fpga_writel
(
FPGA_BASE_RTU
+
RTU_HCAM
+
4
*
(
cam_addr
+
0x3
),
0x00000000
);
_fpga_writel
(
FPGA_BASE_RTU
+
RTU_HCAM
+
4
*
(
cam_addr
+
0x4
),
0x00000000
);
TRACE_DBG
(
TRACE_INFO
,
"write hcam entry: addr %x ent 00000000 00000000 00000000 00000000 00000000"
,
cam_addr
);
}
/**
* \brief Cleans HCAM.
* Cleans all entries in HCAM inactive bank.
*/
void
rtu_clean_hcam
(
void
)
{
int
addr
;
for
(
addr
=
0
;
addr
<
(
RTU_HCAM_WORDS
/
RTU_BANKS
);
addr
++
)
{
_fpga_writel
(
FPGA_BASE_RTU
+
RTU_HCAM
+
4
*
addr
,
0x00000000
);
}
}
// AGING RAM - HTAB
/**
* \brief Read word from aging HTAB.
* Aging RAM Size: 256 32-bit words
*/
uint32_t
rtu_read_agr_htab
(
uint32_t
addr
)
uint32_t
rtu_read_agr_htab
(
uint32_t
addr
)
{
return
_fpga_readl
(
FPGA_BASE_RTU
+
RTU_ARAM_MAIN
+
4
*
addr
)
;
return
rtu_rd
(
RTU_ARAM_BASE
+
4
*
addr
)
;
}
/**
...
...
@@ -394,32 +338,11 @@ uint32_t rtu_read_agr_htab( uint32_t addr )
void
rtu_clean_agr_htab
(
void
)
{
int
addr
;
for
(
addr
=
0
;
addr
<
RTU_ARAM_
MAIN_
WORDS
;
addr
++
)
{
_fpga_writel
(
FPGA_BASE_RTU
+
RTU_ARAM_MAIN
+
4
*
addr
,
0x00000000
);
for
(
addr
=
0
;
addr
<
RTU_ARAM_WORDS
;
addr
++
)
{
rtu_wr
(
RTU_ARAM_BASE
+
4
*
addr
,
0x00000000
);
}
}
// AGING RAM - HCAM
/**
* \brief Read aging register for HCAM.
* Each bit corresponds to one MAC entry in HCAM memory.
*/
uint32_t
rtu_read_agr_hcam
(
void
)
{
return
_fpga_readl
(
FPGA_BASE_RTU
+
RTU_REG_AGR_HCAM
);
}
/**
* \brief Clears aging register for HCAM
*/
void
rtu_clean_agr_hcam
(
void
)
{
_fpga_writel
(
FPGA_BASE_RTU
+
RTU_REG_AGR_HCAM
,
0x00000000
);
}
// VLAN TABLE
/**
...
...
@@ -431,11 +354,11 @@ void rtu_write_vlan_entry(uint32_t addr, struct vlan_table_entry *ent)
{
// printf("write_VLAN_ent: addr %x val %x\n", + RTU_VLAN_TAB + 4*addr, vlan_entry_word0_w(ent));
_fpga_writel
(
FPGA_BASE_RTU
+
RTU_VLAN_TAB
+
4
*
addr
,
vlan_entry_word0_w
(
ent
));
rtu_wr
(
RTU_VLAN_TAB_BASE
+
4
*
addr
,
vlan_entry_word0_w
(
ent
));
TRACE_DBG
(
TRACE_INFO
,
"write vlan entry: addr %x ent %08x %08x %08x %08x %08x"
,
addr
,
addr
,
vlan_entry_word0_w
(
ent
)
);
}
...
...
@@ -447,7 +370,7 @@ void rtu_write_vlan_entry(uint32_t addr, struct vlan_table_entry *ent)
void
rtu_clean_vlan_entry
(
uint32_t
addr
)
{
// Value 0x80000000 sets drop field to 1 (VLAN entry not registered)
_fpga_writel
(
FPGA_BASE_RTU
+
RTU_VLAN_TAB
+
4
*
addr
,
0x80000000
);
rtu_wr
(
RTU_VLAN_TAB_BASE
+
4
*
addr
,
0x80000000
);
}
/**
...
...
@@ -457,7 +380,7 @@ void rtu_clean_vlan(void)
{
int
addr
;
for
(
addr
=
0
;
addr
<
NUM_VLANS
;
addr
++
)
{
_fpga_writel
(
FPGA_BASE_RTU
+
RTU_VLAN_TAB
+
4
*
addr
,
0x80000000
);
rtu_wr
(
RTU_VLAN_TAB_BASE
+
4
*
addr
,
0x80000000
);
}
}
...
...
@@ -469,13 +392,9 @@ void rtu_clean_vlan(void)
*/
void
rtu_enable
(
void
)
{
// Get current GCR
uint32_t
gcr
=
_fpga_readl
(
FPGA_BASE_RTU
+
RTU_REG_GCR
);
// Set G_ENA bit value = 1
gcr
=
gcr
|
RTU_GCR_G_ENA
;
// Update GCR
_fpga_writel
(
FPGA_BASE_RTU
+
RTU_REG_GCR
,
gcr
);
TRACE_DBG
(
TRACE_INFO
,
"updated gcr (enable): %x
\n
"
,
gcr
);
uint32_t
gcr
=
rtu_rd
(
RTU_REG_GCR
);
rtu_wr
(
RTU_REG_GCR
,
gcr
|
RTU_GCR_G_ENA
);
TRACE_DBG
(
TRACE_INFO
,
"updated gcr (enable): %x
\n
"
,
gcr
);
}
/**
...
...
@@ -483,13 +402,9 @@ void rtu_enable(void)
*/
void
rtu_disable
(
void
)
{
// Get current GCR
uint32_t
gcr
=
_fpga_readl
(
FPGA_BASE_RTU
+
RTU_REG_GCR
);
// Set G_ENA bit value = 0
gcr
=
gcr
&
(
~
RTU_GCR_G_ENA
);
// Update GCR
_fpga_writel
(
FPGA_BASE_RTU
+
RTU_REG_GCR
,
gcr
);
TRACE_DBG
(
TRACE_INFO
,
"updated gcr (disable): %x
\n
"
,
gcr
);
uint32_t
gcr
=
rtu_rd
(
RTU_REG_GCR
);
rtu_wr
(
RTU_REG_GCR
,
gcr
&
(
~
RTU_GCR_G_ENA
));
TRACE_DBG
(
TRACE_INFO
,
"updated gcr (disable): %x
\n
"
,
gcr
);
}
/**
...
...
@@ -498,9 +413,8 @@ void rtu_disable(void)
*/
uint16_t
rtu_read_hash_poly
(
void
)
{
// Get current GCR
uint32_t
gcr
=
_fpga_readl
(
FPGA_BASE_RTU
+
RTU_REG_GCR
);
return
RTU_GCR_POLY_VAL_R
(
gcr
);
uint32_t
gcr
=
rtu_rd
(
RTU_REG_GCR
);
return
RTU_GCR_POLY_VAL_R
(
gcr
);
}
/**
...
...
@@ -510,56 +424,14 @@ uint16_t rtu_read_hash_poly(void)
void
rtu_write_hash_poly
(
uint16_t
hash_poly
)
{
// Get current GCR
uint32_t
gcr
=
_fpga_readl
(
FPGA_BASE_RTU
+
RTU_REG_GCR
);
uint32_t
gcr
=
rtu_rd
(
RTU_REG_GCR
);
// Clear previous hash poly and insert the new one
gcr
=
(
gcr
&
(
~
RTU_GCR_POLY_VAL_MASK
))
|
RTU_GCR_POLY_VAL_W
(
hash_poly
);
// Update GCR
_fpga_writel
(
FPGA_BASE_RTU
+
RTU_REG_GCR
,
gcr
);
rtu_wr
(
RTU_REG_GCR
,
gcr
);
TRACE_DBG
(
TRACE_INFO
,
"updated gcr (poly): %x
\n
"
,
gcr
);
}
/**
* \brief Set active ZBT bank.
* @param bank active ZBT bank (0 or 1). Other values will be evaluated as 1.
*/
void
rtu_set_active_htab_bank
(
uint8_t
bank
)
{
uint32_t
gcr
=
_fpga_readl
(
FPGA_BASE_RTU
+
RTU_REG_GCR
);
gcr
=
bank
?
(
RTU_GCR_HT_BSEL
|
gcr
)
:
((
~
RTU_GCR_HT_BSEL
)
&
gcr
)
;
_fpga_writel
(
FPGA_BASE_RTU
+
RTU_REG_GCR
,
gcr
);
TRACE_DBG
(
TRACE_INFO
,
"updated gcr (htab bank): %x
\n
"
,
gcr
);
}
/**
* \brief Set active CAM bank.
* @param bank active CAM bank (0 or 1). Other values will be evaluated as 1.
*/
void
rtu_set_active_hcam_bank
(
uint8_t
bank
)
{
uint32_t
gcr
=
_fpga_readl
(
FPGA_BASE_RTU
+
RTU_REG_GCR
);
gcr
=
bank
?
(
RTU_GCR_HCAM_BSEL
|
gcr
)
:
((
~
RTU_GCR_HCAM_BSEL
)
&
gcr
)
;
_fpga_writel
(
FPGA_BASE_RTU
+
RTU_REG_GCR
,
gcr
);
TRACE_DBG
(
TRACE_INFO
,
"updated gcr (hcam bank): %x
\n
"
,
gcr
);
}
/**
* \brief Set active ZBT and CAM banks at once.
* @param bank active ZBT and CAM bank (0 or 1). Other values will be evaluated as 1.
*/
void
rtu_set_active_bank
(
uint8_t
bank
)
{
uint32_t
gcr
=
_fpga_readl
(
FPGA_BASE_RTU
+
RTU_REG_GCR
);
gcr
=
bank
?
(
RTU_GCR_HT_BSEL
|
RTU_GCR_HCAM_BSEL
|
gcr
)
:
((
~
RTU_GCR_HT_BSEL
)
&
(
~
RTU_GCR_HCAM_BSEL
)
&
gcr
)
;
_fpga_writel
(
FPGA_BASE_RTU
+
RTU_REG_GCR
,
gcr
);
TRACE_DBG
(
TRACE_INFO
,
"updated gcr (htab/hcam bank): %x
\n
"
,
gcr
);
}
// PORT SETTINGS
...
...
@@ -574,11 +446,9 @@ int rtu_set_fixed_prio_on_port(int port, uint8_t prio)
{
if
(
(
port
<
MIN_PORT
)
||
(
port
>
MAX_PORT
)
)
return
-
EINVAL
;
uint32_t
pcr_addr
=
fpga_rtu_pcr_addr
(
port
);
uint32_t
pcr
=
_fpga_readl
(
FPGA_BASE_RTU
+
pcr_addr
);
// Be careful! the following assumes every port control reg has same layout
pcr
=
pcr
|
RTU_PCR0_FIX_PRIO
|
RTU_PCR0_PRIO_VAL_W
(
prio
);
_fpga_writel
(
FPGA_BASE_RTU
+
pcr_addr
,
pcr
);
uint32_t
pcr
=
read_pcr
(
port
);
write_pcr
(
port
,
pcr
|
RTU_PCR_FIX_PRIO
|
RTU_PCR_PRIO_VAL_W
(
prio
));
return
0
;
}
...
...
@@ -592,53 +462,51 @@ int rtu_unset_fixed_prio_on_port(int port)
{
if
(
(
port
<
MIN_PORT
)
||
(
port
>
MAX_PORT
)
)
return
-
EINVAL
;
uint32_t
pcr_addr
=
fpga_rtu_pcr_addr
(
port
);
uint32_t
pcr
=
_fpga_readl
(
FPGA_BASE_RTU
+
pcr_addr
);
// Be careful! the following assumes every port control reg has same layout
pcr
=
pcr
&
(
RTU_PCR0_LEARN_EN
|
RTU_PCR0_PASS_ALL
|
RTU_PCR0_PASS_BPDU
|
RTU_PCR0_B_UNREC
);
_fpga_writel
(
FPGA_BASE_RTU
+
pcr_addr
,
pcr
);
uint32_t
pcr
=
read_pcr
(
port
);
write_pcr
(
port
,
pcr
&
(
RTU_PCR_LEARN_EN
|
RTU_PCR_PASS_ALL
|
RTU_PCR_PASS_BPDU
|
RTU_PCR_B_UNREC
));
return
0
;
}
/**
* \brief Sets the LEARN_EN flag on indicated port.
* @param port port number (0 to 9)
* @param flag 0 disables learning. Otherwise: enables learning porcess on this port.
* @param flag 0 disables learning. Otherwise: enables learning porcess on this port.
* @return error code.
*/
int
rtu_learn_enable_on_port
(
int
port
,
int
flag
)
{
if
(
(
port
<
MIN_PORT
)
||
(
port
>
MAX_PORT
)
)
return
-
EINVAL
;
uint32_t
pcr_addr
=
fpga_rtu_pcr_addr
(
port
);
uint32_t
pcr
=
_fpga_readl
(
FPGA_BASE_RTU
+
pcr_addr
);
// Be careful! the following assumes every port control reg has same layout
pcr
=
flag
?
RTU_PCR0_LEARN_EN
|
pcr
:
(
~
RTU_PCR0_LEARN_EN
)
&
pcr
;
_fpga_writel
(
FPGA_BASE_RTU
+
pcr_addr
,
pcr
);
return
0
;
uint32_t
pcr
=
read_pcr
(
port
);
pcr
=
flag
?
RTU_PCR_LEARN_EN
|
pcr
:
(
~
RTU_PCR_LEARN_EN
)
&
pcr
;
write_pcr
(
port
,
pcr
);
return
0
;
}
/**
* \brief Sets the PASS_BPDU flag on indicated port.
* @param port port number (0 to 9)
* @param flag 0: BPDU packets are passed RTU rules only if PASS_ALL is set.
* Otherwise: BPDU packets are passed according to RTU rules.
* Otherwise: BPDU packets are passed according to RTU rules.
* @return error code.
*/
int
rtu_pass_bpdu_on_port
(
int
port
,
int
flag
)
int
rtu_pass_bpdu_on_port
(
int
port
,
int
flag
)
{
if
(
(
port
<
MIN_PORT
)
||
(
port
>
MAX_PORT
)
)
return
-
EINVAL
;
uint32_t
pcr_addr
=
fpga_rtu_pcr_addr
(
port
);
uint32_t
pcr
=
_fpga_readl
(
FPGA_BASE_RTU
+
pcr_addr
);
// Be careful! the following assumes every port control reg has same layout
pcr
=
flag
?
RTU_PCR0_PASS_BPDU
|
pcr
:
(
~
RTU_PCR0_PASS_BPDU
)
&
pcr
;
_fpga_writel
(
FPGA_BASE_RTU
+
pcr_addr
,
pcr
);
return
0
;
uint32_t
pcr
=
read_pcr
(
port
);
pcr
=
flag
?
RTU_PCR_PASS_BPDU
|
pcr
:
(
~
RTU_PCR_PASS_BPDU
)
&
pcr
;
write_pcr
(
port
,
pcr
);
return
0
;
}
/**
...
...
@@ -647,56 +515,41 @@ int rtu_pass_bpdu_on_port(int port, int flag)
* @param flag 0: all packets are dropped. Otherwise: all packets are passed.
* @return error code.
*/
int
rtu_pass_all_on_port
(
int
port
,
int
flag
)
int
rtu_pass_all_on_port
(
int
port
,
int
flag
)
{
if
(
(
port
<
MIN_PORT
)
||
(
port
>
MAX_PORT
)
)
return
-
EINVAL
;
uint32_t
pcr_addr
=
fpga_rtu_pcr_addr
(
port
);
uint32_t
pcr
=
_fpga_readl
(
FPGA_BASE_RTU
+
pcr_addr
);
// Be careful! the following assumes every port control reg has same layout
pcr
=
flag
?
RTU_PCR0
_PASS_ALL
|
pcr
:
(
~
RTU_PCR0
_PASS_ALL
)
&
pcr
;
_fpga_writel
(
FPGA_BASE_RTU
+
pcr_addr
,
pcr
);
return
0
;
if
(
(
port
<
MIN_PORT
)
||
(
port
>
MAX_PORT
)
)
return
-
EINVAL
;
uint32_t
pcr
=
read_pcr
(
port
);
pcr
=
flag
?
RTU_PCR
_PASS_ALL
|
pcr
:
(
~
RTU_PCR
_PASS_ALL
)
&
pcr
;
write_pcr
(
port
,
pcr
);
return
0
;
}
/**
* \brief Sets the B_UNREC flag on indicated port.
* @param port port number (0 to 9)
* @param flag 0: packet is dropped. Otherwise: packet is broadcast.
* @param flag 0: packet is dropped. Otherwise: packet is broadcast.
* @return error code.
*/
int
rtu_set_unrecognised_behaviour_on_port
(
int
port
,
int
flag
)
int
rtu_set_unrecognised_behaviour_on_port
(
int
port
,
int
flag
)
{
if
(
(
port
<
MIN_PORT
)
||
(
port
>
MAX_PORT
)
)
return
-
EINVAL
;
uint32_t
pcr_addr
=
fpga_rtu_pcr_addr
(
port
);
uint32_t
pcr
=
_fpga_readl
(
FPGA_BASE_RTU
+
pcr_addr
);
// Be careful! the following assumes every port control reg has same layout
pcr
=
flag
?
RTU_PCR0_B_UNREC
|
pcr
:
(
~
RTU_PCR0_B_UNREC
)
&
pcr
;
_fpga_writel
(
FPGA_BASE_RTU
+
pcr_addr
,
pcr
);
return
0
;
}
// IRQs
uint32_t
pcr
=
read_pcr
(
port
);
void
rtu_enable_irq
(
void
)
{
_fpga_writel
(
FPGA_BASE_RTU
+
RTU_REG_EIC_IER
,
RTU_EIC_IER_NEMPTY
);
}
pcr
=
flag
?
RTU_PCR_B_UNREC
|
pcr
:
(
~
RTU_PCR_B_UNREC
)
&
pcr
;
void
rtu_disable_irq
(
void
)
{
_fpga_writel
(
FPGA_BASE_RTU
+
RTU_REG_EIC_IDR
,
RTU_EIC_IDR_NEMPTY
);
write_pcr
(
port
,
pcr
);
return
0
;
}
void
rtu_clear_irq
(
void
)
{
_fpga_writel
(
FPGA_BASE_RTU
+
RTU_REG_EIC_ISR
,
RTU_EIC_ISR_NEMPTY
);
}
//---------------------------------------------
// Private Methods
...
...
@@ -706,33 +559,28 @@ void rtu_clear_irq(void)
static
void
write_mfifo_addr
(
uint32_t
zbt_addr
)
{
// workaround required to solve MFIFO overflow
rtu_clean_mfifo
();
_fpga_writel
(
FPGA_BASE_RTU
+
RTU_REG_MFIFO_R0
,
RTU_MFIFO_R0_AD_SEL
);
_fpga_writel
(
FPGA_BASE_RTU
+
RTU_REG_MFIFO_R1
,
zbt_addr
);
rtu_wr
(
RTU_REG_MFIFO_R0
,
RTU_MFIFO_R0_AD_SEL
);
rtu_wr
(
RTU_REG_MFIFO_R1
,
zbt_addr
);
}
static
void
write_mfifo_data
(
uint32_t
word
)
{
_fpga_writel
(
FPGA_BASE_RTU
+
RTU_REG_MFIFO_R0
,
RTU_MFIFO_R0_DATA_SEL
);
_fpga_writel
(
FPGA_BASE_RTU
+
RTU_REG_MFIFO_R1
,
word
);
// workaround required to solve MFIFO overflow
while
(
rtu_mfifo_is_full
());
rtu_wr
(
RTU_REG_MFIFO_R0
,
RTU_MFIFO_R0_DATA_SEL
);
rtu_wr
(
RTU_REG_MFIFO_R1
,
word
);
}
// to marshall MAC entries
static
uint32_t
mac_entry_word0_w
(
struct
filtering_entry
*
ent
)
{
return
return
((
0xFF
&
ent
->
mac
[
0
])
<<
24
)
|
((
0xFF
&
ent
->
mac
[
1
])
<<
16
)
|
((
0xFF
&
ent
->
fid
)
<<
4
)
|
((
0x1
&
ent
->
go_to_cam
)
<<
3
)
|
((
0x1
&
ent
->
is_bpdu
)
<<
2
)
|
((
0x1
&
ent
->
end_of_bucket
)
<<
1
)
|
((
0x1
&
ent
->
valid
)
)
;
((
0xFF
&
ent
->
fid
)
<<
4
)
|
((
0x1
&
ent
->
go_to_cam
)
<<
3
)
|
((
0x1
&
ent
->
is_bpdu
)
<<
2
)
|
((
0x1
&
ent
->
end_of_bucket
)
<<
1
)
|
((
0x1
&
ent
->
valid
)
)
;
}
static
uint32_t
mac_entry_word1_w
(
struct
filtering_entry
*
ent
)
...
...
@@ -747,28 +595,28 @@ static uint32_t mac_entry_word1_w(struct filtering_entry *ent)
static
uint32_t
mac_entry_word2_w
(
struct
filtering_entry
*
ent
)
{
return
((
0x1
&
ent
->
drop_when_dest
)
<<
28
)
|
((
0x1
&
ent
->
prio_override_dst
)
<<
27
)
|
((
0x7
&
ent
->
prio_dst
)
<<
24
)
|
((
0x1
&
ent
->
has_prio_dst
)
<<
23
)
|
((
0x1
&
ent
->
drop_unmatched_src_ports
)
<<
22
)
|
((
0x1
&
ent
->
drop_when_source
)
<<
21
)
|
((
0x1
&
ent
->
drop_when_dest
)
<<
28
)
|
((
0x1
&
ent
->
prio_override_dst
)
<<
27
)
|
((
0x7
&
ent
->
prio_dst
)
<<
24
)
|
((
0x1
&
ent
->
has_prio_dst
)
<<
23
)
|
((
0x1
&
ent
->
drop_unmatched_src_ports
)
<<
22
)
|
((
0x1
&
ent
->
drop_when_source
)
<<
21
)
|
((
0x1
&
ent
->
prio_override_src
)
<<
20
)
|
((
0x7
&
ent
->
prio_src
)
<<
17
)
|
((
0x1
&
ent
->
has_prio_src
)
<<
16
)
|
((
0x01FF
&
ent
->
cam_addr
)
)
;
((
0x7
&
ent
->
prio_src
)
<<
17
)
|
((
0x1
&
ent
->
has_prio_src
)
<<
16
)
|
((
0x01FF
&
ent
->
cam_addr
)
)
;
}
static
uint32_t
mac_entry_word3_w
(
struct
filtering_entry
*
ent
)
{
return
((
0xFFFF
&
ent
->
port_mask_dst
)
<<
16
)
|
((
0xFFFF
&
ent
->
port_mask_dst
)
<<
16
)
|
((
0xFFFF
&
ent
->
port_mask_src
)
)
;
}
static
uint32_t
mac_entry_word4_w
(
struct
filtering_entry
*
ent
)
{
return
return
(
ent
->
last_access_t
);
}
...
...
@@ -824,8 +672,8 @@ static void mac_entry_word4_r(uint32_t word, struct filtering_entry *ent)
static
uint32_t
vlan_entry_word0_w
(
struct
vlan_table_entry
*
ent
)
{
return
((
0x1
&
ent
->
drop
)
<<
31
)
|
return
((
0x1
&
ent
->
drop
)
<<
31
)
|
((
0x1
&
ent
->
prio_override
)
<<
30
)
|
((
0x7
&
ent
->
prio
)
<<
27
)
|
((
0x1
&
ent
->
has_prio
)
<<
26
)
|
...
...
@@ -833,21 +681,3 @@ static uint32_t vlan_entry_word0_w(struct vlan_table_entry *ent)
((
0xFFFF
&
ent
->
port_mask
)
)
;
}
static
uint32_t
fpga_rtu_pcr_addr
(
int
port
)
{
switch
(
port
){
case
0
:
return
RTU_REG_PCR0
;
case
1
:
return
RTU_REG_PCR1
;
case
2
:
return
RTU_REG_PCR2
;
case
3
:
return
RTU_REG_PCR3
;
case
4
:
return
RTU_REG_PCR4
;
case
5
:
return
RTU_REG_PCR5
;
case
6
:
return
RTU_REG_PCR6
;
case
7
:
return
RTU_REG_PCR7
;
case
8
:
return
RTU_REG_PCR8
;
case
9
:
return
RTU_REG_PCR9
;
default:
return
-
EINVAL
;
}
}
userspace/wrsw_rtud/rtu_drv.h
View file @
2e9542b1
...
...
@@ -33,11 +33,6 @@
#include "rtu.h"
// HW RTU (should be given by wrsw_rtu_wb.h)
#define RTU_HCAM 0x4000
#define RTU_ARAM_MAIN 0x8000
#define RTU_VLAN_TAB 0xc000
#define RTU_MFIFO_R0_DATA_SEL 0x00000000
#define RTU_MFIFO_R1_ADDR_MASK 0x0007FFFF
...
...
userspace/wrsw_rtud/rtu_fd.c
View file @
2e9542b1
/*
/*
\
* White Rabbit RTU (Routing Table Unit)
* Copyright (C) 2010, CERN.
*
...
...
@@ -8,12 +8,12 @@
* Miguel Baizan (miguel.baizan@integrasys.es)
* Maciej Lipinski (maciej.lipinski@cern.ch)
*
* Description: RTU Filtering database.
* Filtering database management related operations and filtering
* database mirror. Note there is a single Filtering Database
* Description: RTU Filtering database.
* Filtering database management related operations and filtering
* database mirror. Note there is a single Filtering Database
* object per Bridge (See 802.1Q - 12.7.1)
*
* Fixes:
* Fixes:
* Alessandro Rubini
* Tomasz Wlostowski
*
...
...
@@ -36,7 +36,7 @@
#include <unistd.h>
#include <pthread.h>
#include <hw/
wrsw_rtu_wb
.h>
#include <hw/
rtu_regs
.h>
#include <hw/trace.h>
#include "rtu_fd.h"
...
...
@@ -45,7 +45,6 @@
// Used to declare memory type at filtering database entry handles.
#define HTAB 0
#define HCAM 1
// Used to declare HW request types.
#define HW_WRITE_REQ 0
...
...
@@ -60,7 +59,7 @@
/**
* \brief Filtering Database entry handle.
* \brief Filtering Database entry handle.
*/
struct
fd_handle
{
int
mem_type
;
// HTAB or HCAM
...
...
@@ -91,22 +90,9 @@ struct hw_req *hw_req_list;
static
struct
filtering_entry
rtu_htab
[
HTAB_ENTRIES
][
RTU_BUCKETS
];
/**
* \brief Mirror of CAM lookup table.
* For RTU entries with more than 4 matches
* \brief Mirror of Aging RAM.
*/
static
struct
filtering_entry
rtu_hcam
[
CAM_ENTRIES
];
/**
* \brief Table bank to write entries to.
* HTAB and HCAM banks will be handled according to this single bank value.
*/
static
uint8_t
bank
;
/**
* \brief Mirror of Aging RAM.
*/
static
uint32_t
rtu_agr_htab
[
RTU_ARAM_MAIN_WORDS
];
static
uint32_t
rtu_agr_hcam
;
static
uint32_t
rtu_agr_htab
[
RTU_ARAM_WORDS
];
/**
* \brief Max time that a dynamic MAC entry can remain
...
...
@@ -129,26 +115,17 @@ static void clean_list(struct hw_req *head);
static
int
add_hw_req
(
int
type
,
int
mem
,
uint16_t
addr
,
struct
filtering_entry
*
ent
);
static
inline
int
write_htab_entry
(
uint16_t
addr
,
struct
filtering_entry
*
e
);
static
inline
int
write_hcam_entry
(
uint16_t
addr
,
struct
filtering_entry
*
e
);
static
inline
int
clean_htab_entry
(
uint16_t
addr
);
static
inline
int
clean_hcam_entry
(
uint16_t
addr
);
static
inline
uint16_t
zbt_addr
(
uint16_t
hash
,
int
bucket
);
static
inline
uint16_t
cam_addr
(
int
bucket
);
static
inline
int
cam_bucket
(
uint16_t
cam_addr
);
static
inline
int
matched
(
uint32_t
word
,
int
offset
);
static
int
htab_contains
(
uint8_t
mac
[
ETH_ALEN
],
uint8_t
fid
,
int
*
bucket
,
static
int
htab_contains
(
uint8_t
mac
[
ETH_ALEN
],
uint8_t
fid
,
int
*
bucket
,
struct
filtering_entry
**
ent
);
static
int
hcam_contains
(
uint8_t
mac
[
ETH_ALEN
],
uint8_t
fid
,
int
*
bucket
,
struct
filtering_entry
**
ent
);
static
int
find_empty_bucket_in_hcam
(
void
);
static
void
set_active_bank
(
int
n
);
static
void
clean_fd
(
void
);
static
void
clean_vd
(
void
);
...
...
@@ -160,10 +137,8 @@ static void rtu_hw_commit(void);
static
void
rtu_fd_commit
(
void
);
static
void
shift_htab_entries
(
uint16_t
hash
,
int
bucket
);
static
int
shift_hcam_entries
(
int
bucket
);
static
void
delete_htab_entry
(
uint16_t
hash
,
int
bucket
);
static
void
delete_hcam_entry
(
int
bucket
);
static
void
rtu_fd_age_out
(
void
);
static
void
rtu_fd_age_update
(
void
);
...
...
@@ -204,12 +179,12 @@ int rtu_fd_init(uint16_t poly, unsigned long aging)
* @param port_map a port map specification with a control element for each
* outbound port to specify filtering for that MAC address specification and VID
* @param dynamic it indicates whether it's a dynamic entry
* @return 0 if entry was created or updated. -ENOMEM if no space is available.
* @return 0 if entry was created or updated. -ENOMEM if no space is available.
*/
int
rtu_fd_create_entry
(
uint8_t
mac
[
ETH_ALEN
],
uint16_t
vid
,
uint32_t
port_map
,
int
dynamic
)
{
struct
filtering_entry
*
ent
;
// pointer to scan hashtable
uint16_t
hash
;
// hashtable key
uint16_t
hash
;
// hashtable key
uint8_t
fid
;
// Filtering database identifier
int
bucket
=
0
;
// bucket loop index
int
ret
=
0
;
// return value
...
...
@@ -224,8 +199,8 @@ int rtu_fd_create_entry(uint8_t mac[ETH_ALEN], uint16_t vid, uint32_t port_map,
// Check HTAB
ent
=
&
rtu_htab
[
hash
][
bucket
];
switch
(
htab_contains
(
mac
,
fid
,
&
bucket
,
&
ent
)){
case
FOUND
:
// update
case
FOUND
:
// update
mask_dst
=
ent
->
port_mask_dst
|
port_map
;
mask_src
=
ent
->
port_mask_src
|
vlan_tab
[
vid
].
port_mask
;
if
((
ent
->
port_mask_dst
!=
mask_dst
)
||
...
...
@@ -246,57 +221,10 @@ int rtu_fd_create_entry(uint8_t mac[ETH_ALEN], uint16_t vid, uint32_t port_map,
write_htab_entry
(
zbt_addr
(
hash
,
bucket
),
ent
);
break
;
case
NOT_FOUND_AND_FULL
:
// Not found and HTAB full for this hash
// Check whether HCAM was already used.
if
(
ent
->
go_to_cam
){
bucket
=
cam_bucket
(
ent
->
cam_addr
);
}
else
{
bucket
=
find_empty_bucket_in_hcam
();
if
(
bucket
<
0
)
{
ret
=
-
ENOMEM
;
break
;
}
// update htab last entry to point to hcam entry
ent
->
go_to_cam
=
1
;
ent
->
cam_addr
=
cam_addr
(
bucket
);
write_htab_entry
(
zbt_addr
(
hash
,
LAST_RTU_BUCKET
),
ent
);
}
// Check HCAM
ent
=
&
rtu_hcam
[
bucket
];
switch
(
hcam_contains
(
mac
,
fid
,
&
bucket
,
&
ent
)){
case
FOUND
:
// update
mask_dst
=
ent
->
port_mask_dst
|
port_map
;
mask_src
=
ent
->
port_mask_src
|
vlan_tab
[
vid
].
port_mask
;
if
((
ent
->
port_mask_dst
!=
mask_dst
)
||
(
ent
->
port_mask_src
!=
mask_src
))
{
// something new
ent
->
port_mask_dst
=
mask_dst
;
ent
->
port_mask_src
=
mask_src
;
write_hcam_entry
(
cam_addr
(
bucket
),
ent
);
}
break
;
case
NOT_FOUND
:
// existing list does not contain the entry and is necessary to
// append new entry at the end of current list
ent
->
end_of_bucket
=
0
;
write_hcam_entry
(
cam_addr
(
bucket
),
ent
);
ent
++
;
bucket
++
;
case
NOT_FOUND_AND_FIRST
:
// First entry in HCAM for this hash.
ent
->
valid
=
1
;
ent
->
end_of_bucket
=
1
;
ent
->
fid
=
fid
;
ent
->
port_mask_src
=
vlan_tab
[
vid
].
port_mask
;
ent
->
port_mask_dst
=
port_map
;
ent
->
dynamic
=
dynamic
;
ent
->
last_access_t
=
now
();
mac_copy
(
ent
->
mac
,
mac
);
write_hcam_entry
(
cam_addr
(
bucket
),
ent
);
break
;
default:
ret
=
-
ENOMEM
;
}
ret
=
-
ENOMEM
;
break
;
/* fixme: allocate an entry in HTAB which is not used by any hash value */
}
}
rtu_fd_commit
();
...
...
@@ -309,24 +237,24 @@ int rtu_fd_create_entry(uint8_t mac[ETH_ALEN], uint16_t vid, uint32_t port_map,
* Changing the hash polynomial requires removing any existing
* entry from RTU table.
* Note in case RTU table becomes full, this function may
* be used to change hash polynomial (thus leading to a different hash
* be used to change hash polynomial (thus leading to a different hash
* distribution).
* @param poly binary polynomial representation.
* CRC-16-CCITT -> 1+x^5+x^12+x^16 -> 0x1021
* @param poly binary polynomial representation.
* CRC-16-CCITT -> 1+x^5+x^12+x^16 -> 0x1021
* CRC-16-IBM -> 1+x^2+x^15+x^16 -> 0x8005
* CRC-16-DECT -> 1+x^3+x^7+x^8+x^10+x^16 -> 0x0589
*/
void
rtu_fd_set_hash_poly
(
uint16_t
poly
)
{
{
pthread_mutex_lock
(
&
fd_mutex
);
rtu_write_hash_poly
(
poly
);
rtu_hash_set_poly
(
poly
);
pthread_mutex_unlock
(
&
fd_mutex
);
rtu_hash_set_poly
(
poly
);
pthread_mutex_unlock
(
&
fd_mutex
);
}
/**
* \brief Sets the aging time for dynamic filtering entries.
* @param t new aging time value [seconds].
* @param t new aging time value [seconds].
* @return -EINVAL if t < 10 or t > 1000000 (802.1Q, Table 8.3); 0 otherwise.
*/
int
rtu_fd_set_aging_time
(
unsigned
long
t
)
...
...
@@ -343,12 +271,12 @@ int rtu_fd_set_aging_time(unsigned long t)
* changes in active topology.
*/
void
rtu_fd_flush
(
void
)
{
{
update_aging_map
();
// Work with latest access info
rtu_fd_age_update
();
// Update filtering entries age
rtu_fd_age_update
();
// Update filtering entries age
pthread_mutex_lock
(
&
fd_mutex
);
rtu_fd_age_out
();
// Remove old entries
rtu_fd_age_out
();
// Remove old entries
pthread_mutex_unlock
(
&
fd_mutex
);
clean_aging_map
();
// Keep track of entries access in next period
...
...
@@ -365,9 +293,9 @@ struct filtering_entry *rtu_fd_lookup_htab_entry(int index)
{
if
(
n
==
index
)
return
&
rtu_htab
[
i
][
j
];
n
++
;
}
}
}
}
}
}
return
NULL
;
}
...
...
@@ -408,7 +336,7 @@ static int add_hw_req(int type, int mem, uint16_t addr, struct filtering_entry *
req
=
(
struct
hw_req
*
)
malloc
(
sizeof
(
struct
hw_req
));
if
(
!
req
)
return
-
ENOMEM
;
req
->
type
=
type
;
req
->
handle
.
mem_type
=
mem
;
req
->
handle
.
addr
=
addr
;
...
...
@@ -423,49 +351,37 @@ static int add_hw_req(int type, int mem, uint16_t addr, struct filtering_entry *
return
0
;
}
static
inline
static
inline
int
write_htab_entry
(
uint16_t
addr
,
struct
filtering_entry
*
e
)
{
return
add_hw_req
(
HW_WRITE_REQ
,
HTAB
,
addr
,
e
);
}
static
inline
int
write_hcam_entry
(
uint16_t
addr
,
struct
filtering_entry
*
e
)
{
return
add_hw_req
(
HW_WRITE_REQ
,
HCAM
,
addr
,
e
);
}
static
inline
static
inline
int
clean_htab_entry
(
uint16_t
addr
)
{
return
add_hw_req
(
HW_CLEAN_REQ
,
HTAB
,
addr
,
NULL
);
}
static
inline
int
clean_hcam_entry
(
uint16_t
addr
)
{
return
add_hw_req
(
HW_CLEAN_REQ
,
HCAM
,
addr
,
NULL
);
}
static
inline
static
inline
uint16_t
zbt_addr
(
uint16_t
hash
,
int
bucket
)
{
return
((
0x07FF
&
hash
)
<<
5
)
|
((
0x0003
&
bucket
)
<<
3
);
}
static
inline
static
inline
uint16_t
cam_addr
(
int
bucket
)
{
return
((
0x001F
&
bucket
)
<<
3
);
}
static
inline
static
inline
int
cam_bucket
(
uint16_t
cam_addr
)
{
return
((
cam_addr
>>
3
)
&
0x001F
);
}
static
inline
static
inline
int
matched
(
uint32_t
word
,
int
offset
)
{
return
(
word
>>
offset
)
&
0x00000001
;
...
...
@@ -481,9 +397,9 @@ int matched(uint32_t word, int offset)
* HTAB was full for the corresponding hash. -EINVAL if bucket >= RTU_BUCKETS
*/
static
int
htab_contains
(
uint8_t
mac
[
ETH_ALEN
],
uint8_t
fid
,
int
*
bucket
,
uint8_t
mac
[
ETH_ALEN
],
uint8_t
fid
,
int
*
bucket
,
struct
filtering_entry
**
ent
)
{
for
(;
*
bucket
<
RTU_BUCKETS
;
(
*
bucket
)
++
,
(
*
ent
)
++
)
{
...
...
@@ -492,97 +408,11 @@ static int htab_contains(
if
(
mac_equal
((
*
ent
)
->
mac
,
mac
)
&&
((
*
ent
)
->
fid
==
fid
))
return
FOUND
;
if
(
*
bucket
==
LAST_RTU_BUCKET
)
return
NOT_FOUND_AND_FULL
;
}
return
-
EINVAL
;
}
/**
* Checks whether a given pair (mac,fid) is at HCAM
* @param mac mac address
* @param fid filtering database identifier
* @param bucket inout param.Returns the bucket number where the entry was found
* @param ent pointer to entry found.
* @return 0 if entry was not found. 1 if entry was found. -1 if entry was not
* found and the end of bucket was reached. -ENOMEM if no more entries after the
* end of bucket. -EINVAL if bucket >= CAM_ENTRIES or HCAM inconsistent.
*/
static
int
hcam_contains
(
uint8_t
mac
[
ETH_ALEN
],
uint8_t
fid
,
int
*
bucket
,
struct
filtering_entry
**
ent
)
{
for
(;
*
bucket
<
CAM_ENTRIES
;
(
*
bucket
)
++
,
(
*
ent
)
++
)
{
if
(
!
(
*
ent
)
->
valid
)
return
NOT_FOUND_AND_FIRST
;
if
(
mac_equal
((
*
ent
)
->
mac
,
mac
)
&&
((
*
ent
)
->
fid
==
fid
))
return
FOUND
;
if
((
*
ent
)
->
end_of_bucket
)
return
(
*
bucket
+
1
<
CAM_ENTRIES
)
&&
!
rtu_hcam
[
*
bucket
+
1
].
valid
?
NOT_FOUND
:-
ENOMEM
;
}
return
-
EINVAL
;
}
/**
* \brief Find the most appropriate empty bucket to insert new hash collision
* list. The algorithm first finds the fragment which contains the max number of
* consecutive empty positions. Then divides this fragment into two parts: first
* block is still available for possible increment of any existing list; The
* second block will be available for the new list.
* The algorithm keeps a fair and uniform distribution of fragments space.
* @return bucket index or -1 if the HCAM table is full.
*/
static
int
find_empty_bucket_in_hcam
(
void
)
{
int
bucket
=
0
;
// bucket loop index
int
res
=
0
;
// result bucket
int
empty
=
0
;
// consecutive empty buckets
int
max
=
0
;
// max consecutive empty buckets
// First obtain position with max consecutive empty space
for
(;
bucket
<
CAM_ENTRIES
;
bucket
++
)
{
if
(
rtu_hcam
[
bucket
].
valid
)
{
if
(
empty
>
max
)
{
max
=
empty
;
res
=
bucket
-
empty
;
}
empty
=
0
;
}
else
{
empty
++
;
}
}
// Update max consecutive empty buckets if necessary
if
(
empty
>
max
)
{
max
=
empty
;
res
=
bucket
-
empty
;
}
if
(
max
==
0
)
// bank is full
return
-
1
;
else
if
(
max
==
CAM_ENTRIES
)
// bank is empty
return
0
;
else
// Divide max space in two blocks and take address of second block
return
res
+
max
/
2
;
return
NOT_FOUND_AND_FULL
;
}
return
-
EINVAL
;
}
/**
* \brief Set the filtering database active bank both in software and hardware.
* Note both HTAB and HCAM active banks are switched at once.
* Bank switching is delayed until MFIFO is empty (method remains blocked
* meanwhile).
*/
static
void
set_active_bank
(
int
b
)
{
// wait until MFIFO is empty
rtu_clean_mfifo
();
// inactive bank becomes active (both banks are switched at once)
rtu_set_active_bank
(
b
);
// active bank becomes inactive one
bank
=
(
b
==
0
)
?
1
:
0
;
}
/**
* Filtering database initialisation.
...
...
@@ -590,18 +420,12 @@ static void set_active_bank(int b)
static
void
clean_fd
(
void
)
{
memset
(
&
rtu_htab
,
0
,
sizeof
(
rtu_htab
));
memset
(
&
rtu_hcam
,
0
,
sizeof
(
rtu_hcam
));
set_active_bank
(
0
);
rtu_clean_htab
();
rtu_clean_hcam
();
set_active_bank
(
1
);
rtu_clean_htab
();
rtu_clean_hcam
();
}
/**
* VLAN database initialisation. VLANs are initially marked as disabled.
* VLAN database initialisation. VLANs are initially marked as disabled.
*/
static
void
clean_vd
(
void
)
{
...
...
@@ -629,10 +453,8 @@ static void clean_vd(void)
static
void
clean_aging_map
(
void
)
{
int
i
;
rtu_agr_hcam
=
0x00000000
;
rtu_clean_agr_hcam
();
for
(
i
=
0
;
i
<
RTU_ARAM_MAIN_WORDS
;
i
++
)
{
for
(
i
=
0
;
i
<
RTU_ARAM_WORDS
;
i
++
)
{
rtu_agr_htab
[
i
]
=
0x00000000
;
}
rtu_clean_agr_htab
();
...
...
@@ -645,20 +467,19 @@ static void update_aging_map(void)
{
int
i
;
rtu_agr_hcam
=
rtu_read_agr_hcam
();
for
(
i
=
0
;
i
<
RTU_ARAM_MAIN_WORDS
;
i
++
)
{
for
(
i
=
0
;
i
<
RTU_ARAM_WORDS
;
i
++
)
{
rtu_agr_htab
[
i
]
=
rtu_read_agr_htab
(
i
);
}
}
/**
* \brief Updates the age of filtering entries accessed in the last period.
* \brief Updates the age of filtering entries accessed in the last period.
*/
static
void
rtu_fd_age_update
(
void
)
{
int
i
;
// Aging Bitmap word loop index
int
j
;
// Word bits loop index
uint32_t
agr_word
;
// Aux var for manipulating aging RAM
uint32_t
agr_word
;
// Aux var for manipulating aging RAM
uint16_t
hash
;
// HTAB entry hash (index)
int
bucket
;
// HTAB entry bucket
int
bit_cnt
;
// Absolute bit counter
...
...
@@ -667,20 +488,20 @@ static void rtu_fd_age_update(void)
// Update 'last access time' for accessed entries
t
=
now
();
// HTAB
for
(
i
=
0
;
i
<
RTU_ARAM_
MAIN_
WORDS
;
i
++
)
{
for
(
i
=
0
;
i
<
RTU_ARAM_WORDS
;
i
++
)
{
agr_word
=
rtu_agr_htab
[
i
];
if
(
agr_word
!=
0x00000000
)
{
for
(
j
=
0
;
j
<
32
;
j
++
){
if
(
matched
(
agr_word
,
j
))
{
// ((word_pos x 32) + bit_pos)
bit_cnt
=
((
i
&
0x00FF
)
<<
5
)
|
(
j
&
0x001F
);
if
(
matched
(
agr_word
,
j
))
{
// ((word_pos x 32) + bit_pos)
bit_cnt
=
((
i
&
0x00FF
)
<<
5
)
|
(
j
&
0x001F
);
hash
=
bit_cnt
>>
2
;
// 4 buckets per hash
bucket
=
bit_cnt
&
0x03
;
// last 2 bits
bucket
=
bit_cnt
&
0x03
;
// last 2 bits
rtu_htab
[
hash
][
bucket
].
last_access_t
=
t
;
TRACE
(
TRACE_INFO
,
"updated htab entry age: mac = %s, hash = %d, bucket = %d
\n
, t = %d"
,
TRACE_INFO
,
"updated htab entry age: mac = %s, hash = %d, bucket = %d
\n
, t = %d"
,
mac_to_string
(
rtu_htab
[
hash
][
bucket
].
mac
),
hash
,
bucket
,
...
...
@@ -690,24 +511,11 @@ static void rtu_fd_age_update(void)
}
}
}
// HCAM
agr_word
=
rtu_agr_hcam
;
for
(
j
=
0
;
j
<
32
;
j
++
){
if
(
matched
(
agr_word
,
j
))
{
rtu_hcam
[
j
].
last_access_t
=
t
;
TRACE
(
TRACE_INFO
,
"updated hcam entry age: mac = %s, bucket = %d
\n
"
,
mac_to_string
(
rtu_hcam
[
j
].
mac
),
j
);
}
}
}
/**
* For each filtering entry in the filtering database, this method checks its
* last access time and removes it in case entry is older than the aging time.
* For each filtering entry in the filtering database, this method checks its
* last access time and removes it in case entry is older than the aging time.
*/
static
void
rtu_fd_age_out
(
void
)
{
...
...
@@ -717,26 +525,13 @@ static void rtu_fd_age_out(void)
unsigned
long
t
;
// (secs)
t
=
now
()
-
aging_time
;
// HCAM
for
(
j
=
CAM_ENTRIES
;
j
--
>
0
;){
ent
=
&
rtu_hcam
[
j
];
if
(
ent
->
valid
&&
ent
->
dynamic
&&
time_after
(
t
,
ent
->
last_access_t
))
{
TRACE
(
TRACE_INFO
,
"deleting hcam entry: mac = %s, bucket = %d
\n
"
,
mac_to_string
(
ent
->
mac
),
j
);
delete_hcam_entry
(
j
);
}
}
// HTAB
// HTAB
for
(
i
=
HTAB_ENTRIES
;
i
--
>
0
;)
{
for
(
j
=
RTU_BUCKETS
;
j
--
>
0
;)
{
ent
=
&
rtu_htab
[
i
][
j
];
if
(
ent
->
valid
&&
ent
->
dynamic
&&
time_after
(
t
,
ent
->
last_access_t
)){
TRACE
(
TRACE_INFO
,
TRACE_INFO
,
"deleting htab entry: mac = %s, hash = %d, bucket = %d
\n
"
,
mac_to_string
(
ent
->
mac
),
i
,
...
...
@@ -751,7 +546,7 @@ static void rtu_fd_age_out(void)
}
/**
* \brief Read changes from hw_req_list and invoke RTU driver to efectively
* \brief Read changes from hw_req_list and invoke RTU driver to efectively
* write or clean the entry.
*/
static
void
rtu_hw_commit
(
void
)
...
...
@@ -763,17 +558,13 @@ static void rtu_hw_commit(void)
case
HW_WRITE_REQ
:
if
(
req
->
handle
.
mem_type
==
HTAB
)
rtu_write_htab_entry
(
req
->
handle
.
addr
,
req
->
handle
.
entry_ptr
);
else
rtu_write_hcam_entry
(
req
->
handle
.
addr
,
req
->
handle
.
entry_ptr
);
break
;
case
HW_CLEAN_REQ
:
if
(
req
->
handle
.
mem_type
==
HTAB
)
rtu_clean_htab_entry
(
req
->
handle
.
addr
);
else
rtu_clean_hcam_entry
(
req
->
handle
.
addr
);
break
;
break
;
}
}
}
}
/**
...
...
@@ -784,11 +575,6 @@ static void rtu_fd_commit(void)
if
(
!
hw_req_list
)
return
;
// write entries to inactive bank
rtu_hw_commit
();
// switch bank to make entries available to RTU at HW
set_active_bank
(
bank
);
// both banks need same content
rtu_hw_commit
();
// this list no longer needed
...
...
@@ -797,7 +583,7 @@ static void rtu_fd_commit(void)
}
/**
* \brief Shifts HTAB list one position, starting at bucket.
* \brief Shifts HTAB list one position, starting at bucket.
*/
static
void
shift_htab_entries
(
uint16_t
hash
,
int
bucket
)
{
...
...
@@ -819,74 +605,9 @@ static void shift_htab_entries(uint16_t hash, int bucket)
}
}
/**
* \brief Shifts HCAM list one position, starting at bucket.
* If entry to remove is end of bucket, marks previous one (if exists) as the
* new end of bucket.
* @return -1 if more entries remain in HCAM. Otherwise, returns the hash for
* entry, in order to help modifying the last HTAB entry
*/
static
int
shift_hcam_entries
(
int
bucket
)
{
struct
filtering_entry
*
ent
;
// entry to remove
struct
filtering_entry
*
next_ent
;
// following entry
struct
filtering_entry
*
prev_ent
;
// previous entry
int
ret
;
// return value
int
i
;
ret
=
-
1
;
ent
=
&
rtu_hcam
[
bucket
];
for
(
i
=
bucket
;
i
<
LAST_CAM_ENTRY
;
i
++
){
if
(
ent
->
end_of_bucket
){
if
(
i
>
bucket
)
// entry to remove was not the last
break
;
if
(
i
==
0
){
// entry to remove was last but there are no previous
ret
=
rtu_hash
(
ent
->
mac
,
ent
->
fid
);
break
;
}
prev_ent
=
ent
-
1
;
if
(
!
prev_ent
->
valid
||
prev_ent
->
end_of_bucket
){
// prev entry not valid or part of another list
ret
=
rtu_hash
(
ent
->
mac
,
ent
->
fid
);
break
;
}
// mark previous as end_of_bucket
prev_ent
->
end_of_bucket
=
1
;
write_hcam_entry
(
cam_addr
(
i
-
1
),
prev_ent
);
break
;
}
next_ent
=
&
rtu_hcam
[
i
+
1
];
rtu_fe_copy
(
ent
,
next_ent
);
write_hcam_entry
(
cam_addr
(
i
),
ent
);
ent
=
next_ent
;
}
rtu_fe_clean
(
ent
);
clean_hcam_entry
(
cam_addr
(
i
));
return
ret
;
}
/**
* \brief Deletes HCAM entry by shifting HCAM list.
* Updates HTAB last entry if neccessary.
* @param bucket CAM entry address
*/
static
void
delete_hcam_entry
(
int
bucket
)
{
struct
filtering_entry
*
ent
;
int
hash
;
hash
=
shift_hcam_entries
(
bucket
);
if
(
hash
>
-
1
){
// no entries remain at HCAM
ent
=
&
rtu_htab
[
hash
][
LAST_RTU_BUCKET
];
ent
->
go_to_cam
=
0
;
ent
->
cam_addr
=
0
;
write_htab_entry
(
zbt_addr
(
hash
,
LAST_RTU_BUCKET
),
ent
);
}
}
/**
* \brief Deletes HTAB entry by shifting HTAB list.
* \brief Deletes HTAB entry by shifting HTAB list.
* If HCAM is used, it also copies first HCAM entry to last HTAB bucket.
* @param hash hashcode for entry to remove.
* @param bucket HTAB bucket for entry to remove
...
...
@@ -894,39 +615,13 @@ static void delete_hcam_entry(int bucket)
static
void
delete_htab_entry
(
uint16_t
hash
,
int
bucket
)
{
struct
filtering_entry
*
ent
;
struct
filtering_entry
*
prev_ent
;
struct
filtering_entry
*
cam_ent
;
int
hcam_bucket
;
shift_htab_entries
(
hash
,
bucket
);
ent
=
&
rtu_htab
[
hash
][
LAST_RTU_BUCKET
];
if
(
ent
->
go_to_cam
)
{
// HCAM used
// go_to_cam was copied to prev_ent while shifting. clean it.
prev_ent
=
ent
-
1
;
prev_ent
->
go_to_cam
=
0
;
prev_ent
->
cam_addr
=
0
;
// changes will be written to hw when shift operations are commited
// copy first cam entry into last HTAB entry
hcam_bucket
=
cam_bucket
(
ent
->
cam_addr
);
cam_ent
=
&
rtu_hcam
[
hcam_bucket
];
rtu_fe_copy
(
ent
,
cam_ent
);
if
(
ent
->
end_of_bucket
){
// entry was the only one in HCAM
ent
->
go_to_cam
=
0
;
ent
->
cam_addr
=
0
;
ent
->
end_of_bucket
=
0
;
}
else
{
// point to the next one
ent
->
go_to_cam
=
1
;
ent
->
cam_addr
=
cam_addr
(
hcam_bucket
+
1
);
}
write_htab_entry
(
zbt_addr
(
hash
,
LAST_RTU_BUCKET
),
ent
);
// clean HCAM entry
rtu_fe_clean
(
cam_ent
);
clean_hcam_entry
(
cam_addr
(
hcam_bucket
));
}
else
if
(
ent
->
valid
)
{
if
(
ent
->
valid
)
{
// clean last HTAB entry
rtu_fe_clean
(
ent
);
clean_htab_entry
(
zbt_addr
(
hash
,
LAST_RTU_BUCKET
));
...
...
userspace/wrsw_rtud/rtu_fd.h
View file @
2e9542b1
...
...
@@ -8,9 +8,9 @@
* Miguel Baizan (miguel.baizan@integrasys.es)
* Maciej Lipinski (maciej.lipinski@cern.ch)
*
* Description: RTU Filtering database header.
* Filtering database management related operations and filtering
* database mirror. Note there is a single Filtering Database
* Description: RTU Filtering database header.
* Filtering database management related operations and filtering
* database mirror. Note there is a single Filtering Database
* object per Bridge (See 802.1Q - 12.7.1)
*
* Fixes:
...
...
@@ -40,13 +40,13 @@
#define STATIC 0
#define DYNAMIC 1
int
rtu_fd_init
(
uint16_t
poly
,
unsigned
long
aging
)
int
rtu_fd_init
(
uint16_t
poly
,
unsigned
long
aging
)
__attribute__
((
warn_unused_result
));
int
rtu_fd_create_entry
(
uint8_t
mac
[
ETH_ALEN
],
uint16_t
vid
,
uint32_t
port_map
,
uint8_t
mac
[
ETH_ALEN
],
uint16_t
vid
,
uint32_t
port_map
,
int
dynamic
)
__attribute__
((
warn_unused_result
));
...
...
userspace/wrsw_rtud/rtu_hash.c
View file @
2e9542b1
...
...
@@ -6,8 +6,8 @@
*
* Authors: Maciej Lipinski (maciej.lipinski@cern.ch)
*
* Description: Hash function presented below, produces hash which corresponds
* to hash produced by VHDL generated on this page:
* Description: Hash function presented below, produces hash which corresponds
* to hash produced by VHDL generated on this page:
* http://outputlogic.com/
*
* Fixes:
...
...
@@ -28,6 +28,8 @@
*/
#include <hw/trace.h>
#include "rtu.h"
#include "rtu_hash.h"
...
...
@@ -47,53 +49,53 @@ void rtu_hash_set_poly(uint16_t poly)
uint16_t
rtu_hash
(
uint8_t
mac
[
ETH_ALEN
],
uint8_t
fid
)
{
uint16_t
hash
=
0xFFFF
;
hash
=
crc16
(
hash
,
(
0xFFFF
&
fid
));
hash
=
crc16
(
hash
,
((
uint16_t
)
mac
[
0
]
<<
8
)
|
mac
[
1
]);
hash
=
crc16
(
hash
,
((
uint16_t
)
mac
[
2
]
<<
8
)
|
mac
[
3
]);
hash
=
crc16
(
hash
,
((
uint16_t
)
mac
[
4
]
<<
8
)
|
mac
[
5
]);
return
hash
&
0x7FF
;
// trim to fit in ZBT SRAM addr
return
hash
&
(
HTAB_ENTRIES
-
1
);
/* warning: assumes that HTAB_ENTRIES is a power of 2 */
}
/*
-------------------------------------------------------------------------------
-- SOME EXPLANATION REGARDING VHDL vs C CRC IMPLEMENTATION BY ML
-------------------------------------------------------------------------------
-- C code to produce exactly the same CRC as VHDL generated
-- C code to produce exactly the same CRC as VHDL generated
-- with http://outputlogic.com/ .
-- it uses naive method, it's not optimal at all
-- but it's good enough to chech whether VHDL works OK
-- It was made (by maciej.lipinski@cern.ch) modifying source from here:
-- http://www.netrino.com/Embedded-Systems/How-To/CRC-Calculation-C-Code
-- the website provides explanation of CRC
--
-- To get the hex representation of POLY to be used with the C function, which
-- is different than hex representation of polly used to generate VHDL code
--
-- To get the hex representation of POLY to be used with the C function, which
-- is different than hex representation of polly used to generate VHDL code
-- (i.e.:0x1021 <->0x88108), here is the trick:
--
-- 1) we are using the following poly equation: 1+x^5+x^12+x^16;
-- 2) it translates to binary: (1) 0001 0000 0010 0001 = 0x1021
-- 2) it translates to binary: (1) 0001 0000 0010 0001 = 0x1021
-- | |
-- | this is default | this you can find in
-- | this is default | this you can find in
-- |-> it's the 16th bit |-> the wiki as description
-- of the polly equation
--
--
-- 3) we include the "default" bit into the polly and add zeroes at the end
-- creating 20 bit polly, like this
-- (1) 0001 0000 0010 0001 => 1000 1000 0001 0000 1000 = 0x88108
-- (1) 0001 0000 0010 0001 => 1000 1000 0001 0000 1000 = 0x88108
--
--------------------------------------------------------------------------------
--| name | polly equation | polly (hex) | our polly | tested |
--------------------------------------------------------------------------------
--| CRC-16-CCITT | 1+x^5+x^12+x^16 | 0x1021 | 0x88108 | yes |
--| CRC-16-IBM | 1+x^2+x^15+x^16 | 0x8005 | 0xC0028 | yes |
--| CRC-16-DECT | 1+x^3+x^7+x^8+x^10+x^16 | 0x0589 | 0x82C48 | yes |
--| CRC-16-DECT | 1+x^3+x^7+x^8+x^10+x^16 | 0x0589 | 0x82C48 | yes |
--------------------------------------------------------------------------------
*/
static
uint16_t
crc16
(
uint16_t
const
init_crc
,
uint16_t
const
message
)
{
uint32_t
remainder
;
uint32_t
remainder
;
int
bit
;
// Initially, the dividend is the remainder.
...
...
userspace/wrsw_rtud/rtu_hash.h
View file @
2e9542b1
...
...
@@ -6,8 +6,8 @@
*
* Authors: Maciej Lipinski (maciej.lipinski@cern.ch)
*
* Description: Hash function presented below, produces hash which corresponds
* to hash produced by VHDL generated on this page:
* Description: Hash function presented below, produces hash which corresponds
* to hash produced by VHDL generated on this page:
* http://outputlogic.com/
*
* Fixes:
...
...
@@ -34,16 +34,16 @@
/*
Hash polynomials implemented by RTU
---------------------------------------------------------
| name | poly equation | poly (hex) |
| name | poly equation | poly (hex) |
---------------------------------------------------------
| CRC-16-CCITT | 1+x^5+x^12+x^16 | 0x1021 |
| CRC-16-IBM | 1+x^2+x^15+x^16 | 0x8005 |
| CRC-16-DECT | 1+x^3+x^7+x^8+x^10+x^16 | 0x0589 |
---------------------------------------------------------
*/
#define HW_POLYNOMIAL_CCITT 0x1021
#define HW_POLYNOMIAL_IBM 0x8005
#define HW_POLYNOMIAL_DECT 0x0589
#define HW_POLYNOMIAL_CCITT 0x1021
#define HW_POLYNOMIAL_IBM 0x8005
#define HW_POLYNOMIAL_DECT 0x0589
void
rtu_hash_set_poly
(
uint16_t
poly
);
uint16_t
rtu_hash
(
uint8_t
mac
[
ETH_ALEN
],
uint8_t
fid
);
...
...
userspace/wrsw_rtud/rtud.c
View file @
2e9542b1
...
...
@@ -7,14 +7,14 @@
* Authors: Juan Luis Manas (juan.manas@integrasys.es)
* Miguel Baizan (miguel.baizan@integrasys.es)
*
* Description: RTU daemon.
* Handles the learning and aging processes.
* Description: RTU daemon.
* Handles the learning and aging processes.
* Manages the filtering and VLAN databases.
*
* Fixes:
* Fixes:
* Alessandro Rubini
* Tomasz Wlostowski
*
* Tomasz Wlostowski
*
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
...
...
@@ -50,7 +50,7 @@ static pthread_t aging_process;
static
pthread_t
wripc_process
;
/**
* \brief Creates the static entries in the filtering database
* \brief Creates the static entries in the filtering database
* @return error code
*/
static
int
rtu_create_static_entries
()
...
...
@@ -66,7 +66,7 @@ static int rtu_create_static_entries()
err
=
rtu_fd_create_entry
(
bcast_mac
,
0
,
0xffffffff
,
STATIC
);
if
(
err
)
return
err
;
// VLAN-aware Bridge reserved addresses (802.1Q-2005 Table 8.1)
TRACE
(
TRACE_INFO
,
"adding static routes for slow protocols..."
);
for
(
i
=
0
;
i
<
NUM_RESERVED_ADDR
;
i
++
)
{
...
...
@@ -75,16 +75,16 @@ static int rtu_create_static_entries()
if
(
err
)
return
err
;
}
// packets addressed to WR card interfaces are forwarded to NIC virtual port
halexp_query_ports
(
&
plist
);
halexp_query_ports
(
&
plist
);
for
(
i
=
0
;
i
<
plist
.
num_ports
;
i
++
)
{
halexp_get_port_state
(
&
pstate
,
plist
.
port_names
[
i
]);
halexp_get_port_state
(
&
pstate
,
plist
.
port_names
[
i
]);
TRACE
(
TRACE_INFO
,
"adding static route for port %s index %d [mac %s]"
,
plist
.
port_names
[
i
],
pstate
.
hw_index
,
"adding static route for port %s index %d [mac %s]"
,
plist
.
port_names
[
i
],
pstate
.
hw_index
,
mac_to_string
(
pstate
.
hw_addr
)
);
err
=
rtu_fd_create_entry
(
pstate
.
hw_addr
,
0
,
(
1
<<
NIC_PORT
),
STATIC
);
...
...
@@ -122,18 +122,18 @@ static void *rtu_daemon_wripc_process(void *arg)
{
while
(
1
){
rtud_handle_wripc
();
sleep
(
1
);
usleep
(
10000
);
}
return
NULL
;
}
/**
* \brief Handles the learning process.
* \brief Handles the learning process.
* @return error code
*/
static
int
rtu_daemon_learning_process
()
{
int
err
;
int
err
;
struct
rtu_request
req
;
// Request read from learning queue
uint32_t
port_map
;
// Destination port map
uint16_t
vid
;
// VLAN identifier
...
...
@@ -144,8 +144,8 @@ static int rtu_daemon_learning_process()
if
(
!
err
)
{
TRACE_DBG
(
TRACE_INFO
,
"ureq: port %d src %s VID %d priority %d"
,
req
.
port_id
,
"ureq: port %d src %s VID %d priority %d"
,
req
.
port_id
,
mac_to_string
(
req
.
src
),
req
.
has_vid
?
req
.
vid
:
0
,
req
.
has_prio
?
req
.
prio
:
0
...
...
@@ -171,7 +171,7 @@ static int rtu_daemon_learning_process()
/**
* \brief RTU set up.
* \brief RTU set up.
* Initialises routing table cache and RTU at hardware.
* @param poly hash polinomial.
* @param aging_time Aging time in seconds.
...
...
@@ -195,7 +195,6 @@ static int rtu_daemon_init(uint16_t poly, unsigned long aging_time)
TRACE
(
TRACE_INFO
,
"init port config."
);
for
(
i
=
MIN_PORT
;
i
<=
MAX_PORT
;
i
++
)
{
// MIN_PORT <= port <= MAX_PORT, thus no err returned
fprintf
(
stderr
,
"**4**"
);
err
=
rtu_learn_enable_on_port
(
i
,
1
);
err
=
rtu_pass_all_on_port
(
i
,
1
);
...
...
@@ -207,7 +206,7 @@ static int rtu_daemon_init(uint16_t poly, unsigned long aging_time)
// init filtering database
TRACE
(
TRACE_INFO
,
"init fd."
);
err
=
rtu_fd_init
(
poly
,
aging_time
);
if
(
err
)
if
(
err
)
return
err
;
// create static filtering entries
...
...
@@ -228,7 +227,7 @@ static int rtu_daemon_init(uint16_t poly, unsigned long aging_time)
* \brief RTU shutdown.
*/
static
void
rtu_daemon_destroy
()
{
{
// Threads stuff
pthread_cancel
(
wripc_process
);
pthread_cancel
(
aging_process
);
...
...
@@ -245,11 +244,11 @@ void sigint(int signum) {
/**
* \brief Starts up the learning and aging processes.
*/
*/
int
main
(
int
argc
,
char
**
argv
)
{
int
op
,
err
;
char
*
s
,
*
name
,
*
optstring
;
char
*
s
,
*
name
,
*
optstring
;
int
run_as_daemon
=
0
;
uint16_t
poly
=
HW_POLYNOMIAL_CCITT
;
// Hash polinomial
unsigned
long
aging_res
=
DEFAULT_AGING_RES
;
// Aging resolution [sec.]
...
...
@@ -272,7 +271,7 @@ int main(int argc, char **argv)
run_as_daemon
=
1
;
break
;
case
'h'
:
usage
(
name
);
usage
(
name
);
case
'p'
:
if
(
strcmp
(
optarg
,
"CCITT"
)
==
0
)
{
poly
=
HW_POLYNOMIAL_CCITT
;
...
...
@@ -293,7 +292,7 @@ int main(int argc, char **argv)
break
;
case
't'
:
aging_time
=
atol
(
optarg
);
if
((
aging_time
<
MIN_AGING_TIME
)
||
if
((
aging_time
<
MIN_AGING_TIME
)
||
(
aging_time
>
MAX_AGING_TIME
))
{
fprintf
(
stderr
,
"Invalid aging time
\n
"
);
usage
(
name
);
...
...
@@ -305,7 +304,7 @@ int main(int argc, char **argv)
}
}
// Initialise RTU.
// Initialise RTU.
if
((
err
=
rtu_daemon_init
(
poly
,
aging_time
))
<
0
)
{
rtu_daemon_destroy
();
return
err
;
...
...
@@ -315,7 +314,7 @@ int main(int argc, char **argv)
signal
(
SIGINT
,
sigint
);
// daemonize _before_ creating threads
if
(
run_as_daemon
)
if
(
run_as_daemon
)
daemonize
();
// Start up aging process and auxiliary WRIPC thread
...
...
@@ -324,7 +323,7 @@ int main(int argc, char **argv)
rtu_daemon_destroy
();
return
err
;
}
// Start up learning process.
err
=
rtu_daemon_learning_process
();
// On error, release RTU resources
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment