Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
c1bc73b5
Commit
c1bc73b5
authored
Jun 18, 2002
by
Jeff Garzik
Browse files
Options
Browse Files
Download
Plain Diff
Merge mandrakesoft.com:/home/jgarzik/vanilla/linus-2.5
into mandrakesoft.com:/home/jgarzik/repo/net-drivers-2.5
parents
362dff46
4c978e6f
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
199 additions
and
40 deletions
+199
-40
Documentation/networking/dl2k.txt
Documentation/networking/dl2k.txt
+27
-17
drivers/net/8139cp.c
drivers/net/8139cp.c
+138
-5
drivers/net/dl2k.c
drivers/net/dl2k.c
+16
-10
drivers/net/dl2k.h
drivers/net/dl2k.h
+8
-7
include/linux/ethtool.h
include/linux/ethtool.h
+10
-1
No files found.
Documentation/networking/dl2k.txt
View file @
c1bc73b5
D-Link DL2000-based Gigabit Ethernet Adapter Installation
for Linux
Jan 29
, 2002
May 23
, 2002
Contents
========
...
...
@@ -202,7 +202,7 @@ media=media_type - Specifies the media type the NIC operates at.
1000mbps_fd and 1000mbps_hd types are only
available for fiber adapter.
vlan=
[0|1]
- Specifies the VLAN ID. If vlan=0, the
vlan=
n
- Specifies the VLAN ID. If vlan=0, the
Virtual Local Area Network (VLAN) function is
disable.
...
...
@@ -211,24 +211,34 @@ jumbo=[0|1] - Specifies the jumbo frame support. If jumbo=1,
function is disabled.
Jumbo frame usually improve the performance
int gigabit.
This feature need jumbo frame compatible
remote.
rx_coalesce=n - Rx frame count each interrupt.
rx_timeout=n - Rx DMA wait time for an interrupt. Proper
values of rx_coalesce and rx_timeout bring
a conspicuous performance in the fast machine.
Ex. rx_coalesce=5 and rx_timeout=750
tx_coalesce=n - Tx transmit count each TxComp interrupt.
Setting value larger than 1 will improve
performance, but this is possible to lower
stability in slow UP machines. By default,
tx_coalesce=1. (dl2k)
rx_coalesce=m - Number of rx frame handled each interrupt.
rx_timeout=n - Rx DMA wait time for an interrupt.
If set rx_coalesce > 0, hardware only assert
an interrupt for m frames. Hardware won't
assert rx interrupt until m frames received or
reach timeout of n * 640 nano seconds.
Set proper rx_coalesce and rx_timeout can
reduce congestion collapse and overload which
has been a bottlenect for high speed network.
tx_flow=[1|0] - Specifies the Tx flow control. If tx_flow=1,
the Tx flow control enable.
For example, rx_coalesce=10 rx_timeout=800.
that is, hardware assert only 1 interrupt
for 10 frames received or timeout of 512 us.
tx_coalesce=n - Number of tx frame handled each interrupt.
Set n > 1 can reduce the interrupts
congestion usually lower performance of
high speed network card. Default is 16.
rx_flow=[1|0] - Specifies the Rx flow control. If rx_flow=1,
the Rx flow control enable.
tx_flow=[1|0] - Specifies the Tx flow control. If tx_flow=0,
the Tx flow control disable else driver
autodetect.
rx_flow=[1|0] - Specifies the Rx flow control. If rx_flow=0,
the Rx flow control enable else driver
autodetect.
Configuration Script Sample
...
...
drivers/net/8139cp.c
View file @
c1bc73b5
...
...
@@ -100,13 +100,16 @@ MODULE_PARM_DESC (multicast_filter_limit, "8139cp maximum number of filtered mul
#define CP_DEF_MSG_ENABLE (NETIF_MSG_DRV | \
NETIF_MSG_PROBE | \
NETIF_MSG_LINK)
#define CP_NUM_STATS 14
/* struct cp_dma_stats, plus one */
#define CP_STATS_SIZE 64
/* size in bytes of DMA stats block */
#define CP_REGS_SIZE (0xff + 1)
#define CP_REGS_VER 1
/* version 1 */
#define CP_RX_RING_SIZE 64
#define CP_TX_RING_SIZE 64
#define CP_RING_BYTES \
((sizeof(struct cp_desc) * CP_RX_RING_SIZE) + \
(sizeof(struct cp_desc) * CP_TX_RING_SIZE))
(sizeof(struct cp_desc) * CP_TX_RING_SIZE) + \
CP_STATS_SIZE)
#define NEXT_TX(N) (((N) + 1) & (CP_TX_RING_SIZE - 1))
#define NEXT_RX(N) (((N) + 1) & (CP_RX_RING_SIZE - 1))
#define TX_BUFFS_AVAIL(CP) \
...
...
@@ -135,6 +138,7 @@ enum {
/* NIC register offsets */
MAC0
=
0x00
,
/* Ethernet hardware address. */
MAR0
=
0x08
,
/* Multicast filter. */
StatsAddr
=
0x10
,
/* 64-bit start addr of 64-byte DMA stats blk */
TxRingAddr
=
0x20
,
/* 64-bit start addr of Tx ring */
HiTxRingAddr
=
0x28
,
/* 64-bit start addr of high priority Tx ring */
Cmd
=
0x37
,
/* Command register */
...
...
@@ -197,6 +201,9 @@ enum {
RxErrLong
=
(
1
<<
21
),
/* Rx error, packet > 4096 bytes */
RxErrFIFO
=
(
1
<<
22
),
/* Rx error, FIFO overflowed, pkt bad */
/* StatsAddr register */
DumpStats
=
(
1
<<
3
),
/* Begin stats dump */
/* RxConfig register */
RxCfgFIFOShift
=
13
,
/* Shift, to get Rx FIFO thresh value */
RxCfgDMAShift
=
8
,
/* Shift, to get Rx Max DMA value */
...
...
@@ -284,6 +291,22 @@ struct ring_info {
unsigned
frag
;
};
struct
cp_dma_stats
{
u64
tx_ok
;
u64
rx_ok
;
u64
tx_err
;
u32
rx_err
;
u16
rx_fifo
;
u16
frame_align
;
u32
tx_ok_1col
;
u32
tx_ok_mcol
;
u64
rx_ok_phys
;
u64
rx_ok_bcast
;
u32
rx_ok_mcast
;
u16
tx_abort
;
u16
tx_underrun
;
}
__attribute__
((
packed
));
struct
cp_extra_stats
{
unsigned
long
rx_frags
;
};
...
...
@@ -312,6 +335,8 @@ struct cp_private {
struct
net_device_stats
net_stats
;
struct
cp_extra_stats
cp_stats
;
struct
cp_dma_stats
*
nic_stats
;
dma_addr_t
nic_stats_dma
;
struct
pci_dev
*
pdev
;
u32
rx_config
;
...
...
@@ -373,6 +398,26 @@ static struct pci_device_id cp_pci_tbl[] __devinitdata = {
};
MODULE_DEVICE_TABLE
(
pci
,
cp_pci_tbl
);
static
struct
{
const
char
str
[
ETH_GSTRING_LEN
];
}
ethtool_stats_keys
[]
=
{
{
"tx_ok"
},
{
"rx_ok"
},
{
"tx_err"
},
{
"rx_err"
},
{
"rx_fifo"
},
{
"frame_align"
},
{
"tx_ok_1col"
},
{
"tx_ok_mcol"
},
{
"rx_ok_phys"
},
{
"rx_ok_bcast"
},
{
"rx_ok_mcast"
},
{
"tx_abort"
},
{
"tx_underrun"
},
{
"rx_frags"
},
};
static
inline
void
cp_set_rxbufsize
(
struct
cp_private
*
cp
)
{
unsigned
int
mtu
=
cp
->
dev
->
mtu
;
...
...
@@ -949,9 +994,9 @@ static void cp_init_hw (struct cp_private *cp)
cpw32_f
(
HiTxRingAddr
+
4
,
0
);
cpw32_f
(
RxRingAddr
,
cp
->
ring_dma
);
cpw32_f
(
RxRingAddr
+
4
,
0
);
cpw32_f
(
RxRingAddr
+
4
,
0
);
/* FIXME: 64-bit PCI */
cpw32_f
(
TxRingAddr
,
cp
->
ring_dma
+
(
sizeof
(
struct
cp_desc
)
*
CP_RX_RING_SIZE
));
cpw32_f
(
TxRingAddr
+
4
,
0
);
cpw32_f
(
TxRingAddr
+
4
,
0
);
/* FIXME: 64-bit PCI */
cpw16
(
MultiIntr
,
0
);
...
...
@@ -1010,10 +1055,19 @@ static int cp_init_rings (struct cp_private *cp)
static
int
cp_alloc_rings
(
struct
cp_private
*
cp
)
{
cp
->
rx_ring
=
pci_alloc_consistent
(
cp
->
pdev
,
CP_RING_BYTES
,
&
cp
->
ring_dma
);
if
(
!
cp
->
rx_ring
)
void
*
mem
;
mem
=
pci_alloc_consistent
(
cp
->
pdev
,
CP_RING_BYTES
,
&
cp
->
ring_dma
);
if
(
!
mem
)
return
-
ENOMEM
;
cp
->
rx_ring
=
mem
;
cp
->
tx_ring
=
&
cp
->
rx_ring
[
CP_RX_RING_SIZE
];
mem
+=
(
CP_RING_BYTES
-
CP_STATS_SIZE
);
cp
->
nic_stats
=
mem
;
cp
->
nic_stats_dma
=
cp
->
ring_dma
+
(
CP_RING_BYTES
-
CP_STATS_SIZE
);
return
cp_init_rings
(
cp
);
}
...
...
@@ -1052,6 +1106,7 @@ static void cp_free_rings (struct cp_private *cp)
pci_free_consistent
(
cp
->
pdev
,
CP_RING_BYTES
,
cp
->
rx_ring
,
cp
->
ring_dma
);
cp
->
rx_ring
=
NULL
;
cp
->
tx_ring
=
NULL
;
cp
->
nic_stats
=
NULL
;
}
static
int
cp_open
(
struct
net_device
*
dev
)
...
...
@@ -1181,6 +1236,7 @@ static int cp_ethtool_ioctl (struct cp_private *cp, void *useraddr)
strcpy
(
info
.
version
,
DRV_VERSION
);
strcpy
(
info
.
bus_info
,
cp
->
pdev
->
slot_name
);
info
.
regdump_len
=
CP_REGS_SIZE
;
info
.
n_stats
=
CP_NUM_STATS
;
if
(
copy_to_user
(
useraddr
,
&
info
,
sizeof
(
info
)))
return
-
EFAULT
;
return
0
;
...
...
@@ -1359,6 +1415,83 @@ static int cp_ethtool_ioctl (struct cp_private *cp, void *useraddr)
return
0
;
}
/* get string list(s) */
case
ETHTOOL_GSTRINGS
:
{
struct
ethtool_gstrings
estr
=
{
ETHTOOL_GSTRINGS
};
if
(
copy_from_user
(
&
estr
,
useraddr
,
sizeof
(
estr
)))
return
-
EFAULT
;
if
(
estr
.
string_set
!=
ETH_SS_STATS
)
return
-
EINVAL
;
estr
.
len
=
CP_NUM_STATS
;
if
(
copy_to_user
(
useraddr
,
&
estr
,
sizeof
(
estr
)))
return
-
EFAULT
;
if
(
copy_to_user
(
useraddr
+
sizeof
(
estr
),
&
ethtool_stats_keys
,
sizeof
(
ethtool_stats_keys
)))
return
-
EFAULT
;
return
0
;
}
/* get NIC-specific statistics */
case
ETHTOOL_GSTATS
:
{
struct
ethtool_stats
estats
=
{
ETHTOOL_GSTATS
};
u64
*
tmp_stats
;
unsigned
int
work
=
100
;
const
unsigned
int
sz
=
sizeof
(
u64
)
*
CP_NUM_STATS
;
int
i
;
/* begin NIC statistics dump */
cpw32
(
StatsAddr
+
4
,
0
);
/* FIXME: 64-bit PCI */
cpw32
(
StatsAddr
,
cp
->
nic_stats_dma
|
DumpStats
);
cpr32
(
StatsAddr
);
estats
.
n_stats
=
CP_NUM_STATS
;
if
(
copy_to_user
(
useraddr
,
&
estats
,
sizeof
(
estats
)))
return
-
EFAULT
;
while
(
work
--
>
0
)
{
if
((
cpr32
(
StatsAddr
)
&
DumpStats
)
==
0
)
break
;
cpu_relax
();
}
if
(
cpr32
(
StatsAddr
)
&
DumpStats
)
return
-
EIO
;
tmp_stats
=
kmalloc
(
sz
,
GFP_KERNEL
);
if
(
!
tmp_stats
)
return
-
ENOMEM
;
memset
(
tmp_stats
,
0
,
sz
);
i
=
0
;
tmp_stats
[
i
++
]
=
le64_to_cpu
(
cp
->
nic_stats
->
tx_ok
);
tmp_stats
[
i
++
]
=
le64_to_cpu
(
cp
->
nic_stats
->
rx_ok
);
tmp_stats
[
i
++
]
=
le64_to_cpu
(
cp
->
nic_stats
->
tx_err
);
tmp_stats
[
i
++
]
=
le32_to_cpu
(
cp
->
nic_stats
->
rx_err
);
tmp_stats
[
i
++
]
=
le16_to_cpu
(
cp
->
nic_stats
->
rx_fifo
);
tmp_stats
[
i
++
]
=
le16_to_cpu
(
cp
->
nic_stats
->
frame_align
);
tmp_stats
[
i
++
]
=
le32_to_cpu
(
cp
->
nic_stats
->
tx_ok_1col
);
tmp_stats
[
i
++
]
=
le32_to_cpu
(
cp
->
nic_stats
->
tx_ok_mcol
);
tmp_stats
[
i
++
]
=
le64_to_cpu
(
cp
->
nic_stats
->
rx_ok_phys
);
tmp_stats
[
i
++
]
=
le64_to_cpu
(
cp
->
nic_stats
->
rx_ok_bcast
);
tmp_stats
[
i
++
]
=
le32_to_cpu
(
cp
->
nic_stats
->
rx_ok_mcast
);
tmp_stats
[
i
++
]
=
le16_to_cpu
(
cp
->
nic_stats
->
tx_abort
);
tmp_stats
[
i
++
]
=
le16_to_cpu
(
cp
->
nic_stats
->
tx_underrun
);
tmp_stats
[
i
++
]
=
cp
->
cp_stats
.
rx_frags
;
if
(
i
!=
CP_NUM_STATS
)
BUG
();
i
=
copy_to_user
(
useraddr
+
sizeof
(
estats
),
tmp_stats
,
sz
);
kfree
(
tmp_stats
);
if
(
i
)
return
-
EFAULT
;
return
0
;
}
default:
break
;
}
...
...
drivers/net/dl2k.c
View file @
c1bc73b5
/* D-Link DL2000-based Gigabit Ethernet Adapter Linux driver */
/*
Copyright (c) 2001,2002 by D-Link Corporation
Copyright (c) 2001,
2002 by D-Link Corporation
Written by Edward Peng.<edward_peng@dlink.com.tw>
Created 03-May-2001, base on Linux' sundance.c.
...
...
@@ -33,12 +33,13 @@
1.11 2002/05/23 Added ISR schedule scheme.
Fixed miscount of rx frame error for DGE-550SX.
Fixed VLAN bug.
1.12 2002/06/13 Lock tx_coalesce=1 on 10/100Mbps mode.
*/
#include "dl2k.h"
static
char
version
[]
__devinitdata
=
KERN_INFO
"D-Link DL2000-based linux driver v1.1
1 2002/05/2
3
\n
"
;
KERN_INFO
"D-Link DL2000-based linux driver v1.1
2 2002/06/1
3
\n
"
;
#define MAX_UNITS 8
static
int
mtu
[
MAX_UNITS
];
...
...
@@ -138,15 +139,15 @@ rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent)
}
SET_MODULE_OWNER
(
dev
);
#ifdef USE_IO_OPS
ioaddr
=
pci_resource_start
(
pdev
,
0
);
#else
#ifdef MEM_MAPPING
ioaddr
=
pci_resource_start
(
pdev
,
1
);
ioaddr
=
(
long
)
ioremap
(
ioaddr
,
RIO_IO_SIZE
);
if
(
!
ioaddr
)
{
err
=
-
ENOMEM
;
goto
err_out_dev
;
}
#else
ioaddr
=
pci_resource_start
(
pdev
,
0
);
#endif
dev
->
base_addr
=
ioaddr
;
dev
->
irq
=
irq
;
...
...
@@ -158,6 +159,7 @@ rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent)
/* Parse manual configuration */
np
->
an_enable
=
1
;
np
->
tx_coalesce
=
1
;
if
(
card_idx
<
MAX_UNITS
)
{
if
(
media
[
card_idx
]
!=
NULL
)
{
np
->
an_enable
=
0
;
...
...
@@ -213,7 +215,7 @@ rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent)
if
(
tx_coalesce
<
1
)
tx_coalesce
=
1
;
if
(
tx_coalesce
>
TX_RING_SIZE
-
1
)
else
if
(
tx_coalesce
>
TX_RING_SIZE
-
1
)
tx_coalesce
=
TX_RING_SIZE
-
1
;
}
dev
->
open
=
&
rio_open
;
...
...
@@ -303,7 +305,7 @@ rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent)
err_out_unmap_tx:
pci_free_consistent
(
pdev
,
TX_TOTAL_SIZE
,
np
->
tx_ring
,
np
->
tx_ring_dma
);
err_out_iounmap:
#if
ndef USE_IO_OPS
#if
def MEM_MAPPING
iounmap
((
void
*
)
ioaddr
);
err_out_dev:
...
...
@@ -361,7 +363,7 @@ parse_eeprom (struct net_device *dev)
}
/* Check CRC */
crc
=
~
ether_crc_le
(
256
-
4
,
sromdata
);
crc
=
~
ether_crc_le
(
256
-
4
,
sromdata
);
if
(
psrom
->
crc
!=
crc
)
{
printk
(
KERN_ERR
"%s: EEPROM data CRC error.
\n
"
,
dev
->
name
);
return
-
1
;
...
...
@@ -636,7 +638,7 @@ start_xmit (struct sk_buff *skb, struct net_device *dev)
/* DL2K bug: DMA fails to get next descriptor ptr in 10Mbps mode
* Work around: Always use 1 descriptor in 10Mbps mode */
if
(
entry
%
tx_coalesce
==
0
||
np
->
speed
==
10
)
if
(
entry
%
np
->
tx_coalesce
==
0
||
np
->
speed
==
10
)
txdesc
->
status
=
cpu_to_le64
(
entry
|
tfc_vlan_tag
|
WordAlignDisable
|
TxDMAIndicate
|
...
...
@@ -936,6 +938,10 @@ rio_error (struct net_device *dev, int int_status)
mii_get_media_pcs
(
dev
);
else
mii_get_media
(
dev
);
if
(
np
->
speed
==
1000
)
np
->
tx_coalesce
=
tx_coalesce
;
else
np
->
tx_coalesce
=
1
;
macctrl
=
0
;
macctrl
|=
(
np
->
vlan
)
?
AutoVLANuntagging
:
0
;
macctrl
|=
(
np
->
full_duplex
)
?
DuplexSelect
:
0
;
...
...
@@ -1671,7 +1677,7 @@ rio_remove1 (struct pci_dev *pdev)
np
->
rx_ring_dma
);
pci_free_consistent
(
pdev
,
TX_TOTAL_SIZE
,
np
->
tx_ring
,
np
->
tx_ring_dma
);
#if
ndef USE_IO_OPS
#if
def MEM_MAPPING
iounmap
((
char
*
)
(
dev
->
base_addr
));
#endif
kfree
(
dev
);
...
...
drivers/net/dl2k.h
View file @
c1bc73b5
...
...
@@ -33,15 +33,15 @@
#include <linux/delay.h>
#include <linux/spinlock.h>
#include <linux/time.h>
#define TX_RING_SIZE
128
#define TX_QUEUE_LEN
120
/* Limit ring entries actually used.
*/
#define RX_RING_SIZE
128
#define TX_RING_SIZE
256
#define TX_QUEUE_LEN
(TX_RING_SIZE - 1)
/* Limit ring entries actually used.
*/
#define RX_RING_SIZE
256
#define TX_TOTAL_SIZE TX_RING_SIZE*sizeof(struct netdev_desc)
#define RX_TOTAL_SIZE RX_RING_SIZE*sizeof(struct netdev_desc)
/* This driver was written to use PCI memory space, however x86-oriented
hardware often uses I/O space accesses. */
#if
def USE_IO_OPS
#if
ndef MEM_MAPPING
#undef readb
#undef readw
#undef readl
...
...
@@ -658,6 +658,7 @@ struct netdev_private {
unsigned
int
chip_id
;
/* PCI table chip id */
unsigned
int
rx_coalesce
;
/* Maximum frames each RxDMAComplete intr */
unsigned
int
rx_timeout
;
/* Wait time between RxDMAComplete intr */
unsigned
int
tx_coalesce
;
/* Maximum frames each tx interrupt */
unsigned
int
full_duplex
:
1
;
/* Full-duplex operation requested. */
unsigned
int
an_enable
:
2
;
/* Auto-Negotiated Enable */
unsigned
int
jumbo
:
1
;
/* Jumbo frame enable */
...
...
@@ -681,10 +682,10 @@ struct netdev_private {
};
/* The station address location in the EEPROM. */
#ifdef USE_IO_OPS
#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_IO | PCI_ADDR0)
#else
#ifdef MEM_MAPPING
#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_MEM | PCI_ADDR1)
#else
#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_IO | PCI_ADDR0)
#endif
/* The struct pci_device_id consist of:
vendor, device Vendor and device ID to match (or PCI_ANY_ID)
...
...
include/linux/ethtool.h
View file @
c1bc73b5
...
...
@@ -39,7 +39,8 @@ struct ethtool_drvinfo {
char
bus_info
[
ETHTOOL_BUSINFO_LEN
];
/* Bus info for this IF. */
/* For PCI devices, use pci_dev->slot_name. */
char
reserved1
[
32
];
char
reserved2
[
20
];
char
reserved2
[
16
];
u32
n_stats
;
/* number of u64's from ETHTOOL_GSTATS */
u32
testinfo_len
;
u32
eedump_len
;
/* Size of data from ETHTOOL_GEEPROM (bytes) */
u32
regdump_len
;
/* Size of data from ETHTOOL_GREGS (bytes) */
...
...
@@ -242,6 +243,13 @@ struct ethtool_test {
u64
data
[
0
];
};
/* for dumping NIC-specific statistics */
struct
ethtool_stats
{
u32
cmd
;
/* ETHTOOL_GSTATS */
u32
n_stats
;
/* number of u64's being returned */
u64
data
[
0
];
};
/* CMDs currently supported */
#define ETHTOOL_GSET 0x00000001
/* Get settings. */
#define ETHTOOL_SSET 0x00000002
/* Set settings, privileged. */
...
...
@@ -272,6 +280,7 @@ struct ethtool_test {
#define ETHTOOL_TEST 0x0000001a
/* execute NIC self-test, priv. */
#define ETHTOOL_GSTRINGS 0x0000001b
/* get specified string set */
#define ETHTOOL_PHYS_ID 0x0000001c
/* identify the NIC */
#define ETHTOOL_GSTATS 0x0000001d
/* get NIC-specific statistics */
/* compatibility with older code */
#define SPARC_ETH_GSET ETHTOOL_GSET
...
...
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