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
Kirill Smelkov
linux
Commits
7ca66aff
Commit
7ca66aff
authored
Jun 18, 2002
by
Linus Torvalds
Browse files
Options
Browse Files
Download
Plain Diff
Merge
http://gkernel.bkbits.net/net-drivers-2.5
into home.transmeta.com:/home/torvalds/v2.5/linux
parents
33e448ef
c1bc73b5
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 @
7ca66aff
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 @
7ca66aff
...
...
@@ -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 @
7ca66aff
/* 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 @
7ca66aff
...
...
@@ -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 @
7ca66aff
...
...
@@ -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