Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
S
Simple PCIe FMC carrier SPEC - Software
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
3
Issues
3
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
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
Simple PCIe FMC carrier SPEC - Software
Commits
18dcb14a
Commit
18dcb14a
authored
Apr 01, 2019
by
Miguel Jimenez Lopez
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Merge changes from "adam-wr-nic-rebased" branch.
parent
36f70fe4
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
298 additions
and
91 deletions
+298
-91
spec-sw.in
doc/spec-sw.in
+7
-0
Kbuild
kernel/Kbuild
+1
-0
device.c
kernel/wr_nic/device.c
+47
-35
endpoint.c
kernel/wr_nic/endpoint.c
+88
-32
nic-core.c
kernel/wr_nic/nic-core.c
+85
-20
nic-hardware.h
kernel/wr_nic/nic-hardware.h
+59
-3
wr-nic.h
kernel/wr_nic/wr-nic.h
+11
-1
No files found.
doc/spec-sw.in
View file @
18dcb14a
...
...
@@ -659,6 +659,10 @@ The module receives the following parameters:
The name of the LM32 program to load, if any. There is no support
currently to load different LM32 programs to different cards.
@item macaddr=
Use given MAC address. If not provided or 0 read MAC from LM32.
@end table
@c ==========================================================================
...
...
@@ -743,6 +747,9 @@ following:
ifconfig wr0 hw ether 12:34:56:78:9a:bc
@end example
MAC address can also be set by using @code
{
macaddr=
}
parameter
at load of @i
{
wr-nic
}
kernel module.
The fiber controlled by the SPEC can carry normal data traffic in
addition to the PTP frames of @i
{
White Rabbit
}
, that remain
invisible to the host computer. The
...
...
kernel/Kbuild
View file @
18dcb14a
...
...
@@ -18,6 +18,7 @@ LINUXINCLUDE := -I$(FMC_BUS_ABS)/kernel/include -I$(src)/include/linux $(LINUXI
ccflags-y += -I$(src)/include
ccflags-y += $(WR_NIC_CFLAGS)
ccflags-y += -DGIT_VERSION=\"$(GIT_VERSION)\"
ccflags-y += -DWR_NODE
# this is a bad hack. Sometimes we are a submodule, and wr-nic can
...
...
kernel/wr_nic/device.c
View file @
18dcb14a
...
...
@@ -23,20 +23,27 @@
#include "wr-nic.h"
#include "nic-mem.h"
#if WR_IS_NODE
#include "../spec-nic.h"
#endif
/* The remove function is used by probe, so it's not __devexit */
static
int
wrn_remove
(
struct
platform_device
*
pdev
)
{
#if WR_IS_NODE
struct
wrn_drvdata
*
drvdata
=
pdev
->
dev
.
platform_data
;
struct
wrn_dev
*
wrn
=
drvdata
->
wrn
;
#endif
#if WR_IS_SWITCH
struct
wrn_dev
*
wrn
=
pdev
->
dev
.
platform_data
;
#endif
int
i
;
#if 0
spin_lock(&wrn->lock);
--wrn->use_count; /* Hmmm... looks like overkill... */
spin_unlock(&wrn->lock);
#endif
if
(
WR_IS_SWITCH
)
{
spin_lock
(
&
wrn
->
lock
);
--
wrn
->
use_count
;
/* Hmmm... looks like overkill... */
spin_unlock
(
&
wrn
->
lock
);
}
/* First of all, stop any transmission */
writel
(
0
,
&
wrn
->
regs
->
CR
);
...
...
@@ -59,7 +66,6 @@ static int wrn_remove(struct platform_device *pdev)
/* Unregister all interrupts that were registered */
for
(
i
=
0
;
wrn
->
irq_registered
;
i
++
)
{
static
int
irqs
[]
=
WRN_IRQ_NUMBERS
;
if
(
wrn
->
irq_registered
&
(
1
<<
i
))
free_irq
(
irqs
[
i
],
wrn
);
wrn
->
irq_registered
&=
~
(
1
<<
i
);
...
...
@@ -73,9 +79,13 @@ static int __wrn_map_resources(struct platform_device *pdev)
int
i
;
struct
resource
*
res
;
void
__iomem
*
ptr
;
#if WR_IS_NODE
struct
wrn_drvdata
*
drvdata
=
pdev
->
dev
.
platform_data
;
struct
wrn_dev
*
wrn
=
drvdata
->
wrn
;
#endif
#if WR_IS_SWITCH
struct
wrn_dev
*
wrn
=
pdev
->
dev
.
platform_data
;
#endif
/*
* The memory regions are mapped once for all endpoints.
* We don't populate the whole array, but use the resource list
...
...
@@ -86,13 +96,13 @@ static int __wrn_map_resources(struct platform_device *pdev)
continue
;
ptr
=
ioremap
(
res
->
start
,
res
->
end
+
1
-
res
->
start
);
if
(
!
ptr
)
{
dev_err
(
&
pdev
->
dev
,
"Remap for res %i (%
08lx
) failed
\n
"
,
i
,
(
long
)
res
->
start
);
dev_err
(
&
pdev
->
dev
,
"Remap for res %i (%
pa
) failed
\n
"
,
i
,
(
void
*
)
res
->
start
);
return
-
ENOMEM
;
}
/* Hack: find the block number and fill the array */
pr_debug
(
"Remapped %
08lx
(block %i) to %p
\n
"
,
(
long
)
res
->
start
,
i
,
ptr
);
pr_debug
(
"Remapped %
pa
(block %i) to %p
\n
"
,
(
void
*
)
res
->
start
,
i
,
ptr
);
wrn
->
bases
[
i
]
=
ptr
;
}
return
0
;
...
...
@@ -102,32 +112,35 @@ static int wrn_probe(struct platform_device *pdev)
{
struct
net_device
*
netdev
;
struct
wrn_ep
*
ep
;
#if WR_IS_NODE
struct
wrn_drvdata
*
drvdata
=
pdev
->
dev
.
platform_data
;
struct
wrn_dev
*
wrn
=
drvdata
->
wrn
;
#endif
#if WR_IS_SWITCH
struct
wrn_dev
*
wrn
=
pdev
->
dev
.
platform_data
;
#endif
int
i
,
err
=
0
;
#if 0
/* Lazily: irqs are not in the resource list */
static
int
irqs
[]
=
WRN_IRQ_NUMBERS
;
static
char
*
irq_names
[]
=
WRN_IRQ_NAMES
;
static
irq_handler_t
irq_handlers
[]
=
WRN_IRQ_HANDLERS
;
#endif
/* No need to lock_irq: we only protect count and continue unlocked */
#if 0
spin_lock(&wrn->lock);
if (++wrn->use_count != 1) {
--wrn->use_count;
if
(
WR_IS_SWITCH
)
{
spin_lock
(
&
wrn
->
lock
);
if
(
++
wrn
->
use_count
!=
1
)
{
--
wrn
->
use_count
;
spin_unlock
(
&
wrn
->
lock
);
return
-
EBUSY
;
}
spin_unlock
(
&
wrn
->
lock
);
dev_err
(
&
pdev
->
dev
,
"use count %i
\n
"
,
wrn
->
use_count
);
return
-
EBUSY
;
}
spin_unlock(&wrn->lock);
#endif
/* Map our resource list and instantiate the shortcut pointers */
err
=
__wrn_map_resources
(
pdev
);
if
(
err
)
if
(
(
err
=
__wrn_map_resources
(
pdev
))
)
goto
out
;
wrn
->
regs
=
wrn
->
bases
[
WRN_FB_NIC
];
wrn
->
txtsu_regs
=
wrn
->
bases
[
WRN_FB_TS
];
...
...
@@ -140,16 +153,16 @@ static int wrn_probe(struct platform_device *pdev)
dev_info
(
&
pdev
->
dev
,
"regs %p, txd %p, rxd %p, buffer %p
\n
"
,
wrn
->
regs
,
wrn
->
txd
,
wrn
->
rxd
,
wrn
->
databuf
);
#if 0
/* Register the interrupt handlers (not shared) */
for (i = 0; i < ARRAY_SIZE(irq_names); i++) {
err = request_irq(irqs[i], irq_handlers[i],
IRQF_TRIGGER_LOW, irq_names[i], wrn);
if (err)
goto out
;
wrn->irq_registered |= 1 << i;
if
(
WR_IS_SWITCH
)
{
/* Register the interrupt handlers (not shared) */
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
irq_names
);
i
++
)
{
err
=
request_irq
(
irqs
[
i
],
irq_handlers
[
i
],
IRQF_TRIGGER_LOW
,
irq_names
[
i
],
wrn
);
if
(
err
)
goto
out
;
wrn
->
irq_registered
|=
1
<<
i
;
}
}
#endif
/* Reset the device, just to be sure, before making anything */
writel
(
0
,
&
wrn
->
regs
->
CR
);
mdelay
(
10
);
...
...
@@ -184,15 +197,14 @@ static int wrn_probe(struct platform_device *pdev)
wrn
->
dev
[
i
]
=
netdev
;
err
=
wrn_mezzanine_init
(
netdev
);
if
(
err
)
dev_err
(
&
pdev
->
dev
,
"
Init mezzanine code:
error %i
\n
"
,
err
);
dev_err
(
&
pdev
->
dev
,
"Init mezzanine code: "
"error %i
\n
"
,
err
);
}
if
(
i
==
0
)
return
-
ENODEV
;
/* no endpoints */
for
(
i
=
0
;
i
<
WRN_NR_TXDESC
;
i
++
)
{
/* Clear all tx descriptors */
struct
wrn_txd
*
tx
;
tx
=
wrn
->
txd
+
i
;
writel
(
0
,
&
tx
->
tx1
);
}
...
...
@@ -204,7 +216,7 @@ static int wrn_probe(struct platform_device *pdev)
rx
=
wrn
->
rxd
+
i
;
offset
=
__wrn_desc_offset
(
wrn
,
WRN_DDIR_RX
,
i
);
writel
((
2000
<<
16
)
|
offset
,
&
rx
->
rx3
);
writel
(
(
2000
<<
16
)
|
offset
,
&
rx
->
rx3
);
writel
(
NIC_RX1_D1_EMPTY
,
&
rx
->
rx1
);
}
...
...
kernel/wr_nic/endpoint.c
View file @
18dcb14a
...
...
@@ -16,9 +16,37 @@
#include <linux/errno.h>
#include <linux/etherdevice.h>
#include <linux/io.h>
#include <linux/moduleparam.h>
#include "wr-nic.h"
static
char
*
macaddr
=
"00:00:00:00:00:00"
;
module_param
(
macaddr
,
charp
,
0444
);
/* Copied from kernel 3.6 net/utils.c, it converts from MAC string to u8 array */
__weak
int
mac_pton
(
const
char
*
s
,
u8
*
mac
)
{
int
i
;
/* XX:XX:XX:XX:XX:XX */
if
(
strlen
(
s
)
<
3
*
ETH_ALEN
-
1
)
return
0
;
/* Don't dirty result unless string is valid MAC. */
for
(
i
=
0
;
i
<
ETH_ALEN
;
i
++
)
{
if
(
!
strchr
(
"0123456789abcdefABCDEF"
,
s
[
i
*
3
]))
return
0
;
if
(
!
strchr
(
"0123456789abcdefABCDEF"
,
s
[
i
*
3
+
1
]))
return
0
;
if
(
i
!=
ETH_ALEN
-
1
&&
s
[
i
*
3
+
2
]
!=
':'
)
return
0
;
}
for
(
i
=
0
;
i
<
ETH_ALEN
;
i
++
)
{
mac
[
i
]
=
(
hex_to_bin
(
s
[
i
*
3
])
<<
4
)
|
hex_to_bin
(
s
[
i
*
3
+
1
]);
}
return
1
;
}
/*
* Phy access: used by link status, enable, calibration ioctl etc.
* Called with endpoint lock (you'll lock the whole sequence of r/w)
...
...
@@ -28,7 +56,7 @@ int wrn_phy_read(struct net_device *dev, int phy_id, int location)
struct
wrn_ep
*
ep
=
netdev_priv
(
dev
);
u32
val
;
if
(
1
)
{
if
(
WR_IS_NODE
)
{
/*
* We cannot access the phy from Linux, because the phy
* is managed by the lm32 core. However, network manager
...
...
@@ -39,7 +67,7 @@ int wrn_phy_read(struct net_device *dev, int phy_id, int location)
}
wrn_ep_write
(
ep
,
MDIO_CR
,
EP_MDIO_CR_ADDR_W
(
location
));
while
(
(
wrn_ep_read
(
ep
,
MDIO_ASR
)
&
EP_MDIO_ASR_READY
)
==
0
)
while
(
(
wrn_ep_read
(
ep
,
MDIO_ASR
)
&
EP_MDIO_ASR_READY
)
==
0
)
;
val
=
wrn_ep_read
(
ep
,
MDIO_ASR
);
/* mask from wbgen macros */
...
...
@@ -51,7 +79,7 @@ void wrn_phy_write(struct net_device *dev, int phy_id, int location,
{
struct
wrn_ep
*
ep
=
netdev_priv
(
dev
);
if
(
1
)
{
if
(
WR_IS_NODE
)
{
/*
* We cannot access the phy from Linux, because the phy
* is managed by the lm32 core. However, network manager
...
...
@@ -65,7 +93,7 @@ void wrn_phy_write(struct net_device *dev, int phy_id, int location,
EP_MDIO_CR_ADDR_W
(
location
)
|
EP_MDIO_CR_DATA_W
(
value
)
|
EP_MDIO_CR_RW
);
while
(
(
wrn_ep_read
(
ep
,
MDIO_ASR
)
&
EP_MDIO_ASR_READY
)
==
0
)
while
(
(
wrn_ep_read
(
ep
,
MDIO_ASR
)
&
EP_MDIO_ASR_READY
)
==
0
)
;
}
...
...
@@ -83,7 +111,7 @@ static void wrn_update_link_status(struct net_device *dev)
/* Link wnt down? */
if
(
!
mii_link_ok
(
&
ep
->
mii
))
{
if
(
netif_carrier_ok
(
dev
))
{
if
(
netif_carrier_ok
(
dev
))
{
netif_carrier_off
(
dev
);
clear_bit
(
WRN_EP_UP
,
&
ep
->
ep_flags
);
netdev_info
(
dev
,
"Link down.
\n
"
);
...
...
@@ -93,7 +121,7 @@ static void wrn_update_link_status(struct net_device *dev)
}
/* Currently the link is active */
if
(
netif_carrier_ok
(
dev
))
{
if
(
netif_carrier_ok
(
dev
))
{
/* Software already knows it's up */
return
;
}
...
...
@@ -110,7 +138,7 @@ static void wrn_update_link_status(struct net_device *dev)
if
(
0
)
{
/* was commented in minic */
wrn_ep_write
(
ep
,
FCR
,
EP_FCR_TXPAUSE
|
EP_FCR_RXPAUSE
EP_FCR_TXPAUSE
|
EP_FCR_RXPAUSE
|
EP_FCR_TX_THR_W
(
128
)
|
EP_FCR_TX_QUANTA_W
(
200
));
}
...
...
@@ -126,7 +154,7 @@ static void wrn_update_link_status(struct net_device *dev)
/* reset RMON counters */
ecr
=
wrn_ep_read
(
ep
,
ECR
);
wrn_ep_write
(
ep
,
ECR
,
ecr
|
EP_ECR_RST_CNT
);
wrn_ep_write
(
ep
,
ECR
,
ecr
);
wrn_ep_write
(
ep
,
ECR
,
ecr
);
}
/* Actual timer function. Takes the lock and calls above function */
...
...
@@ -157,8 +185,9 @@ int wrn_ep_open(struct net_device *dev)
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)
unsigned
long
timerarg
=
(
unsigned
long
)
dev
;
#endif
int
prio
,
prio_map
;
if
(
1
)
{
if
(
WR_IS_NODE
)
{
netif_carrier_on
(
dev
);
return
0
;
/* No access to EP registers in the SPEC */
}
...
...
@@ -169,12 +198,20 @@ int wrn_ep_open(struct net_device *dev)
|
EP_VCR0_PRIO_VAL_W
(
4
),
/* some mid priority */
&
ep
->
ep_regs
->
VCR0
);
/* Write default 802.1Q tag priority to traffic class mapping */
prio_map
=
0
;
for
(
prio
=
0
;
prio
<
8
;
++
prio
)
{
prio_map
|=
(
0x7
&
prio
)
<<
(
prio
*
3
);
}
writel
(
prio_map
,
&
ep
->
ep_regs
->
TCAR
);
/*
* enable RX timestamping (it has no impact on performance)
* and we need the RX OOB block to identify orginating endpoints
* for RXed packets -- Tom
*/
writel
(
EP_TSCR_EN_TXTS
|
EP_TSCR_EN_RXTS
,
&
ep
->
ep_regs
->
TSCR
);
writel
(
EP_TSCR_EN_TXTS
|
EP_TSCR_EN_RXTS
,
&
ep
->
ep_regs
->
TSCR
);
writel
(
0
|
EP_ECR_PORTID_W
(
ep
->
ep_number
)
...
...
@@ -189,16 +226,10 @@ int wrn_ep_open(struct net_device *dev)
/* Prepare the timer for link-up notifications */
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)
setup_timer
(
&
ep
->
ep_link_timer
,
wrn_ep_check_link
,
timerarg
);
#else
timer_setup
(
&
ep
->
ep_link_timer
,
wrn_ep_check_link
,
0
);
#endif
if
(
0
)
{
/* not on spec */
mod_timer
(
&
ep
->
ep_link_timer
,
jiffies
+
WRN_LINK_POLL_INTERVAL
);
}
else
{
/* Assume it's already on */
netif_carrier_on
(
dev
);
}
/* Not on spec. On spec this part of the function is never reached
* due to return in if(WR_IS_NODE) */
mod_timer
(
&
ep
->
ep_link_timer
,
jiffies
+
WRN_LINK_POLL_INTERVAL
);
return
0
;
}
...
...
@@ -206,11 +237,11 @@ int wrn_ep_close(struct net_device *dev)
{
struct
wrn_ep
*
ep
=
netdev_priv
(
dev
);
if
(
1
)
if
(
WR_IS_NODE
)
return
0
;
/* No access to EP registers in the SPEC */
/*
* Beware: the system loops in the del_timer_sync below if timer_setup
* had not been called either (see "if (
1)"
in ep_open above)
* had not been called either (see "if (
WR_IS_NODE)"
in ep_open above)
*/
writel
(
0
,
&
ep
->
ep_regs
->
ECR
);
...
...
@@ -234,10 +265,41 @@ int wrn_endpoint_probe(struct net_device *dev)
{
struct
wrn_ep
*
ep
=
netdev_priv
(
dev
);
int
epnum
,
err
;
static
u8
wraddr
[
6
];
u32
val
;
epnum
=
ep
->
ep_number
;
if
(
WR_IS_NODE
)
{
/* If address is not provided as parameter read from lm32 */
if
(
is_zero_ether_addr
(
wraddr
))
{
/* on the SPEC the lm32 already configured the mac address */
val
=
readl
(
&
ep
->
ep_regs
->
MACH
);
put_unaligned_be16
(
val
,
wraddr
);
val
=
readl
(
&
ep
->
ep_regs
->
MACL
);
put_unaligned_be32
(
val
,
wraddr
+
2
);
}
}
if
(
WR_IS_SWITCH
)
{
/* If the MAC address is 0, then randomize the first MAC */
/* Do not randomize for SPEC */
if
(
is_zero_ether_addr
(
wraddr
))
{
pr_warn
(
"wr_nic: missing MAC address, randomize
\n
"
);
/* randomize a MAC address, so lazy users can avoid ifconfig */
random_ether_addr
(
wraddr
);
/* Clear the MSB on fourth octect to prevent bit overflow on OUI */
wraddr
[
3
]
&=
0x7F
;
}
}
if
(
ep
->
ep_number
==
0
)
pr_info
(
"WR-nic: Using address %pM
\n
"
,
wraddr
);
/* Use wraddr as MAC */
memcpy
(
dev
->
dev_addr
,
wraddr
,
ETH_ALEN
);
pr_debug
(
"wr_nic: assign MAC %pM to wr%d
\n
"
,
dev
->
dev_addr
,
ep
->
ep_number
);
/* Check whether the ep has been sinthetized or not */
val
=
readl
(
&
ep
->
ep_regs
->
IDCODE
);
if
(
val
!=
WRN_EP_MAGIC
)
{
...
...
@@ -265,6 +327,11 @@ int wrn_endpoint_probe(struct net_device *dev)
/* Finally, register and succeed, or fail and undo */
err
=
register_netdev
(
dev
);
/* Increment MAC address for next endpoint */
val
=
get_unaligned_be32
(
wraddr
+
2
);
put_unaligned_be32
(
val
+
1
,
wraddr
+
2
);
if
(
err
)
{
netdev_err
(
dev
,
"Can't register device
\n
"
);
__wrn_endpoint_shutdown
(
ep
);
...
...
@@ -272,17 +339,6 @@ int wrn_endpoint_probe(struct net_device *dev)
return
err
==
-
ENODEV
?
-
EIO
:
err
;
}
if
(
0
)
{
/* randomize a MAC address, so lazy users can avoid ifconfig */
random_ether_addr
(
dev
->
dev_addr
);
}
else
{
/* on the SPEC the lm32 already configured the mac address */
val
=
readl
(
&
ep
->
ep_regs
->
MACH
);
put_unaligned_be16
(
val
,
dev
->
dev_addr
);
val
=
readl
(
&
ep
->
ep_regs
->
MACL
);
put_unaligned_be32
(
val
,
dev
->
dev_addr
+
2
);
}
return
0
;
}
...
...
kernel/wr_nic/nic-core.c
View file @
18dcb14a
...
...
@@ -21,6 +21,9 @@
#include <asm/unaligned.h>
#include "wr-nic.h"
#if WR_IS_SWITCH
#include "wr_pstats.h"
#endif
#include "nic-mem.h"
#undef WRN_TRANS_UPDATE
...
...
@@ -72,6 +75,14 @@ static int wrn_open(struct net_device *dev)
if
(
!
is_valid_ether_addr
(
dev
->
dev_addr
))
return
-
EADDRNOTAVAIL
;
if
(
WR_IS_SWITCH
)
{
/* MACH gets the first two bytes, MACL the rest */
val
=
get_unaligned_be16
(
dev
->
dev_addr
);
writel
(
val
,
&
ep
->
ep_regs
->
MACH
);
val
=
get_unaligned_be32
(
dev
->
dev_addr
+
2
);
writel
(
val
,
&
ep
->
ep_regs
->
MACL
);
}
/* Mark it as down, and start the ep-specific polling timer */
clear_bit
(
WRN_EP_UP
,
&
ep
->
ep_flags
);
wrn_ep_open
(
dev
);
...
...
@@ -89,7 +100,7 @@ static int wrn_open(struct net_device *dev)
* malformed packets
*/
val
=
readl
(
&
ep
->
ep_regs
->
RFCR
)
&
~
EP_RFCR_MRU_MASK
;
writel
(
val
|
EP_RFCR_MRU_W
(
2048
),
&
ep
->
ep_regs
->
RFCR
);
writel
(
val
|
EP_RFCR_MRU_W
(
2048
),
&
ep
->
ep_regs
->
RFCR
);
/* Most drivers call platform_set_drvdata() but we don't need it */
return
0
;
...
...
@@ -100,8 +111,7 @@ static int wrn_close(struct net_device *dev)
struct
wrn_ep
*
ep
=
netdev_priv
(
dev
);
int
ret
;
ret
=
wrn_ep_close
(
dev
);
if
(
ret
)
if
(
(
ret
=
wrn_ep_close
(
dev
))
)
return
ret
;
/* FIXME: software-only fixing at close time */
...
...
@@ -111,7 +121,7 @@ static int wrn_close(struct net_device *dev)
return
0
;
}
static
int
wrn_set_mac_address
(
struct
net_device
*
dev
,
void
*
vaddr
)
static
int
wrn_set_mac_address
(
struct
net_device
*
dev
,
void
*
vaddr
)
{
struct
wrn_ep
*
ep
=
netdev_priv
(
dev
);
struct
sockaddr
*
addr
=
vaddr
;
...
...
@@ -193,7 +203,7 @@ static int wrn_start_xmit(struct sk_buff *skb, struct net_device *dev)
struct
wrn_ep
*
ep
=
netdev_priv
(
dev
);
struct
wrn_dev
*
wrn
=
ep
->
wrn
;
struct
skb_shared_info
*
info
=
skb_shinfo
(
skb
);
//
unsigned long flags;
unsigned
long
flags
;
int
desc
;
int
id
;
int
do_stamp
=
0
;
...
...
@@ -207,13 +217,23 @@ static int wrn_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
/* Allocate a descriptor and id (start from last allocated) */
//spin_lock_irqsave(&wrn->lock, flags);
if
(
WR_IS_SWITCH
){
spin_lock_irqsave
(
&
wrn
->
lock
,
flags
);
}
desc
=
__wrn_alloc_tx_desc
(
wrn
);
id
=
(
wrn
->
id
++
)
&
0xffff
;
if
(
id
==
0
)
id
=
wrn
->
id
++
;
/* 0 cannot be used in the SPEC */
//spin_unlock_irqrestore(&wrn->lock, flags);
if
(
WR_IS_SWITCH
){
spin_unlock_irqrestore
(
&
wrn
->
lock
,
flags
);
}
if
(
WR_IS_NODE
){
if
(
id
==
0
)
id
=
wrn
->
id
++
;
/* 0 cannot be used in the SPEC */
}
if
(
desc
<
0
)
/* error */
return
desc
;
...
...
@@ -249,13 +269,50 @@ static int wrn_start_xmit(struct sk_buff *skb, struct net_device *dev)
return
0
;
}
#if WR_IS_SWITCH
int
(
*
wr_nic_pstats_callback
)(
int
epnum
,
unsigned
int
ctr
[
PSTATS_CNT_PP
]);
EXPORT_SYMBOL
(
wr_nic_pstats_callback
);
static
unsigned
int
nic_counters
[
PSTATS_CNT_PP
];
static
DEFINE_SPINLOCK
(
nic_counters_lock
);
#endif
struct
net_device_stats
*
wrn_get_stats
(
struct
net_device
*
dev
)
{
struct
wrn_ep
*
ep
=
netdev_priv
(
dev
);
/* FIXME: we should get the RMON information from endpoint */
#if WR_IS_SWITCH
if
(
wr_nic_pstats_callback
)
{
int
i
;
spin_lock
(
&
nic_counters_lock
);
wr_nic_pstats_callback
(
ep
->
ep_number
,
nic_counters
);
if
(
0
)
{
/* A stupid diagnostics, happens oh so often... */
printk
(
KERN_INFO
"counters for %i:"
,
ep
->
ep_number
);
for
(
i
=
0
;
i
<
PSTATS_CNT_PP
;
i
++
)
printk
(
KERN_CONT
" %u"
,
nic_counters
[
i
]);
printk
(
KERN_CONT
"
\n
"
);
}
else
{
/* Recover values in the kernel structure */
ep
->
stats
.
rx_packets
=
nic_counters
[
PSTATS_C_R_FRAME
];
ep
->
stats
.
tx_packets
=
nic_counters
[
PSTATS_C_T_FRAME
];
ep
->
stats
.
rx_length_errors
=
nic_counters
[
PSTATS_C_R_GIANT
];
ep
->
stats
.
rx_crc_errors
=
nic_counters
[
PSTATS_C_R_CRC_ERROR
];
ep
->
stats
.
rx_fifo_errors
=
nic_counters
[
PSTATS_C_R_OVERRUN
];
ep
->
stats
.
tx_fifo_errors
=
nic_counters
[
PSTATS_C_T_UNDERRUN
];
}
spin_unlock
(
&
nic_counters_lock
);
}
#endif
return
&
ep
->
stats
;
return
NULL
;
}
/*
...
...
@@ -275,6 +332,7 @@ int __weak wrn_mezzanine_init(struct net_device *dev)
void
__weak
wrn_mezzanine_exit
(
struct
net_device
*
dev
)
{
return
;
}
...
...
@@ -407,35 +465,42 @@ static void __wrn_rx_descriptor(struct wrn_dev *wrn, int desc)
__wrn_copy_in
(
skb_put
(
skb
,
len
),
wrn
->
databuf
+
off
,
len
);
/* Rewrite lenght (modified during rx) and mark it free ASAP */
writel
((
2000
<<
16
)
|
offset
,
&
rx
->
rx3
);
writel
(
(
2000
<<
16
)
|
offset
,
&
rx
->
rx3
);
writel
(
NIC_RX1_D1_EMPTY
,
&
rx
->
rx1
);
/* RX timestamping part */
wrn_ppsg_read_time
(
wrn
,
&
counter_ppsg
,
&
utc
);
if
(
counter_ppsg
<
ts_r
)
utc
--
;
if
(
WR_IS_NODE
)
if
(
counter_ppsg
<
ts_r
)
utc
--
;
if
(
WR_IS_SWITCH
)
if
(
counter_ppsg
<
REFCLK_FREQ
/
4
&&
ts_r
>
3
*
REFCLK_FREQ
/
4
)
utc
--
;
ts
.
tv_sec
=
(
s32
)
utc
&
0x7fffffff
;
cntr_diff
=
(
ts_r
&
0xf
)
-
ts_f
;
/* the bit says the rising edge cnter is 1tick ahead */
if
(
cntr_diff
==
1
||
cntr_diff
==
(
-
0xf
))
if
(
cntr_diff
==
1
||
cntr_diff
==
(
-
0xf
))
ts
.
tv_sec
|=
0x80000000
;
ts
.
tv_nsec
=
ts_r
*
NSEC_PER_TICK
;
pr_debug
(
"Timestamp: %li:%li, ahead = %d
\n
"
,
ts
.
tv_sec
&
0x7fffffff
,
ts
.
tv_nsec
&
0x7fffffff
,
ts
.
tv_sec
&
0x80000000
?
1
:
0
);
ts
.
tv_sec
&
0x7fffffff
,
ts
.
tv_nsec
&
0x7fffffff
,
ts
.
tv_sec
&
0x80000000
?
1
:
0
);
if
(
1
)
{
if
(
WR_IS_NODE
)
{
/* SPEC: don't do the strange stuff for wr-ptp */
ts
.
tv_sec
&=
~
0x80000000
;
ts
.
tv_nsec
&=
0x7fffffff
;
}
if
(
!
(
r1
&
NIC_RX1_D1_TS_INCORRECT
))
{
/* If the timestamp was reported as incorrect, pass 0 instead */
if
(
!
(
r1
&
NIC_RX1_D1_TS_INCORRECT
))
/* FIXME: bit name possibly? */
{
hwts
=
skb_hwtstamps
(
skb
);
hwts
->
hwtstamp
=
timespec_to_ktime
(
ts
);
}
...
...
@@ -449,7 +514,7 @@ static void __wrn_rx_descriptor(struct wrn_dev *wrn, int desc)
return
;
err_out:
/* Mark it free anyways -- with its full length */
writel
((
2000
<<
16
)
|
offset
,
&
rx
->
rx3
);
writel
(
(
2000
<<
16
)
|
offset
,
&
rx
->
rx3
);
writel
(
NIC_RX1_D1_EMPTY
,
&
rx
->
rx1
);
/* account the error to endpoint 0 -- we don't know who it is */
...
...
@@ -490,7 +555,7 @@ static void wrn_tx_interrupt(struct wrn_dev *wrn)
int
i
;
/* Loop using our tail until one is not sent */
while
((
i
=
wrn
->
next_tx_tail
)
!=
wrn
->
next_tx_head
)
{
while
(
(
i
=
wrn
->
next_tx_tail
)
!=
wrn
->
next_tx_head
)
{
/* Check if this is txdone */
tx
=
wrn
->
txd
+
i
;
reg
=
readl
(
&
tx
->
tx1
);
...
...
kernel/wr_nic/nic-hardware.h
View file @
18dcb14a
/*
* hardware-specific definitions for the White Rabbit NIC
*
* Copyright (C) 2010-201
2
CERN (www.cern.ch)
* Copyright (C) 2010-201
4
CERN (www.cern.ch)
* Author: Alessandro Rubini <rubini@gnudd.com>
*
* This program is free software; you can redistribute it and/or modify
...
...
@@ -10,7 +10,56 @@
*/
#ifndef __WR_NIC_HARDWARE_H__
#define __WR_NIC_HARDWARE_H__
#if (!defined WR_IS_NODE) && (!defined WR_IS_SWITCH)
#error "WR_NODE and WR_SWITCH not defined!"
#endif
#if WR_IS_SWITCH
/* This is the clock used in internal counters. */
#define REFCLK_FREQ (125000000 / 2)
#define NSEC_PER_TICK (NSEC_PER_SEC / REFCLK_FREQ)
/* The interrupt is one of those managed by our WRVIC device */
#define WRN_IRQ_BASE 192
#define WRN_IRQ_NIC (WRN_IRQ_BASE + 0)
#define WRN_IRQ_TSTAMP (WRN_IRQ_BASE + 1)
//#define WRN_IRQ_PPSG (WRN_IRQ_BASE + )
//#define WRN_IRQ_RTU (WRN_IRQ_BASE + )
//#define WRN_IRQ_RTUT (WRN_IRQ_BASE + )
/*
* V3 Memory map, temporarily (Jan 2012)
*
* 0x00000 - 0x1ffff: RT Subsystem
* 0x00000 - 0x0ffff: RT Subsystem Program Memory (16 - 64 kB)
* 0x10000 - 0x100ff: RT Subsystem UART
* 0x10100 - 0x101ff: RT Subsystem SoftPLL-adv
* 0x10200 - 0x102ff: RT Subsystem SPI Master
* 0x10300 - 0x103ff: RT Subsystem GPIO
* 0x10500 - 0x105ff: PPS gen
* 0x20000 - 0x3ffff: NIC
* 0x20000 - 0x20fff NIC control regs and descriptor area
* 0x28000 - 0x2bfff NIC packet buffer (16k)
* 0x30000 - 0x4ffff: Endpoints
* 0x30000 + N * 0x400 Endpoint N control registers
* 0x50000 - 0x50fff: VIC
* 0x51000 - 0x51fff: Tstamp unit
*/
/* This is the base address of all the FPGA regions (EBI1, CS0) */
#define FPGA_BASE_PPSG 0x10010500
#define FPGA_SIZE_PPSG 0x00000100
#define FPGA_BASE_NIC 0x10020000
#define FPGA_SIZE_NIC 0x00010000
#define FPGA_BASE_EP 0x10030000
#define FPGA_SIZE_EP 0x00010000
#define FPGA_SIZE_EACH_EP 0x400
#define FPGA_BASE_VIC 0x10050000
/* not used here */
#define FPGA_SIZE_VIC 0x00001000
#define FPGA_BASE_TS 0x10051000
#define FPGA_SIZE_TS 0x00001000
#endif
/* WR_IS_SWITCH */
#if WR_IS_NODE
/* This is the clock used in internal counters. */
#define REFCLK_FREQ (125000000)
#define NSEC_PER_TICK (NSEC_PER_SEC / REFCLK_FREQ)
...
...
@@ -70,6 +119,8 @@
#define FPGA_SIZE_VIC 0x00000100
#define FPGA_BASE_TS 0x00061000
#define FPGA_SIZE_TS 0x0000 100
#endif
/* ifdef WR_IS_NODE */
enum
fpga_blocks
{
WRN_FB_NIC
,
...
...
@@ -80,14 +131,19 @@ enum fpga_blocks {
};
/* In addition to the above enumeration, we scan for those many endpoints */
#define WRN_NR_ENDPOINTS 1
#if WR_IS_NODE
# define WRN_NR_ENDPOINTS 1
#endif
#if WR_IS_SWITCH
# define WRN_NR_ENDPOINTS 18
#endif
/* 8 tx and 8 rx descriptors */
#define WRN_NR_DESC 8
#define WRN_NR_TXDESC WRN_NR_DESC
#define WRN_NR_RXDESC WRN_NR_DESC
/* Magic number for endpoint
(missing, I fear)
*/
/* Magic number for endpoint */
#define WRN_EP_MAGIC 0xcafebabe
/*
...
...
kernel/wr_nic/wr-nic.h
View file @
18dcb14a
...
...
@@ -25,6 +25,17 @@
#ifdef __KERNEL__
/* The rest is kernel-only */
/* The NIC can build for both the switch and the node. Prefer if to ifdef */
#if defined WR_NODE
# define WR_IS_NODE 1
# define WR_IS_SWITCH 0
#elif defined WR_SWITCH
# define WR_IS_NODE 0
# define WR_IS_SWITCH 1
#else
# error "Please define WR_NODE or WR_SWITCH"
#endif
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/mii.h>
/* Needed for stuct mii_if_info in wrn_dev */
...
...
@@ -33,7 +44,6 @@
#include "nic-hardware.h"
/* Magic numbers: please fix them as needed */
#define DRV_NAME "wr-nic"
/* Used in messages and device/driver names */
#define DRV_VERSION "0.1"
/* For ethtool->get_drvinfo -- FIXME: auto-vers */
/*
...
...
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