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
c43fb198
Commit
c43fb198
authored
Feb 04, 2004
by
Jeff Garzik
Browse files
Options
Browse Files
Download
Plain Diff
Merge redhat.com:/spare/repo/netdev-2.6/8139too
into redhat.com:/spare/repo/net-drivers-2.5
parents
6791a22a
e790cf5f
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
245 additions
and
582 deletions
+245
-582
Documentation/networking/8139too.txt
Documentation/networking/8139too.txt
+0
-449
drivers/net/8139too.c
drivers/net/8139too.c
+227
-133
drivers/net/Kconfig
drivers/net/Kconfig
+18
-0
No files found.
Documentation/networking/8139too.txt
deleted
100644 → 0
View file @
6791a22a
"8139too" Fast Ethernet driver for Linux
RTL-8139, -8129, and -8130 10/100 Fast Ethernet adapters
Copyright 2000,2001 Jeff Garzik <jgarzik@pobox.com>
http://sourceforge.net/projects/gkernel/
Architectures supported (all PCI platforms):
x86, Alpha AXP, PowerPC, Sparc64
Kernel versions supported: 2.4.x
Disclaimer
----------
DO NOT CONTACT DONALD BECKER FOR SUPPORT OF THIS DRIVER, his driver is
completely different and maintained independently of the 8139too code base.
Requirements
------------
Kernel 2.4.3 or later.
A Fast Ethernet adapter containing an RTL8139-based chip.
Introduction
------------
The "8139too" Fast Ethernet driver for Linux 2.4.0 is a substantial
modification of the experimental rtl8139 driver from Donald Becker,
some versions of which appeared in 2.2.x and 2.3.x kernels. The
RTL-8139 is a very low-cost Fast Ethernet chip, which makes it very
popular.
The step from 2.2.x to 2.4.x kernels brings many new features to Linux
device drivers. Features for MMIO resources, a standard hot-plug API,
and other interfaces are now becoming requirements, as drivers move
off the x86 platform. With that in mind, I have begun updating the
RTL-8139 driver to current 2.3.x (2.4) kernel standards and APIs, and
fixing the problems that users have been encountering.
Features of 8139too
-------------------
[note - this list intended for people familiar with kernel drivers]
** 100% MMIO, for full speed operation. All users (so far) have
reported performance increases over their existing RTL drivers.
** Multi-platform support: x86, Alpha, PPC, ...
** Use proper SMP spinlocking, fixing SMP interrupt bugs, making the
driver portable to non-x86 SMP platforms in the process.
** Use new PCI driver API for seamless, low-maintenance hot-plug support
** Several bugs fixes from original rtl8139 1.08r (October 5, 1999),
including the very common "transmit timeout" problem.
* Use new resource allocation API, required for hot-plug support
* Use new register read/write macros
* initcall support (module_init/exit)
* vastly improved debug tracing support
* code formatting in many places for readability
* use new init_etherdev() facilities
...and probably some other less important changes which I forgot.
Installation
------------
OPTION 1: Build inside kernel tree (into kernel image, or as module)
(overwrite 8139too driver in kernel tree with different version)
1) cp 8139too.c $my_source_tree/drivers/net/8139too.c
OPTION 2: Build outside kernel tree
Use the included Makefile.
Tested Adapters
---------------
AOpen ALN-325C
AT-2500TX 10/100 PCI Fast Ethernet Network Adapter Card
D-Link DFE-530TX
Cnet CNF401 'SinglePoint' 10/100 Base-TX
Genius GF 100TXR4 Fast Ethernet 10/100M PCI Network Card
KTI KF-230TX
KTI KF-230TX/2
Lantech FastNet TX
Ovislink Fast Ethernet
Planet ENW-9504 (V.4) 10/100
SDT Jeoun Fast PCI-TX
SMC EZNET 10/100
UNEX NexNIC ND012C
(please add your adapter model to this list)
Status of Platform Support
--------------------------
(see errata below for details)
x86: tested, stable
Alpha AXP: tested, stable
PowerPC: tested, unstable
Sparc64: not tested
Special Thanks
--------------
The following people contributed invaluable testing time, feedback
and/or patches during the development of this driver. Thanks to all
of them.
Donald Becker, Alan Cox, Richard Stallman, Linus Torvalds - inspiration
Alan Cox, Gerard Roudier - insight on posted MMIO writes
Martin Mares - code review
Tigran Aivazian - testing, code review, and a bug fix
Chmouel Boudjnah, Alexander Dietrich, Oleg Drokin,
James Fidell, Taso Hatzi, Peter K - intrepid test team
And thanks to every supporter free software.
(see top of 8139too.c for further credits and kudos)
Submitting Bug Reports
----------------------
Obtain and compile the modified rtl8139-diag source code from the
8139too driver Web site, http://sourceforge.net/projects/gkernel/
This diagnostics programs, originally from Donald Becker, has been
modified to display all registers on your RTL8139 chip, not just the
first 0x80.
If possible, send the output of a working and broken driver with
rtl8139-diag -mmaaavvveefN > my-output-file.txt
Send "lspci -vvv" or "cat /proc/pci" output for PCI information.
Known Bugs / Errata / To-Do
---------------------------
The following issues are known, and are actively being pursued. Patches
to resolve these issues is welcome. If a problem occurs which is not in
the list, please report it. That's why we do beta releases, after all...
1) Work with Donald to merge fixes and updates into his driver.
2) ETHTOOL_SSET support
3) PPC platform has stability problems. (XXX: verify this is still true)
4) Sparc64 platform not tested at all.
8) Much improved command line / module parameter setup. (patches and
suggestions welcome) (WIP)
9) Better documentation. (patches welcome)
12) 10base-T support flaky or slow (todo: verify this is still true)
Change History
--------------
Version 0.9.26 - August 9, 2002
* Fix MII ioctl phy id corruption.
* Fix big-endian multicast bug.
* Support register dumps via ethtool.
* Fix several uses of 'len' after potential skb free, in dev->hard_start_xmit
* Replace several "magic numbers" with their proper representation
constants in linux/mii.h.
* Support ethtool media interface via generic kernel MII API
* Export NIC-specific statistics via ethtool.
* Proper support for RTL8139 rev K. (can be disabled via
compile-time conditional)
* Add PCI ids for new 8139 boards.
* Use ethernet crc via generic linux/crc32.h kernel API.
* Better RX reset. Old rx-reset method still available via
a compile-time conditional.
* Only account specific RX errors if rx_status is !OK
Version 0.9.22 - November 8, 2001
* Additional retries before aborting Tx
* Do not write other TxConfig bits when writing clear-abort bit.
* Ack TxErr intr status after each Tx abort, too.
* Fix oops in interface restart
Version 0.9.21 - November 1, 2001
* Disable early Rx, it hurts performance and creates races.
* Remove DPRINTK macro function tracing.
* Better interrupt sharing behavior.
* Acknowledge PCI errors.
* Remove early-Rx acknowledgement, unnecessary
* Remove code for uncommon case where Tx packets are
properly aligned, and do not need to be copied.
Tx packets are now always copied into a static DMA buffer,
which is allocated at interface open.
* Fix problems with kernel thread exit.
Version 0.9.20 - October 18, 2001
* Print out notice when 8139C+ chip is detected
* Add id for D-Link DFE690TXD pcmcia cardbus card (Gert Dewit)
Version 0.9.19 - October 9, 2001
* Eliminate buffer copy for unaligned Tx's (manfred)
* Better RX error recovery (manfred)
* Wake-On-LAN and ETHTOOL_GSET support (Kalle Niemitalo)
* Fix assertion in PIO mode (various)
Version 0.9.18 - July 6, 2001
* Fix race leading to crashes on some machines.
* Minimize race leading to low performance.
* Correct interrupt acknowledgement to cover all three
relevant Rx events.
* Add ethtool driver info support.
* Collect additional driver-internal statistics.
* Add descriptions for module parameters.
* Support new SIOCxMIIxxx ioctls added in kernel 2.4.6.
* Multicast filter big endian fix.
* Support new PCI PM API added in kernel 2.4.6.
Version 0.9.17 - May 7, 2001
* Fix chipset wakeup bug which prevent media connection for 8139B
* Print out "media is unconnected..." instead of
"partner ability 0000"
Version 0.9.16 - April 14, 2001
* Complete MMIO audit, disable read-after-every-write
* Update Rx interrupt handling
* Enable Early Rx thresholds, highly recommended to reduce
Rx FIFO overflow
* Make 8129 support conditional
* Support for new 2.4.3 kernel APIs
* More correct PIO/MMIO PCI BAR region size checking
* Add check for totally dead/missing hardware
* Disable media timer code to "set full duplex"
* s/spin_lock_irq/spin_lock_irqsave/
* Only set AcceptMulticast if more than one mc address
* Only set rx_mode if changed, in set_rx_mode
* Only suspend/resume if interface is up
* Always print out version upon module load, even if no devices found
Version 0.9.15 - February 20, 2001
* Call pci_enable_device to wake up/assign resource to device,
before actually using it.
* Support wacky clone PCI ids (report from Norival Toniato Junior)
* Text spelling corrections
* Make sure tp->phys[] is signed
* Always wake queue after hw restart, in tx_timeout
* Record time of last received packet
Version 0.9.14 - January 11, 2001
* Merge some changes from Becker version 1.13:
* Add DFE 538TX PCI id
* MII read/write functions updated
* Cfg93[45]6 lock/unlock fix
* RTL-8129 (MII) support
* Clean up spinlocking
Version 0.9.13 - December, 2000
* Clear blocked signals, avoid buffer overrun setting current->comm
* Remove bogus PCI BAR length assertions
* Remove unused 'debug' module parameter
Version 0.9.12 - November 23, 2000
* Kill major Tx stop/wake queue race
* Use SET_MODULE_OWNER and fix module unload race
* Fix cable length ("Twister") tuning
* Proper media[] array length checking
* Replace timer with kernel thread for twister tuning state machine
and media checking. Fixes mdio_xxx locking, now mdio_xxx is always
protected by rtnl_lock semaphore.
* Correct some sledgehammer a.k.a. overzealous spin-locks
* Performance: Eliminate atomic_t for Tx counters, we don't need it
* Performance: Don't copy Tx buffer if the rare case occurs where it
is aligned perfectly for us.
* Eliminate needless casting of dev->priv
* PIO mode selection and Twister tuning are now CONFIG_xxx options
(though purposefully not in net/Config.in... yet)
Version 0.9.11 - October 28, 2000
* Do not fail when PIO and MMIO region lengths do not match.
(They don't on some CardBus models, at least)
* Sanity check Rx packet status and size (Tobias)
* When handling a Tx timeout, disable Tx ASAP if not already.
* Do not inline Tx interrupt handler (better register usage)
* Handle dirty_tx signed integer wrap
* Do not abort Rx processing on lack of memory, keep going
until the current Rx ring is completely handling. (Tobias)
* Clean up rtl8139_close
* Whitespace correction for dev_kfree_skb_irq call
Version 0.9.10 - September 12, 2000
* Never wrap an Rx packet (faster Rx interrupt handling)
* Clear all TxAborted conditions (bug fix)
* Correct copyright
* More credits
* Update NWay doc URL
* Clean up commonly used ifdef switches
* Reorg info displayed at bootup/modprobe time
* Remove some unneeded spinlocks
* Misc cosmetic code cleanup
* Always print interrupt status for abnormal interrupts
* Use RealTek-recommended FIFO and DMA burst settings (1024 bytes)
Version 0.9.9 - September 9, 2000
* Fix oops-able bug in Rx ring wrap calculation (David Ford)
* Use PIO instead of MMIO when USE_IO_OPS is defined
* Move Rx error handling out of Rx interrupt handler, resulting in
tighter Rx interrupt processing
Version 0.9.8 - September 7, 2000
* Propagate request_irq error value (andrew morton)
* Correct potential oops bug in PCI DMA unmap code
* Fix bugs related to counting/discounting of 32-bit CRC in each Rx packet
* Fix 16/32-bit bug in interrupt status check
* Timer cleanups (andrew morton)
Version 0.9.7 - June 11, 2000
* Fix support for older chips (RTL8139 early chips should now work again)
Version 0.9.6 - May 30, 2000
* Fix 4-extra-bytes bug
(thanks to Markus Westergren, via Santiago Garcia Mantinan)
* Yet more improved chip recognition
Version 0.9.5 - May 17, 2000
* Improved chip version recognition
* Continue banging away at receiver hang problem
* Use spin_lock_irq in another spot
* Don't print anything on pci_enable_device, it does so for us
* Disable buggy NWay code
* Define TxConfig bitmasks
Version 0.9.4.1 - April 27, 2000 - third public beta release
* Replace several "magic numbers" with symbolic constants
* Differentiate between board-specific info and chip-specific info
(allows for easier support of specific boards or chips)
* Move some of the transmit side outside of the spinlock
by using atomic variables. Use spin_lock_irq instead of
spin_lock_irq{save,restore} in select places, for better performance.
* New module option "media" for forcing media selection. Functions the
same as "options" in other drivers, and will soon be renamed
'options' to be homogeneous.
* New power management wake-up code
* Slightly more verbose chip id messages in kernel log
* Add/correct chip register constant list
* New chipset wake up (open) logic
* No longer locks CONFIGx updates
* Do not set Interfame Gap (IFG) bits in TxConfig
* Better Rx reset logic in case of Rx FIFO Overflow
* For chips which support it, enable bit to automatically clear Rx
FIFO overflow
* No longer enable and disable interrupts in interrupt handler
(technique borrowed from BSD driver, appears to have problems
with some chips)
* H/W spinlock now protects ioctl
* Chipset-dependent RxConfig settings
Version 0.9.3.3.2 - Feb 22, 2000 - second public beta release
* Begin integration of Daniel Kobras' MMIO flush patch (disabled for now)
* Softnet logic updates to fix bugs and improve performance
* Dynamic sizing of I/O resources (0x80 for older chips, 0xFF for newer ones)
* Remove bogus SiS entries from PCI probe table
* Add support for cards
"Delta Electronics 8139 10/100BaseTX"
"Addtron Technolgy 8139 10/100BaseTX"
* Fix major bug with rx ring buffer size (also present in rtl8139.c 1.08r)
* PCI DMA mapping by Dave Miller
* Complete rewrite of SMP locking logic
* Hotplug support
* Call rtl8139_hw_start from rtl8139_open, and remove duplicated code
from rtl8139_open
* Reset NWay registers to sane defaults on rtl8139_open/hw_start
* Miscellaneous code cleanup
Version 0.7.0 - Feb 7, 2000 - first public beta release
* Initial public version, derived from Donald Becker's rtl8139.c v1.08r
[EOF]
drivers/net/8139too.c
View file @
c43fb198
...
...
@@ -92,7 +92,7 @@
*/
#define DRV_NAME "8139too"
#define DRV_VERSION "0.9.2
6
"
#define DRV_VERSION "0.9.2
7
"
#include <linux/config.h>
...
...
@@ -117,17 +117,17 @@
#define RTL8139_DRIVER_NAME DRV_NAME " Fast Ethernet driver " DRV_VERSION
#define PFX DRV_NAME ": "
/* Default Message level */
#define RTL8139_DEF_MSG_ENABLE (NETIF_MSG_DRV | \
NETIF_MSG_PROBE | \
NETIF_MSG_LINK)
/* enable PIO instead of MMIO, if CONFIG_8139TOO_PIO is selected */
#ifdef CONFIG_8139TOO_PIO
#define USE_IO_OPS 1
#endif
/* use a 16K rx ring buffer instead of the default 32K */
#ifdef CONFIG_SH_DREAMCAST
#define USE_BUF16K 1
#endif
/* define to 1 to enable copious debugging info */
#undef RTL8139_DEBUG
...
...
@@ -146,8 +146,8 @@
# define assert(expr) do {} while (0)
#else
# define assert(expr) \
if(
!(expr)) {
\
printk( "Assertion failed! %s,%s,%s,line=%d\n", \
if(
unlikely(!(expr))) {
\
printk(
KERN_ERR
"Assertion failed! %s,%s,%s,line=%d\n", \
#expr,__FILE__,__FUNCTION__,__LINE__); \
}
#endif
...
...
@@ -159,9 +159,6 @@
static
int
media
[
MAX_UNITS
]
=
{
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
};
static
int
full_duplex
[
MAX_UNITS
]
=
{
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
};
/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
static
int
max_interrupt_work
=
20
;
/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
The RTL chips use a 64 element hash table based on the Ethernet CRC. */
static
int
multicast_filter_limit
=
32
;
...
...
@@ -169,16 +166,16 @@ static int multicast_filter_limit = 32;
/* bitmapped message enable number */
static
int
debug
=
-
1
;
/* Size of the in-memory receive ring. */
#ifdef USE_BUF16K
#define RX_BUF_LEN_IDX 1
/* 0==8K, 1==16K, 2==32K, 3==64K */
#else
#define RX_BUF_LEN_IDX 2
/* 0==8K, 1==16K, 2==32K, 3==64K */
#endif
#define RX_BUF_LEN (8192 << RX_BUF_LEN_IDX)
/* Ring size is now a config option */
#define RX_BUF_LEN (8192 << CONFIG_8139_RXBUF_IDX)
#define RX_BUF_PAD 16
#define RX_BUF_WRAP_PAD 2048
/* spare padding to handle lack of packet wrap */
#if RX_BUF_LEN == 65536
#define RX_BUF_TOT_LEN RX_BUF_LEN
#else
#define RX_BUF_TOT_LEN (RX_BUF_LEN + RX_BUF_PAD + RX_BUF_WRAP_PAD)
#endif
/* Number of Tx descriptor registers. */
#define NUM_TX_DESC 4
...
...
@@ -251,6 +248,10 @@ static struct pci_device_id rtl8139_pci_tbl[] = {
{
0x11db
,
0x1234
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
RTL8139
},
{
0x1432
,
0x9130
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
RTL8139
},
{
0x02ac
,
0x1012
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
RTL8139
},
{
0x018a
,
0x0106
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
RTL8139
},
{
0x126c
,
0x1211
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
RTL8139
},
{
0x1743
,
0x8139
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
RTL8139
},
{
0x021b
,
0x8139
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
RTL8139
},
#ifdef CONFIG_SH_SECUREEDGE5410
/* Bogus 8139 silicon reports 8129 without external PROM :-( */
...
...
@@ -450,7 +451,7 @@ enum RxConfigBits {
RxCfgRcv32K
=
(
1
<<
12
),
RxCfgRcv64K
=
(
1
<<
11
)
|
(
1
<<
12
),
/* Disable packet wrap at end of Rx buffer */
/* Disable packet wrap at end of Rx buffer
. (not possible with 64k)
*/
RxNoWrap
=
(
1
<<
7
),
};
...
...
@@ -560,6 +561,7 @@ struct rtl8139_private {
int
drv_flags
;
struct
pci_dev
*
pci_dev
;
u32
pci_state
[
16
];
u32
msg_enable
;
struct
net_device_stats
stats
;
unsigned
char
*
rx_ring
;
unsigned
int
cur_rx
;
/* Index into the Rx buffer of next Rx pkt. */
...
...
@@ -574,6 +576,7 @@ struct rtl8139_private {
char
twistie
,
twist_row
,
twist_col
;
/* Twister tune state. */
unsigned
int
default_port
:
4
;
/* Last dev->if_port value. */
spinlock_t
lock
;
spinlock_t
rx_lock
;
chip_t
chipset
;
pid_t
thr_pid
;
wait_queue_head_t
thr_wait
;
...
...
@@ -590,13 +593,11 @@ MODULE_DESCRIPTION ("RealTek RTL-8139 Fast Ethernet driver");
MODULE_LICENSE
(
"GPL"
);
MODULE_PARM
(
multicast_filter_limit
,
"i"
);
MODULE_PARM
(
max_interrupt_work
,
"i"
);
MODULE_PARM
(
media
,
"1-"
__MODULE_STRING
(
MAX_UNITS
)
"i"
);
MODULE_PARM
(
full_duplex
,
"1-"
__MODULE_STRING
(
MAX_UNITS
)
"i"
);
MODULE_PARM
(
debug
,
"i"
);
MODULE_PARM_DESC
(
debug
,
"8139too bitmapped message enable number"
);
MODULE_PARM_DESC
(
multicast_filter_limit
,
"8139too maximum number of filtered multicast addresses"
);
MODULE_PARM_DESC
(
max_interrupt_work
,
"8139too maximum events handled per interrupt"
);
MODULE_PARM_DESC
(
media
,
"8139too: Bits 4+9: force full duplex, bit 5: 100Mbps"
);
MODULE_PARM_DESC
(
full_duplex
,
"8139too: Force full duplex for board(s) (1)"
);
...
...
@@ -610,6 +611,10 @@ static void rtl8139_tx_timeout (struct net_device *dev);
static
void
rtl8139_init_ring
(
struct
net_device
*
dev
);
static
int
rtl8139_start_xmit
(
struct
sk_buff
*
skb
,
struct
net_device
*
dev
);
static
int
rtl8139_poll
(
struct
net_device
*
dev
,
int
*
budget
);
#ifdef CONFIG_NET_POLL_CONTROLLER
static
void
rtl8139_poll_controller
(
struct
net_device
*
dev
);
#endif
static
irqreturn_t
rtl8139_interrupt
(
int
irq
,
void
*
dev_instance
,
struct
pt_regs
*
regs
);
static
int
rtl8139_close
(
struct
net_device
*
dev
);
...
...
@@ -682,16 +687,32 @@ static const u16 rtl8139_intr_mask =
PCIErr
|
PCSTimeout
|
RxUnderrun
|
RxOverflow
|
RxFIFOOver
|
TxErr
|
TxOK
|
RxErr
|
RxOK
;
#ifdef USE_BUF16K
static
const
u16
rtl8139_norx_intr_mask
=
PCIErr
|
PCSTimeout
|
RxUnderrun
|
TxErr
|
TxOK
|
RxErr
;
#if CONFIG_8139_RXBUF_IDX == 0
static
const
unsigned
int
rtl8139_rx_config
=
RxCfgRcv8K
|
RxNoWrap
|
(
RX_FIFO_THRESH
<<
RxCfgFIFOShift
)
|
(
RX_DMA_BURST
<<
RxCfgDMAShift
);
#elif CONFIG_8139_RXBUF_IDX == 1
static
const
unsigned
int
rtl8139_rx_config
=
RxCfgRcv16K
|
RxNoWrap
|
(
RX_FIFO_THRESH
<<
RxCfgFIFOShift
)
|
(
RX_DMA_BURST
<<
RxCfgDMAShift
);
#el
se
#el
if CONFIG_8139_RXBUF_IDX == 2
static
const
unsigned
int
rtl8139_rx_config
=
RxCfgRcv32K
|
RxNoWrap
|
(
RX_FIFO_THRESH
<<
RxCfgFIFOShift
)
|
(
RX_DMA_BURST
<<
RxCfgDMAShift
);
#elif CONFIG_8139_RXBUF_IDX == 3
static
const
unsigned
int
rtl8139_rx_config
=
RxCfgRcv64K
|
(
RX_FIFO_THRESH
<<
RxCfgFIFOShift
)
|
(
RX_DMA_BURST
<<
RxCfgDMAShift
);
#else
#error "Invalid configuration for 8139_RXBUF_IDX"
#endif
static
const
unsigned
int
rtl8139_tx_config
=
...
...
@@ -868,9 +889,7 @@ static int __devinit rtl8139_init_board (struct pci_dev *pdev,
match:
DPRINTK
(
"chipset id (%d) == index %d, '%s'
\n
"
,
tmp
,
tp
->
chipset
,
rtl_chip_info
[
tp
->
chipset
].
name
);
version
,
i
,
rtl_chip_info
[
i
].
name
);
if
(
tp
->
chipset
>=
CH_8139B
)
{
u8
new_tmp8
=
tmp8
=
RTL_R8
(
Config1
);
...
...
@@ -964,6 +983,8 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev,
/* The Rtl8139-specific entries in the device structure. */
dev
->
open
=
rtl8139_open
;
dev
->
hard_start_xmit
=
rtl8139_start_xmit
;
dev
->
poll
=
rtl8139_poll
;
dev
->
weight
=
64
;
dev
->
stop
=
rtl8139_close
;
dev
->
get_stats
=
rtl8139_get_stats
;
dev
->
set_multicast_list
=
rtl8139_set_rx_mode
;
...
...
@@ -971,6 +992,9 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev,
dev
->
ethtool_ops
=
&
rtl8139_ethtool_ops
;
dev
->
tx_timeout
=
rtl8139_tx_timeout
;
dev
->
watchdog_timeo
=
TX_TIMEOUT
;
#ifdef CONFIG_NET_POLL_CONTROLLER
dev
->
poll_controller
=
rtl8139_poll_controller
;
#endif
/* note: the hardware is not capable of sg/csum/highdma, however
* through the use of skb_copy_and_csum_dev we enable these
...
...
@@ -986,7 +1010,10 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev,
/* note: tp->chipset set in rtl8139_init_board */
tp
->
drv_flags
=
board_info
[
ent
->
driver_data
].
hw_flags
;
tp
->
mmio_addr
=
ioaddr
;
tp
->
msg_enable
=
(
debug
<
0
?
RTL8139_DEF_MSG_ENABLE
:
((
1
<<
debug
)
-
1
));
spin_lock_init
(
&
tp
->
lock
);
spin_lock_init
(
&
tp
->
rx_lock
);
init_waitqueue_head
(
&
tp
->
thr_wait
);
init_completion
(
&
tp
->
thr_exited
);
tp
->
mii
.
dev
=
dev
;
...
...
@@ -1288,9 +1315,7 @@ static int rtl8139_open (struct net_device *dev)
{
struct
rtl8139_private
*
tp
=
dev
->
priv
;
int
retval
;
#ifdef RTL8139_DEBUG
void
*
ioaddr
=
tp
->
mmio_addr
;
#endif
retval
=
request_irq
(
dev
->
irq
,
rtl8139_interrupt
,
SA_SHIRQ
,
dev
->
name
,
dev
);
if
(
retval
)
...
...
@@ -1319,8 +1344,10 @@ static int rtl8139_open (struct net_device *dev)
rtl8139_init_ring
(
dev
);
rtl8139_hw_start
(
dev
);
netif_start_queue
(
dev
);
DPRINTK
(
"%s: rtl8139_open() ioaddr %#lx IRQ %d"
if
(
netif_msg_ifup
(
tp
))
printk
(
KERN_DEBUG
"%s: rtl8139_open() ioaddr %#lx IRQ %d"
" GP Pins %2.2x %s-duplex.
\n
"
,
dev
->
name
,
pci_resource_start
(
tp
->
pci_dev
,
1
),
dev
->
irq
,
RTL_R8
(
MediaStatus
),
...
...
@@ -1337,7 +1364,7 @@ static void rtl_check_media (struct net_device *dev, unsigned int init_media)
struct
rtl8139_private
*
tp
=
dev
->
priv
;
if
(
tp
->
phys
[
0
]
>=
0
)
{
mii_check_media
(
&
tp
->
mii
,
1
,
init_media
);
mii_check_media
(
&
tp
->
mii
,
netif_msg_link
(
tp
)
,
init_media
);
}
}
...
...
@@ -1407,8 +1434,6 @@ static void rtl8139_hw_start (struct net_device *dev)
/* Enable all known interrupts by setting the interrupt mask. */
RTL_W16
(
IntrMask
,
rtl8139_intr_mask
);
netif_start_queue
(
dev
);
}
...
...
@@ -1631,7 +1656,7 @@ static inline void rtl8139_start_thread(struct net_device *dev)
}
}
static
void
rtl8139_tx_clear
(
struct
rtl8139_private
*
tp
)
static
inline
void
rtl8139_tx_clear
(
struct
rtl8139_private
*
tp
)
{
tp
->
cur_tx
=
0
;
tp
->
dirty_tx
=
0
;
...
...
@@ -1661,6 +1686,7 @@ static void rtl8139_tx_timeout (struct net_device *dev)
if
(
tmp8
&
CmdTxEnb
)
RTL_W8
(
ChipCmd
,
CmdRxEnb
);
spin_lock
(
&
tp
->
rx_lock
);
/* Disable interrupts by clearing the interrupt mask. */
RTL_W16
(
IntrMask
,
0x0000
);
...
...
@@ -1679,9 +1705,12 @@ static void rtl8139_tx_timeout (struct net_device *dev)
spin_unlock_irqrestore
(
&
tp
->
lock
,
flags
);
/* ...and finally, reset everything */
if
(
netif_running
(
dev
))
{
rtl8139_hw_start
(
dev
);
netif_wake_queue
(
dev
);
}
spin_unlock
(
&
tp
->
rx_lock
);
}
...
...
@@ -1695,6 +1724,7 @@ static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev)
/* Calculate the next Tx descriptor entry. */
entry
=
tp
->
cur_tx
%
NUM_TX_DESC
;
/* Note: the chip doesn't have auto-pad! */
if
(
likely
(
len
<
TX_BUF_SIZE
))
{
if
(
len
<
ETH_ZLEN
)
memset
(
tp
->
tx_buf
[
entry
],
0
,
ETH_ZLEN
);
...
...
@@ -1706,7 +1736,6 @@ static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev)
return
0
;
}
/* Note: the chip doesn't have auto-pad! */
spin_lock_irq
(
&
tp
->
lock
);
RTL_W32_F
(
TxStatus0
+
(
entry
*
sizeof
(
u32
)),
tp
->
tx_flag
|
max
(
len
,
(
unsigned
int
)
ETH_ZLEN
));
...
...
@@ -1720,7 +1749,8 @@ static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev)
netif_stop_queue
(
dev
);
spin_unlock_irq
(
&
tp
->
lock
);
DPRINTK
(
"%s: Queued Tx packet size %u to slot %d.
\n
"
,
if
(
netif_msg_tx_queued
(
tp
))
printk
(
KERN_DEBUG
"%s: Queued Tx packet size %u to slot %d.
\n
"
,
dev
->
name
,
len
,
entry
);
return
0
;
...
...
@@ -1751,7 +1781,8 @@ static void rtl8139_tx_interrupt (struct net_device *dev,
/* Note: TxCarrierLost is always asserted at 100mbps. */
if
(
txstatus
&
(
TxOutOfWindow
|
TxAborted
))
{
/* There was an major error, log it. */
DPRINTK
(
"%s: Transmit error, Tx status %8.8x.
\n
"
,
if
(
netif_msg_tx_err
(
tp
))
printk
(
KERN_DEBUG
"%s: Transmit error, Tx status %8.8x.
\n
"
,
dev
->
name
,
txstatus
);
tp
->
stats
.
tx_errors
++
;
if
(
txstatus
&
TxAborted
)
{
...
...
@@ -1792,7 +1823,6 @@ static void rtl8139_tx_interrupt (struct net_device *dev,
if
(
tp
->
dirty_tx
!=
dirty_tx
)
{
tp
->
dirty_tx
=
dirty_tx
;
mb
();
if
(
netif_queue_stopped
(
dev
))
netif_wake_queue
(
dev
);
}
}
...
...
@@ -1807,7 +1837,8 @@ static void rtl8139_rx_err (u32 rx_status, struct net_device *dev,
int
tmp_work
;
#endif
DPRINTK
(
"%s: Ethernet frame had errors, status %8.8x.
\n
"
,
if
(
netif_msg_rx_err
(
tp
))
printk
(
KERN_DEBUG
"%s: Ethernet frame had errors, status %8.8x.
\n
"
,
dev
->
name
,
rx_status
);
tp
->
stats
.
rx_errors
++
;
if
(
!
(
rx_status
&
RxStatusOK
))
{
...
...
@@ -1880,30 +1911,41 @@ static void rtl8139_rx_err (u32 rx_status, struct net_device *dev,
#endif
}
static
void
rtl8139_rx_interrupt
(
struct
net_device
*
dev
,
struct
rtl8139_private
*
tp
,
void
*
ioaddr
)
#if CONFIG_8139_RXBUF_IDX == 3
static
__inline__
void
wrap_copy
(
struct
sk_buff
*
skb
,
const
unsigned
char
*
ring
,
u32
offset
,
unsigned
int
size
)
{
unsigned
char
*
rx_ring
;
u16
cur_rx
;
u32
left
=
RX_BUF_LEN
-
offset
;
assert
(
dev
!=
NULL
);
assert
(
tp
!=
NULL
);
assert
(
ioaddr
!=
NULL
);
if
(
size
>
left
)
{
memcpy
(
skb
->
data
,
ring
+
offset
,
left
);
memcpy
(
skb
->
data
+
left
,
ring
,
size
-
left
);
}
else
memcpy
(
skb
->
data
,
ring
+
offset
,
size
);
}
#endif
rx_ring
=
tp
->
rx_ring
;
cur_rx
=
tp
->
cur_rx
;
static
int
rtl8139_rx
(
struct
net_device
*
dev
,
struct
rtl8139_private
*
tp
,
int
budget
)
{
void
*
ioaddr
=
tp
->
mmio_addr
;
int
received
=
0
;
unsigned
char
*
rx_ring
=
tp
->
rx_ring
;
unsigned
int
cur_rx
=
tp
->
cur_rx
;
DPRINTK
(
"%s: In rtl8139_rx(), current %4.4x BufAddr %4.4x,"
" free to %4.4x, Cmd %2.2x.
\n
"
,
dev
->
name
,
cur_rx
,
RTL_R16
(
RxBufAddr
),
RTL_R16
(
RxBufPtr
),
RTL_R8
(
ChipCmd
));
while
((
RTL_R8
(
ChipCmd
)
&
RxBufEmpty
)
==
0
)
{
int
ring_offset
=
cur_rx
%
RX_BUF_LEN
;
while
(
netif_running
(
dev
)
&&
received
<
budget
&&
(
RTL_R8
(
ChipCmd
)
&
RxBufEmpty
)
==
0
)
{
u32
ring_offset
=
cur_rx
%
RX_BUF_LEN
;
u32
rx_status
;
unsigned
int
rx_size
;
unsigned
int
pkt_size
;
struct
sk_buff
*
skb
;
u16
status
;
rmb
();
...
...
@@ -1912,7 +1954,8 @@ static void rtl8139_rx_interrupt (struct net_device *dev,
rx_size
=
rx_status
>>
16
;
pkt_size
=
rx_size
-
4
;
DPRINTK
(
"%s: rtl8139_rx() status %4.4x, size %4.4x,"
if
(
netif_msg_rx_status
(
tp
))
printk
(
KERN_DEBUG
"%s: rtl8139_rx() status %4.4x, size %4.4x,"
" cur %4.4x.
\n
"
,
dev
->
name
,
rx_status
,
rx_size
,
cur_rx
);
#if RTL8139_DEBUG > 2
...
...
@@ -1930,9 +1973,9 @@ static void rtl8139_rx_interrupt (struct net_device *dev,
* Theoretically, this should never happen
* since EarlyRx is disabled.
*/
if
(
rx_size
==
0xfff0
)
{
if
(
unlikely
(
rx_size
==
0xfff0
)
)
{
tp
->
xstats
.
early_rx
++
;
break
;
goto
done
;
}
/* If Rx err or invalid rx_size/rx_status received
...
...
@@ -1940,55 +1983,69 @@ static void rtl8139_rx_interrupt (struct net_device *dev,
* Rx process gets reset, so we abort any further
* Rx processing.
*/
if
((
rx_size
>
(
MAX_ETH_FRAME_SIZE
+
4
))
||
if
(
unlikely
(
(
rx_size
>
(
MAX_ETH_FRAME_SIZE
+
4
))
||
(
rx_size
<
8
)
||
(
!
(
rx_status
&
RxStatusOK
)))
{
(
!
(
rx_status
&
RxStatusOK
)
)))
{
rtl8139_rx_err
(
rx_status
,
dev
,
tp
,
ioaddr
);
return
;
return
-
1
;
}
/* Malloc up new buffer, compatible with net-2e. */
/* Omit the four octet CRC from the length. */
/* TODO: consider allocating skb's outside of
* interrupt context, both to speed interrupt processing,
* and also to reduce the chances of having to
* drop packets here under memory pressure.
*/
skb
=
dev_alloc_skb
(
pkt_size
+
2
);
if
(
skb
)
{
if
(
likely
(
skb
)
)
{
skb
->
dev
=
dev
;
skb_reserve
(
skb
,
2
);
/* 16 byte align the IP fields. */
#if CONFIG_8139_RXBUF_IDX == 3
wrap_copy
(
skb
,
rx_ring
,
ring_offset
+
4
,
pkt_size
);
#else
eth_copy_and_sum
(
skb
,
&
rx_ring
[
ring_offset
+
4
],
pkt_size
,
0
);
#endif
skb_put
(
skb
,
pkt_size
);
skb
->
protocol
=
eth_type_trans
(
skb
,
dev
);
netif_rx
(
skb
);
dev
->
last_rx
=
jiffies
;
tp
->
stats
.
rx_bytes
+=
pkt_size
;
tp
->
stats
.
rx_packets
++
;
netif_receive_skb
(
skb
);
}
else
{
if
(
net_ratelimit
())
printk
(
KERN_WARNING
"%s: Memory squeeze, dropping packet.
\n
"
,
dev
->
name
);
tp
->
stats
.
rx_dropped
++
;
}
received
++
;
cur_rx
=
(
cur_rx
+
rx_size
+
4
+
3
)
&
~
3
;
RTL_W16
(
RxBufPtr
,
cur_rx
-
16
);
RTL_W16
(
RxBufPtr
,
(
u16
)
(
cur_rx
-
16
)
);
if
(
RTL_R16
(
IntrStatus
)
&
RxAckBits
)
/* Clear out errors and receive interrupts */
status
=
RTL_R16
(
IntrStatus
)
&
RxAckBits
;
if
(
likely
(
status
!=
0
))
{
if
(
unlikely
(
status
&
(
RxFIFOOver
|
RxOverflow
)))
{
tp
->
stats
.
rx_errors
++
;
if
(
status
&
RxFIFOOver
)
tp
->
stats
.
rx_fifo_errors
++
;
}
RTL_W16_F
(
IntrStatus
,
RxAckBits
);
}
}
done:
#if RTL8139_DEBUG > 1
DPRINTK
(
"%s: Done rtl8139_rx(), current %4.4x BufAddr %4.4x,"
" free to %4.4x, Cmd %2.2x.
\n
"
,
dev
->
name
,
cur_rx
,
RTL_R16
(
RxBufAddr
),
RTL_R16
(
RxBufPtr
),
RTL_R8
(
ChipCmd
));
#endif
tp
->
cur_rx
=
cur_rx
;
return
received
;
}
...
...
@@ -2014,14 +2071,12 @@ static void rtl8139_weird_interrupt (struct net_device *dev,
status
&=
~
RxUnderrun
;
}
/* XXX along with rtl8139_rx_err, are we double-counting errors? */
if
(
status
&
(
RxUnderrun
|
RxOverflow
|
RxErr
|
RxFIFOOver
))
if
(
status
&
(
RxUnderrun
|
RxErr
))
tp
->
stats
.
rx_errors
++
;
if
(
status
&
PCSTimeout
)
tp
->
stats
.
rx_length_errors
++
;
if
(
status
&
(
RxUnderrun
|
RxFIFOOver
)
)
if
(
status
&
RxUnderrun
)
tp
->
stats
.
rx_fifo_errors
++
;
if
(
status
&
PCIErr
)
{
u16
pci_cmd_status
;
...
...
@@ -2033,6 +2088,39 @@ static void rtl8139_weird_interrupt (struct net_device *dev,
}
}
static
int
rtl8139_poll
(
struct
net_device
*
dev
,
int
*
budget
)
{
struct
rtl8139_private
*
tp
=
dev
->
priv
;
void
*
ioaddr
=
tp
->
mmio_addr
;
int
orig_budget
=
min
(
*
budget
,
dev
->
quota
);
int
done
=
1
;
spin_lock
(
&
tp
->
rx_lock
);
if
(
likely
(
RTL_R16
(
IntrStatus
)
&
RxAckBits
))
{
int
work_done
;
work_done
=
rtl8139_rx
(
dev
,
tp
,
orig_budget
);
if
(
likely
(
work_done
>
0
))
{
*
budget
-=
work_done
;
dev
->
quota
-=
work_done
;
done
=
(
work_done
<
orig_budget
);
}
}
if
(
done
)
{
/*
* Order is important since data can get interrupted
* again when we think we are done.
*/
local_irq_disable
();
RTL_W16_F
(
IntrMask
,
rtl8139_intr_mask
);
__netif_rx_complete
(
dev
);
local_irq_enable
();
}
spin_unlock
(
&
tp
->
rx_lock
);
return
!
done
;
}
/* The interrupt handler does all of the Rx thread work and cleans up
after the Tx thread. */
...
...
@@ -2041,68 +2129,59 @@ static irqreturn_t rtl8139_interrupt (int irq, void *dev_instance,
{
struct
net_device
*
dev
=
(
struct
net_device
*
)
dev_instance
;
struct
rtl8139_private
*
tp
=
dev
->
priv
;
int
boguscnt
=
max_interrupt_work
;
void
*
ioaddr
=
tp
->
mmio_addr
;
int
ackstat
,
status
;
u16
status
,
ackstat
;
int
link_changed
=
0
;
/* avoid bogus "uninit" warning */
int
handled
=
0
;
spin_lock
(
&
tp
->
lock
);
do
{
status
=
RTL_R16
(
IntrStatus
);
/* h/w no longer present (hotplug?) or major error, bail */
if
(
status
==
0xFFFF
)
break
;
if
((
status
&
(
PCIErr
|
PCSTimeout
|
RxUnderrun
|
RxOverflow
|
RxFIFOOver
|
TxErr
|
TxOK
|
RxErr
|
RxOK
))
==
0
)
break
;
/* shared irq? */
if
(
unlikely
((
status
&
rtl8139_intr_mask
)
==
0
))
goto
out
;
handled
=
1
;
/* h/w no longer present (hotplug?) or major error, bail */
if
(
unlikely
(
status
==
0xFFFF
))
goto
out
;
/* close possible race's with dev_close */
if
(
unlikely
(
!
netif_running
(
dev
)))
{
RTL_W16
(
IntrMask
,
0
);
goto
out
;
}
/* Acknowledge all of the current interrupt sources ASAP, but
an first get an additional status bit from CSCR. */
if
(
status
&
RxUnderrun
)
if
(
unlikely
(
status
&
RxUnderrun
)
)
link_changed
=
RTL_R16
(
CSCR
)
&
CSCR_LinkChangeBit
;
/* The chip takes special action when we clear RxAckBits,
* so we clear them later in rtl8139_rx_interrupt
*/
ackstat
=
status
&
~
(
RxAckBits
|
TxErr
);
if
(
ackstat
)
RTL_W16
(
IntrStatus
,
ackstat
);
DPRINTK
(
"%s: interrupt status=%#4.4x ackstat=%#4.4x new intstat=%#4.4x.
\n
"
,
dev
->
name
,
status
,
ackstat
,
RTL_R16
(
IntrStatus
));
if
(
netif_running
(
dev
)
&&
(
status
&
RxAckBits
))
rtl8139_rx_interrupt
(
dev
,
tp
,
ioaddr
);
/* Receive packets are processed by poll routine.
If not running start it now. */
if
(
status
&
RxAckBits
){
if
(
netif_rx_schedule_prep
(
dev
))
{
RTL_W16_F
(
IntrMask
,
rtl8139_norx_intr_mask
);
__netif_rx_schedule
(
dev
);
}
}
/* Check uncommon events with one test. */
if
(
status
&
(
PCIErr
|
PCSTimeout
|
RxUnderrun
|
RxOverflow
|
RxFIFOOver
|
RxErr
))
if
(
unlikely
(
status
&
(
PCIErr
|
PCSTimeout
|
RxUnderrun
|
RxErr
)))
rtl8139_weird_interrupt
(
dev
,
tp
,
ioaddr
,
status
,
link_changed
);
if
(
netif_running
(
dev
)
&&
(
status
&
(
TxOK
|
TxErr
)
))
{
if
(
status
&
(
TxOK
|
TxErr
))
{
rtl8139_tx_interrupt
(
dev
,
tp
,
ioaddr
);
if
(
status
&
TxErr
)
RTL_W16
(
IntrStatus
,
TxErr
);
}
boguscnt
--
;
}
while
(
boguscnt
>
0
);
if
(
boguscnt
<=
0
)
{
printk
(
KERN_WARNING
"%s: Too much work at interrupt, "
"IntrStatus=0x%4.4x.
\n
"
,
dev
->
name
,
status
);
/* Clear all interrupt sources. */
RTL_W16
(
IntrStatus
,
0xffff
);
}
out:
spin_unlock
(
&
tp
->
lock
);
DPRINTK
(
"%s: exiting interrupt, intr_status=%#4.4x.
\n
"
,
...
...
@@ -2110,6 +2189,18 @@ static irqreturn_t rtl8139_interrupt (int irq, void *dev_instance,
return
IRQ_RETVAL
(
handled
);
}
#ifdef CONFIG_NET_POLL_CONTROLLER
/*
* Polling receive - used by netconsole and other diagnostic tools
* to allow network i/o with interrupts disabled.
*/
static
void
rtl8139_poll_controller
(
struct
net_device
*
dev
)
{
disable_irq
(
dev
->
irq
);
rtl8139_interrupt
(
dev
->
irq
,
dev
,
NULL
);
enable_irq
(
dev
->
irq
);
}
#endif
static
int
rtl8139_close
(
struct
net_device
*
dev
)
{
...
...
@@ -2131,7 +2222,8 @@ static int rtl8139_close (struct net_device *dev)
wait_for_completion
(
&
tp
->
thr_exited
);
}
DPRINTK
(
"%s: Shutting down ethercard, status was 0x%4.4x.
\n
"
,
if
(
netif_msg_ifdown
(
tp
))
printk
(
KERN_DEBUG
"%s: Shutting down ethercard, status was 0x%4.4x.
\n
"
,
dev
->
name
,
RTL_R16
(
IntrStatus
));
spin_lock_irqsave
(
&
tp
->
lock
,
flags
);
...
...
@@ -2289,12 +2381,14 @@ static u32 rtl8139_get_link(struct net_device *dev)
static
u32
rtl8139_get_msglevel
(
struct
net_device
*
dev
)
{
return
debug
;
struct
rtl8139_private
*
np
=
dev
->
priv
;
return
np
->
msg_enable
;
}
static
void
rtl8139_set_msglevel
(
struct
net_device
*
dev
,
u32
datum
)
{
debug
=
datum
;
struct
rtl8139_private
*
np
=
dev
->
priv
;
np
->
msg_enable
=
datum
;
}
/* TODO: we are too slack to do reg dumping for pio, for now */
...
...
drivers/net/Kconfig
View file @
c43fb198
...
...
@@ -1577,6 +1577,24 @@ config 8139_OLD_RX_RESET
experience problems, you can enable this option to restore the
old RX-reset behavior. If unsure, say N.
config 8139_RXBUF_IDX
int "Receive ring size (0 => 8K, 1 => 16K, 2 => 32K, 3 => 64K)"
depends on 8139TOO
range 0 3
default 1 if EMBEDDED || SH_DREAMCAST
default 2
help
The 8139too driver has a fixed area of memory for receiving data.
The default value is adequate for most systems. The 64KB
ring size has hardware issues that may cause problems.
Values:
0 => 8 KB
1 => 16 KB embedded systems
2 => 32 KB default for most systems
3 => 64 KB
If unsure, use the default 2.
config SIS900
tristate "SiS 900/7016 PCI Fast Ethernet Adapter support"
depends on NET_PCI && PCI
...
...
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