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
46e23b39
Commit
46e23b39
authored
Jan 13, 2012
by
Alessandro Rubini
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
kernel modules: removed minic, renamed stuff
parent
bbd3ead4
Hide whitespace changes
Inline
Side-by-side
Showing
22 changed files
with
2 additions
and
1285 deletions
+2
-1285
Makefile
kernel/Makefile
+1
-1
README.minic
kernel/wr_minic/README.minic
+0
-35
wr_minic.c
kernel/wr_minic/wr_minic.c
+0
-1248
Makefile
kernel/wr_nic/Makefile
+0
-0
device.c
kernel/wr_nic/device.c
+0
-0
dmtd.c
kernel/wr_nic/dmtd.c
+0
-0
endpoint.c
kernel/wr_nic/endpoint.c
+0
-0
ethtool.c
kernel/wr_nic/ethtool.c
+0
-0
module.c
kernel/wr_nic/module.c
+0
-0
nic-core.c
kernel/wr_nic/nic-core.c
+0
-0
nic-hardware.h
kernel/wr_nic/nic-hardware.h
+0
-0
nic-mem.h
kernel/wr_nic/nic-mem.h
+0
-0
pps.c
kernel/wr_nic/pps.c
+0
-0
timestamp.c
kernel/wr_nic/timestamp.c
+0
-0
wr-nic.h
kernel/wr_nic/wr-nic.h
+0
-0
Makefile
kernel/wr_vic/Makefile
+1
-1
README.vic
kernel/wr_vic/README.vic
+0
-0
endpoint_mdio.h
kernel/wr_vic/endpoint_mdio.h
+0
-0
endpoint_regs.h
kernel/wr_vic/endpoint_regs.h
+0
-0
minic_regs.h
kernel/wr_vic/minic_regs.h
+0
-0
pps_gen_regs.h
kernel/wr_vic/pps_gen_regs.h
+0
-0
wr_vic.c
kernel/wr_vic/wr_vic.c
+0
-0
No files found.
kernel/Makefile
View file @
46e23b39
DIRS
=
wr_
minic
nic wr_rtu
DIRS
=
wr_
vic wr_
nic wr_rtu
# We may "LINUX ?= /usr/src/linux-wrswitch", but it's better to leave it empty
...
...
kernel/wr_minic/README.minic
deleted
100644 → 0
View file @
bbd3ead4
This is a very simple, but working kernel driver for WhiteRabbit mini-NIC (hdl/modules/wrsw_mini_nic) with proper WR timestamping.
TODO:
- add calibration/DMTD ioctls()
- add support for more than 1 endpoint + miNIC (configurable platform_devices)
- add NAPI polling
- add support for sending multiple descriptors (TX ring buffer)
- cleanup, adapt to kernel coding rules
- add TX_TS interrupt handler for proper reception of TX timestamps
BUGS:
- sometimes drops a warning like this one:
# ping 192.168.100.1
PING 192.168.100.1 (192.168.100.1): 56 data bytes
------------[ cut here ]------------
WARNING: at kernel/softirq.c:143 local_bh_enable+0x44/0xac()
Modules linked in: wr_minic whiterabbit_vic
[<c00291f8>] (unwind_backtrace+0x0/0xf0) from [<c00390fc>] (warn_slowpath_common+0x4c/0x64)
[<c00390fc>] (warn_slowpath_common+0x4c/0x64) from [<c003912c>] (warn_slowpath_null+0x18/0x1c)
[<c003912c>] (warn_slowpath_null+0x18/0x1c) from [<c003e23c>] (local_bh_enable+0x44/0xac)
[<c003e23c>] (local_bh_enable+0x44/0xac) from [<c01982d0>] (neigh_lookup+0xb0/0xb8)
[<c01982d0>] (neigh_lookup+0xb0/0xb8) from [<c01ccd10>] (arp_process+0x514/0x680)
[<c01ccd10>] (arp_process+0x514/0x680) from [<c018ece8>] (__netif_receive_skb+0x244/0x26c)
[<c018ece8>] (__netif_receive_skb+0x244/0x26c) from [<bf01484c>] (minic_rx_frame+0x1f4/0x238 [wr_minic])
[<bf01484c>] (minic_rx_frame+0x1f4/0x238 [wr_minic]) from [<00000002>] (0x2)
---[ end trace b836ae4c93691b2b ]---
- fix compilation warning:
MODPOST 1 modules
WARNING: "wrmch_vic_request_irq" [/home/slayer/wrdev-new/software/drivers/wr_minic/wr-minic.ko] undefined!
WARNING: "wrmch_vic_free_irq" [/home/slayer/wrdev-new/software/drivers/wr_minic/wr-minic.ko] undefined!
\ No newline at end of file
kernel/wr_minic/wr_minic.c
deleted
100644 → 0
View file @
bbd3ead4
/*
* Copyright (c) 2010 Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* Copyright (c) 2009 Emilio G. Cota <cota@braap.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/platform_device.h>
#include <linux/etherdevice.h>
#include <linux/net_tstamp.h>
#include <linux/interrupt.h>
#include <linux/netdevice.h>
#include <linux/ethtool.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/mii.h>
#include <linux/swab.h>
#include <linux/irq.h>
#include <linux/clk.h>
#include <linux/if.h>
#include <asm/atomic.h>
#include "minic_regs.h"
#include "endpoint_regs.h"
#include "pps_gen_regs.h"
#ifndef WRVIC_BASE_IRQ
#define WRVIC_BASE_IRQ (NR_AIC_IRQS + (5 * 32))
/* top of GPIO interrupts */
#endif
#define DMTD_AVG_SAMPLES 256
#define DMTD_MAX_PHASE 16384
#define F_COUNTER_BITS 4
#define F_COUNTER_MASK ((1<<F_COUNTER_BITS)-1)
#define LINK_POLL_INTERVAL (HZ/5)
#define DRV_NAME "wr_minic"
#define DRV_VERSION "0.5.1"
#define MINIC_NAPI_WEIGHT 10
#define MINIC_MTU 1540
#define MINIC_TX_MAX_TS 64
#define RX_DESC_VALID(d) ((d) & (1<<31) ? 1 : 0)
#define RX_DESC_ERROR(d) ((d) & (1<<30) ? 1 : 0)
#define RX_DESC_HAS_OOB(d) ((d) & (1<<29) ? 1 : 0)
#define RX_DESC_SIZE(d) (((d) & (1<<0) ? -1 : 0) + (d & 0xfffe))
#define TX_DESC_VALID (1<<31)
#define TX_DESC_WITH_OOB (1<<30)
#define TX_DESC_HAS_OWN_MAC (1<<28)
#define RX_OOB_SIZE 6
#define REFCLK_FREQ 125000000
/*
* Extracts the values of TS rising and falling edge counters
* from the descriptor header
*/
#define EXPLODE_WR_TIMESTAMP(raw, rc, fc) \
rc = (raw) & 0xfffffff; \
fc = (raw >> 28) & 0xf;
/* UGLY HACK WARNING:
remove the PPS subsystem and put it in a separate driver */
struct
tx_timestamp
{
u16
fid
;
u16
port
;
struct
skb_shared_hwtstamps
ts_val
;
int
valid
;
};
struct
wr_minic
{
void
__iomem
*
base
;
// address of the Minic+RAM+Endpoint combo
void
__iomem
*
minic_regs
;
// address of the miNIC registers
void
__iomem
*
ep_regs
;
// address of the Endpoint registers
void
__iomem
*
pbuf
;
// address of the Packet RAM
void
__iomem
*
ppsg
;
// address of the PPS generator
spinlock_t
lock
;
int
tx_hwtstamp_enable
;
int
rx_hwtstamp_enable
;
u16
tx_hwtstamp_oob
;
struct
tx_timestamp
tx_tstable
[
MINIC_TX_MAX_TS
];
struct
platform_device
*
pdev
;
struct
device
*
dev
;
struct
net_device
*
netdev
;
struct
net_device_stats
stats
;
struct
napi_struct
napi
;
struct
sk_buff
*
current_skb
;
struct
timer_list
link_timer
;
unsigned
int
rx_head
,
rx_avail
,
rx_base
,
rx_size
;
unsigned
int
tx_head
,
tx_avail
,
tx_base
,
tx_size
;
bool
synced
;
bool
syncing_counters
;
int
iface_up
;
u32
cur_rx_desc
;
struct
mii_if_info
mii
;
};
MODULE_DESCRIPTION
(
"White Rabbit miNIC driver"
);
MODULE_AUTHOR
(
"Tomasz Wlostowski <tomasz.wlostowsk@cern.ch>"
);
MODULE_LICENSE
(
"GPL"
);
MODULE_ALIAS
(
"platform:wr-minic"
);
#define minic_readl(m, offs) \
__raw_readl((m)->minic_regs + (offs))
#define minic_writel(m, offs, value) \
__raw_writel((value), (m)->minic_regs + (offs))
#define endpoint_readl(m, offs) \
__raw_readl((m)->ep_regs + (offs))
#define endpoint_writel(m, offs, value) \
__raw_writel((value), (m)->ep_regs + (offs))
#define ppsg_readl(m, offs) \
__raw_readl((m)->ppsg + (offs))
#define ppsg_writel(m, offs, value) \
__raw_writel((value), (m)->ppsg + (offs))
// reads an MDIO register
static
int
phy_read
(
struct
net_device
*
dev
,
int
phy_id
,
int
location
)
{
struct
wr_minic
*
nic
=
netdev_priv
(
dev
);
endpoint_writel
(
nic
,
EP_REG_MDIO_CR
,
EP_MDIO_CR_ADDR_W
(
location
));
while
(
(
endpoint_readl
(
nic
,
EP_REG_MDIO_SR
)
&
EP_MDIO_SR_READY
)
==
0
)
;
return
EP_MDIO_SR_RDATA_R
(
endpoint_readl
(
nic
,
EP_REG_MDIO_SR
));
}
static
void
phy_write
(
struct
net_device
*
dev
,
int
phy_id
,
int
location
,
int
value
)
{
struct
wr_minic
*
nic
=
netdev_priv
(
dev
);
endpoint_writel
(
nic
,
EP_REG_MDIO_CR
,
EP_MDIO_CR_ADDR_W
(
location
)
|
EP_MDIO_CR_DATA_W
(
value
)
|
EP_MDIO_CR_RW
);
while
(
(
endpoint_readl
(
nic
,
EP_REG_MDIO_SR
)
&
EP_MDIO_SR_READY
)
==
0
)
;
}
static
int
minic_get_settings
(
struct
net_device
*
dev
,
struct
ethtool_cmd
*
cmd
)
{
struct
wr_minic
*
lp
=
netdev_priv
(
dev
);
int
ret
;
spin_lock_irq
(
&
lp
->
lock
);
ret
=
mii_ethtool_gset
(
&
lp
->
mii
,
cmd
);
spin_unlock_irq
(
&
lp
->
lock
);
cmd
->
supported
=
SUPPORTED_FIBRE
|
SUPPORTED_Autoneg
|
SUPPORTED_1000baseKX_Full
;
cmd
->
advertising
=
ADVERTISED_1000baseKX_Full
|
ADVERTISED_Autoneg
;
cmd
->
port
=
PORT_FIBRE
;
cmd
->
speed
=
SPEED_1000
;
cmd
->
duplex
=
DUPLEX_FULL
;
cmd
->
autoneg
=
AUTONEG_ENABLE
;
return
ret
;
}
static
int
minic_set_settings
(
struct
net_device
*
dev
,
struct
ethtool_cmd
*
cmd
)
{
struct
wr_minic
*
lp
=
netdev_priv
(
dev
);
int
ret
;
spin_lock_irq
(
&
lp
->
lock
);
ret
=
mii_ethtool_sset
(
&
lp
->
mii
,
cmd
);
spin_unlock_irq
(
&
lp
->
lock
);
return
ret
;
}
static
int
minic_nwayreset
(
struct
net_device
*
dev
)
{
struct
wr_minic
*
lp
=
netdev_priv
(
dev
);
int
ret
;
spin_lock_irq
(
&
lp
->
lock
);
ret
=
mii_nway_restart
(
&
lp
->
mii
);
spin_unlock_irq
(
&
lp
->
lock
);
return
ret
;
}
static
void
minic_get_drvinfo
(
struct
net_device
*
dev
,
struct
ethtool_drvinfo
*
info
)
{
strlcpy
(
info
->
driver
,
DRV_NAME
,
sizeof
(
info
->
driver
));
strlcpy
(
info
->
version
,
DRV_VERSION
,
sizeof
(
info
->
version
));
strlcpy
(
info
->
bus_info
,
dev_name
(
dev
->
dev
.
parent
),
sizeof
(
info
->
bus_info
));
}
static
const
struct
ethtool_ops
minic_ethtool_ops
=
{
.
get_settings
=
minic_get_settings
,
.
set_settings
=
minic_set_settings
,
.
get_drvinfo
=
minic_get_drvinfo
,
.
nway_reset
=
minic_nwayreset
,
.
get_link
=
ethtool_op_get_link
,
};
// use in locked context, please
static
void
minic_ppsg_read_time
(
struct
wr_minic
*
nic
,
u32
*
cntr
,
u64
*
utc
)
{
uint32_t
cyc_before
,
cyc_after
;
uint32_t
utc_lo
,
utc_hi
;
for
(;;)
{
cyc_before
=
ppsg_readl
(
nic
,
PPSG_REG_CNTR_NSEC
)
&
0xfffffff
;
utc_lo
=
ppsg_readl
(
nic
,
PPSG_REG_CNTR_UTCLO
)
;
utc_hi
=
ppsg_readl
(
nic
,
PPSG_REG_CNTR_UTCHI
)
&
0xff
;
cyc_after
=
ppsg_readl
(
nic
,
PPSG_REG_CNTR_NSEC
)
&
0xfffffff
;
// there was an UTC transition. (nanosecond counter overflow),
// read the value again.
if
(
cyc_after
<
REFCLK_FREQ
/
4
&&
cyc_before
>
(
REFCLK_FREQ
-
REFCLK_FREQ
/
4
))
{
continue
;
}
else
{
if
(
utc
)
*
utc
=
(
u64
)
utc_lo
|
(
u64
)
utc_hi
<<
32
;
if
(
cntr
)
*
cntr
=
cyc_after
;
return
;
}
}
}
static
inline
u32
minic_ppsg_get_nsecs
(
struct
wr_minic
*
nic
)
{
return
ppsg_readl
(
nic
,
PPSG_REG_CNTR_NSEC
)
&
0xfffffff
;
}
static
void
minic_disable_irq
(
struct
wr_minic
*
nic
,
u32
mask
)
{
// dev_dbg(nic->dev, "wr_disable_irq() - mask %x\n", mask);
minic_writel
(
nic
,
MINIC_REG_EIC_IDR
,
mask
);
}
static
void
minic_enable_irq
(
struct
wr_minic
*
nic
,
u32
mask
)
{
// dev_dbg(nic->dev, "wr_enable_irq() - mask %x\n", mask);
minic_writel
(
nic
,
MINIC_REG_EIC_IER
,
mask
);
}
static
void
minic_clear_irq
(
struct
wr_minic
*
nic
,
u32
mask
)
{
minic_writel
(
nic
,
MINIC_REG_EIC_ISR
,
mask
);
}
static
struct
net_device_stats
*
minic_get_stats
(
struct
net_device
*
netdev
)
{
struct
wr_minic
*
nic
=
netdev_priv
(
netdev
);
// wr_update_tx_stats(nic);
// wr_update_rx_stats(nic);
return
&
nic
->
stats
;
}
static
void
minic_new_rx_buffer
(
struct
wr_minic
*
nic
)
{
nic
->
rx_head
=
nic
->
rx_base
;
minic_writel
(
nic
,
MINIC_REG_MCR
,
0
);
minic_writel
(
nic
,
MINIC_REG_RX_ADDR
,
nic
->
rx_base
);
minic_writel
(
nic
,
MINIC_REG_RX_AVAIL
,
(
nic
->
rx_size
-
MINIC_MTU
)
>>
2
);
minic_writel
(
nic
,
MINIC_REG_MCR
,
MINIC_MCR_RX_EN
);
}
static
void
minic_new_tx_buffer
(
struct
wr_minic
*
nic
)
{
nic
->
tx_head
=
nic
->
tx_base
;
nic
->
tx_avail
=
(
nic
->
tx_size
-
MINIC_MTU
)
>>
2
;
minic_writel
(
nic
,
MINIC_REG_TX_ADDR
,
nic
->
tx_base
);
}
static
int
minic_rx_frame
(
struct
wr_minic
*
nic
)
{
struct
net_device
*
netdev
=
nic
->
netdev
;
struct
sk_buff
*
skb
;
u32
__iomem
*
rx_head
;
u32
*
tmp_ptr
;
u32
payload_size
,
num_words
;
u32
desc_hdr
;
u32
rx_addr_cur
;
u32
rx_oob
;
u32
tmp_buf
[(
MINIC_MTU
>>
2
)
+
8
];
int
i
;
/* get the address of the latest RX descriptor */
rx_addr_cur
=
minic_readl
(
nic
,
MINIC_REG_RX_ADDR
)
&
0xffffff
;
if
(
rx_addr_cur
<
nic
->
rx_head
)
/* nothing new in the buffer? */
return
1
;
rx_head
=
nic
->
pbuf
+
nic
->
rx_head
;
desc_hdr
=
__raw_readl
(
rx_head
++
);
/* read 32-bit descriptor header */
if
(
!
RX_DESC_VALID
(
desc_hdr
))
{
/*
* invalid descriptor? Weird, the RX_ADDR seems
* to be saying something different. Ignore the packet
* and purge the RX buffer.
*/
dev_info
(
nic
->
dev
,
"%s: weird, invalid RX descriptor "
"(%x, head %x)"
,
__func__
,
desc_hdr
,
(
unsigned
int
)
rx_head
-
1
);
minic_new_rx_buffer
(
nic
);
return
0
;
}
// if(RX_DESC_HAS_OOB(desc_hdr))
payload_size
=
RX_DESC_SIZE
(
desc_hdr
);
num_words
=
(
payload_size
+
3
)
>>
2
;
/* valid packet */
if
(
!
RX_DESC_ERROR
(
desc_hdr
))
{
skb
=
netdev_alloc_skb
(
netdev
,
payload_size
+
9
);
if
(
unlikely
(
skb
==
NULL
))
{
if
(
net_ratelimit
())
dev_warn
(
nic
->
dev
,
"-ENOMEM - pckt dropped
\n
"
);
return
0
;
}
/* Make the IP header aligned (the eth header is 14 bytes) */
skb_reserve
(
skb
,
2
);
for
(
i
=
num_words
,
tmp_ptr
=
tmp_buf
;
i
>=
0
;
i
--
)
*
tmp_ptr
++
=
__raw_readl
(
rx_head
++
);
if
(
RX_DESC_HAS_OOB
(
desc_hdr
))
// RX timestamping
{
struct
skb_shared_hwtstamps
*
hwts
=
skb_hwtstamps
(
skb
);
u32
counter_r
,
counter_f
;
// timestamp counter values
u32
counter_ppsg
;
// PPS generator nanosecond counter
u64
utc
;
s32
cntr_diff
;
payload_size
-=
RX_OOB_SIZE
;
memcpy
(
&
rx_oob
,
((
void
*
)
tmp_buf
)
+
payload_size
+
2
,
4
);
rx_oob
=
swab32
(
rx_oob
);
EXPLODE_WR_TIMESTAMP
(
rx_oob
,
counter_r
,
counter_f
);
minic_ppsg_read_time
(
nic
,
&
counter_ppsg
,
&
utc
);
if
(
counter_r
>
(
3
*
REFCLK_FREQ
/
4
)
&&
counter_ppsg
<
REFCLK_FREQ
/
4
)
utc
--
;
/* fixme: we need to pass the phase value somehow
* for RX timestamps. For the time being, we pass
* the R-F counter difference on the MSB of UTC
* (instead of sign value), so the PTP can detect
* the valid counter
*/
hwts
->
hwtstamp
.
tv
.
sec
=
(
s32
)
utc
&
0x7fffffff
;
cntr_diff
=
(
counter_r
&
F_COUNTER_MASK
)
-
counter_f
;
/* the bit says the rising edge cnter is 1tick ahead */
if
(
cntr_diff
==
1
||
cntr_diff
==
(
-
F_COUNTER_MASK
))
hwts
->
hwtstamp
.
tv
.
sec
|=
0x80000000
;
hwts
->
hwtstamp
.
tv
.
nsec
=
counter_r
*
8
;
}
memcpy
(
skb_put
(
skb
,
payload_size
),
tmp_buf
,
payload_size
);
/* determine protocol id */
skb
->
protocol
=
eth_type_trans
(
skb
,
netdev
);
/* @fixme ignore the checksum for the time being */
skb
->
ip_summed
=
CHECKSUM_UNNECESSARY
;
/* update the rx buffer head to point to the next descriptor */
nic
->
rx_head
+=
(
num_words
+
1
)
<<
2
;
netdev
->
last_rx
=
jiffies
;
nic
->
stats
.
rx_packets
++
;
nic
->
stats
.
rx_bytes
+=
payload_size
;
netif_receive_skb
(
skb
);
}
else
{
// RX_DESC_ERROR
nic
->
stats
.
rx_errors
++
;
nic
->
rx_head
+=
(
num_words
+
1
)
<<
2
;
}
wmb
();
return
0
;
}
static
int
minic_poll_txts_fifo
(
struct
wr_minic
*
nic
,
u16
oob_fid
,
struct
skb_shared_hwtstamps
*
hwts
)
{
int
i
;
u32
dmsr
;
int
dmtd_phase
;
dmsr
=
endpoint_readl
(
nic
,
EP_REG_DMSR
);
if
(
dmsr
&
EP_DMSR_PS_RDY
)
dmtd_phase
=
EP_DMSR_PS_VAL_R
(
dmsr
);
else
dmtd_phase
=
0
;
// sign-extend, fix the average if its out of range due to jitter
if
(
dmtd_phase
&
0x800000
)
dmtd_phase
|=
0xff000000
;
// calculate the average
dmtd_phase
/=
DMTD_AVG_SAMPLES
;
if
(
dmtd_phase
>
DMTD_MAX_PHASE
)
dmtd_phase
-=
DMTD_MAX_PHASE
;
if
(
dmtd_phase
<
0
)
dmtd_phase
+=
DMTD_MAX_PHASE
;
while
(
!
(
minic_readl
(
nic
,
MINIC_REG_TSFIFO_CSR
)
&
MINIC_TSFIFO_CSR_EMPTY
))
{
u32
tsval_raw
=
minic_readl
(
nic
,
MINIC_REG_TSFIFO_R0
);
u32
fid
=
(
minic_readl
(
nic
,
MINIC_REG_TSFIFO_R1
)
>>
5
)
&
0xffff
;
u32
counter_r
,
counter_f
;
// timestamp counter values
u32
counter_ppsg
;
// PPS generator nanosecond counter
u64
utc
;
struct
skb_shared_hwtstamps
tsval
;
EXPLODE_WR_TIMESTAMP
(
tsval_raw
,
counter_r
,
counter_f
);
// printk("About to read time\n");
minic_ppsg_read_time
(
nic
,
&
counter_ppsg
,
&
utc
);
// printk("After read time\n");
// the timestamp was taken at the end of previous second
// of UTC time, and now we are at the beg. of the next second
if
(
counter_r
>
(
3
*
REFCLK_FREQ
/
4
)
&&
counter_ppsg
<
REFCLK_FREQ
/
4
)
utc
--
;
// fixme
tsval
.
hwtstamp
.
tv
.
sec
=
((
s32
)
utc
&
0x7fffffff
);
tsval
.
hwtstamp
.
tv
.
nsec
=
counter_r
*
8
;
for
(
i
=
0
;
i
<
MINIC_TX_MAX_TS
;
i
++
)
if
(
!
nic
->
tx_tstable
[
i
].
valid
)
{
// printk("Addts: fid %d tsval %x\n",
// fid, tsval);
nic
->
tx_tstable
[
i
].
valid
=
1
;
nic
->
tx_tstable
[
i
].
ts_val
=
tsval
;
nic
->
tx_tstable
[
i
].
fid
=
fid
;
break
;
}
}
// printk("queryts: fid %d\n", oob_fid);
for
(
i
=
0
;
i
<
MINIC_TX_MAX_TS
;
i
++
)
{
if
(
nic
->
tx_tstable
[
i
].
valid
&&
oob_fid
==
nic
->
tx_tstable
[
i
].
fid
)
{
// printk("GotTS: fid %d\n", oob_fid);
if
(
hwts
)
memcpy
(
hwts
,
&
nic
->
tx_tstable
[
i
].
ts_val
,
sizeof
(
struct
skb_shared_hwtstamps
));
nic
->
tx_tstable
[
i
].
valid
=
0
;
return
0
;
}
}
// printk("Missed timestamp...");
return
-
1
;
}
static
inline
void
minic_tx_handle_irq
(
struct
wr_minic
*
nic
)
{
struct
net_device
*
netdev
=
nic
->
netdev
;
struct
skb_shared_hwtstamps
hwts
;
struct
skb_shared_hwtstamps
*
hwoob
=
skb_hwtstamps
(
nic
->
current_skb
);
union
skb_shared_tx
*
shtx
=
skb_tx
(
nic
->
current_skb
);
unsigned
long
flags
;
u16
oob_tag
;
spin_lock_irqsave
(
&
nic
->
lock
,
flags
);
/*
* this will only work for the NIC directly connected to the endpoint.
* In case of a switch, the packet will reach the output port after
* being completely transmitted by the NIC (i.e. after TX interrupt)
*/
if
(
shtx
->
in_progress
)
{
oob_tag
=
*
(
u16
*
)
hwoob
;
if
(
!
minic_poll_txts_fifo
(
nic
,
oob_tag
,
&
hwts
))
skb_tstamp_tx
(
nic
->
current_skb
,
&
hwts
);
}
dev_kfree_skb_irq
(
nic
->
current_skb
);
if
(
netif_queue_stopped
(
nic
->
netdev
))
netif_wake_queue
(
netdev
);
spin_unlock_irqrestore
(
&
nic
->
lock
,
flags
);
minic_clear_irq
(
nic
,
MINIC_EIC_ISR_TX
);
// clear the TX interrupt
}
static
inline
void
minic_rx_handle_irq
(
struct
wr_minic
*
nic
)
{
int
buf_full
;
buf_full
=
minic_readl
(
nic
,
MINIC_REG_MCR
)
&
MINIC_MCR_RX_FULL
?
1
:
0
;
while
(
!
minic_rx_frame
(
nic
));
if
(
buf_full
)
minic_new_rx_buffer
(
nic
);
minic_clear_irq
(
nic
,
MINIC_EIC_ISR_RX
);
}
/* called by WRVIC driver */
static
irqreturn_t
minic_interrupt
(
int
irq
,
void
*
dev_id
)
{
struct
net_device
*
netdev
=
dev_id
;
struct
wr_minic
*
nic
=
netdev_priv
(
netdev
);
u32
isr
;
isr
=
minic_readl
(
nic
,
MINIC_REG_EIC_ISR
);
if
(
isr
&
MINIC_EIC_ISR_TX
)
minic_tx_handle_irq
(
nic
);
if
(
isr
&
MINIC_EIC_ISR_RX
)
minic_rx_handle_irq
(
nic
);
return
IRQ_HANDLED
;
}
static
int
minic_hw_tx
(
struct
wr_minic
*
nic
,
char
*
data
,
unsigned
size
,
u16
tx_oob_val
)
{
u32
__iomem
*
dst
,
*
dptr
;
u32
nwords
;
u32
mcr
;
int
i
;
u32
pkt_buf
[(
MINIC_MTU
>>
2
)
+
4
];
nwords
=
((
size
+
1
)
>>
1
)
-
1
;
memset
(
pkt_buf
,
0x0
,
size
+
16
);
memcpy
(
pkt_buf
+
1
,
data
,
size
);
if
(
nwords
<
30
)
nwords
=
30
;
// min length = 60 bytes (CRC excluded)
if
(
tx_oob_val
)
{
// do the TX timestamping?
tx_oob_val
=
swab16
(
tx_oob_val
);
memcpy
((
void
*
)
pkt_buf
+
4
+
size
,
&
tx_oob_val
,
sizeof
(
u16
));
nwords
++
;
pkt_buf
[
0
]
=
TX_DESC_WITH_OOB
;
// printk("add oob\n");
}
else
{
pkt_buf
[
0
]
=
0
;
}
pkt_buf
[
0
]
|=
TX_DESC_VALID
|
TX_DESC_HAS_OWN_MAC
|
nwords
;
dptr
=
(
u32
*
)
pkt_buf
;
dst
=
nic
->
pbuf
+
nic
->
tx_head
;
for
(
i
=
((
nwords
+
1
)
>>
1
)
+
3
;
i
;
i
--
)
*
dst
++
=
*
dptr
++
;
minic_enable_irq
(
nic
,
MINIC_EIC_IER_TX
);
mcr
=
minic_readl
(
nic
,
MINIC_REG_MCR
);
minic_writel
(
nic
,
MINIC_REG_MCR
,
mcr
|
MINIC_MCR_TX_START
);
return
0
;
}
static
int
minic_start_xmit
(
struct
sk_buff
*
skb
,
struct
net_device
*
netdev
)
{
struct
wr_minic
*
nic
=
netdev_priv
(
netdev
);
union
skb_shared_tx
*
shtx
=
skb_tx
(
skb
);
u16
tx_oob
=
0
;
char
*
data
;
unsigned
len
;
if
(
unlikely
(
skb
->
len
>
MINIC_MTU
))
{
nic
->
stats
.
tx_errors
++
;
return
-
EMSGSIZE
;
}
data
=
skb
->
data
;
len
=
skb
->
len
;
spin_lock_irq
(
&
nic
->
lock
);
nic
->
current_skb
=
skb
;
netif_stop_queue
(
netdev
);
// queue is stopped until packet is tx'ed
if
(
nic
->
tx_hwtstamp_enable
&&
shtx
->
hardware
)
{
struct
skb_shared_hwtstamps
*
hwts
=
skb_hwtstamps
(
skb
);
shtx
->
in_progress
=
1
;
*
(
u16
*
)
hwts
=
tx_oob
=
nic
->
tx_hwtstamp_oob
;
nic
->
tx_hwtstamp_oob
++
;
if
(
nic
->
tx_hwtstamp_oob
==
60000
)
nic
->
tx_hwtstamp_oob
=
1
;
}
else
{
tx_oob
=
0
;
}
minic_new_tx_buffer
(
nic
);
minic_hw_tx
(
nic
,
data
,
len
,
tx_oob
);
nic
->
stats
.
tx_packets
++
;
nic
->
stats
.
tx_bytes
+=
len
;
netdev
->
trans_start
=
jiffies
;
spin_unlock_irq
(
&
nic
->
lock
);
return
0
;
}
static
void
minic_update_ts_config
(
struct
wr_minic
*
nic
)
{
endpoint_writel
(
nic
,
EP_REG_TSCR
,
(
nic
->
tx_hwtstamp_enable
?
EP_TSCR_EN_TXTS
:
0
)
|
(
nic
->
rx_hwtstamp_enable
?
EP_TSCR_EN_RXTS
:
0
)
);
// printk("update_ts_config: TSCR %x\n",
// endpoint_readl(nic, EP_REG_TSCR));
}
static
int
minic_tstamp_ioctl
(
struct
net_device
*
netdev
,
struct
ifreq
*
rq
,
int
cmd
)
{
struct
wr_minic
*
nic
=
netdev_priv
(
netdev
);
struct
hwtstamp_config
config
;
if
(
copy_from_user
(
&
config
,
rq
->
ifr_data
,
sizeof
(
config
)))
return
-
EFAULT
;
// printk("hwtstamp_ioctl()\n" );
switch
(
config
.
tx_type
)
{
case
HWTSTAMP_TX_ON
:
// printk("%s: hw tx timestamping ON\n", __func__);
nic
->
tx_hwtstamp_enable
=
1
;
memset
(
nic
->
tx_tstable
,
0
,
sizeof
(
nic
->
tx_tstable
));
break
;
case
HWTSTAMP_TX_OFF
:
// printk("%s: hw tx timestamping OFF\n", __func__);
nic
->
tx_hwtstamp_enable
=
0
;
break
;
default:
return
-
ERANGE
;
}
/*
* For the time being, make this really simple and stupid: either
* time-tag _all_ the incoming packets or none of them.
*/
switch
(
config
.
rx_filter
)
{
case
HWTSTAMP_FILTER_NONE
:
//dev_dbg(nic->dev, "%s - hw rx timestamping OFF\n", __func__);
nic
->
rx_hwtstamp_enable
=
0
;
break
;
case
HWTSTAMP_FILTER_PTP_V2_L2_EVENT
:
// printk( "%s - hw rx timestamping ON for PTP L2 events\n",
// __func__);
nic
->
rx_hwtstamp_enable
=
1
;
// Only PTPv2 supported by now
config
.
rx_filter
=
HWTSTAMP_FILTER_ALL
;
break
;
default:
return
-
ERANGE
;
}
minic_update_ts_config
(
nic
);
return
copy_to_user
(
rq
->
ifr_data
,
&
config
,
sizeof
(
config
))
?
-
EFAULT
:
0
;
}
#define PRIV_IOCGCALIBRATE (SIOCDEVPRIVATE+1)
#define PRIV_IOCGGETPHASE (SIOCDEVPRIVATE+2)
#define CAL_CMD_TX_ON 1
#define CAL_CMD_TX_OFF 2
#define CAL_CMD_RX_ON 3
#define CAL_CMD_RX_OFF 4
#define CAL_CMD_RX_CHECK 5
struct
wrmch_calibration_req
{
int
cmd
;
// int tx_rx;
int
cal_present
;
};
struct
wrmch_phase_req
{
int
ready
;
u32
phase
;
};
static
int
phase_ioctl
(
struct
net_device
*
netdev
,
struct
ifreq
*
rq
,
int
cmd
)
{
struct
wrmch_phase_req
phase_req
;
struct
wr_minic
*
nic
=
netdev_priv
(
netdev
);
u32
dmsr
=
endpoint_readl
(
nic
,
EP_REG_DMSR
);
if
(
dmsr
&
EP_DMSR_PS_RDY
)
{
s32
dmtd_phase
=
EP_DMSR_PS_VAL_R
(
dmsr
);
// sign-extend, fix the average if out of range due to jitter
if
(
dmtd_phase
&
0x800000
)
dmtd_phase
|=
0xff000000
;
// calculate the average
dmtd_phase
/=
DMTD_AVG_SAMPLES
;
if
(
dmtd_phase
>
DMTD_MAX_PHASE
)
dmtd_phase
-=
DMTD_MAX_PHASE
;
if
(
dmtd_phase
<
0
)
dmtd_phase
+=
DMTD_MAX_PHASE
;
phase_req
.
phase
=
dmtd_phase
;
phase_req
.
ready
=
1
;
}
else
{
phase_req
.
phase
=
0
;
phase_req
.
ready
=
0
;
}
return
copy_to_user
(
rq
->
ifr_data
,
&
phase_req
,
sizeof
(
phase_req
))
?
-
EFAULT
:
0
;
}
static
int
calibration_ioctl
(
struct
net_device
*
netdev
,
struct
ifreq
*
rq
,
int
cmd
)
{
struct
wrmch_calibration_req
cal_req
;
struct
wr_minic
*
nic
=
netdev_priv
(
netdev
);
u32
tmp
;
if
(
copy_from_user
(
&
cal_req
,
rq
->
ifr_data
,
sizeof
(
cal_req
)))
return
-
EFAULT
;
switch
(
cal_req
.
cmd
)
{
case
CAL_CMD_TX_ON
:
tmp
=
phy_read
(
netdev
,
0
,
MDIO_REG_WR_SPEC
);
phy_write
(
netdev
,
0
,
MDIO_REG_WR_SPEC
,
tmp
|
MDIO_WR_SPEC_TX_CAL
);
break
;
case
CAL_CMD_TX_OFF
:
tmp
=
phy_read
(
netdev
,
0
,
MDIO_REG_WR_SPEC
);
phy_write
(
netdev
,
0
,
MDIO_REG_WR_SPEC
,
tmp
&
(
~
MDIO_WR_SPEC_TX_CAL
));
break
;
case
CAL_CMD_RX_ON
:
if
(
nic
->
iface_up
)
{
tmp
=
phy_read
(
netdev
,
0
,
MDIO_REG_WR_SPEC
);
phy_write
(
netdev
,
0
,
MDIO_REG_WR_SPEC
,
tmp
|
MDIO_WR_SPEC_CAL_CRST
);
}
else
{
return
-
EFAULT
;
}
break
;
case
CAL_CMD_RX_OFF
:
if
(
nic
->
iface_up
)
{
// do nothing.....
}
else
{
return
-
EFAULT
;
}
break
;
case
CAL_CMD_RX_CHECK
:
if
(
nic
->
iface_up
)
{
tmp
=
phy_read
(
netdev
,
0
,
MDIO_REG_WR_SPEC
);
cal_req
.
cal_present
=
tmp
&
MDIO_WR_SPEC_RX_CAL_STAT
?
1
:
0
;
if
(
copy_to_user
(
rq
->
ifr_data
,
&
cal_req
,
sizeof
(
cal_req
)))
return
-
EFAULT
;
return
0
;
}
else
{
return
-
EFAULT
;
}
break
;
}
return
0
;
}
static
int
minic_ioctl
(
struct
net_device
*
netdev
,
struct
ifreq
*
rq
,
int
cmd
)
{
struct
wr_minic
*
nic
=
netdev_priv
(
netdev
);
int
res
;
switch
(
cmd
)
{
case
SIOCSHWTSTAMP
:
return
minic_tstamp_ioctl
(
netdev
,
rq
,
cmd
);
case
PRIV_IOCGCALIBRATE
:
return
calibration_ioctl
(
netdev
,
rq
,
cmd
);
case
PRIV_IOCGGETPHASE
:
return
phase_ioctl
(
netdev
,
rq
,
cmd
);
default:
spin_lock_irq
(
&
nic
->
lock
);
res
=
generic_mii_ioctl
(
&
nic
->
mii
,
if_mii
(
rq
),
cmd
,
NULL
);
spin_unlock_irq
(
&
nic
->
lock
);
return
res
;
}
}
static
void
ep_enable
(
struct
net_device
*
netdev
)
{
struct
wr_minic
*
nic
=
netdev_priv
(
netdev
);
endpoint_writel
(
nic
,
EP_REG_DMCR
,
EP_DMCR_EN
|
EP_DMCR_N_AVG_W
(
DMTD_AVG_SAMPLES
));
endpoint_writel
(
nic
,
EP_REG_ECR
,
EP_ECR_TX_EN_FRA
|
EP_ECR_RX_EN_FRA
|
EP_ECR_RST_CNT
);
endpoint_writel
(
nic
,
EP_REG_RFCR
,
3
<<
EP_RFCR_QMODE_SHIFT
);
// QMODE = UNQUALIFIED
endpoint_writel
(
nic
,
EP_REG_TSCR
,
0
);
// disable the timestamping
endpoint_writel
(
nic
,
EP_REG_FCR
,
0
);
// no flow control by now
phy_write
(
netdev
,
0
,
MII_ADVERTISE
,
0x01a0
);
// adv. TX+RX flow, full
phy_write
(
netdev
,
0
,
MII_BMCR
,
0
);
//phy_read(netdev, 0, MII_BMCR) | BMCR_ANENABLE | BMCR_ANRESTART);
}
static
void
ep_disable
(
struct
net_device
*
netdev
)
{
struct
wr_minic
*
nic
=
netdev_priv
(
netdev
);
endpoint_writel
(
nic
,
EP_REG_ECR
,
0
);
endpoint_writel
(
nic
,
EP_REG_TSCR
,
0
);
}
static
void
update_link_status
(
unsigned
long
dev_id
)
{
struct
net_device
*
netdev
=
(
struct
net_device
*
)
dev_id
;
struct
wr_minic
*
nic
=
netdev_priv
(
netdev
);
u32
ecr
,
bmsr
,
bmcr
,
lpa
;
bmsr
=
phy_read
(
netdev
,
0
,
MII_BMSR
);
bmcr
=
phy_read
(
netdev
,
0
,
MII_BMCR
);
// printk(KERN_INFO "iface %s naddr %x bmsr %x\n",
// netdev->name, nic->mii.dev, bmsr);
if
(
!
mii_link_ok
(
&
nic
->
mii
))
{
/* no link */
if
(
netif_carrier_ok
(
netdev
))
{
netif_carrier_off
(
netdev
);
nic
->
iface_up
=
0
;
printk
(
KERN_INFO
"%s: Link down.
\n
"
,
netdev
->
name
);
}
return
;
}
if
(
netif_carrier_ok
(
netdev
))
return
;
if
(
bmcr
&
BMCR_ANENABLE
)
{
/* AutoNegotiation is enabled */
if
(
!
(
bmsr
&
BMSR_ANEGCOMPLETE
))
{
/*
* Do nothing - another interrupt is generated
* when negotiation complete
*/
return
;
}
lpa
=
phy_read
(
netdev
,
0
,
MII_LPA
);
netif_carrier_on
(
netdev
);
nic
->
iface_up
=
1
;
// endpoint_writel(nic, EP_REG_FCR,
// EP_FCR_TXPAUSE |EP_FCR_RXPAUSE | EP_FCR_TX_THR_W(128)
// | EP_FCR_TX_QUANTA_W(200));
printk
(
KERN_INFO
"%s: Link up, lpa 0x%04x.
\n
"
,
netdev
->
name
,
lpa
);
}
else
{
netif_carrier_on
(
netdev
);
printk
(
KERN_INFO
"%s: Link up.
\n
"
,
netdev
->
name
);
nic
->
iface_up
=
1
;
}
ecr
=
endpoint_readl
(
nic
,
EP_REG_ECR
);
/* reset RMON counters */
endpoint_writel
(
nic
,
EP_REG_ECR
,
ecr
|
EP_ECR_RST_CNT
);
endpoint_writel
(
nic
,
EP_REG_ECR
,
ecr
);
}
static
void
minic_check_link
(
unsigned
long
dev_id
)
{
struct
net_device
*
dev
=
(
struct
net_device
*
)
dev_id
;
struct
wr_minic
*
lp
=
netdev_priv
(
dev
);
update_link_status
(
dev_id
);
mod_timer
(
&
lp
->
link_timer
,
jiffies
+
LINK_POLL_INTERVAL
);
}
static
int
minic_open
(
struct
net_device
*
netdev
)
{
struct
wr_minic
*
nic
=
netdev_priv
(
netdev
);
// printk("Bringing up: %s\n", netdev->name);
if
(
!
is_valid_ether_addr
(
netdev
->
dev_addr
))
return
-
EADDRNOTAVAIL
;
minic_writel
(
nic
,
MINIC_REG_MCR
,
0
);
minic_disable_irq
(
nic
,
0xffffffff
);
ep_enable
(
netdev
);
netif_carrier_off
(
netdev
);
init_timer
(
&
nic
->
link_timer
);
nic
->
link_timer
.
data
=
(
unsigned
long
)
netdev
;
nic
->
link_timer
.
function
=
minic_check_link
;
mod_timer
(
&
nic
->
link_timer
,
jiffies
+
LINK_POLL_INTERVAL
);
nic
->
synced
=
false
;
nic
->
syncing_counters
=
false
;
nic
->
rx_base
=
MINIC_PBUF_SIZE
>>
1
;
nic
->
rx_size
=
MINIC_PBUF_SIZE
>>
1
;
nic
->
tx_base
=
0
;
nic
->
tx_size
=
MINIC_PBUF_SIZE
>>
1
;
nic
->
tx_hwtstamp_enable
=
0
;
nic
->
rx_hwtstamp_enable
=
0
;
nic
->
tx_hwtstamp_oob
=
1
;
minic_new_rx_buffer
(
nic
);
minic_enable_irq
(
nic
,
MINIC_EIC_IER_RX
);
// enable RX irq
minic_writel
(
nic
,
MINIC_REG_MCR
,
MINIC_MCR_RX_EN
);
// enable RX
if
(
netif_queue_stopped
(
nic
->
netdev
))
{
netif_wake_queue
(
netdev
);
}
else
{
netif_start_queue
(
netdev
);
}
nic
->
iface_up
=
0
;
return
0
;
}
static
int
minic_close
(
struct
net_device
*
netdev
)
{
struct
wr_minic
*
nic
=
netdev_priv
(
netdev
);
// napi_disable(&nic->napi);
del_timer_sync
(
&
nic
->
link_timer
);
nic
->
iface_up
=
0
;
ep_disable
(
netdev
);
if
(
!
netif_queue_stopped
(
netdev
))
netif_stop_queue
(
netdev
);
minic_writel
(
nic
,
MINIC_REG_MCR
,
0
);
minic_writel
(
nic
,
MINIC_REG_EIC_IDR
,
0xffffffff
);
// dev_info(nic->dev, "wr_close() done\n");
return
0
;
}
static
void
minic_update_mac
(
struct
net_device
*
netdev
)
{
struct
wr_minic
*
nic
=
netdev_priv
(
netdev
);
endpoint_writel
(
nic
,
EP_REG_MACL
,
(
netdev
->
dev_addr
[
3
]
<<
24
)
|
(
netdev
->
dev_addr
[
2
]
<<
16
)
|
(
netdev
->
dev_addr
[
1
]
<<
8
)
|
(
netdev
->
dev_addr
[
0
]));
endpoint_writel
(
nic
,
EP_REG_MACH
,
(
netdev
->
dev_addr
[
5
]
<<
8
)
|
(
netdev
->
dev_addr
[
4
]));
}
static
int
minic_set_mac_address
(
struct
net_device
*
netdev
,
void
*
addr
)
{
struct
sockaddr
*
address
=
addr
;
if
(
!
is_valid_ether_addr
(
address
->
sa_data
))
return
-
EADDRNOTAVAIL
;
memcpy
(
netdev
->
dev_addr
,
address
->
sa_data
,
netdev
->
addr_len
);
minic_update_mac
(
netdev
);
// printk("%s: Setting MAC address to %pM\n",
//netdev->name, netdev->dev_addr);
return
0
;
}
static
const
struct
net_device_ops
minic_netdev_ops
=
{
.
ndo_open
=
minic_open
,
.
ndo_stop
=
minic_close
,
.
ndo_start_xmit
=
minic_start_xmit
,
.
ndo_validate_addr
=
eth_validate_addr
,
.
ndo_get_stats
=
minic_get_stats
,
// .ndo_set_multicast_list = wr_set_multicast_list,
.
ndo_set_mac_address
=
minic_set_mac_address
,
// .ndo_change_mtu = wr_change_mtu,
.
ndo_do_ioctl
=
minic_ioctl
,
#ifdef CONFIG_NET_POLL_CONTROLLER
.
ndo_poll_controller
=
NULL
;
//wr_netpoll;
#endif
};
static
int
__devinit
minic_probe
(
struct
platform_device
*
pdev
)
{
struct
net_device
*
netdev
;
struct
resource
*
base_minic
,
*
base_ppsg
;
struct
wr_minic
*
nic
;
int
err
;
base_minic
=
platform_get_resource
(
pdev
,
IORESOURCE_MEM
,
0
);
if
(
!
base_minic
)
{
dev_err
(
&
pdev
->
dev
,
"no mmio resource defined
\n
"
);
err
=
-
ENXIO
;
goto
err_out
;
}
base_ppsg
=
platform_get_resource
(
pdev
,
IORESOURCE_MEM
,
1
);
if
(
!
base_ppsg
)
{
dev_err
(
&
pdev
->
dev
,
"no mmio resource defined
\n
"
);
err
=
-
ENXIO
;
goto
err_out
;
}
netdev
=
alloc_etherdev
(
sizeof
(
struct
wr_minic
));
if
(
!
netdev
)
{
dev_err
(
&
pdev
->
dev
,
"etherdev alloc failed, aborting.
\n
"
);
err
=
-
ENOMEM
;
goto
err_out
;
}
// printk("base-addr 0x%x-0x%x\n", base->start, base->end);
SET_NETDEV_DEV
(
netdev
,
&
pdev
->
dev
);
/* initialise the nic structure */
nic
=
netdev_priv
(
netdev
);
nic
->
pdev
=
pdev
;
nic
->
netdev
=
netdev
;
nic
->
dev
=
&
pdev
->
dev
;
nic
->
iface_up
=
0
;
spin_lock_init
(
&
nic
->
lock
);
nic
->
base
=
ioremap
(
base_minic
->
start
,
base_minic
->
end
-
base_minic
->
start
+
1
);
nic
->
ppsg
=
ioremap
(
base_ppsg
->
start
,
base_ppsg
->
end
-
base_ppsg
->
start
+
1
);
// dev_info(&pdev->dev, "io at 0x%x, pbuf at 0x%x\n",
// nic->minic_regs, nic->pbuf);
if
(
!
nic
->
base
||
!
nic
->
ppsg
)
{
// if (netif_msg_probe(nic))
dev_err
(
&
pdev
->
dev
,
"failed to map minic address space
\n
"
);
err
=
-
ENOMEM
;
goto
err_out_free_netdev
;
}
nic
->
minic_regs
=
nic
->
base
+
MINIC_BASE_IO
;
nic
->
ep_regs
=
nic
->
base
+
MINIC_BASE_ENDPOINT
;
nic
->
pbuf
=
nic
->
base
+
MINIC_BASE_PBUF
;
netdev
->
base_addr
=
(
u32
)
nic
->
base
;
strcpy
(
netdev
->
name
,
(
char
*
)
pdev
->
dev
.
platform_data
);
if
(
endpoint_readl
(
nic
,
EP_REG_IDCODE
)
!=
0xcafebabe
)
{
printk
(
KERN_INFO
"Looks like the port %s "
"hasn't been synthesized...
\n
"
,
netdev
->
name
);
free_netdev
(
netdev
);
iounmap
(
nic
->
base
);
iounmap
(
nic
->
ppsg
);
return
0
;
}
memset
(
netdev
->
dev_addr
,
0
,
6
);
// minic_get_mac_addr(nic);
netdev
->
irq
=
platform_get_irq
(
pdev
,
0
);
if
(
netdev
->
irq
<
0
)
{
err
=
-
ENXIO
;
goto
err_out_iounmap
;
}
err
=
request_irq
(
WRVIC_BASE_IRQ
+
netdev
->
irq
,
minic_interrupt
,
IRQF_SHARED
,
"wr-minic"
,
netdev
);
if
(
err
)
{
// if (netif_msg_probe(nic)) {
dev_err
(
&
netdev
->
dev
,
"request IRQ %d failed, err=%d
\n
"
,
netdev
->
irq
,
err
);
// }
goto
err_out_iounmap
;
}
netdev
->
netdev_ops
=
&
minic_netdev_ops
;
netdev
->
ethtool_ops
=
&
minic_ethtool_ops
;
netdev
->
features
|=
0
;
/* setup NAPI */
memset
(
&
nic
->
napi
,
0
,
sizeof
(
nic
->
napi
));
// netif_napi_add(netdev, &nic->napi, minic_poll, MINIC_NAPI_WEIGHT);
nic
->
mii
.
dev
=
netdev
;
/* Support for ethtool */
nic
->
mii
.
mdio_read
=
phy_read
;
nic
->
mii
.
mdio_write
=
phy_write
;
nic
->
mii
.
phy_id
=
0
;
nic
->
mii
.
phy_id_mask
=
0x1f
;
nic
->
mii
.
reg_num_mask
=
0x1f
;
nic
->
mii
.
force_media
=
0
;
nic
->
mii
.
advertising
=
ADVERTISE_1000XFULL
;
nic
->
mii
.
full_duplex
=
1
;
err
=
register_netdev
(
netdev
);
if
(
err
)
{
// if (netif_msg_probe(nic))
dev_err
(
&
pdev
->
dev
,
"unable to register net device
\n
"
);
goto
err_out_freeirq
;
}
platform_set_drvdata
(
pdev
,
netdev
);
/* WR NIC banner */
// if (netif_msg_probe(nic)) {
dev_info
(
&
pdev
->
dev
,
"White Rabbit miNIC at 0x%08lx irq %d
\n
"
,
netdev
->
base_addr
,
netdev
->
irq
);
// }
return
0
;
err_out_freeirq:
free_irq
(
netdev
->
irq
,
&
pdev
->
dev
);
err_out_iounmap:
iounmap
(
nic
->
base
);
err_out_free_netdev:
free_netdev
(
netdev
);
err_out:
platform_set_drvdata
(
pdev
,
NULL
);
return
err
;
}
static
int
__devexit
minic_remove
(
struct
platform_device
*
pdev
)
{
struct
net_device
*
netdev
;
struct
wr_minic
*
nic
;
netdev
=
platform_get_drvdata
(
pdev
);
if
(
!
netdev
)
return
0
;
free_irq
(
WRVIC_BASE_IRQ
+
netdev
->
irq
,
netdev
);
nic
=
netdev_priv
(
netdev
);
unregister_netdev
(
netdev
);
iounmap
(
nic
->
base
);
free_netdev
(
netdev
);
platform_set_drvdata
(
pdev
,
NULL
);
return
0
;
}
#define minic_suspend NULL
#define minic_resume NULL
static
struct
platform_driver
minic_driver
=
{
.
remove
=
__exit_p
(
minic_remove
),
.
suspend
=
minic_suspend
,
.
resume
=
minic_resume
,
.
driver
=
{
.
name
=
DRV_NAME
,
.
owner
=
THIS_MODULE
,
},
};
static
int
__devinit
minic_init_module
(
void
)
{
return
platform_driver_probe
(
&
minic_driver
,
minic_probe
);
}
static
void
__devexit
minic_cleanup_module
(
void
)
{
platform_driver_unregister
(
&
minic_driver
);
}
module_init
(
minic_init_module
);
module_exit
(
minic_cleanup_module
);
kernel/nic/Makefile
→
kernel/
wr_
nic/Makefile
View file @
46e23b39
File moved
kernel/nic/device.c
→
kernel/
wr_
nic/device.c
View file @
46e23b39
File moved
kernel/nic/dmtd.c
→
kernel/
wr_
nic/dmtd.c
View file @
46e23b39
File moved
kernel/nic/endpoint.c
→
kernel/
wr_
nic/endpoint.c
View file @
46e23b39
File moved
kernel/nic/ethtool.c
→
kernel/
wr_
nic/ethtool.c
View file @
46e23b39
File moved
kernel/nic/module.c
→
kernel/
wr_
nic/module.c
View file @
46e23b39
File moved
kernel/nic/nic-core.c
→
kernel/
wr_
nic/nic-core.c
View file @
46e23b39
File moved
kernel/nic/nic-hardware.h
→
kernel/
wr_
nic/nic-hardware.h
View file @
46e23b39
File moved
kernel/nic/nic-mem.h
→
kernel/
wr_
nic/nic-mem.h
View file @
46e23b39
File moved
kernel/nic/pps.c
→
kernel/
wr_
nic/pps.c
View file @
46e23b39
File moved
kernel/nic/timestamp.c
→
kernel/
wr_
nic/timestamp.c
View file @
46e23b39
File moved
kernel/nic/wr-nic.h
→
kernel/
wr_
nic/wr-nic.h
View file @
46e23b39
File moved
kernel/wr_
min
ic/Makefile
→
kernel/wr_
v
ic/Makefile
View file @
46e23b39
obj-m
:=
wr_vic.o
wr_minic.o
obj-m
:=
wr_vic.o
export
ARCH
?=
arm
export
CROSS_COMPILE
?=
$(CROSS_COMPILE_ARM)
...
...
kernel/wr_
min
ic/README.vic
→
kernel/wr_
v
ic/README.vic
View file @
46e23b39
File moved
kernel/wr_
min
ic/endpoint_mdio.h
→
kernel/wr_
v
ic/endpoint_mdio.h
View file @
46e23b39
File moved
kernel/wr_
min
ic/endpoint_regs.h
→
kernel/wr_
v
ic/endpoint_regs.h
View file @
46e23b39
File moved
kernel/wr_
min
ic/minic_regs.h
→
kernel/wr_
v
ic/minic_regs.h
View file @
46e23b39
File moved
kernel/wr_
min
ic/pps_gen_regs.h
→
kernel/wr_
v
ic/pps_gen_regs.h
View file @
46e23b39
File moved
kernel/wr_
min
ic/wr_vic.c
→
kernel/wr_
v
ic/wr_vic.c
View file @
46e23b39
File moved
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