summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/networking/spider_net.txt204
-rw-r--r--MAINTAINERS10
-rw-r--r--drivers/misc/Kconfig6
-rw-r--r--drivers/misc/Makefile1
-rw-r--r--drivers/misc/eeprom_93cx6.c241
-rw-r--r--drivers/net/8139cp.c11
-rw-r--r--drivers/net/Kconfig172
-rw-r--r--drivers/net/Makefile1
-rw-r--r--drivers/net/acenic.c4
-rw-r--r--drivers/net/arm/Kconfig12
-rw-r--r--drivers/net/b44.c56
-rw-r--r--drivers/net/b44.h2
-rw-r--r--drivers/net/cxgb3/adapter.h38
-rw-r--r--drivers/net/cxgb3/common.h28
-rw-r--r--drivers/net/cxgb3/cxgb3_main.c43
-rw-r--r--drivers/net/cxgb3/regs.h11
-rw-r--r--drivers/net/cxgb3/sge.c423
-rw-r--r--drivers/net/cxgb3/t3_hw.c128
-rw-r--r--drivers/net/cxgb3/version.h2
-rw-r--r--drivers/net/ehea/ehea.h14
-rw-r--r--drivers/net/ehea/ehea_hw.h24
-rw-r--r--drivers/net/ehea/ehea_main.c32
-rw-r--r--drivers/net/ehea/ehea_qmr.c56
-rw-r--r--drivers/net/fec_8xx/Kconfig2
-rw-r--r--drivers/net/fs_enet/Kconfig2
-rw-r--r--drivers/net/gianfar.c27
-rw-r--r--drivers/net/gianfar.h6
-rw-r--r--drivers/net/gianfar_mii.c55
-rw-r--r--drivers/net/lasi_82596.c1460
-rw-r--r--drivers/net/lib82596.c1434
-rw-r--r--drivers/net/mlx4/qp.c3
-rw-r--r--drivers/net/netxen/netxen_nic_niu.c6
-rw-r--r--drivers/net/pasemi_mac.c2
-rw-r--r--drivers/net/pcmcia/axnet_cs.c7
-rw-r--r--drivers/net/pcmcia/fmvj18x_cs.c23
-rw-r--r--drivers/net/pcmcia/pcnet_cs.c10
-rw-r--r--drivers/net/phy/Kconfig5
-rw-r--r--drivers/net/phy/Makefile1
-rw-r--r--drivers/net/phy/icplus.c134
-rw-r--r--drivers/net/phy/marvell.c16
-rwxr-xr-xdrivers/net/qla3xxx.c33
-rw-r--r--drivers/net/r8169.c944
-rw-r--r--drivers/net/s2io.c116
-rw-r--r--drivers/net/s2io.h6
-rw-r--r--drivers/net/sky2.c224
-rw-r--r--drivers/net/sky2.h163
-rw-r--r--drivers/net/sni_82596.c185
-rw-r--r--drivers/net/spider_net.c184
-rw-r--r--drivers/net/spider_net.h21
-rw-r--r--drivers/net/tulip/Kconfig27
-rw-r--r--drivers/net/tulip/de2104x.c1
-rw-r--r--drivers/net/tulip/de4x5.c98
-rw-r--r--drivers/net/tulip/de4x5.h9
-rw-r--r--drivers/net/usb/usbnet.c76
-rw-r--r--drivers/net/usb/usbnet.h10
-rw-r--r--drivers/net/wireless/Kconfig12
-rw-r--r--drivers/net/wireless/Makefile3
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_phy.c2
-rw-r--r--drivers/net/wireless/hostap/hostap_ap.c34
-rw-r--r--drivers/net/wireless/hostap/hostap_config.h2
-rw-r--r--drivers/net/wireless/hostap/hostap_cs.c4
-rw-r--r--drivers/net/wireless/hostap/hostap_ioctl.c2
-rw-r--r--drivers/net/wireless/hostap/hostap_main.c1
-rw-r--r--drivers/net/wireless/hostap/hostap_pci.c5
-rw-r--r--drivers/net/wireless/hostap/hostap_plx.c5
-rw-r--r--drivers/net/wireless/rtl8187.h145
-rw-r--r--drivers/net/wireless/rtl8187_dev.c731
-rw-r--r--drivers/net/wireless/rtl8187_rtl8225.c745
-rw-r--r--drivers/net/wireless/rtl8187_rtl8225.h44
-rw-r--r--drivers/net/wireless/rtl818x.h226
-rw-r--r--drivers/net/wireless/zd1211rw/Makefile2
-rw-r--r--drivers/net/wireless/zd1211rw/zd_chip.c5
-rw-r--r--drivers/net/wireless/zd1211rw/zd_chip.h3
-rw-r--r--drivers/net/wireless/zd1211rw/zd_rf.c21
-rw-r--r--drivers/net/wireless/zd1211rw/zd_rf.h28
-rw-r--r--drivers/net/wireless/zd1211rw/zd_rf_al2230.c1
-rw-r--r--drivers/net/wireless/zd1211rw/zd_rf_al7230b.c1
-rw-r--r--drivers/net/wireless/zd1211rw/zd_rf_uw2453.c534
-rw-r--r--drivers/net/wireless/zd1211rw/zd_usb.c1
-rw-r--r--drivers/serial/serial_cs.c4
-rw-r--r--include/linux/eeprom_93cx6.h72
-rw-r--r--include/pcmcia/ciscode.h2
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_module.c32
83 files changed, 6793 insertions, 2683 deletions
diff --git a/Documentation/networking/spider_net.txt b/Documentation/networking/spider_net.txt
new file mode 100644
index 000000000000..4b4adb8eb14f
--- /dev/null
+++ b/Documentation/networking/spider_net.txt
@@ -0,0 +1,204 @@
+
+ The Spidernet Device Driver
+ ===========================
+
+Written by Linas Vepstas <linas@austin.ibm.com>
+
+Version of 7 June 2007
+
+Abstract
+========
+This document sketches the structure of portions of the spidernet
+device driver in the Linux kernel tree. The spidernet is a gigabit
+ethernet device built into the Toshiba southbridge commonly used
+in the SONY Playstation 3 and the IBM QS20 Cell blade.
+
+The Structure of the RX Ring.
+=============================
+The receive (RX) ring is a circular linked list of RX descriptors,
+together with three pointers into the ring that are used to manage its
+contents.
+
+The elements of the ring are called "descriptors" or "descrs"; they
+describe the received data. This includes a pointer to a buffer
+containing the received data, the buffer size, and various status bits.
+
+There are three primary states that a descriptor can be in: "empty",
+"full" and "not-in-use". An "empty" or "ready" descriptor is ready
+to receive data from the hardware. A "full" descriptor has data in it,
+and is waiting to be emptied and processed by the OS. A "not-in-use"
+descriptor is neither empty or full; it is simply not ready. It may
+not even have a data buffer in it, or is otherwise unusable.
+
+During normal operation, on device startup, the OS (specifically, the
+spidernet device driver) allocates a set of RX descriptors and RX
+buffers. These are all marked "empty", ready to receive data. This
+ring is handed off to the hardware, which sequentially fills in the
+buffers, and marks them "full". The OS follows up, taking the full
+buffers, processing them, and re-marking them empty.
+
+This filling and emptying is managed by three pointers, the "head"
+and "tail" pointers, managed by the OS, and a hardware current
+descriptor pointer (GDACTDPA). The GDACTDPA points at the descr
+currently being filled. When this descr is filled, the hardware
+marks it full, and advances the GDACTDPA by one. Thus, when there is
+flowing RX traffic, every descr behind it should be marked "full",
+and everything in front of it should be "empty". If the hardware
+discovers that the current descr is not empty, it will signal an
+interrupt, and halt processing.
+
+The tail pointer tails or trails the hardware pointer. When the
+hardware is ahead, the tail pointer will be pointing at a "full"
+descr. The OS will process this descr, and then mark it "not-in-use",
+and advance the tail pointer. Thus, when there is flowing RX traffic,
+all of the descrs in front of the tail pointer should be "full", and
+all of those behind it should be "not-in-use". When RX traffic is not
+flowing, then the tail pointer can catch up to the hardware pointer.
+The OS will then note that the current tail is "empty", and halt
+processing.
+
+The head pointer (somewhat mis-named) follows after the tail pointer.
+When traffic is flowing, then the head pointer will be pointing at
+a "not-in-use" descr. The OS will perform various housekeeping duties
+on this descr. This includes allocating a new data buffer and
+dma-mapping it so as to make it visible to the hardware. The OS will
+then mark the descr as "empty", ready to receive data. Thus, when there
+is flowing RX traffic, everything in front of the head pointer should
+be "not-in-use", and everything behind it should be "empty". If no
+RX traffic is flowing, then the head pointer can catch up to the tail
+pointer, at which point the OS will notice that the head descr is
+"empty", and it will halt processing.
+
+Thus, in an idle system, the GDACTDPA, tail and head pointers will
+all be pointing at the same descr, which should be "empty". All of the
+other descrs in the ring should be "empty" as well.
+
+The show_rx_chain() routine will print out the the locations of the
+GDACTDPA, tail and head pointers. It will also summarize the contents
+of the ring, starting at the tail pointer, and listing the status
+of the descrs that follow.
+
+A typical example of the output, for a nearly idle system, might be
+
+net eth1: Total number of descrs=256
+net eth1: Chain tail located at descr=20
+net eth1: Chain head is at 20
+net eth1: HW curr desc (GDACTDPA) is at 21
+net eth1: Have 1 descrs with stat=x40800101
+net eth1: HW next desc (GDACNEXTDA) is at 22
+net eth1: Last 255 descrs with stat=xa0800000
+
+In the above, the hardware has filled in one descr, number 20. Both
+head and tail are pointing at 20, because it has not yet been emptied.
+Meanwhile, hw is pointing at 21, which is free.
+
+The "Have nnn decrs" refers to the descr starting at the tail: in this
+case, nnn=1 descr, starting at descr 20. The "Last nnn descrs" refers
+to all of the rest of the descrs, from the last status change. The "nnn"
+is a count of how many descrs have exactly the same status.
+
+The status x4... corresponds to "full" and status xa... corresponds
+to "empty". The actual value printed is RXCOMST_A.
+
+In the device driver source code, a different set of names are
+used for these same concepts, so that
+
+"empty" == SPIDER_NET_DESCR_CARDOWNED == 0xa
+"full" == SPIDER_NET_DESCR_FRAME_END == 0x4
+"not in use" == SPIDER_NET_DESCR_NOT_IN_USE == 0xf
+
+
+The RX RAM full bug/feature
+===========================
+
+As long as the OS can empty out the RX buffers at a rate faster than
+the hardware can fill them, there is no problem. If, for some reason,
+the OS fails to empty the RX ring fast enough, the hardware GDACTDPA
+pointer will catch up to the head, notice the not-empty condition,
+ad stop. However, RX packets may still continue arriving on the wire.
+The spidernet chip can save some limited number of these in local RAM.
+When this local ram fills up, the spider chip will issue an interrupt
+indicating this (GHIINT0STS will show ERRINT, and the GRMFLLINT bit
+will be set in GHIINT1STS). When the RX ram full condition occurs,
+a certain bug/feature is triggered that has to be specially handled.
+This section describes the special handling for this condition.
+
+When the OS finally has a chance to run, it will empty out the RX ring.
+In particular, it will clear the descriptor on which the hardware had
+stopped. However, once the hardware has decided that a certain
+descriptor is invalid, it will not restart at that descriptor; instead
+it will restart at the next descr. This potentially will lead to a
+deadlock condition, as the tail pointer will be pointing at this descr,
+which, from the OS point of view, is empty; the OS will be waiting for
+this descr to be filled. However, the hardware has skipped this descr,
+and is filling the next descrs. Since the OS doesn't see this, there
+is a potential deadlock, with the OS waiting for one descr to fill,
+while the hardware is waiting for a different set of descrs to become
+empty.
+
+A call to show_rx_chain() at this point indicates the nature of the
+problem. A typical print when the network is hung shows the following:
+
+net eth1: Spider RX RAM full, incoming packets might be discarded!
+net eth1: Total number of descrs=256
+net eth1: Chain tail located at descr=255
+net eth1: Chain head is at 255
+net eth1: HW curr desc (GDACTDPA) is at 0
+net eth1: Have 1 descrs with stat=xa0800000
+net eth1: HW next desc (GDACNEXTDA) is at 1
+net eth1: Have 127 descrs with stat=x40800101
+net eth1: Have 1 descrs with stat=x40800001
+net eth1: Have 126 descrs with stat=x40800101
+net eth1: Last 1 descrs with stat=xa0800000
+
+Both the tail and head pointers are pointing at descr 255, which is
+marked xa... which is "empty". Thus, from the OS point of view, there
+is nothing to be done. In particular, there is the implicit assumption
+that everything in front of the "empty" descr must surely also be empty,
+as explained in the last section. The OS is waiting for descr 255 to
+become non-empty, which, in this case, will never happen.
+
+The HW pointer is at descr 0. This descr is marked 0x4.. or "full".
+Since its already full, the hardware can do nothing more, and thus has
+halted processing. Notice that descrs 0 through 254 are all marked
+"full", while descr 254 and 255 are empty. (The "Last 1 descrs" is
+descr 254, since tail was at 255.) Thus, the system is deadlocked,
+and there can be no forward progress; the OS thinks there's nothing
+to do, and the hardware has nowhere to put incoming data.
+
+This bug/feature is worked around with the spider_net_resync_head_ptr()
+routine. When the driver receives RX interrupts, but an examination
+of the RX chain seems to show it is empty, then it is probable that
+the hardware has skipped a descr or two (sometimes dozens under heavy
+network conditions). The spider_net_resync_head_ptr() subroutine will
+search the ring for the next full descr, and the driver will resume
+operations there. Since this will leave "holes" in the ring, there
+is also a spider_net_resync_tail_ptr() that will skip over such holes.
+
+As of this writing, the spider_net_resync() strategy seems to work very
+well, even under heavy network loads.
+
+
+The TX ring
+===========
+The TX ring uses a low-watermark interrupt scheme to make sure that
+the TX queue is appropriately serviced for large packet sizes.
+
+For packet sizes greater than about 1KBytes, the kernel can fill
+the TX ring quicker than the device can drain it. Once the ring
+is full, the netdev is stopped. When there is room in the ring,
+the netdev needs to be reawakened, so that more TX packets are placed
+in the ring. The hardware can empty the ring about four times per jiffy,
+so its not appropriate to wait for the poll routine to refill, since
+the poll routine runs only once per jiffy. The low-watermark mechanism
+marks a descr about 1/4th of the way from the bottom of the queue, so
+that an interrupt is generated when the descr is processed. This
+interrupt wakes up the netdev, which can then refill the queue.
+For large packets, this mechanism generates a relatively small number
+of interrupts, about 1K/sec. For smaller packets, this will drop to zero
+interrupts, as the hardware can empty the queue faster than the kernel
+can fill it.
+
+
+ ======= END OF DOCUMENT ========
+
diff --git a/MAINTAINERS b/MAINTAINERS
index df40a4ec87fb..2c1dfb271613 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3049,6 +3049,16 @@ S: Maintained
RISCOM8 DRIVER
S: Orphan
+RTL818X WIRELESS DRIVER
+P: Michael Wu
+M: flamingice@sourmilk.net
+P: Andrea Merello
+M: andreamrl@tiscali.it
+L: linux-wireless@vger.kernel.org
+W: http://linuxwireless.org/
+T: git kernel.org:/pub/scm/linux/kernel/git/mwu/mac80211-drivers.git
+S: Maintained
+
S3 SAVAGE FRAMEBUFFER DRIVER
P: Antonino Daplas
M: adaplas@gmail.com
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 616eee9c04f1..bd601efa7bd1 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -34,6 +34,11 @@ config PHANTOM
If you choose to build module, its name will be phantom. If unsure,
say N here.
+config EEPROM_93CX6
+ tristate "EEPROM 93CX6 support"
+ ---help---
+ This is a driver for the EEPROM chipsets 93c46 and 93c66.
+ The driver supports both read as well as write commands.
If unsure, say N.
@@ -187,5 +192,4 @@ config THINKPAD_ACPI_BAY
If you are not sure, say Y here.
-
endmenu
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 8abbf2f07a65..b5ce0e3dba86 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -14,3 +14,4 @@ obj-$(CONFIG_PHANTOM) += phantom.o
obj-$(CONFIG_SGI_IOC4) += ioc4.o
obj-$(CONFIG_SONY_LAPTOP) += sony-laptop.o
obj-$(CONFIG_THINKPAD_ACPI) += thinkpad_acpi.o
+obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o
diff --git a/drivers/misc/eeprom_93cx6.c b/drivers/misc/eeprom_93cx6.c
new file mode 100644
index 000000000000..ac515b0ef67c
--- /dev/null
+++ b/drivers/misc/eeprom_93cx6.c
@@ -0,0 +1,241 @@
+/*
+ Copyright (C) 2004 - 2006 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: eeprom_93cx6
+ Abstract: EEPROM reader routines for 93cx6 chipsets.
+ Supported chipsets: 93c46 & 93c66.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/delay.h>
+#include <linux/eeprom_93cx6.h>
+
+MODULE_AUTHOR("http://rt2x00.serialmonkey.com");
+MODULE_VERSION("1.0");
+MODULE_DESCRIPTION("EEPROM 93cx6 chip driver");
+MODULE_LICENSE("GPL");
+
+static inline void eeprom_93cx6_pulse_high(struct eeprom_93cx6 *eeprom)
+{
+ eeprom->reg_data_clock = 1;
+ eeprom->register_write(eeprom);
+
+ /*
+ * Add a short delay for the pulse to work.
+ * According to the specifications the "maximum minimum"
+ * time should be 450ns.
+ */
+ ndelay(450);
+}
+
+static inline void eeprom_93cx6_pulse_low(struct eeprom_93cx6 *eeprom)
+{
+ eeprom->reg_data_clock = 0;
+ eeprom->register_write(eeprom);
+
+ /*
+ * Add a short delay for the pulse to work.
+ * According to the specifications the minimal time
+ * should be 450ns so a 1us delay is sufficient.
+ */
+ udelay(1);
+}
+
+static void eeprom_93cx6_startup(struct eeprom_93cx6 *eeprom)
+{
+ /*
+ * Clear all flags, and enable chip select.
+ */
+ eeprom->register_read(eeprom);
+ eeprom->reg_data_in = 0;
+ eeprom->reg_data_out = 0;
+ eeprom->reg_data_clock = 0;
+ eeprom->reg_chip_select = 1;
+ eeprom->register_write(eeprom);
+
+ /*
+ * kick a pulse.
+ */
+ eeprom_93cx6_pulse_high(eeprom);
+ eeprom_93cx6_pulse_low(eeprom);
+}
+
+static void eeprom_93cx6_cleanup(struct eeprom_93cx6 *eeprom)
+{
+ /*
+ * Clear chip_select and data_in flags.
+ */
+ eeprom->register_read(eeprom);
+ eeprom->reg_data_in = 0;
+ eeprom->reg_chip_select = 0;
+ eeprom->register_write(eeprom);
+
+ /*
+ * kick a pulse.
+ */
+ eeprom_93cx6_pulse_high(eeprom);
+ eeprom_93cx6_pulse_low(eeprom);
+}
+
+static void eeprom_93cx6_write_bits(struct eeprom_93cx6 *eeprom,
+ const u16 data, const u16 count)
+{
+ unsigned int i;
+
+ eeprom->register_read(eeprom);
+
+ /*
+ * Clear data flags.
+ */
+ eeprom->reg_data_in = 0;
+ eeprom->reg_data_out = 0;
+
+ /*
+ * Start writing all bits.
+ */
+ for (i = count; i > 0; i--) {
+ /*
+ * Check if this bit needs to be set.
+ */
+ eeprom->reg_data_in = !!(data & (1 << (i - 1)));
+
+ /*
+ * Write the bit to the eeprom register.
+ */
+ eeprom->register_write(eeprom);
+
+ /*
+ * Kick a pulse.
+ */
+ eeprom_93cx6_pulse_high(eeprom);
+ eeprom_93cx6_pulse_low(eeprom);
+ }
+
+ eeprom->reg_data_in = 0;
+ eeprom->register_write(eeprom);
+}
+
+static void eeprom_93cx6_read_bits(struct eeprom_93cx6 *eeprom,
+ u16 *data, const u16 count)
+{
+ unsigned int i;
+ u16 buf = 0;
+
+ eeprom->register_read(eeprom);
+
+ /*
+ * Clear data flags.
+ */
+ eeprom->reg_data_in = 0;
+ eeprom->reg_data_out = 0;
+
+ /*
+ * Start reading all bits.
+ */
+ for (i = count; i > 0; i--) {
+ eeprom_93cx6_pulse_high(eeprom);
+
+ eeprom->register_read(eeprom);
+
+ /*
+ * Clear data_in flag.
+ */
+ eeprom->reg_data_in = 0;
+
+ /*
+ * Read if the bit has been set.
+ */
+ if (eeprom->reg_data_out)
+ buf |= (1 << (i - 1));
+
+ eeprom_93cx6_pulse_low(eeprom);
+ }
+
+ *data = buf;
+}
+
+/**
+ * eeprom_93cx6_read - Read multiple words from eeprom
+ * @eeprom: Pointer to eeprom structure
+ * @word: Word index from where we should start reading
+ * @data: target pointer where the information will have to be stored
+ *
+ * This function will read the eeprom data as host-endian word
+ * into the given data pointer.
+ */
+void eeprom_93cx6_read(struct eeprom_93cx6 *eeprom, const u8 word,
+ u16 *data)
+{
+ u16 command;
+
+ /*
+ * Initialize the eeprom register
+ */
+ eeprom_93cx6_startup(eeprom);
+
+ /*
+ * Select the read opcode and the word to be read.
+ */
+ command = (PCI_EEPROM_READ_OPCODE << eeprom->width) | word;
+ eeprom_93cx6_write_bits(eeprom, command,
+ PCI_EEPROM_WIDTH_OPCODE + eeprom->width);
+
+ /*
+ * Read the requested 16 bits.
+ */
+ eeprom_93cx6_read_bits(eeprom, data, 16);
+
+ /*
+ * Cleanup eeprom register.
+ */
+ eeprom_93cx6_cleanup(eeprom);
+}
+EXPORT_SYMBOL_GPL(eeprom_93cx6_read);
+
+/**
+ * eeprom_93cx6_multiread - Read multiple words from eeprom
+ * @eeprom: Pointer to eeprom structure
+ * @word: Word index from where we should start reading
+ * @data: target pointer where the information will have to be stored
+ * @words: Number of words that should be read.
+ *
+ * This function will read all requested words from the eeprom,
+ * this is done by calling eeprom_93cx6_read() multiple times.
+ * But with the additional change that while the eeprom_93cx6_read
+ * will return host ordered bytes, this method will return little
+ * endian words.
+ */
+void eeprom_93cx6_multiread(struct eeprom_93cx6 *eeprom, const u8 word,
+ __le16 *data, const u16 words)
+{
+ unsigned int i;
+ u16 tmp;
+
+ for (i = 0; i < words; i++) {
+ tmp = 0;
+ eeprom_93cx6_read(eeprom, word + i, &tmp);
+ data[i] = cpu_to_le16(tmp);
+ }
+}
+EXPORT_SYMBOL_GPL(eeprom_93cx6_multiread);
+
diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c
index a804965e6542..58bbc3e6d0de 100644
--- a/drivers/net/8139cp.c
+++ b/drivers/net/8139cp.c
@@ -107,11 +107,6 @@ MODULE_PARM_DESC (multicast_filter_limit, "8139cp: maximum number of filtered mu
#define PFX DRV_NAME ": "
-#ifndef TRUE
-#define FALSE 0
-#define TRUE (!FALSE)
-#endif
-
#define CP_DEF_MSG_ENABLE (NETIF_MSG_DRV | \
NETIF_MSG_PROBE | \
NETIF_MSG_LINK)
@@ -661,7 +656,7 @@ static irqreturn_t cp_interrupt (int irq, void *dev_instance)
if (status & (TxOK | TxErr | TxEmpty | SWInt))
cp_tx(cp);
if (status & LinkChg)
- mii_check_media(&cp->mii_if, netif_msg_link(cp), FALSE);
+ mii_check_media(&cp->mii_if, netif_msg_link(cp), false);
spin_unlock(&cp->lock);
@@ -1188,7 +1183,7 @@ static int cp_open (struct net_device *dev)
goto err_out_hw;
netif_carrier_off(dev);
- mii_check_media(&cp->mii_if, netif_msg_link(cp), TRUE);
+ mii_check_media(&cp->mii_if, netif_msg_link(cp), true);
netif_start_queue(dev);
return 0;
@@ -2050,7 +2045,7 @@ static int cp_resume (struct pci_dev *pdev)
spin_lock_irqsave (&cp->lock, flags);
- mii_check_media(&cp->mii_if, netif_msg_link(cp), FALSE);
+ mii_check_media(&cp->mii_if, netif_msg_link(cp), false);
spin_unlock_irqrestore (&cp->lock, flags);
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index b49375abb5f4..5cc3d517e39b 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -3,10 +3,7 @@
# Network device configuration
#
-menu "Network device support"
- depends on NET
-
-config NETDEVICES
+menuconfig NETDEVICES
default y if UML
bool "Network device support"
---help---
@@ -151,11 +148,9 @@ source "drivers/net/phy/Kconfig"
# Ethernet
#
-menu "Ethernet (10 or 100Mbit)"
- depends on !UML
-
-config NET_ETHERNET
+menuconfig NET_ETHERNET
bool "Ethernet (10 or 100Mbit)"
+ depends on !UML
---help---
Ethernet (also called IEEE 802.3 or ISO 8802-2) is the most common
type of Local Area Network (LAN) in universities and companies.
@@ -180,9 +175,10 @@ config NET_ETHERNET
kernel: saying N will just cause the configurator to skip all
the questions about Ethernet network cards. If unsure, say N.
+if NET_ETHERNET
+
config MII
tristate "Generic Media Independent Interface device support"
- depends on NET_ETHERNET
help
Most ethernet controllers have MII transceiver either as an external
or internal device. It is safe to say Y or M here even if your
@@ -190,7 +186,7 @@ config MII
config MACB
tristate "Atmel MACB support"
- depends on NET_ETHERNET && (AVR32 || ARCH_AT91SAM9260 || ARCH_AT91SAM9263)
+ depends on AVR32 || ARCH_AT91SAM9260 || ARCH_AT91SAM9263
select MII
help
The Atmel MACB ethernet interface is found on many AT32 and AT91
@@ -203,7 +199,7 @@ source "drivers/net/arm/Kconfig"
config MACE
tristate "MACE (Power Mac ethernet) support"
- depends on NET_ETHERNET && PPC_PMAC && PPC32
+ depends on PPC_PMAC && PPC32
select CRC32
help
Power Macintoshes and clones with Ethernet built-in on the
@@ -226,7 +222,7 @@ config MACE_AAUI_PORT
config BMAC
tristate "BMAC (G3 ethernet) support"
- depends on NET_ETHERNET && PPC_PMAC && PPC32
+ depends on PPC_PMAC && PPC32
select CRC32
help
Say Y for support of BMAC Ethernet interfaces. These are used on G3
@@ -237,7 +233,7 @@ config BMAC
config ARIADNE
tristate "Ariadne support"
- depends on NET_ETHERNET && ZORRO
+ depends on ZORRO
help
If you have a Village Tronic Ariadne Ethernet adapter, say Y.
Otherwise, say N.
@@ -247,7 +243,7 @@ config ARIADNE
config A2065
tristate "A2065 support"
- depends on NET_ETHERNET && ZORRO
+ depends on ZORRO
select CRC32
help
If you have a Commodore A2065 Ethernet adapter, say Y. Otherwise,
@@ -258,7 +254,7 @@ config A2065
config HYDRA
tristate "Hydra support"
- depends on NET_ETHERNET && ZORRO
+ depends on ZORRO
select CRC32
help
If you have a Hydra Ethernet adapter, say Y. Otherwise, say N.
@@ -268,7 +264,7 @@ config HYDRA
config ZORRO8390
tristate "Zorro NS8390-based Ethernet support"
- depends on NET_ETHERNET && ZORRO
+ depends on ZORRO
select CRC32
help
This driver is for Zorro Ethernet cards using an NS8390-compatible
@@ -281,7 +277,7 @@ config ZORRO8390
config APNE
tristate "PCMCIA NE2000 support"
- depends on NET_ETHERNET && AMIGA_PCMCIA
+ depends on AMIGA_PCMCIA
select CRC32
help
If you have a PCMCIA NE2000 compatible adapter, say Y. Otherwise,
@@ -292,7 +288,7 @@ config APNE
config APOLLO_ELPLUS
tristate "Apollo 3c505 support"
- depends on NET_ETHERNET && APOLLO
+ depends on APOLLO
help
Say Y or M here if your Apollo has a 3Com 3c505 ISA Ethernet card.
If you don't have one made for Apollos, you can use one from a PC,
@@ -301,7 +297,7 @@ config APOLLO_ELPLUS
config MAC8390
bool "Macintosh NS 8390 based ethernet cards"
- depends on NET_ETHERNET && MAC
+ depends on MAC
select CRC32
help
If you want to include a driver to support Nubus or LC-PDS
@@ -311,7 +307,7 @@ config MAC8390
config MAC89x0
tristate "Macintosh CS89x0 based ethernet cards"
- depends on NET_ETHERNET && MAC
+ depends on MAC
---help---
Support for CS89x0 chipset based Ethernet cards. If you have a
Nubus or LC-PDS network (Ethernet) card of this type, say Y and
@@ -324,7 +320,7 @@ config MAC89x0
config MACSONIC
tristate "Macintosh SONIC based ethernet (onboard, NuBus, LC, CS)"
- depends on NET_ETHERNET && MAC
+ depends on MAC
---help---
Support for NatSemi SONIC based Ethernet devices. This includes
the onboard Ethernet in many Quadras as well as some LC-PDS,
@@ -338,7 +334,7 @@ config MACSONIC
config MACMACE
bool "Macintosh (AV) onboard MACE ethernet"
- depends on NET_ETHERNET && MAC
+ depends on MAC
select CRC32
help
Support for the onboard AMD 79C940 MACE Ethernet controller used in
@@ -348,7 +344,7 @@ config MACMACE
config MVME147_NET
tristate "MVME147 (Lance) Ethernet support"
- depends on NET_ETHERNET && MVME147
+ depends on MVME147
select CRC32
help
Support for the on-board Ethernet interface on the Motorola MVME147
@@ -358,7 +354,7 @@ config MVME147_NET
config MVME16x_NET
tristate "MVME16x Ethernet support"
- depends on NET_ETHERNET && MVME16x
+ depends on MVME16x
help
This is the driver for the Ethernet interface on the Motorola
MVME162, 166, 167, 172 and 177 boards. Say Y here to include the
@@ -367,7 +363,7 @@ config MVME16x_NET
config BVME6000_NET
tristate "BVME6000 Ethernet support"
- depends on NET_ETHERNET && BVME6000
+ depends on BVME6000
help
This is the driver for the Ethernet interface on BVME4000 and
BVME6000 VME boards. Say Y here to include the driver for this chip
@@ -376,7 +372,7 @@ config BVME6000_NET
config ATARILANCE
tristate "Atari Lance support"
- depends on NET_ETHERNET && ATARI
+ depends on ATARI
help
Say Y to include support for several Atari Ethernet adapters based
on the AMD Lance chipset: RieblCard (with or without battery), or
@@ -384,7 +380,7 @@ config ATARILANCE
config ATARI_BIONET
tristate "BioNet-100 support"
- depends on NET_ETHERNET && ATARI && ATARI_ACSI && BROKEN
+ depends on ATARI && ATARI_ACSI && BROKEN
help
Say Y to include support for BioData's BioNet-100 Ethernet adapter
for the ACSI port. The driver works (has to work...) with a polled
@@ -392,7 +388,7 @@ config ATARI_BIONET
config ATARI_PAMSNET
tristate "PAMsNet support"
- depends on NET_ETHERNET && ATARI && ATARI_ACSI && BROKEN
+ depends on ATARI && ATARI_ACSI && BROKEN
help
Say Y to include support for the PAMsNet Ethernet adapter for the
ACSI port ("ACSI node"). The driver works (has to work...) with a
@@ -400,7 +396,7 @@ config ATARI_PAMSNET
config SUN3LANCE
tristate "Sun3/Sun3x on-board LANCE support"
- depends on NET_ETHERNET && (SUN3 || SUN3X)
+ depends on SUN3 || SUN3X
help
Most Sun3 and Sun3x motherboards (including the 3/50, 3/60 and 3/80)
featured an AMD Lance 10Mbit Ethernet controller on board; say Y
@@ -413,7 +409,7 @@ config SUN3LANCE
config SUN3_82586
bool "Sun3 on-board Intel 82586 support"
- depends on NET_ETHERNET && SUN3
+ depends on SUN3
help
This driver enables support for the on-board Intel 82586 based
Ethernet adapter found on Sun 3/1xx and 3/2xx motherboards. Note
@@ -422,7 +418,7 @@ config SUN3_82586
config HPLANCE
bool "HP on-board LANCE support"
- depends on NET_ETHERNET && DIO
+ depends on DIO
select CRC32
help
If you want to use the builtin "LANCE" Ethernet controller on an
@@ -430,21 +426,28 @@ config HPLANCE
config LASI_82596
tristate "Lasi ethernet"
- depends on NET_ETHERNET && GSC
+ depends on GSC
help
Say Y here to support the builtin Intel 82596 ethernet controller
found in Hewlett-Packard PA-RISC machines with 10Mbit ethernet.
+config SNI_82596
+ tristate "SNI RM ethernet"
+ depends on NET_ETHERNET && SNI_RM
+ help
+ Say Y here to support the on-board Intel 82596 ethernet controller
+ built into SNI RM machines.
+
config MIPS_JAZZ_SONIC
tristate "MIPS JAZZ onboard SONIC Ethernet support"
- depends on NET_ETHERNET && MACH_JAZZ
+ depends on MACH_JAZZ
help
This is the driver for the onboard card of MIPS Magnum 4000,
Acer PICA, Olivetti M700-10 and a few other identical OEM systems.
config MIPS_AU1X00_ENET
bool "MIPS AU1000 Ethernet support"
- depends on NET_ETHERNET && SOC_AU1X00
+ depends on SOC_AU1X00
select PHYLIB
select CRC32
help
@@ -453,11 +456,11 @@ config MIPS_AU1X00_ENET
config NET_SB1250_MAC
tristate "SB1250 Ethernet support"
- depends on NET_ETHERNET && SIBYTE_SB1xxx_SOC
+ depends on SIBYTE_SB1xxx_SOC
config SGI_IOC3_ETH
bool "SGI IOC3 Ethernet"
- depends on NET_ETHERNET && PCI && SGI_IP27
+ depends on PCI && SGI_IP27
select CRC32
select MII
help
@@ -487,7 +490,7 @@ config SGI_IOC3_ETH_HW_TX_CSUM
config MIPS_SIM_NET
tristate "MIPS simulator Network device"
- depends on NET_ETHERNET && MIPS_SIM
+ depends on MIPS_SIM
help
The MIPSNET device is a simple Ethernet network device which is
emulated by the MIPS Simulator.
@@ -495,11 +498,11 @@ config MIPS_SIM_NET
config SGI_O2MACE_ETH
tristate "SGI O2 MACE Fast Ethernet support"
- depends on NET_ETHERNET && SGI_IP32=y
+ depends on SGI_IP32=y
config STNIC
tristate "National DP83902AV support"
- depends on NET_ETHERNET && SUPERH
+ depends on SUPERH
select CRC32
help
Support for cards based on the National Semiconductor DP83902AV
@@ -511,7 +514,7 @@ config STNIC
config SUNLANCE
tristate "Sun LANCE support"
- depends on NET_ETHERNET && SBUS
+ depends on SBUS
select CRC32
help
This driver supports the "le" interface present on all 32-bit Sparc
@@ -524,7 +527,7 @@ config SUNLANCE
config HAPPYMEAL
tristate "Sun Happy Meal 10/100baseT support"
- depends on NET_ETHERNET && (SBUS || PCI)
+ depends on SBUS || PCI
select CRC32
help
This driver supports the "hme" interface present on most Ultra
@@ -537,7 +540,7 @@ config HAPPYMEAL
config SUNBMAC
tristate "Sun BigMAC 10/100baseT support (EXPERIMENTAL)"
- depends on NET_ETHERNET && SBUS && EXPERIMENTAL
+ depends on SBUS && EXPERIMENTAL
select CRC32
help
This driver supports the "be" interface available as an Sbus option.
@@ -548,7 +551,7 @@ config SUNBMAC
config SUNQE
tristate "Sun QuadEthernet support"
- depends on NET_ETHERNET && SBUS
+ depends on SBUS
select CRC32
help
This driver supports the "qe" 10baseT Ethernet device, available as
@@ -560,7 +563,7 @@ config SUNQE
config SUNGEM
tristate "Sun GEM support"
- depends on NET_ETHERNET && PCI
+ depends on PCI
select CRC32
help
Support for the Sun GEM chip, aka Sun GigabitEthernet/P 2.0. See also
@@ -568,7 +571,7 @@ config SUNGEM
config CASSINI
tristate "Sun Cassini support"
- depends on NET_ETHERNET && PCI
+ depends on PCI
select CRC32
help
Support for the Sun Cassini chip, aka Sun GigaSwift Ethernet. See also
@@ -576,7 +579,7 @@ config CASSINI
config NET_VENDOR_3COM
bool "3COM cards"
- depends on NET_ETHERNET && (ISA || EISA || MCA || PCI)
+ depends on ISA || EISA || MCA || PCI
help
If you have a network (Ethernet) card belonging to this class, say Y
and read the Ethernet-HOWTO, available from
@@ -736,7 +739,7 @@ config TYPHOON
config LANCE
tristate "AMD LANCE and PCnet (AT1500 and NE2100) support"
- depends on NET_ETHERNET && ISA && ISA_DMA_API
+ depends on ISA && ISA_DMA_API
help
If you have a network (Ethernet) card of this type, say Y and read
the Ethernet-HOWTO, available from
@@ -748,7 +751,7 @@ config LANCE
config NET_VENDOR_SMC
bool "Western Digital/SMC cards"
- depends on NET_ETHERNET && (ISA || MCA || EISA || MAC)
+ depends on ISA || MCA || EISA || MAC
help
If you have a network (Ethernet) card belonging to this class, say Y
and read the Ethernet-HOWTO, available from
@@ -818,11 +821,27 @@ config ULTRA32
<file:Documentation/networking/net-modules.txt>. The module
will be called smc-ultra32.
+config SMC9194
+ tristate "SMC 9194 support"
+ depends on NET_VENDOR_SMC && (ISA || MAC && BROKEN)
+ select CRC32
+ ---help---
+ This is support for the SMC9xxx based Ethernet cards. Choose this
+ option if you have a DELL laptop with the docking station, or
+ another SMC9192/9194 based chipset. Say Y if you want it compiled
+ into the kernel, and read the file
+ <file:Documentation/networking/smc9.txt> and the Ethernet-HOWTO,
+ available from <http://www.tldp.org/docs.html#howto>.
+
+ To compile this driver as a module, choose M here and read
+ <file:Documentation/networking/net-modules.txt>. The module
+ will be called smc9194.
+
config SMC91X
tristate "SMC 91C9x/91C1xxx support"
select CRC32
select MII
- depends on NET_ETHERNET && (ARM || REDWOOD_5 || REDWOOD_6 || M32R || SUPERH || SOC_AU1X00 || BFIN)
+ depends on ARM || REDWOOD_5 || REDWOOD_6 || M32R || SUPERH || SOC_AU1X00 || BFIN
help
This is a driver for SMC's 91x series of Ethernet chipsets,
including the SMC91C94 and the SMC91C111. Say Y if you want it
@@ -836,26 +855,10 @@ config SMC91X
module, say M here and read <file:Documentation/kbuild/modules.txt>
as well as <file:Documentation/networking/net-modules.txt>.
-config SMC9194
- tristate "SMC 9194 support"
- depends on NET_VENDOR_SMC && (ISA || MAC && BROKEN)
- select CRC32
- ---help---
- This is support for the SMC9xxx based Ethernet cards. Choose this
- option if you have a DELL laptop with the docking station, or
- another SMC9192/9194 based chipset. Say Y if you want it compiled
- into the kernel, and read the file
- <file:Documentation/networking/smc9.txt> and the Ethernet-HOWTO,
- available from <http://www.tldp.org/docs.html#howto>.
-
- To compile this driver as a module, choose M here and read
- <file:Documentation/networking/net-modules.txt>. The module
- will be called smc9194.
-
config NET_NETX
tristate "NetX Ethernet support"
select MII
- depends on NET_ETHERNET && ARCH_NETX
+ depends on ARCH_NETX
help
This is support for the Hilscher netX builtin Ethernet ports
@@ -865,7 +868,7 @@ config NET_NETX
config DM9000
tristate "DM9000 support"
- depends on (ARM || MIPS) && NET_ETHERNET
+ depends on ARM || MIPS
select CRC32
select MII
---help---
@@ -879,7 +882,7 @@ config SMC911X
tristate "SMSC LAN911[5678] support"
select CRC32
select MII
- depends on NET_ETHERNET && ARCH_PXA
+ depends on ARCH_PXA
help
This is a driver for SMSC's LAN911x series of Ethernet chipsets
including the new LAN9115, LAN9116, LAN9117, and LAN9118.
@@ -893,7 +896,7 @@ config SMC911X
config NET_VENDOR_RACAL
bool "Racal-Interlan (Micom) NI cards"
- depends on NET_ETHERNET && ISA
+ depends on ISA
help
If you have a network (Ethernet) card belonging to this class, such
as the NI5010, NI5210 or NI6210, say Y and read the Ethernet-HOWTO,
@@ -945,7 +948,7 @@ source "drivers/net/tulip/Kconfig"
config AT1700
tristate "AT1700/1720 support (EXPERIMENTAL)"
- depends on NET_ETHERNET && (ISA || MCA_LEGACY) && EXPERIMENTAL
+ depends on (ISA || MCA_LEGACY) && EXPERIMENTAL
select CRC32
---help---
If you have a network (Ethernet) card of this type, say Y and read
@@ -958,7 +961,7 @@ config AT1700
config DEPCA
tristate "DEPCA, DE10x, DE200, DE201, DE202, DE422 support"
- depends on NET_ETHERNET && (ISA || EISA || MCA)
+ depends on ISA || EISA || MCA
select CRC32
---help---
If you have a network (Ethernet) card of this type, say Y and read
@@ -972,7 +975,7 @@ config DEPCA
config HP100
tristate "HP 10/100VG PCLAN (ISA, EISA, PCI) support"
- depends on NET_ETHERNET && (ISA || EISA || PCI)
+ depends on ISA || EISA || PCI
help
If you have a network (Ethernet) card of this type, say Y and read
the Ethernet-HOWTO, available from
@@ -984,7 +987,7 @@ config HP100
config NET_ISA
bool "Other ISA cards"
- depends on NET_ETHERNET && ISA
+ depends on ISA
---help---
If your network (Ethernet) card hasn't been mentioned yet and its
bus system (that's the way the cards talks to the other components
@@ -1147,7 +1150,7 @@ config SEEQ8005
config NE2_MCA
tristate "NE/2 (ne2000 MCA version) support"
- depends on NET_ETHERNET && MCA_LEGACY
+ depends on MCA_LEGACY
select CRC32
help
If you have a network (Ethernet) card of this type, say Y and read
@@ -1160,7 +1163,7 @@ config NE2_MCA
config IBMLANA
tristate "IBM LAN Adapter/A support"
- depends on NET_ETHERNET && MCA && MCA_LEGACY
+ depends on MCA && MCA_LEGACY
---help---
This is a Micro Channel Ethernet adapter. You need to set
CONFIG_MCA to use this driver. It is both available as an in-kernel
@@ -1176,7 +1179,7 @@ config IBMLANA
config IBMVETH
tristate "IBM LAN Virtual Ethernet support"
- depends on NET_ETHERNET && PPC_PSERIES
+ depends on PPC_PSERIES
---help---
This driver supports virtual ethernet adapters on newer IBM iSeries
and pSeries systems.
@@ -1257,7 +1260,7 @@ config IBM_EMAC_TAH
config NET_PCI
bool "EISA, VLB, PCI and on board controllers"
- depends on NET_ETHERNET && (ISA || EISA || PCI)
+ depends on ISA || EISA || PCI
help
This is another class of network cards which attach directly to the
bus. If you have one of those, say Y and read the Ethernet-HOWTO,
@@ -1313,6 +1316,7 @@ config AMD8111_ETH
To compile this driver as a module, choose M here and read
<file:Documentation/networking/net-modules.txt>. The module
will be called amd8111e.
+
config AMD8111E_NAPI
bool "Enable NAPI support"
depends on AMD8111_ETH
@@ -1778,7 +1782,7 @@ config SC92031
config NET_POCKET
bool "Pocket and portable adapters"
- depends on NET_ETHERNET && PARPORT
+ depends on PARPORT
---help---
Cute little network (Ethernet) devices which attach to the parallel
port ("pocket adapters"), commonly used with laptops. If you have
@@ -1847,14 +1851,14 @@ config DE620
config SGISEEQ
tristate "SGI Seeq ethernet controller support"
- depends on NET_ETHERNET && SGI_IP22
+ depends on SGI_IP22
help
Say Y here if you have an Seeq based Ethernet network card. This is
used in many Silicon Graphics machines.
config DECLANCE
tristate "DEC LANCE ethernet controller support"
- depends on NET_ETHERNET && MACH_DECSTATION
+ depends on MACH_DECSTATION
select CRC32
help
This driver is for the series of Ethernet controllers produced by
@@ -1884,7 +1888,7 @@ config FEC2
config NE_H8300
tristate "NE2000 compatible support for H8/300"
- depends on H8300 && NET_ETHERNET
+ depends on H8300
help
Say Y here if you want to use the NE2000 compatible
controller on the Renesas H8/300 processor.
@@ -1892,7 +1896,7 @@ config NE_H8300
source "drivers/net/fec_8xx/Kconfig"
source "drivers/net/fs_enet/Kconfig"
-endmenu
+endif # NET_ETHERNET
#
# Gigabit Ethernet
@@ -2948,8 +2952,6 @@ config NETCONSOLE
If you want to log kernel messages over the network, enable this.
See <file:Documentation/networking/netconsole.txt> for details.
-endif #NETDEVICES
-
config NETPOLL
def_bool NETCONSOLE
@@ -2961,4 +2963,4 @@ config NETPOLL_TRAP
config NET_POLL_CONTROLLER
def_bool NETPOLL
-endmenu
+endif # NETDEVICES
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index a77affa4f6e6..eb62fb48e4b7 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -157,6 +157,7 @@ obj-$(CONFIG_ELPLUS) += 3c505.o
obj-$(CONFIG_AC3200) += ac3200.o 8390.o
obj-$(CONFIG_APRICOT) += 82596.o
obj-$(CONFIG_LASI_82596) += lasi_82596.o
+obj-$(CONFIG_SNI_82596) += sni_82596.o
obj-$(CONFIG_MVME16x_NET) += 82596.o
obj-$(CONFIG_BVME6000_NET) += 82596.o
obj-$(CONFIG_SC92031) += sc92031.o
diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c
index 04382f979c99..b78a4e5ceeb2 100644
--- a/drivers/net/acenic.c
+++ b/drivers/net/acenic.c
@@ -159,10 +159,6 @@ static struct pci_device_id acenic_pci_tbl[] = {
};
MODULE_DEVICE_TABLE(pci, acenic_pci_tbl);
-#ifndef SET_NETDEV_DEV
-#define SET_NETDEV_DEV(net, pdev) do{} while(0)
-#endif
-
#define ace_sync_irq(irq) synchronize_irq(irq)
#ifndef offset_in_page
diff --git a/drivers/net/arm/Kconfig b/drivers/net/arm/Kconfig
index 678e4f48d36b..5bf2d33887ac 100644
--- a/drivers/net/arm/Kconfig
+++ b/drivers/net/arm/Kconfig
@@ -4,7 +4,7 @@
#
config ARM_AM79C961A
bool "ARM EBSA110 AM79C961A support"
- depends on NET_ETHERNET && ARM && ARCH_EBSA110
+ depends on ARM && ARCH_EBSA110
select CRC32
help
If you wish to compile a kernel for the EBSA-110, then you should
@@ -12,21 +12,21 @@ config ARM_AM79C961A
config ARM_ETHER1
tristate "Acorn Ether1 support"
- depends on NET_ETHERNET && ARM && ARCH_ACORN
+ depends on ARM && ARCH_ACORN
help
If you have an Acorn system with one of these (AKA25) network cards,
you should say Y to this option if you wish to use it with Linux.
config ARM_ETHER3
tristate "Acorn/ANT Ether3 support"
- depends on NET_ETHERNET && ARM && ARCH_ACORN
+ depends on ARM && ARCH_ACORN
help
If you have an Acorn system with one of these network cards, you
should say Y to this option if you wish to use it with Linux.
config ARM_ETHERH
tristate "I-cubed EtherH/ANT EtherM support"
- depends on NET_ETHERNET && ARM && ARCH_ACORN
+ depends on ARM && ARCH_ACORN
select CRC32
help
If you have an Acorn system with one of these network cards, you
@@ -34,7 +34,7 @@ config ARM_ETHERH
config ARM_AT91_ETHER
tristate "AT91RM9200 Ethernet support"
- depends on NET_ETHERNET && ARM && ARCH_AT91RM9200
+ depends on ARM && ARCH_AT91RM9200
select MII
help
If you wish to compile a kernel for the AT91RM9200 and enable
@@ -42,7 +42,7 @@ config ARM_AT91_ETHER
config EP93XX_ETH
tristate "EP93xx Ethernet support"
- depends on NET_ETHERNET && ARM && ARCH_EP93XX
+ depends on ARM && ARCH_EP93XX
help
This is a driver for the ethernet hardware included in EP93xx CPUs.
Say Y if you are building a kernel for EP93xx based devices.
diff --git a/drivers/net/b44.c b/drivers/net/b44.c
index 879a2fff474e..96fb0ec905a7 100644
--- a/drivers/net/b44.c
+++ b/drivers/net/b44.c
@@ -15,6 +15,7 @@
#include <linux/ethtool.h>
#include <linux/mii.h>
#include <linux/if_ether.h>
+#include <linux/if_vlan.h>
#include <linux/etherdevice.h>
#include <linux/pci.h>
#include <linux/delay.h>
@@ -68,8 +69,8 @@
(BP)->tx_cons - (BP)->tx_prod - TX_RING_GAP(BP))
#define NEXT_TX(N) (((N) + 1) & (B44_TX_RING_SIZE - 1))
-#define RX_PKT_BUF_SZ (1536 + bp->rx_offset + 64)
-#define TX_PKT_BUF_SZ (B44_MAX_MTU + ETH_HLEN + 8)
+#define RX_PKT_OFFSET 30
+#define RX_PKT_BUF_SZ (1536 + RX_PKT_OFFSET + 64)
/* minimum number of free TX descriptors required to wake up TX process */
#define B44_TX_WAKEUP_THRESH (B44_TX_RING_SIZE / 4)
@@ -599,8 +600,7 @@ static void b44_timer(unsigned long __opaque)
spin_unlock_irq(&bp->lock);
- bp->timer.expires = jiffies + HZ;
- add_timer(&bp->timer);
+ mod_timer(&bp->timer, round_jiffies(jiffies + HZ));
}
static void b44_tx(struct b44 *bp)
@@ -653,7 +653,7 @@ static int b44_alloc_rx_skb(struct b44 *bp, int src_idx, u32 dest_idx_unmasked)
src_map = &bp->rx_buffers[src_idx];
dest_idx = dest_idx_unmasked & (B44_RX_RING_SIZE - 1);
map = &bp->rx_buffers[dest_idx];
- skb = dev_alloc_skb(RX_PKT_BUF_SZ);
+ skb = netdev_alloc_skb(bp->dev, RX_PKT_BUF_SZ);
if (skb == NULL)
return -ENOMEM;
@@ -669,7 +669,7 @@ static int b44_alloc_rx_skb(struct b44 *bp, int src_idx, u32 dest_idx_unmasked)
if (!dma_mapping_error(mapping))
pci_unmap_single(bp->pdev, mapping, RX_PKT_BUF_SZ,PCI_DMA_FROMDEVICE);
dev_kfree_skb_any(skb);
- skb = __dev_alloc_skb(RX_PKT_BUF_SZ,GFP_DMA);
+ skb = __netdev_alloc_skb(bp->dev, RX_PKT_BUF_SZ, GFP_ATOMIC|GFP_DMA);
if (skb == NULL)
return -ENOMEM;
mapping = pci_map_single(bp->pdev, skb->data,
@@ -684,11 +684,9 @@ static int b44_alloc_rx_skb(struct b44 *bp, int src_idx, u32 dest_idx_unmasked)
}
}
- skb->dev = bp->dev;
- skb_reserve(skb, bp->rx_offset);
+ rh = (struct rx_header *) skb->data;
+ skb_reserve(skb, RX_PKT_OFFSET);
- rh = (struct rx_header *)
- (skb->data - bp->rx_offset);
rh->len = 0;
rh->flags = 0;
@@ -698,13 +696,13 @@ static int b44_alloc_rx_skb(struct b44 *bp, int src_idx, u32 dest_idx_unmasked)
if (src_map != NULL)
src_map->skb = NULL;
- ctrl = (DESC_CTRL_LEN & (RX_PKT_BUF_SZ - bp->rx_offset));
+ ctrl = (DESC_CTRL_LEN & (RX_PKT_BUF_SZ - RX_PKT_OFFSET));
if (dest_idx == (B44_RX_RING_SIZE - 1))
ctrl |= DESC_CTRL_EOT;
dp = &bp->rx_ring[dest_idx];
dp->ctrl = cpu_to_le32(ctrl);
- dp->addr = cpu_to_le32((u32) mapping + bp->rx_offset + bp->dma_offset);
+ dp->addr = cpu_to_le32((u32) mapping + RX_PKT_OFFSET + bp->dma_offset);
if (bp->flags & B44_FLAG_RX_RING_HACK)
b44_sync_dma_desc_for_device(bp->pdev, bp->rx_ring_dma,
@@ -783,7 +781,7 @@ static int b44_rx(struct b44 *bp, int budget)
PCI_DMA_FROMDEVICE);
rh = (struct rx_header *) skb->data;
len = le16_to_cpu(rh->len);
- if ((len > (RX_PKT_BUF_SZ - bp->rx_offset)) ||
+ if ((len > (RX_PKT_BUF_SZ - RX_PKT_OFFSET)) ||
(rh->flags & cpu_to_le16(RX_FLAG_ERRORS))) {
drop_it:
b44_recycle_rx(bp, cons, bp->rx_prod);
@@ -815,8 +813,8 @@ static int b44_rx(struct b44 *bp, int budget)
pci_unmap_single(bp->pdev, map,
skb_size, PCI_DMA_FROMDEVICE);
/* Leave out rx_header */
- skb_put(skb, len+bp->rx_offset);
- skb_pull(skb,bp->rx_offset);
+ skb_put(skb, len + RX_PKT_OFFSET);
+ skb_pull(skb, RX_PKT_OFFSET);
} else {
struct sk_buff *copy_skb;
@@ -828,7 +826,7 @@ static int b44_rx(struct b44 *bp, int budget)
skb_reserve(copy_skb, 2);
skb_put(copy_skb, len);
/* DMA sync done above, copy just the actual packet */
- skb_copy_from_linear_data_offset(skb, bp->rx_offset,
+ skb_copy_from_linear_data_offset(skb, RX_PKT_OFFSET,
copy_skb->data, len);
skb = copy_skb;
}
@@ -969,7 +967,6 @@ static void b44_tx_timeout(struct net_device *dev)
static int b44_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct b44 *bp = netdev_priv(dev);
- struct sk_buff *bounce_skb;
int rc = NETDEV_TX_OK;
dma_addr_t mapping;
u32 len, entry, ctrl;
@@ -987,12 +984,13 @@ static int b44_start_xmit(struct sk_buff *skb, struct net_device *dev)
mapping = pci_map_single(bp->pdev, skb->data, len, PCI_DMA_TODEVICE);
if (dma_mapping_error(mapping) || mapping + len > DMA_30BIT_MASK) {
+ struct sk_buff *bounce_skb;
+
/* Chip can't handle DMA to/from >1GB, use bounce buffer */
if (!dma_mapping_error(mapping))
pci_unmap_single(bp->pdev, mapping, len, PCI_DMA_TODEVICE);
- bounce_skb = __dev_alloc_skb(TX_PKT_BUF_SZ,
- GFP_ATOMIC|GFP_DMA);
+ bounce_skb = __dev_alloc_skb(len, GFP_ATOMIC | GFP_DMA);
if (!bounce_skb)
goto err_out;
@@ -1001,13 +999,12 @@ static int b44_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (dma_mapping_error(mapping) || mapping + len > DMA_30BIT_MASK) {
if (!dma_mapping_error(mapping))
pci_unmap_single(bp->pdev, mapping,
- len, PCI_DMA_TODEVICE);
+ len, PCI_DMA_TODEVICE);
dev_kfree_skb_any(bounce_skb);
goto err_out;
}
- skb_copy_from_linear_data(skb, skb_put(bounce_skb, len),
- skb->len);
+ skb_copy_from_linear_data(skb, skb_put(bounce_skb, len), len);
dev_kfree_skb_any(skb);
skb = bounce_skb;
}
@@ -1396,12 +1393,12 @@ static void b44_init_hw(struct b44 *bp, int reset_kind)
bw32(bp, B44_TX_WMARK, 56); /* XXX magic */
if (reset_kind == B44_PARTIAL_RESET) {
bw32(bp, B44_DMARX_CTRL, (DMARX_CTRL_ENABLE |
- (bp->rx_offset << DMARX_CTRL_ROSHIFT)));
+ (RX_PKT_OFFSET << DMARX_CTRL_ROSHIFT)));
} else {
bw32(bp, B44_DMATX_CTRL, DMATX_CTRL_ENABLE);
bw32(bp, B44_DMATX_ADDR, bp->tx_ring_dma + bp->dma_offset);
bw32(bp, B44_DMARX_CTRL, (DMARX_CTRL_ENABLE |
- (bp->rx_offset << DMARX_CTRL_ROSHIFT)));
+ (RX_PKT_OFFSET << DMARX_CTRL_ROSHIFT)));
bw32(bp, B44_DMARX_ADDR, bp->rx_ring_dma + bp->dma_offset);
bw32(bp, B44_DMARX_PTR, bp->rx_pending);
@@ -2093,11 +2090,6 @@ static int __devinit b44_get_invariants(struct b44 *bp)
bp->phy_addr = eeprom[90] & 0x1f;
- /* With this, plus the rx_header prepended to the data by the
- * hardware, we'll land the ethernet header on a 2-byte boundary.
- */
- bp->rx_offset = 30;
-
bp->imask = IMASK_DEF;
bp->core_unit = ssb_core_unit(bp);
@@ -2348,11 +2340,11 @@ static int b44_resume(struct pci_dev *pdev)
netif_device_attach(bp->dev);
spin_unlock_irq(&bp->lock);
- bp->timer.expires = jiffies + HZ;
- add_timer(&bp->timer);
-
b44_enable_ints(bp);
netif_wake_queue(dev);
+
+ mod_timer(&bp->timer, jiffies + 1);
+
return 0;
}
diff --git a/drivers/net/b44.h b/drivers/net/b44.h
index 18fc13336628..e537e63f292e 100644
--- a/drivers/net/b44.h
+++ b/drivers/net/b44.h
@@ -443,8 +443,6 @@ struct b44 {
#define B44_FLAG_TX_RING_HACK 0x40000000
#define B44_FLAG_WOL_ENABLE 0x80000000
- u32 rx_offset;
-
u32 msg_enable;
struct timer_list timer;
diff --git a/drivers/net/cxgb3/adapter.h b/drivers/net/cxgb3/adapter.h
index 80c3d8f268a7..ab72563b81ee 100644
--- a/drivers/net/cxgb3/adapter.h
+++ b/drivers/net/cxgb3/adapter.h
@@ -71,27 +71,29 @@ enum { /* adapter flags */
QUEUES_BOUND = (1 << 3),
};
+struct fl_pg_chunk {
+ struct page *page;
+ void *va;
+ unsigned int offset;
+};
+
struct rx_desc;
struct rx_sw_desc;
-struct sge_fl_page {
- struct skb_frag_struct frag;
- unsigned char *va;
-};
-
-struct sge_fl { /* SGE per free-buffer list state */
- unsigned int buf_size; /* size of each Rx buffer */
- unsigned int credits; /* # of available Rx buffers */
- unsigned int size; /* capacity of free list */
- unsigned int cidx; /* consumer index */
- unsigned int pidx; /* producer index */
- unsigned int gen; /* free list generation */
- unsigned int cntxt_id; /* SGE context id for the free list */
- struct sge_fl_page page;
- struct rx_desc *desc; /* address of HW Rx descriptor ring */
- struct rx_sw_desc *sdesc; /* address of SW Rx descriptor ring */
- dma_addr_t phys_addr; /* physical address of HW ring start */
- unsigned long empty; /* # of times queue ran out of buffers */
+struct sge_fl { /* SGE per free-buffer list state */
+ unsigned int buf_size; /* size of each Rx buffer */
+ unsigned int credits; /* # of available Rx buffers */
+ unsigned int size; /* capacity of free list */
+ unsigned int cidx; /* consumer index */
+ unsigned int pidx; /* producer index */
+ unsigned int gen; /* free list generation */
+ struct fl_pg_chunk pg_chunk;/* page chunk cache */
+ unsigned int use_pages; /* whether FL uses pages or sk_buffs */
+ struct rx_desc *desc; /* address of HW Rx descriptor ring */
+ struct rx_sw_desc *sdesc; /* address of SW Rx descriptor ring */
+ dma_addr_t phys_addr; /* physical address of HW ring start */
+ unsigned int cntxt_id; /* SGE context id for the free list */
+ unsigned long empty; /* # of times queue ran out of buffers */
unsigned long alloc_failed; /* # of times buffer allocation failed */
};
diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h
index 8d1379633698..16378004507a 100644
--- a/drivers/net/cxgb3/common.h
+++ b/drivers/net/cxgb3/common.h
@@ -101,6 +101,7 @@ enum {
TCB_SIZE = 128, /* TCB size */
NMTUS = 16, /* size of MTU table */
NCCTRL_WIN = 32, /* # of congestion control windows */
+ PROTO_SRAM_LINES = 128, /* size of TP sram */
};
#define MAX_RX_COALESCING_LEN 16224U
@@ -124,6 +125,30 @@ enum { /* adapter interrupt-maintained statistics */
};
enum {
+ TP_VERSION_MAJOR = 1,
+ TP_VERSION_MINOR = 0,
+ TP_VERSION_MICRO = 44
+};
+
+#define S_TP_VERSION_MAJOR 16
+#define M_TP_VERSION_MAJOR 0xFF
+#define V_TP_VERSION_MAJOR(x) ((x) << S_TP_VERSION_MAJOR)
+#define G_TP_VERSION_MAJOR(x) \
+ (((x) >> S_TP_VERSION_MAJOR) & M_TP_VERSION_MAJOR)
+
+#define S_TP_VERSION_MINOR 8
+#define M_TP_VERSION_MINOR 0xFF
+#define V_TP_VERSION_MINOR(x) ((x) << S_TP_VERSION_MINOR)
+#define G_TP_VERSION_MINOR(x) \
+ (((x) >> S_TP_VERSION_MINOR) & M_TP_VERSION_MINOR)
+
+#define S_TP_VERSION_MICRO 0
+#define M_TP_VERSION_MICRO 0xFF
+#define V_TP_VERSION_MICRO(x) ((x) << S_TP_VERSION_MICRO)
+#define G_TP_VERSION_MICRO(x) \
+ (((x) >> S_TP_VERSION_MICRO) & M_TP_VERSION_MICRO)
+
+enum {
SGE_QSETS = 8, /* # of SGE Tx/Rx/RspQ sets */
SGE_RXQ_PER_SET = 2, /* # of Rx queues per set */
SGE_TXQ_PER_SET = 3 /* # of Tx queues per set */
@@ -654,6 +679,9 @@ const struct adapter_info *t3_get_adapter_info(unsigned int board_id);
int t3_seeprom_read(struct adapter *adapter, u32 addr, u32 *data);
int t3_seeprom_write(struct adapter *adapter, u32 addr, u32 data);
int t3_seeprom_wp(struct adapter *adapter, int enable);
+int t3_check_tpsram_version(struct adapter *adapter);
+int t3_check_tpsram(struct adapter *adapter, u8 *tp_ram, unsigned int size);
+int t3_set_proto_sram(struct adapter *adap, u8 *data);
int t3_read_flash(struct adapter *adapter, unsigned int addr,
unsigned int nwords, u32 *data, int byte_oriented);
int t3_load_fw(struct adapter *adapter, const u8 * fw_data, unsigned int size);
diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c
index d8a1f5452c51..15defe4c4f05 100644
--- a/drivers/net/cxgb3/cxgb3_main.c
+++ b/drivers/net/cxgb3/cxgb3_main.c
@@ -2088,6 +2088,42 @@ static void cxgb_netpoll(struct net_device *dev)
}
#endif
+#define TPSRAM_NAME "t3%c_protocol_sram-%d.%d.%d.bin"
+int update_tpsram(struct adapter *adap)
+{
+ const struct firmware *tpsram;
+ char buf[64];
+ struct device *dev = &adap->pdev->dev;
+ int ret;
+ char rev;
+
+ rev = adap->params.rev == T3_REV_B2 ? 'b' : 'a';
+
+ snprintf(buf, sizeof(buf), TPSRAM_NAME, rev,
+ TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO);
+
+ ret = request_firmware(&tpsram, buf, dev);
+ if (ret < 0) {
+ dev_err(dev, "could not load TP SRAM: unable to load %s\n",
+ buf);
+ return ret;
+ }
+
+ ret = t3_check_tpsram(adap, tpsram->data, tpsram->size);
+ if (ret)
+ goto release_tpsram;
+
+ ret = t3_set_proto_sram(adap, tpsram->data);
+ if (ret)
+ dev_err(dev, "loading protocol SRAM failed\n");
+
+release_tpsram:
+ release_firmware(tpsram);
+
+ return ret;
+}
+
+
/*
* Periodic accumulation of MAC statistics.
*/
@@ -2437,6 +2473,13 @@ static int __devinit init_one(struct pci_dev *pdev,
goto out_free_dev;
}
+ err = t3_check_tpsram_version(adapter);
+ if (err == -EINVAL)
+ err = update_tpsram(adapter);
+
+ if (err)
+ goto out_free_dev;
+
/*
* The card is now ready to go. If any errors occur during device
* registration we do not fail the whole card but rather proceed only
diff --git a/drivers/net/cxgb3/regs.h b/drivers/net/cxgb3/regs.h
index 020859c855d7..aa80313c922e 100644
--- a/drivers/net/cxgb3/regs.h
+++ b/drivers/net/cxgb3/regs.h
@@ -1160,6 +1160,8 @@
#define A_TP_MOD_CHANNEL_WEIGHT 0x434
+#define A_TP_MOD_RATE_LIMIT 0x438
+
#define A_TP_PIO_ADDR 0x440
#define A_TP_PIO_DATA 0x444
@@ -1214,6 +1216,15 @@
#define G_TXDROPCNTCH0RCVD(x) (((x) >> S_TXDROPCNTCH0RCVD) & \
M_TXDROPCNTCH0RCVD)
+#define A_TP_PROXY_FLOW_CNTL 0x4b0
+
+#define A_TP_EMBED_OP_FIELD0 0x4e8
+#define A_TP_EMBED_OP_FIELD1 0x4ec
+#define A_TP_EMBED_OP_FIELD2 0x4f0
+#define A_TP_EMBED_OP_FIELD3 0x4f4
+#define A_TP_EMBED_OP_FIELD4 0x4f8
+#define A_TP_EMBED_OP_FIELD5 0x4fc
+
#define A_ULPRX_CTL 0x500
#define S_ROUND_ROBIN 4
diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c
index a60ec4d4707c..a2cfd68ac757 100644
--- a/drivers/net/cxgb3/sge.c
+++ b/drivers/net/cxgb3/sge.c
@@ -46,23 +46,16 @@
#define SGE_RX_SM_BUF_SIZE 1536
-/*
- * If USE_RX_PAGE is defined, the small freelist populated with (partial)
- * pages instead of skbs. Pages are carved up into RX_PAGE_SIZE chunks (must
- * be a multiple of the host page size).
- */
-#define USE_RX_PAGE
-#define RX_PAGE_SIZE 2048
-
-/*
- * skb freelist packets are copied into a new skb (and the freelist one is
- * reused) if their len is <=
- */
#define SGE_RX_COPY_THRES 256
+#define SGE_RX_PULL_LEN 128
/*
- * Minimum number of freelist entries before we start dropping TUNNEL frames.
+ * Page chunk size for FL0 buffers if FL0 is to be populated with page chunks.
+ * It must be a divisor of PAGE_SIZE. If set to 0 FL0 will use sk_buffs
+ * directly.
*/
+#define FL0_PG_CHUNK_SIZE 2048
+
#define SGE_RX_DROP_THRES 16
/*
@@ -100,12 +93,12 @@ struct tx_sw_desc { /* SW state per Tx descriptor */
struct sk_buff *skb;
};
-struct rx_sw_desc { /* SW state per Rx descriptor */
+struct rx_sw_desc { /* SW state per Rx descriptor */
union {
struct sk_buff *skb;
- struct sge_fl_page page;
- } t;
- DECLARE_PCI_UNMAP_ADDR(dma_addr);
+ struct fl_pg_chunk pg_chunk;
+ };
+ DECLARE_PCI_UNMAP_ADDR(dma_addr);
};
struct rsp_desc { /* response queue descriptor */
@@ -351,27 +344,26 @@ static void free_rx_bufs(struct pci_dev *pdev, struct sge_fl *q)
pci_unmap_single(pdev, pci_unmap_addr(d, dma_addr),
q->buf_size, PCI_DMA_FROMDEVICE);
-
- if (q->buf_size != RX_PAGE_SIZE) {
- kfree_skb(d->t.skb);
- d->t.skb = NULL;
+ if (q->use_pages) {
+ put_page(d->pg_chunk.page);
+ d->pg_chunk.page = NULL;
} else {
- if (d->t.page.frag.page)
- put_page(d->t.page.frag.page);
- d->t.page.frag.page = NULL;
+ kfree_skb(d->skb);
+ d->skb = NULL;
}
if (++cidx == q->size)
cidx = 0;
}
- if (q->page.frag.page)
- put_page(q->page.frag.page);
- q->page.frag.page = NULL;
+ if (q->pg_chunk.page) {
+ __free_page(q->pg_chunk.page);
+ q->pg_chunk.page = NULL;
+ }
}
/**
* add_one_rx_buf - add a packet buffer to a free-buffer list
- * @va: va of the buffer to add
+ * @va: buffer start VA
* @len: the buffer length
* @d: the HW Rx descriptor to write
* @sd: the SW Rx descriptor to write
@@ -381,7 +373,7 @@ static void free_rx_bufs(struct pci_dev *pdev, struct sge_fl *q)
* Add a buffer of the given length to the supplied HW and SW Rx
* descriptors.
*/
-static inline void add_one_rx_buf(unsigned char *va, unsigned int len,
+static inline void add_one_rx_buf(void *va, unsigned int len,
struct rx_desc *d, struct rx_sw_desc *sd,
unsigned int gen, struct pci_dev *pdev)
{
@@ -397,6 +389,27 @@ static inline void add_one_rx_buf(unsigned char *va, unsigned int len,
d->gen2 = cpu_to_be32(V_FLD_GEN2(gen));
}
+static int alloc_pg_chunk(struct sge_fl *q, struct rx_sw_desc *sd, gfp_t gfp)
+{
+ if (!q->pg_chunk.page) {
+ q->pg_chunk.page = alloc_page(gfp);
+ if (unlikely(!q->pg_chunk.page))
+ return -ENOMEM;
+ q->pg_chunk.va = page_address(q->pg_chunk.page);
+ q->pg_chunk.offset = 0;
+ }
+ sd->pg_chunk = q->pg_chunk;
+
+ q->pg_chunk.offset += q->buf_size;
+ if (q->pg_chunk.offset == PAGE_SIZE)
+ q->pg_chunk.page = NULL;
+ else {
+ q->pg_chunk.va += q->buf_size;
+ get_page(q->pg_chunk.page);
+ }
+ return 0;
+}
+
/**
* refill_fl - refill an SGE free-buffer list
* @adapter: the adapter
@@ -410,49 +423,29 @@ static inline void add_one_rx_buf(unsigned char *va, unsigned int len,
*/
static void refill_fl(struct adapter *adap, struct sge_fl *q, int n, gfp_t gfp)
{
+ void *buf_start;
struct rx_sw_desc *sd = &q->sdesc[q->pidx];
struct rx_desc *d = &q->desc[q->pidx];
- struct sge_fl_page *p = &q->page;
while (n--) {
- unsigned char *va;
-
- if (unlikely(q->buf_size != RX_PAGE_SIZE)) {
- struct sk_buff *skb = alloc_skb(q->buf_size, gfp);
-
- if (!skb) {
- q->alloc_failed++;
+ if (q->use_pages) {
+ if (unlikely(alloc_pg_chunk(q, sd, gfp))) {
+nomem: q->alloc_failed++;
break;
}
- va = skb->data;
- sd->t.skb = skb;
+ buf_start = sd->pg_chunk.va;
} else {
- if (!p->frag.page) {
- p->frag.page = alloc_pages(gfp, 0);
- if (unlikely(!p->frag.page)) {
- q->alloc_failed++;
- break;
- } else {
- p->frag.size = RX_PAGE_SIZE;
- p->frag.page_offset = 0;
- p->va = page_address(p->frag.page);
- }
- }
+ struct sk_buff *skb = alloc_skb(q->buf_size, gfp);
- memcpy(&sd->t, p, sizeof(*p));
- va = p->va;
+ if (!skb)
+ goto nomem;
- p->frag.page_offset += RX_PAGE_SIZE;
- BUG_ON(p->frag.page_offset > PAGE_SIZE);
- p->va += RX_PAGE_SIZE;
- if (p->frag.page_offset == PAGE_SIZE)
- p->frag.page = NULL;
- else
- get_page(p->frag.page);
+ sd->skb = skb;
+ buf_start = skb->data;
}
- add_one_rx_buf(va, q->buf_size, d, sd, q->gen, adap->pdev);
-
+ add_one_rx_buf(buf_start, q->buf_size, d, sd, q->gen,
+ adap->pdev);
d++;
sd++;
if (++q->pidx == q->size) {
@@ -487,7 +480,7 @@ static void recycle_rx_buf(struct adapter *adap, struct sge_fl *q,
struct rx_desc *from = &q->desc[idx];
struct rx_desc *to = &q->desc[q->pidx];
- memcpy(&q->sdesc[q->pidx], &q->sdesc[idx], sizeof(struct rx_sw_desc));
+ q->sdesc[q->pidx] = q->sdesc[idx];
to->addr_lo = from->addr_lo; /* already big endian */
to->addr_hi = from->addr_hi; /* likewise */
wmb();
@@ -650,6 +643,132 @@ static inline unsigned int flits_to_desc(unsigned int n)
}
/**
+ * get_packet - return the next ingress packet buffer from a free list
+ * @adap: the adapter that received the packet
+ * @fl: the SGE free list holding the packet
+ * @len: the packet length including any SGE padding
+ * @drop_thres: # of remaining buffers before we start dropping packets
+ *
+ * Get the next packet from a free list and complete setup of the
+ * sk_buff. If the packet is small we make a copy and recycle the
+ * original buffer, otherwise we use the original buffer itself. If a
+ * positive drop threshold is supplied packets are dropped and their
+ * buffers recycled if (a) the number of remaining buffers is under the
+ * threshold and the packet is too big to copy, or (b) the packet should
+ * be copied but there is no memory for the copy.
+ */
+static struct sk_buff *get_packet(struct adapter *adap, struct sge_fl *fl,
+ unsigned int len, unsigned int drop_thres)
+{
+ struct sk_buff *skb = NULL;
+ struct rx_sw_desc *sd = &fl->sdesc[fl->cidx];
+
+ prefetch(sd->skb->data);
+ fl->credits--;
+
+ if (len <= SGE_RX_COPY_THRES) {
+ skb = alloc_skb(len, GFP_ATOMIC);
+ if (likely(skb != NULL)) {
+ __skb_put(skb, len);
+ pci_dma_sync_single_for_cpu(adap->pdev,
+ pci_unmap_addr(sd, dma_addr), len,
+ PCI_DMA_FROMDEVICE);
+ memcpy(skb->data, sd->skb->data, len);
+ pci_dma_sync_single_for_device(adap->pdev,
+ pci_unmap_addr(sd, dma_addr), len,
+ PCI_DMA_FROMDEVICE);
+ } else if (!drop_thres)
+ goto use_orig_buf;
+recycle:
+ recycle_rx_buf(adap, fl, fl->cidx);
+ return skb;
+ }
+
+ if (unlikely(fl->credits < drop_thres))
+ goto recycle;
+
+use_orig_buf:
+ pci_unmap_single(adap->pdev, pci_unmap_addr(sd, dma_addr),
+ fl->buf_size, PCI_DMA_FROMDEVICE);
+ skb = sd->skb;
+ skb_put(skb, len);
+ __refill_fl(adap, fl);
+ return skb;
+}
+
+/**
+ * get_packet_pg - return the next ingress packet buffer from a free list
+ * @adap: the adapter that received the packet
+ * @fl: the SGE free list holding the packet
+ * @len: the packet length including any SGE padding
+ * @drop_thres: # of remaining buffers before we start dropping packets
+ *
+ * Get the next packet from a free list populated with page chunks.
+ * If the packet is small we make a copy and recycle the original buffer,
+ * otherwise we attach the original buffer as a page fragment to a fresh
+ * sk_buff. If a positive drop threshold is supplied packets are dropped
+ * and their buffers recycled if (a) the number of remaining buffers is
+ * under the threshold and the packet is too big to copy, or (b) there's
+ * no system memory.
+ *
+ * Note: this function is similar to @get_packet but deals with Rx buffers
+ * that are page chunks rather than sk_buffs.
+ */
+static struct sk_buff *get_packet_pg(struct adapter *adap, struct sge_fl *fl,
+ unsigned int len, unsigned int drop_thres)
+{
+ struct sk_buff *skb = NULL;
+ struct rx_sw_desc *sd = &fl->sdesc[fl->cidx];
+
+ if (len <= SGE_RX_COPY_THRES) {
+ skb = alloc_skb(len, GFP_ATOMIC);
+ if (likely(skb != NULL)) {
+ __skb_put(skb, len);
+ pci_dma_sync_single_for_cpu(adap->pdev,
+ pci_unmap_addr(sd, dma_addr), len,
+ PCI_DMA_FROMDEVICE);
+ memcpy(skb->data, sd->pg_chunk.va, len);
+ pci_dma_sync_single_for_device(adap->pdev,
+ pci_unmap_addr(sd, dma_addr), len,
+ PCI_DMA_FROMDEVICE);
+ } else if (!drop_thres)
+ return NULL;
+recycle:
+ fl->credits--;
+ recycle_rx_buf(adap, fl, fl->cidx);
+ return skb;
+ }
+
+ if (unlikely(fl->credits <= drop_thres))
+ goto recycle;
+
+ skb = alloc_skb(SGE_RX_PULL_LEN, GFP_ATOMIC);
+ if (unlikely(!skb)) {
+ if (!drop_thres)
+ return NULL;
+ goto recycle;
+ }
+
+ pci_unmap_single(adap->pdev, pci_unmap_addr(sd, dma_addr),
+ fl->buf_size, PCI_DMA_FROMDEVICE);
+ __skb_put(skb, SGE_RX_PULL_LEN);
+ memcpy(skb->data, sd->pg_chunk.va, SGE_RX_PULL_LEN);
+ skb_fill_page_desc(skb, 0, sd->pg_chunk.page,
+ sd->pg_chunk.offset + SGE_RX_PULL_LEN,
+ len - SGE_RX_PULL_LEN);
+ skb->len = len;
+ skb->data_len = len - SGE_RX_PULL_LEN;
+ skb->truesize += skb->data_len;
+
+ fl->credits--;
+ /*
+ * We do not refill FLs here, we let the caller do it to overlap a
+ * prefetch.
+ */
+ return skb;
+}
+
+/**
* get_imm_packet - return the next ingress packet buffer from a response
* @resp: the response descriptor containing the packet data
*
@@ -1715,85 +1834,6 @@ static void rx_eth(struct adapter *adap, struct sge_rspq *rq,
netif_rx(skb);
}
-#define SKB_DATA_SIZE 128
-
-static void skb_data_init(struct sk_buff *skb, struct sge_fl_page *p,
- unsigned int len)
-{
- skb->len = len;
- if (len <= SKB_DATA_SIZE) {
- skb_copy_to_linear_data(skb, p->va, len);
- skb->tail += len;
- put_page(p->frag.page);
- } else {
- skb_copy_to_linear_data(skb, p->va, SKB_DATA_SIZE);
- skb_shinfo(skb)->frags[0].page = p->frag.page;
- skb_shinfo(skb)->frags[0].page_offset =
- p->frag.page_offset + SKB_DATA_SIZE;
- skb_shinfo(skb)->frags[0].size = len - SKB_DATA_SIZE;
- skb_shinfo(skb)->nr_frags = 1;
- skb->data_len = len - SKB_DATA_SIZE;
- skb->tail += SKB_DATA_SIZE;
- skb->truesize += skb->data_len;
- }
-}
-
-/**
-* get_packet - return the next ingress packet buffer from a free list
-* @adap: the adapter that received the packet
-* @fl: the SGE free list holding the packet
-* @len: the packet length including any SGE padding
-* @drop_thres: # of remaining buffers before we start dropping packets
-*
-* Get the next packet from a free list and complete setup of the
-* sk_buff. If the packet is small we make a copy and recycle the
-* original buffer, otherwise we use the original buffer itself. If a
-* positive drop threshold is supplied packets are dropped and their
-* buffers recycled if (a) the number of remaining buffers is under the
-* threshold and the packet is too big to copy, or (b) the packet should
-* be copied but there is no memory for the copy.
-*/
-static struct sk_buff *get_packet(struct adapter *adap, struct sge_fl *fl,
- unsigned int len, unsigned int drop_thres)
-{
- struct sk_buff *skb = NULL;
- struct rx_sw_desc *sd = &fl->sdesc[fl->cidx];
-
- prefetch(sd->t.skb->data);
-
- if (len <= SGE_RX_COPY_THRES) {
- skb = alloc_skb(len, GFP_ATOMIC);
- if (likely(skb != NULL)) {
- struct rx_desc *d = &fl->desc[fl->cidx];
- dma_addr_t mapping =
- (dma_addr_t)((u64) be32_to_cpu(d->addr_hi) << 32 |
- be32_to_cpu(d->addr_lo));
-
- __skb_put(skb, len);
- pci_dma_sync_single_for_cpu(adap->pdev, mapping, len,
- PCI_DMA_FROMDEVICE);
- skb_copy_from_linear_data(sd->t.skb, skb->data, len);
- pci_dma_sync_single_for_device(adap->pdev, mapping, len,
- PCI_DMA_FROMDEVICE);
- } else if (!drop_thres)
- goto use_orig_buf;
-recycle:
- recycle_rx_buf(adap, fl, fl->cidx);
- return skb;
- }
-
- if (unlikely(fl->credits < drop_thres))
- goto recycle;
-
-use_orig_buf:
- pci_unmap_single(adap->pdev, pci_unmap_addr(sd, dma_addr),
- fl->buf_size, PCI_DMA_FROMDEVICE);
- skb = sd->t.skb;
- skb_put(skb, len);
- __refill_fl(adap, fl);
- return skb;
-}
-
/**
* handle_rsp_cntrl_info - handles control information in a response
* @qs: the queue set corresponding to the response
@@ -1935,7 +1975,7 @@ static int process_responses(struct adapter *adap, struct sge_qset *qs,
} else if (flags & F_RSPD_IMM_DATA_VALID) {
skb = get_imm_packet(r);
if (unlikely(!skb)) {
- no_mem:
+no_mem:
q->next_holdoff = NOMEM_INTR_DELAY;
q->nomem++;
/* consume one credit since we tried */
@@ -1945,53 +1985,29 @@ static int process_responses(struct adapter *adap, struct sge_qset *qs,
q->imm_data++;
ethpad = 0;
} else if ((len = ntohl(r->len_cq)) != 0) {
- struct sge_fl *fl =
- (len & F_RSPD_FLQ) ? &qs->fl[1] : &qs->fl[0];
+ struct sge_fl *fl;
- if (fl->buf_size == RX_PAGE_SIZE) {
- struct rx_sw_desc *sd = &fl->sdesc[fl->cidx];
- struct sge_fl_page *p = &sd->t.page;
-
- prefetch(p->va);
- prefetch(p->va + L1_CACHE_BYTES);
+ fl = (len & F_RSPD_FLQ) ? &qs->fl[1] : &qs->fl[0];
+ if (fl->use_pages) {
+ void *addr = fl->sdesc[fl->cidx].pg_chunk.va;
+ prefetch(addr);
+#if L1_CACHE_BYTES < 128
+ prefetch(addr + L1_CACHE_BYTES);
+#endif
__refill_fl(adap, fl);
- pci_unmap_single(adap->pdev,
- pci_unmap_addr(sd, dma_addr),
- fl->buf_size,
- PCI_DMA_FROMDEVICE);
-
- if (eth) {
- if (unlikely(fl->credits <
- SGE_RX_DROP_THRES))
- goto eth_recycle;
-
- skb = alloc_skb(SKB_DATA_SIZE,
- GFP_ATOMIC);
- if (unlikely(!skb)) {
-eth_recycle:
- q->rx_drops++;
- recycle_rx_buf(adap, fl,
- fl->cidx);
- goto eth_done;
- }
- } else {
- skb = alloc_skb(SKB_DATA_SIZE,
- GFP_ATOMIC);
- if (unlikely(!skb))
- goto no_mem;
- }
-
- skb_data_init(skb, p, G_RSPD_LEN(len));
-eth_done:
- fl->credits--;
- q->eth_pkts++;
- } else {
- fl->credits--;
+ skb = get_packet_pg(adap, fl, G_RSPD_LEN(len),
+ eth ? SGE_RX_DROP_THRES : 0);
+ } else
skb = get_packet(adap, fl, G_RSPD_LEN(len),
eth ? SGE_RX_DROP_THRES : 0);
- }
+ if (unlikely(!skb)) {
+ if (!eth)
+ goto no_mem;
+ q->rx_drops++;
+ } else if (unlikely(r->rss_hdr.opcode == CPL_TRACE_PKT))
+ __skb_pull(skb, 2);
if (++fl->cidx == fl->size)
fl->cidx = 0;
@@ -2016,20 +2032,15 @@ eth_done:
q->credits = 0;
}
- if (skb) {
- /* Preserve the RSS info in csum & priority */
- skb->csum = rss_hi;
- skb->priority = rss_lo;
-
+ if (likely(skb != NULL)) {
if (eth)
rx_eth(adap, q, skb, ethpad);
else {
- if (unlikely(r->rss_hdr.opcode ==
- CPL_TRACE_PKT))
- __skb_pull(skb, ethpad);
-
- ngathered = rx_offload(&adap->tdev, q,
- skb, offload_skbs,
+ /* Preserve the RSS info in csum & priority */
+ skb->csum = rss_hi;
+ skb->priority = rss_lo;
+ ngathered = rx_offload(&adap->tdev, q, skb,
+ offload_skbs,
ngathered);
}
}
@@ -2635,25 +2646,15 @@ int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports,
q->txq[TXQ_ETH].stop_thres = nports *
flits_to_desc(sgl_len(MAX_SKB_FRAGS + 1) + 3);
- if (!is_offload(adapter)) {
-#ifdef USE_RX_PAGE
- q->fl[0].buf_size = RX_PAGE_SIZE;
+#if FL0_PG_CHUNK_SIZE > 0
+ q->fl[0].buf_size = FL0_PG_CHUNK_SIZE;
#else
- q->fl[0].buf_size = SGE_RX_SM_BUF_SIZE + 2 +
- sizeof(struct cpl_rx_pkt);
+ q->fl[0].buf_size = SGE_RX_SM_BUF_SIZE + sizeof(struct cpl_rx_data);
#endif
- q->fl[1].buf_size = MAX_FRAME_SIZE + 2 +
- sizeof(struct cpl_rx_pkt);
- } else {
-#ifdef USE_RX_PAGE
- q->fl[0].buf_size = RX_PAGE_SIZE;
-#else
- q->fl[0].buf_size = SGE_RX_SM_BUF_SIZE +
- sizeof(struct cpl_rx_data);
-#endif
- q->fl[1].buf_size = (16 * 1024) -
- SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
- }
+ q->fl[0].use_pages = FL0_PG_CHUNK_SIZE > 0;
+ q->fl[1].buf_size = is_offload(adapter) ?
+ (16 * 1024) - SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) :
+ MAX_FRAME_SIZE + 2 + sizeof(struct cpl_rx_pkt);
spin_lock(&adapter->sge.reg_lock);
diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c
index fb485d0a43d8..dd3149d94ba8 100644
--- a/drivers/net/cxgb3/t3_hw.c
+++ b/drivers/net/cxgb3/t3_hw.c
@@ -847,6 +847,64 @@ static int t3_write_flash(struct adapter *adapter, unsigned int addr,
return 0;
}
+/**
+ * t3_check_tpsram_version - read the tp sram version
+ * @adapter: the adapter
+ *
+ * Reads the protocol sram version from serial eeprom.
+ */
+int t3_check_tpsram_version(struct adapter *adapter)
+{
+ int ret;
+ u32 vers;
+ unsigned int major, minor;
+
+ /* Get version loaded in SRAM */
+ t3_write_reg(adapter, A_TP_EMBED_OP_FIELD0, 0);
+ ret = t3_wait_op_done(adapter, A_TP_EMBED_OP_FIELD0,
+ 1, 1, 5, 1);
+ if (ret)
+ return ret;
+
+ vers = t3_read_reg(adapter, A_TP_EMBED_OP_FIELD1);
+
+ major = G_TP_VERSION_MAJOR(vers);
+ minor = G_TP_VERSION_MINOR(vers);
+
+ if (major == TP_VERSION_MAJOR && minor == TP_VERSION_MINOR)
+ return 0;
+
+ return -EINVAL;
+}
+
+/**
+ * t3_check_tpsram - check if provided protocol SRAM
+ * is compatible with this driver
+ * @adapter: the adapter
+ * @tp_sram: the firmware image to write
+ * @size: image size
+ *
+ * Checks if an adapter's tp sram is compatible with the driver.
+ * Returns 0 if the versions are compatible, a negative error otherwise.
+ */
+int t3_check_tpsram(struct adapter *adapter, u8 *tp_sram, unsigned int size)
+{
+ u32 csum;
+ unsigned int i;
+ const u32 *p = (const u32 *)tp_sram;
+
+ /* Verify checksum */
+ for (csum = 0, i = 0; i < size / sizeof(csum); i++)
+ csum += ntohl(p[i]);
+ if (csum != 0xffffffff) {
+ CH_ERR(adapter, "corrupted protocol SRAM image, checksum %u\n",
+ csum);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
enum fw_version_type {
FW_VERSION_N3,
FW_VERSION_T3
@@ -921,7 +979,7 @@ static int t3_flash_erase_sectors(struct adapter *adapter, int start, int end)
/*
* t3_load_fw - download firmware
* @adapter: the adapter
- * @fw_data: the firrware image to write
+ * @fw_data: the firmware image to write
* @size: image size
*
* Write the supplied firmware image to the card's serial flash.
@@ -2362,7 +2420,7 @@ static void tp_config(struct adapter *adap, const struct tp_params *p)
F_TCPCHECKSUMOFFLOAD | V_IPTTL(64));
t3_write_reg(adap, A_TP_TCP_OPTIONS, V_MTUDEFAULT(576) |
F_MTUENABLE | V_WINDOWSCALEMODE(1) |
- V_TIMESTAMPSMODE(1) | V_SACKMODE(1) | V_SACKRX(1));
+ V_TIMESTAMPSMODE(0) | V_SACKMODE(1) | V_SACKRX(1));
t3_write_reg(adap, A_TP_DACK_CONFIG, V_AUTOSTATE3(1) |
V_AUTOSTATE2(1) | V_AUTOSTATE1(0) |
V_BYTETHRESHOLD(16384) | V_MSSTHRESHOLD(2) |
@@ -2371,16 +2429,18 @@ static void tp_config(struct adapter *adap, const struct tp_params *p)
F_IPV6ENABLE | F_NICMODE);
t3_write_reg(adap, A_TP_TX_RESOURCE_LIMIT, 0x18141814);
t3_write_reg(adap, A_TP_PARA_REG4, 0x5050105);
- t3_set_reg_field(adap, A_TP_PARA_REG6,
- adap->params.rev > 0 ? F_ENABLEESND : F_T3A_ENABLEESND,
- 0);
+ t3_set_reg_field(adap, A_TP_PARA_REG6, 0,
+ adap->params.rev > 0 ? F_ENABLEESND :
+ F_T3A_ENABLEESND);
t3_set_reg_field(adap, A_TP_PC_CONFIG,
- F_ENABLEEPCMDAFULL | F_ENABLEOCSPIFULL,
- F_TXDEFERENABLE | F_HEARBEATDACK | F_TXCONGESTIONMODE |
- F_RXCONGESTIONMODE);
+ F_ENABLEEPCMDAFULL,
+ F_ENABLEOCSPIFULL |F_TXDEFERENABLE | F_HEARBEATDACK |
+ F_TXCONGESTIONMODE | F_RXCONGESTIONMODE);
t3_set_reg_field(adap, A_TP_PC_CONFIG2, F_CHDRAFULL, 0);
-
+ t3_write_reg(adap, A_TP_PROXY_FLOW_CNTL, 1080);
+ t3_write_reg(adap, A_TP_PROXY_FLOW_CNTL, 1000);
+
if (adap->params.rev > 0) {
tp_wr_indirect(adap, A_TP_EGRESS_CONFIG, F_REWRITEFORCETOSIZE);
t3_set_reg_field(adap, A_TP_PARA_REG3, F_TXPACEAUTO,
@@ -2390,9 +2450,10 @@ static void tp_config(struct adapter *adap, const struct tp_params *p)
} else
t3_set_reg_field(adap, A_TP_PARA_REG3, 0, F_TXPACEFIXED);
- t3_write_reg(adap, A_TP_TX_MOD_QUEUE_WEIGHT1, 0x12121212);
- t3_write_reg(adap, A_TP_TX_MOD_QUEUE_WEIGHT0, 0x12121212);
- t3_write_reg(adap, A_TP_MOD_CHANNEL_WEIGHT, 0x1212);
+ t3_write_reg(adap, A_TP_TX_MOD_QUEUE_WEIGHT1, 0);
+ t3_write_reg(adap, A_TP_TX_MOD_QUEUE_WEIGHT0, 0);
+ t3_write_reg(adap, A_TP_MOD_CHANNEL_WEIGHT, 0);
+ t3_write_reg(adap, A_TP_MOD_RATE_LIMIT, 0xf2200000);
}
/* Desired TP timer resolution in usec */
@@ -2468,6 +2529,7 @@ int t3_tp_set_coalescing_size(struct adapter *adap, unsigned int size, int psh)
val |= F_RXCOALESCEENABLE;
if (psh)
val |= F_RXCOALESCEPSHEN;
+ size = min(MAX_RX_COALESCING_LEN, size);
t3_write_reg(adap, A_TP_PARA_REG2, V_RXCOALESCESIZE(size) |
V_MAXRXDATA(MAX_RX_COALESCING_LEN));
}
@@ -2496,11 +2558,11 @@ static void __devinit init_mtus(unsigned short mtus[])
* it can accomodate max size TCP/IP headers when SACK and timestamps
* are enabled and still have at least 8 bytes of payload.
*/
- mtus[0] = 88;
- mtus[1] = 256;
- mtus[2] = 512;
- mtus[3] = 576;
- mtus[4] = 808;
+ mtus[1] = 88;
+ mtus[1] = 88;
+ mtus[2] = 256;
+ mtus[3] = 512;
+ mtus[4] = 576;
mtus[5] = 1024;
mtus[6] = 1280;
mtus[7] = 1492;
@@ -2682,6 +2744,34 @@ static void ulp_config(struct adapter *adap, const struct tp_params *p)
t3_write_reg(adap, A_ULPRX_TDDP_TAGMASK, 0xffffffff);
}
+/**
+ * t3_set_proto_sram - set the contents of the protocol sram
+ * @adapter: the adapter
+ * @data: the protocol image
+ *
+ * Write the contents of the protocol SRAM.
+ */
+int t3_set_proto_sram(struct adapter *adap, u8 *data)
+{
+ int i;
+ u32 *buf = (u32 *)data;
+
+ for (i = 0; i < PROTO_SRAM_LINES; i++) {
+ t3_write_reg(adap, A_TP_EMBED_OP_FIELD5, cpu_to_be32(*buf++));
+ t3_write_reg(adap, A_TP_EMBED_OP_FIELD4, cpu_to_be32(*buf++));
+ t3_write_reg(adap, A_TP_EMBED_OP_FIELD3, cpu_to_be32(*buf++));
+ t3_write_reg(adap, A_TP_EMBED_OP_FIELD2, cpu_to_be32(*buf++));
+ t3_write_reg(adap, A_TP_EMBED_OP_FIELD1, cpu_to_be32(*buf++));
+
+ t3_write_reg(adap, A_TP_EMBED_OP_FIELD0, i << 1 | 1 << 31);
+ if (t3_wait_op_done(adap, A_TP_EMBED_OP_FIELD0, 1, 1, 5, 1))
+ return -EIO;
+ }
+ t3_write_reg(adap, A_TP_EMBED_OP_FIELD0, 0);
+
+ return 0;
+}
+
void t3_config_trace_filter(struct adapter *adapter,
const struct trace_params *tp, int filter_index,
int invert, int enable)
@@ -2802,7 +2892,7 @@ static void init_hw_for_avail_ports(struct adapter *adap, int nports)
t3_set_reg_field(adap, A_ULPTX_CONFIG, F_CFG_RR_ARB, 0);
t3_write_reg(adap, A_MPS_CFG, F_TPRXPORTEN | F_TPTXPORT0EN |
F_PORT0ACTIVE | F_ENFORCEPKT);
- t3_write_reg(adap, A_PM1_TX_CFG, 0xc000c000);
+ t3_write_reg(adap, A_PM1_TX_CFG, 0xffffffff);
} else {
t3_set_reg_field(adap, A_ULPRX_CTL, 0, F_ROUND_ROBIN);
t3_set_reg_field(adap, A_ULPTX_CONFIG, 0, F_CFG_RR_ARB);
@@ -3097,7 +3187,7 @@ int t3_init_hw(struct adapter *adapter, u32 fw_params)
else
t3_set_reg_field(adapter, A_PCIX_CFG, 0, F_CLIDECEN);
- t3_write_reg(adapter, A_PM1_RX_CFG, 0xf000f000);
+ t3_write_reg(adapter, A_PM1_RX_CFG, 0xffffffff);
init_hw_for_avail_ports(adapter, adapter->params.nports);
t3_sge_init(adapter, &adapter->params.sge);
diff --git a/drivers/net/cxgb3/version.h b/drivers/net/cxgb3/version.h
index b112317f033e..8eddd23a3a51 100644
--- a/drivers/net/cxgb3/version.h
+++ b/drivers/net/cxgb3/version.h
@@ -39,6 +39,6 @@
/* Firmware version */
#define FW_VERSION_MAJOR 4
-#define FW_VERSION_MINOR 0
+#define FW_VERSION_MINOR 1
#define FW_VERSION_MICRO 0
#endif /* __CHELSIO_VERSION_H */
diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ehea/ehea.h
index c0f81b5a30fb..abaf3ac94936 100644
--- a/drivers/net/ehea/ehea.h
+++ b/drivers/net/ehea/ehea.h
@@ -39,7 +39,7 @@
#include <asm/io.h>
#define DRV_NAME "ehea"
-#define DRV_VERSION "EHEA_0064"
+#define DRV_VERSION "EHEA_0065"
#define EHEA_MSG_DEFAULT (NETIF_MSG_LINK | NETIF_MSG_TIMER \
| NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR)
@@ -136,10 +136,10 @@ void ehea_dump(void *adr, int len, char *msg);
(0xffffffffffffffffULL >> ((64 - (mask)) & 0xffff))
#define EHEA_BMASK_SET(mask, value) \
- ((EHEA_BMASK_MASK(mask) & ((u64)(value))) << EHEA_BMASK_SHIFTPOS(mask))
+ ((EHEA_BMASK_MASK(mask) & ((u64)(value))) << EHEA_BMASK_SHIFTPOS(mask))
#define EHEA_BMASK_GET(mask, value) \
- (EHEA_BMASK_MASK(mask) & (((u64)(value)) >> EHEA_BMASK_SHIFTPOS(mask)))
+ (EHEA_BMASK_MASK(mask) & (((u64)(value)) >> EHEA_BMASK_SHIFTPOS(mask)))
/*
* Generic ehea page
@@ -190,7 +190,7 @@ struct ehea_av;
* Queue attributes passed to ehea_create_qp()
*/
struct ehea_qp_init_attr {
- /* input parameter */
+ /* input parameter */
u32 qp_token; /* queue token */
u8 low_lat_rq1;
u8 signalingtype; /* cqe generation flag */
@@ -212,7 +212,7 @@ struct ehea_qp_init_attr {
u64 recv_cq_handle;
u64 aff_eq_handle;
- /* output parameter */
+ /* output parameter */
u32 qp_nr;
u16 act_nr_send_wqes;
u16 act_nr_rwqes_rq1;
@@ -279,12 +279,12 @@ struct ehea_qp {
* Completion Queue attributes
*/
struct ehea_cq_attr {
- /* input parameter */
+ /* input parameter */
u32 max_nr_of_cqes;
u32 cq_token;
u64 eq_handle;
- /* output parameter */
+ /* output parameter */
u32 act_nr_of_cqes;
u32 nr_pages;
};
diff --git a/drivers/net/ehea/ehea_hw.h b/drivers/net/ehea/ehea_hw.h
index 1246757f2c22..1af7ca499ec5 100644
--- a/drivers/net/ehea/ehea_hw.h
+++ b/drivers/net/ehea/ehea_hw.h
@@ -211,34 +211,34 @@ static inline void epa_store_acc(struct h_epa epa, u32 offset, u64 value)
}
#define epa_store_eq(epa, offset, value)\
- epa_store(epa, EQTEMM_OFFSET(offset), value)
+ epa_store(epa, EQTEMM_OFFSET(offset), value)
#define epa_load_eq(epa, offset)\
- epa_load(epa, EQTEMM_OFFSET(offset))
+ epa_load(epa, EQTEMM_OFFSET(offset))
#define epa_store_cq(epa, offset, value)\
- epa_store(epa, CQTEMM_OFFSET(offset), value)
+ epa_store(epa, CQTEMM_OFFSET(offset), value)
#define epa_load_cq(epa, offset)\
- epa_load(epa, CQTEMM_OFFSET(offset))
+ epa_load(epa, CQTEMM_OFFSET(offset))
#define epa_store_qp(epa, offset, value)\
- epa_store(epa, QPTEMM_OFFSET(offset), value)
+ epa_store(epa, QPTEMM_OFFSET(offset), value)
#define epa_load_qp(epa, offset)\
- epa_load(epa, QPTEMM_OFFSET(offset))
+ epa_load(epa, QPTEMM_OFFSET(offset))
#define epa_store_qped(epa, offset, value)\
- epa_store(epa, QPEDMM_OFFSET(offset), value)
+ epa_store(epa, QPEDMM_OFFSET(offset), value)
#define epa_load_qped(epa, offset)\
- epa_load(epa, QPEDMM_OFFSET(offset))
+ epa_load(epa, QPEDMM_OFFSET(offset))
#define epa_store_mrmw(epa, offset, value)\
- epa_store(epa, MRMWMM_OFFSET(offset), value)
+ epa_store(epa, MRMWMM_OFFSET(offset), value)
#define epa_load_mrmw(epa, offset)\
- epa_load(epa, MRMWMM_OFFSET(offset))
+ epa_load(epa, MRMWMM_OFFSET(offset))
#define epa_store_base(epa, offset, value)\
- epa_store(epa, HCAGR_OFFSET(offset), value)
+ epa_store(epa, HCAGR_OFFSET(offset), value)
#define epa_load_base(epa, offset)\
- epa_load(epa, HCAGR_OFFSET(offset))
+ epa_load(epa, HCAGR_OFFSET(offset))
static inline void ehea_update_sqa(struct ehea_qp *qp, u16 nr_wqes)
{
diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c
index 9e13433a268a..bdb52419dbf5 100644
--- a/drivers/net/ehea/ehea_main.c
+++ b/drivers/net/ehea/ehea_main.c
@@ -81,7 +81,7 @@ MODULE_PARM_DESC(use_mcs, " 0:NAPI, 1:Multiple receive queues, Default = 1 ");
static int port_name_cnt = 0;
static int __devinit ehea_probe_adapter(struct ibmebus_dev *dev,
- const struct of_device_id *id);
+ const struct of_device_id *id);
static int __devexit ehea_remove(struct ibmebus_dev *dev);
@@ -236,7 +236,7 @@ static int ehea_refill_rq_def(struct ehea_port_res *pr,
rwqe = ehea_get_next_rwqe(qp, rq_nr);
rwqe->wr_id = EHEA_BMASK_SET(EHEA_WR_ID_TYPE, wqe_type)
- | EHEA_BMASK_SET(EHEA_WR_ID_INDEX, index);
+ | EHEA_BMASK_SET(EHEA_WR_ID_INDEX, index);
rwqe->sg_list[0].l_key = pr->recv_mr.lkey;
rwqe->sg_list[0].vaddr = (u64)skb->data;
rwqe->sg_list[0].len = packet_size;
@@ -427,7 +427,7 @@ static struct ehea_cqe *ehea_proc_rwqes(struct net_device *dev,
break;
}
skb_copy_to_linear_data(skb, ((char*)cqe) + 64,
- cqe->num_bytes_transfered - 4);
+ cqe->num_bytes_transfered - 4);
ehea_fill_skb(port->netdev, skb, cqe);
} else if (rq == 2) { /* RQ2 */
skb = get_skb_by_index(skb_arr_rq2,
@@ -618,7 +618,7 @@ static struct ehea_port *ehea_get_port(struct ehea_adapter *adapter,
for (i = 0; i < EHEA_MAX_PORTS; i++)
if (adapter->port[i])
- if (adapter->port[i]->logical_port_id == logical_port)
+ if (adapter->port[i]->logical_port_id == logical_port)
return adapter->port[i];
return NULL;
}
@@ -1695,6 +1695,7 @@ static void ehea_xmit2(struct sk_buff *skb, struct net_device *dev,
{
if (skb->protocol == htons(ETH_P_IP)) {
const struct iphdr *iph = ip_hdr(skb);
+
/* IPv4 */
swqe->tx_control |= EHEA_SWQE_CRC
| EHEA_SWQE_IP_CHECKSUM
@@ -1705,13 +1706,12 @@ static void ehea_xmit2(struct sk_buff *skb, struct net_device *dev,
write_ip_start_end(swqe, skb);
if (iph->protocol == IPPROTO_UDP) {
- if ((iph->frag_off & IP_MF) ||
- (iph->frag_off & IP_OFFSET))
+ if ((iph->frag_off & IP_MF)
+ || (iph->frag_off & IP_OFFSET))
/* IP fragment, so don't change cs */
swqe->tx_control &= ~EHEA_SWQE_TCP_CHECKSUM;
else
write_udp_offset_end(swqe, skb);
-
} else if (iph->protocol == IPPROTO_TCP) {
write_tcp_offset_end(swqe, skb);
}
@@ -1739,6 +1739,7 @@ static void ehea_xmit3(struct sk_buff *skb, struct net_device *dev,
if (skb->protocol == htons(ETH_P_IP)) {
const struct iphdr *iph = ip_hdr(skb);
+
/* IPv4 */
write_ip_start_end(swqe, skb);
@@ -1751,8 +1752,8 @@ static void ehea_xmit3(struct sk_buff *skb, struct net_device *dev,
write_tcp_offset_end(swqe, skb);
} else if (iph->protocol == IPPROTO_UDP) {
- if ((iph->frag_off & IP_MF) ||
- (iph->frag_off & IP_OFFSET))
+ if ((iph->frag_off & IP_MF)
+ || (iph->frag_off & IP_OFFSET))
/* IP fragment, so don't change cs */
swqe->tx_control |= EHEA_SWQE_CRC
| EHEA_SWQE_IMM_DATA_PRESENT;
@@ -2407,7 +2408,7 @@ static void __devinit logical_port_release(struct device *dev)
}
static int ehea_driver_sysfs_add(struct device *dev,
- struct device_driver *driver)
+ struct device_driver *driver)
{
int ret;
@@ -2424,7 +2425,7 @@ static int ehea_driver_sysfs_add(struct device *dev,
}
static void ehea_driver_sysfs_remove(struct device *dev,
- struct device_driver *driver)
+ struct device_driver *driver)
{
struct device_driver *drv = driver;
@@ -2453,7 +2454,7 @@ static struct device *ehea_register_port(struct ehea_port *port,
}
ret = device_create_file(&port->ofdev.dev, &dev_attr_log_port_id);
- if (ret) {
+ if (ret) {
ehea_error("failed to register attributes, ret=%d", ret);
goto out_unreg_of_dev;
}
@@ -2601,6 +2602,7 @@ static int ehea_setup_ports(struct ehea_adapter *adapter)
{
struct device_node *lhea_dn;
struct device_node *eth_dn = NULL;
+
const u32 *dn_log_port_id;
int i = 0;
@@ -2608,7 +2610,7 @@ static int ehea_setup_ports(struct ehea_adapter *adapter)
while ((eth_dn = of_get_next_child(lhea_dn, eth_dn))) {
dn_log_port_id = of_get_property(eth_dn, "ibm,hea-port-no",
- NULL);
+ NULL);
if (!dn_log_port_id) {
ehea_error("bad device node: eth_dn name=%s",
eth_dn->full_name);
@@ -2648,7 +2650,7 @@ static struct device_node *ehea_get_eth_dn(struct ehea_adapter *adapter,
while ((eth_dn = of_get_next_child(lhea_dn, eth_dn))) {
dn_log_port_id = of_get_property(eth_dn, "ibm,hea-port-no",
- NULL);
+ NULL);
if (dn_log_port_id)
if (*dn_log_port_id == logical_port_id)
return eth_dn;
@@ -2789,7 +2791,7 @@ static int __devinit ehea_probe_adapter(struct ibmebus_dev *dev,
adapter->ebus_dev = dev;
adapter_handle = of_get_property(dev->ofdev.node, "ibm,hea-handle",
- NULL);
+ NULL);
if (adapter_handle)
adapter->handle = *adapter_handle;
diff --git a/drivers/net/ehea/ehea_qmr.c b/drivers/net/ehea/ehea_qmr.c
index f24a8862977d..29eaa46948b0 100644
--- a/drivers/net/ehea/ehea_qmr.c
+++ b/drivers/net/ehea/ehea_qmr.c
@@ -211,7 +211,7 @@ u64 ehea_destroy_cq_res(struct ehea_cq *cq, u64 force)
u64 hret;
u64 adapter_handle = cq->adapter->handle;
- /* deregister all previous registered pages */
+ /* deregister all previous registered pages */
hret = ehea_h_free_resource(adapter_handle, cq->fw_handle, force);
if (hret != H_SUCCESS)
return hret;
@@ -362,7 +362,7 @@ int ehea_destroy_eq(struct ehea_eq *eq)
if (hret != H_SUCCESS) {
ehea_error("destroy EQ failed");
return -EIO;
- }
+ }
return 0;
}
@@ -507,44 +507,44 @@ out_freemem:
u64 ehea_destroy_qp_res(struct ehea_qp *qp, u64 force)
{
- u64 hret;
- struct ehea_qp_init_attr *qp_attr = &qp->init_attr;
+ u64 hret;
+ struct ehea_qp_init_attr *qp_attr = &qp->init_attr;
- ehea_h_disable_and_get_hea(qp->adapter->handle, qp->fw_handle);
- hret = ehea_h_free_resource(qp->adapter->handle, qp->fw_handle, force);
- if (hret != H_SUCCESS)
- return hret;
+ ehea_h_disable_and_get_hea(qp->adapter->handle, qp->fw_handle);
+ hret = ehea_h_free_resource(qp->adapter->handle, qp->fw_handle, force);
+ if (hret != H_SUCCESS)
+ return hret;
- hw_queue_dtor(&qp->hw_squeue);
- hw_queue_dtor(&qp->hw_rqueue1);
+ hw_queue_dtor(&qp->hw_squeue);
+ hw_queue_dtor(&qp->hw_rqueue1);
- if (qp_attr->rq_count > 1)
- hw_queue_dtor(&qp->hw_rqueue2);
- if (qp_attr->rq_count > 2)
- hw_queue_dtor(&qp->hw_rqueue3);
- kfree(qp);
+ if (qp_attr->rq_count > 1)
+ hw_queue_dtor(&qp->hw_rqueue2);
+ if (qp_attr->rq_count > 2)
+ hw_queue_dtor(&qp->hw_rqueue3);
+ kfree(qp);
- return hret;
+ return hret;
}
int ehea_destroy_qp(struct ehea_qp *qp)
{
- u64 hret;
- if (!qp)
- return 0;
+ u64 hret;
+ if (!qp)
+ return 0;
- if ((hret = ehea_destroy_qp_res(qp, NORMAL_FREE)) == H_R_STATE) {
- ehea_error_data(qp->adapter, qp->fw_handle);
- hret = ehea_destroy_qp_res(qp, FORCE_FREE);
- }
+ if ((hret = ehea_destroy_qp_res(qp, NORMAL_FREE)) == H_R_STATE) {
+ ehea_error_data(qp->adapter, qp->fw_handle);
+ hret = ehea_destroy_qp_res(qp, FORCE_FREE);
+ }
- if (hret != H_SUCCESS) {
- ehea_error("destroy QP failed");
- return -EIO;
- }
+ if (hret != H_SUCCESS) {
+ ehea_error("destroy QP failed");
+ return -EIO;
+ }
- return 0;
+ return 0;
}
int ehea_reg_kernel_mr(struct ehea_adapter *adapter, struct ehea_mr *mr)
diff --git a/drivers/net/fec_8xx/Kconfig b/drivers/net/fec_8xx/Kconfig
index a84c232395e3..afb34ded26ee 100644
--- a/drivers/net/fec_8xx/Kconfig
+++ b/drivers/net/fec_8xx/Kconfig
@@ -1,6 +1,6 @@
config FEC_8XX
tristate "Motorola 8xx FEC driver"
- depends on NET_ETHERNET && 8xx
+ depends on 8XX
select MII
config FEC_8XX_GENERIC_PHY
diff --git a/drivers/net/fs_enet/Kconfig b/drivers/net/fs_enet/Kconfig
index 6aaee67dd4b7..e27ee210b605 100644
--- a/drivers/net/fs_enet/Kconfig
+++ b/drivers/net/fs_enet/Kconfig
@@ -1,6 +1,6 @@
config FS_ENET
tristate "Freescale Ethernet Driver"
- depends on NET_ETHERNET && (CPM1 || CPM2)
+ depends on CPM1 || CPM2
select MII
config FS_ENET_HAS_SCC
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 1b854bf07b09..d7a1a58de766 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -130,6 +130,9 @@ static int gfar_remove(struct platform_device *pdev);
static void free_skb_resources(struct gfar_private *priv);
static void gfar_set_multi(struct net_device *dev);
static void gfar_set_hash_for_addr(struct net_device *dev, u8 *addr);
+static void gfar_configure_serdes(struct net_device *dev);
+extern int gfar_local_mdio_write(struct gfar_mii *regs, int mii_id, int regnum, u16 value);
+extern int gfar_local_mdio_read(struct gfar_mii *regs, int mii_id, int regnum);
#ifdef CONFIG_GFAR_NAPI
static int gfar_poll(struct net_device *dev, int *budget);
#endif
@@ -451,6 +454,9 @@ static int init_phy(struct net_device *dev)
phydev = phy_connect(dev, phy_id, &adjust_link, 0, interface);
+ if (interface == PHY_INTERFACE_MODE_SGMII)
+ gfar_configure_serdes(dev);
+
if (IS_ERR(phydev)) {
printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name);
return PTR_ERR(phydev);
@@ -465,6 +471,27 @@ static int init_phy(struct net_device *dev)
return 0;
}
+static void gfar_configure_serdes(struct net_device *dev)
+{
+ struct gfar_private *priv = netdev_priv(dev);
+ struct gfar_mii __iomem *regs =
+ (void __iomem *)&priv->regs->gfar_mii_regs;
+
+ /* Initialise TBI i/f to communicate with serdes (lynx phy) */
+
+ /* Single clk mode, mii mode off(for aerdes communication) */
+ gfar_local_mdio_write(regs, TBIPA_VALUE, MII_TBICON, TBICON_CLK_SELECT);
+
+ /* Supported pause and full-duplex, no half-duplex */
+ gfar_local_mdio_write(regs, TBIPA_VALUE, MII_ADVERTISE,
+ ADVERTISE_1000XFULL | ADVERTISE_1000XPAUSE |
+ ADVERTISE_1000XPSE_ASYM);
+
+ /* ANEG enable, restart ANEG, full duplex mode, speed[1] set */
+ gfar_local_mdio_write(regs, TBIPA_VALUE, MII_BMCR, BMCR_ANENABLE |
+ BMCR_ANRESTART | BMCR_FULLDPLX | BMCR_SPEED1000);
+}
+
static void init_registers(struct net_device *dev)
{
struct gfar_private *priv = netdev_priv(dev);
diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h
index 39e9e321fcbc..d8e779c102fa 100644
--- a/drivers/net/gianfar.h
+++ b/drivers/net/gianfar.h
@@ -136,6 +136,12 @@ extern const char gfar_driver_version[];
#define MIIMCFG_RESET 0x80000000
#define MIIMIND_BUSY 0x00000001
+/* TBI register addresses */
+#define MII_TBICON 0x11
+
+/* TBICON register bit fields */
+#define TBICON_CLK_SELECT 0x0020
+
/* MAC register bits */
#define MACCFG1_SOFT_RESET 0x80000000
#define MACCFG1_RESET_RX_MC 0x00080000
diff --git a/drivers/net/gianfar_mii.c b/drivers/net/gianfar_mii.c
index bcc6b82f4a33..5dd34a1a7b89 100644
--- a/drivers/net/gianfar_mii.c
+++ b/drivers/net/gianfar_mii.c
@@ -43,13 +43,18 @@
#include "gianfar.h"
#include "gianfar_mii.h"
-/* Write value to the PHY at mii_id at register regnum,
- * on the bus, waiting until the write is done before returning.
- * All PHY configuration is done through the TSEC1 MIIM regs */
-int gfar_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value)
+/*
+ * Write value to the PHY at mii_id at register regnum,
+ * on the bus attached to the local interface, which may be different from the
+ * generic mdio bus (tied to a single interface), waiting until the write is
+ * done before returning. This is helpful in programming interfaces like
+ * the TBI which control interfaces like onchip SERDES and are always tied to
+ * the local mdio pins, which may not be the same as system mdio bus, used for
+ * controlling the external PHYs, for example.
+ */
+int gfar_local_mdio_write(struct gfar_mii *regs, int mii_id,
+ int regnum, u16 value)
{
- struct gfar_mii __iomem *regs = (void __iomem *)bus->priv;
-
/* Set the PHY address and the register address we want to write */
gfar_write(&regs->miimadd, (mii_id << 8) | regnum);
@@ -63,12 +68,19 @@ int gfar_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value)
return 0;
}
-/* Read the bus for PHY at addr mii_id, register regnum, and
- * return the value. Clears miimcom first. All PHY
- * configuration has to be done through the TSEC1 MIIM regs */
-int gfar_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
+/*
+ * Read the bus for PHY at addr mii_id, register regnum, and
+ * return the value. Clears miimcom first. All PHY operation
+ * done on the bus attached to the local interface,
+ * which may be different from the generic mdio bus
+ * This is helpful in programming interfaces like
+ * the TBI which, inturn, control interfaces like onchip SERDES
+ * and are always tied to the local mdio pins, which may not be the
+ * same as system mdio bus, used for controlling the external PHYs, for eg.
+ */
+int gfar_local_mdio_read(struct gfar_mii *regs, int mii_id, int regnum)
+
{
- struct gfar_mii __iomem *regs = (void __iomem *)bus->priv;
u16 value;
/* Set the PHY address and the register address we want to read */
@@ -88,6 +100,27 @@ int gfar_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
return value;
}
+/* Write value to the PHY at mii_id at register regnum,
+ * on the bus, waiting until the write is done before returning.
+ * All PHY configuration is done through the TSEC1 MIIM regs */
+int gfar_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value)
+{
+ struct gfar_mii __iomem *regs = (void __iomem *)bus->priv;
+
+ /* Write to the local MII regs */
+ return(gfar_local_mdio_write(regs, mii_id, regnum, value));
+}
+
+/* Read the bus for PHY at addr mii_id, register regnum, and
+ * return the value. Clears miimcom first. All PHY
+ * configuration has to be done through the TSEC1 MIIM regs */
+int gfar_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
+{
+ struct gfar_mii __iomem *regs = (void __iomem *)bus->priv;
+
+ /* Read the local MII regs */
+ return(gfar_local_mdio_read(regs, mii_id, regnum));
+}
/* Reset the MIIM registers, and wait for the bus to free */
int gfar_mdio_reset(struct mii_bus *bus)
diff --git a/drivers/net/lasi_82596.c b/drivers/net/lasi_82596.c
index 741780e14b2c..efbae4b8398e 100644
--- a/drivers/net/lasi_82596.c
+++ b/drivers/net/lasi_82596.c
@@ -86,93 +86,36 @@
#include <linux/dma-mapping.h>
#include <asm/io.h>
-#include <asm/pgtable.h>
#include <asm/irq.h>
#include <asm/pdc.h>
-#include <asm/cache.h>
#include <asm/parisc-device.h>
#define LASI_82596_DRIVER_VERSION "LASI 82596 driver - Revision: 1.30"
-/* DEBUG flags
- */
-
-#define DEB_INIT 0x0001
-#define DEB_PROBE 0x0002
-#define DEB_SERIOUS 0x0004
-#define DEB_ERRORS 0x0008
-#define DEB_MULTI 0x0010
-#define DEB_TDR 0x0020
-#define DEB_OPEN 0x0040
-#define DEB_RESET 0x0080
-#define DEB_ADDCMD 0x0100
-#define DEB_STATUS 0x0200
-#define DEB_STARTTX 0x0400
-#define DEB_RXADDR 0x0800
-#define DEB_TXADDR 0x1000
-#define DEB_RXFRAME 0x2000
-#define DEB_INTS 0x4000
-#define DEB_STRUCT 0x8000
-#define DEB_ANY 0xffff
-
-
-#define DEB(x,y) if (i596_debug & (x)) { y; }
-
-
-#define CHECK_WBACK(priv, addr,len) \
- do { dma_cache_sync((priv)->dev, (void *)addr, len, DMA_TO_DEVICE); } while (0)
-
-#define CHECK_INV(priv, addr,len) \
- do { dma_cache_sync((priv)->dev, (void *)addr, len, DMA_FROM_DEVICE); } while(0)
-
-#define CHECK_WBACK_INV(priv, addr,len) \
- do { dma_cache_sync((priv)->dev, (void *)addr, len, DMA_BIDIRECTIONAL); } while (0)
-
-
#define PA_I82596_RESET 0 /* Offsets relative to LASI-LAN-Addr.*/
#define PA_CPU_PORT_L_ACCESS 4
#define PA_CHANNEL_ATTENTION 8
+#define OPT_SWAP_PORT 0x0001 /* Need to wordswp on the MPU port */
-/*
- * Define various macros for Channel Attention, word swapping etc., dependent
- * on architecture. MVME and BVME are 680x0 based, otherwise it is Intel.
- */
+#define DMA_ALLOC dma_alloc_noncoherent
+#define DMA_FREE dma_free_noncoherent
+#define DMA_WBACK(ndev, addr, len) \
+ do { dma_cache_sync((ndev)->dev.parent, (void *)addr, len, DMA_TO_DEVICE); } while (0)
-#ifdef __BIG_ENDIAN
-#define WSWAPrfd(x) (((u32)(x)<<16) | ((((u32)(x)))>>16))
-#define WSWAPrbd(x) (((u32)(x)<<16) | ((((u32)(x)))>>16))
-#define WSWAPiscp(x) (((u32)(x)<<16) | ((((u32)(x)))>>16))
-#define WSWAPscb(x) (((u32)(x)<<16) | ((((u32)(x)))>>16))
-#define WSWAPcmd(x) (((u32)(x)<<16) | ((((u32)(x)))>>16))
-#define WSWAPtbd(x) (((u32)(x)<<16) | ((((u32)(x)))>>16))
-#define WSWAPchar(x) (((u32)(x)<<16) | ((((u32)(x)))>>16))
-#define ISCP_BUSY 0x00010000
-#define MACH_IS_APRICOT 0
-#else
-#define WSWAPrfd(x) ((struct i596_rfd *)(x))
-#define WSWAPrbd(x) ((struct i596_rbd *)(x))
-#define WSWAPiscp(x) ((struct i596_iscp *)(x))
-#define WSWAPscb(x) ((struct i596_scb *)(x))
-#define WSWAPcmd(x) ((struct i596_cmd *)(x))
-#define WSWAPtbd(x) ((struct i596_tbd *)(x))
-#define WSWAPchar(x) ((char *)(x))
-#define ISCP_BUSY 0x0001
-#define MACH_IS_APRICOT 1
-#endif
+#define DMA_INV(ndev, addr, len) \
+ do { dma_cache_sync((ndev)->dev.parent, (void *)addr, len, DMA_FROM_DEVICE); } while (0)
-/*
- * The MPU_PORT command allows direct access to the 82596. With PORT access
- * the following commands are available (p5-18). The 32-bit port command
- * must be word-swapped with the most significant word written first.
- * This only applies to VME boards.
- */
-#define PORT_RESET 0x00 /* reset 82596 */
-#define PORT_SELFTEST 0x01 /* selftest */
-#define PORT_ALTSCP 0x02 /* alternate SCB address */
-#define PORT_ALTDUMP 0x03 /* Alternate DUMP address */
+#define DMA_WBACK_INV(ndev, addr, len) \
+ do { dma_cache_sync((ndev)->dev.parent, (void *)addr, len, DMA_BIDIRECTIONAL); } while (0)
+
+#define SYSBUS 0x0000006c;
+
+/* big endian CPU, 82596 "big" endian mode */
+#define SWAP32(x) (((u32)(x)<<16) | ((((u32)(x)))>>16))
+#define SWAP16(x) (x)
-static int i596_debug = (DEB_SERIOUS|DEB_PROBE);
+#include "lib82596.c"
MODULE_AUTHOR("Richard Hirst");
MODULE_DESCRIPTION("i82596 driver");
@@ -180,255 +123,15 @@ MODULE_LICENSE("GPL");
module_param(i596_debug, int, 0);
MODULE_PARM_DESC(i596_debug, "lasi_82596 debug mask");
-/* Copy frames shorter than rx_copybreak, otherwise pass on up in
- * a full sized sk_buff. Value of 100 stolen from tulip.c (!alpha).
- */
-static int rx_copybreak = 100;
-
-#define MAX_DRIVERS 4 /* max count of drivers */
-
-#define PKT_BUF_SZ 1536
-#define MAX_MC_CNT 64
-
-#define I596_NULL ((u32)0xffffffff)
-
-#define CMD_EOL 0x8000 /* The last command of the list, stop. */
-#define CMD_SUSP 0x4000 /* Suspend after doing cmd. */
-#define CMD_INTR 0x2000 /* Interrupt after doing cmd. */
-
-#define CMD_FLEX 0x0008 /* Enable flexible memory model */
-
-enum commands {
- CmdNOp = 0, CmdSASetup = 1, CmdConfigure = 2, CmdMulticastList = 3,
- CmdTx = 4, CmdTDR = 5, CmdDump = 6, CmdDiagnose = 7
-};
-
-#define STAT_C 0x8000 /* Set to 0 after execution */
-#define STAT_B 0x4000 /* Command being executed */
-#define STAT_OK 0x2000 /* Command executed ok */
-#define STAT_A 0x1000 /* Command aborted */
-
-#define CUC_START 0x0100
-#define CUC_RESUME 0x0200
-#define CUC_SUSPEND 0x0300
-#define CUC_ABORT 0x0400
-#define RX_START 0x0010
-#define RX_RESUME 0x0020
-#define RX_SUSPEND 0x0030
-#define RX_ABORT 0x0040
-
-#define TX_TIMEOUT 5
-
-#define OPT_SWAP_PORT 0x0001 /* Need to wordswp on the MPU port */
-
-
-struct i596_reg {
- unsigned short porthi;
- unsigned short portlo;
- u32 ca;
-};
-
-#define EOF 0x8000
-#define SIZE_MASK 0x3fff
-
-struct i596_tbd {
- unsigned short size;
- unsigned short pad;
- dma_addr_t next;
- dma_addr_t data;
- u32 cache_pad[5]; /* Total 32 bytes... */
-};
-
-/* The command structure has two 'next' pointers; v_next is the address of
- * the next command as seen by the CPU, b_next is the address of the next
- * command as seen by the 82596. The b_next pointer, as used by the 82596
- * always references the status field of the next command, rather than the
- * v_next field, because the 82596 is unaware of v_next. It may seem more
- * logical to put v_next at the end of the structure, but we cannot do that
- * because the 82596 expects other fields to be there, depending on command
- * type.
- */
-
-struct i596_cmd {
- struct i596_cmd *v_next; /* Address from CPUs viewpoint */
- unsigned short status;
- unsigned short command;
- dma_addr_t b_next; /* Address from i596 viewpoint */
-};
-
-struct tx_cmd {
- struct i596_cmd cmd;
- dma_addr_t tbd;
- unsigned short size;
- unsigned short pad;
- struct sk_buff *skb; /* So we can free it after tx */
- dma_addr_t dma_addr;
-#ifdef __LP64__
- u32 cache_pad[6]; /* Total 64 bytes... */
-#else
- u32 cache_pad[1]; /* Total 32 bytes... */
-#endif
-};
-
-struct tdr_cmd {
- struct i596_cmd cmd;
- unsigned short status;
- unsigned short pad;
-};
-
-struct mc_cmd {
- struct i596_cmd cmd;
- short mc_cnt;
- char mc_addrs[MAX_MC_CNT*6];
-};
-
-struct sa_cmd {
- struct i596_cmd cmd;
- char eth_addr[8];
-};
-
-struct cf_cmd {
- struct i596_cmd cmd;
- char i596_config[16];
-};
-
-struct i596_rfd {
- unsigned short stat;
- unsigned short cmd;
- dma_addr_t b_next; /* Address from i596 viewpoint */
- dma_addr_t rbd;
- unsigned short count;
- unsigned short size;
- struct i596_rfd *v_next; /* Address from CPUs viewpoint */
- struct i596_rfd *v_prev;
-#ifndef __LP64__
- u32 cache_pad[2]; /* Total 32 bytes... */
-#endif
-};
-
-struct i596_rbd {
- /* hardware data */
- unsigned short count;
- unsigned short zero1;
- dma_addr_t b_next;
- dma_addr_t b_data; /* Address from i596 viewpoint */
- unsigned short size;
- unsigned short zero2;
- /* driver data */
- struct sk_buff *skb;
- struct i596_rbd *v_next;
- dma_addr_t b_addr; /* This rbd addr from i596 view */
- unsigned char *v_data; /* Address from CPUs viewpoint */
- /* Total 32 bytes... */
-#ifdef __LP64__
- u32 cache_pad[4];
-#endif
-};
-
-/* These values as chosen so struct i596_private fits in one page... */
-
-#define TX_RING_SIZE 32
-#define RX_RING_SIZE 16
-
-struct i596_scb {
- unsigned short status;
- unsigned short command;
- dma_addr_t cmd;
- dma_addr_t rfd;
- u32 crc_err;
- u32 align_err;
- u32 resource_err;
- u32 over_err;
- u32 rcvdt_err;
- u32 short_err;
- unsigned short t_on;
- unsigned short t_off;
-};
-
-struct i596_iscp {
- u32 stat;
- dma_addr_t scb;
-};
-
-struct i596_scp {
- u32 sysbus;
- u32 pad;
- dma_addr_t iscp;
-};
-
-struct i596_private {
- volatile struct i596_scp scp __attribute__((aligned(32)));
- volatile struct i596_iscp iscp __attribute__((aligned(32)));
- volatile struct i596_scb scb __attribute__((aligned(32)));
- struct sa_cmd sa_cmd __attribute__((aligned(32)));
- struct cf_cmd cf_cmd __attribute__((aligned(32)));
- struct tdr_cmd tdr_cmd __attribute__((aligned(32)));
- struct mc_cmd mc_cmd __attribute__((aligned(32)));
- struct i596_rfd rfds[RX_RING_SIZE] __attribute__((aligned(32)));
- struct i596_rbd rbds[RX_RING_SIZE] __attribute__((aligned(32)));
- struct tx_cmd tx_cmds[TX_RING_SIZE] __attribute__((aligned(32)));
- struct i596_tbd tbds[TX_RING_SIZE] __attribute__((aligned(32)));
- u32 stat;
- int last_restart;
- struct i596_rfd *rfd_head;
- struct i596_rbd *rbd_head;
- struct i596_cmd *cmd_tail;
- struct i596_cmd *cmd_head;
- int cmd_backlog;
- u32 last_cmd;
- struct net_device_stats stats;
- int next_tx_cmd;
- int options;
- spinlock_t lock;
- dma_addr_t dma_addr;
- struct device *dev;
-};
-
-static const char init_setup[] =
-{
- 0x8E, /* length, prefetch on */
- 0xC8, /* fifo to 8, monitor off */
- 0x80, /* don't save bad frames */
- 0x2E, /* No source address insertion, 8 byte preamble */
- 0x00, /* priority and backoff defaults */
- 0x60, /* interframe spacing */
- 0x00, /* slot time LSB */
- 0xf2, /* slot time and retries */
- 0x00, /* promiscuous mode */
- 0x00, /* collision detect */
- 0x40, /* minimum frame length */
- 0xff,
- 0x00,
- 0x7f /* *multi IA */ };
-
-static int i596_open(struct net_device *dev);
-static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t i596_interrupt(int irq, void *dev_id);
-static int i596_close(struct net_device *dev);
-static struct net_device_stats *i596_get_stats(struct net_device *dev);
-static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd);
-static void i596_tx_timeout (struct net_device *dev);
-static void print_eth(unsigned char *buf, char *str);
-static void set_multicast_list(struct net_device *dev);
-
-static int rx_ring_size = RX_RING_SIZE;
-static int ticks_limit = 100;
-static int max_cmd_backlog = TX_RING_SIZE-1;
-
-#ifdef CONFIG_NET_POLL_CONTROLLER
-static void i596_poll_controller(struct net_device *dev);
-#endif
-
-
-static inline void CA(struct net_device *dev)
+static inline void ca(struct net_device *dev)
{
gsc_writel(0, dev->base_addr + PA_CHANNEL_ATTENTION);
}
-static inline void MPU_PORT(struct net_device *dev, int c, dma_addr_t x)
+static void mpu_port(struct net_device *dev, int c, dma_addr_t x)
{
- struct i596_private *lp = dev->priv;
+ struct i596_private *lp = netdev_priv(dev);
u32 v = (u32) (c) | (u32) (x);
u16 a, b;
@@ -446,1078 +149,15 @@ static inline void MPU_PORT(struct net_device *dev, int c, dma_addr_t x)
gsc_writel(b, dev->base_addr + PA_CPU_PORT_L_ACCESS);
}
-
-static inline int wait_istat(struct net_device *dev, struct i596_private *lp, int delcnt, char *str)
-{
- CHECK_INV(lp, &(lp->iscp), sizeof(struct i596_iscp));
- while (--delcnt && lp->iscp.stat) {
- udelay(10);
- CHECK_INV(lp, &(lp->iscp), sizeof(struct i596_iscp));
- }
- if (!delcnt) {
- printk("%s: %s, iscp.stat %04x, didn't clear\n",
- dev->name, str, lp->iscp.stat);
- return -1;
- }
- else
- return 0;
-}
-
-
-static inline int wait_cmd(struct net_device *dev, struct i596_private *lp, int delcnt, char *str)
-{
- CHECK_INV(lp, &(lp->scb), sizeof(struct i596_scb));
- while (--delcnt && lp->scb.command) {
- udelay(10);
- CHECK_INV(lp, &(lp->scb), sizeof(struct i596_scb));
- }
- if (!delcnt) {
- printk("%s: %s, status %4.4x, cmd %4.4x.\n",
- dev->name, str, lp->scb.status, lp->scb.command);
- return -1;
- }
- else
- return 0;
-}
-
-
-static void i596_display_data(struct net_device *dev)
-{
- struct i596_private *lp = dev->priv;
- struct i596_cmd *cmd;
- struct i596_rfd *rfd;
- struct i596_rbd *rbd;
-
- printk("lp and scp at %p, .sysbus = %08x, .iscp = %08x\n",
- &lp->scp, lp->scp.sysbus, lp->scp.iscp);
- printk("iscp at %p, iscp.stat = %08x, .scb = %08x\n",
- &lp->iscp, lp->iscp.stat, lp->iscp.scb);
- printk("scb at %p, scb.status = %04x, .command = %04x,"
- " .cmd = %08x, .rfd = %08x\n",
- &lp->scb, lp->scb.status, lp->scb.command,
- lp->scb.cmd, lp->scb.rfd);
- printk(" errors: crc %x, align %x, resource %x,"
- " over %x, rcvdt %x, short %x\n",
- lp->scb.crc_err, lp->scb.align_err, lp->scb.resource_err,
- lp->scb.over_err, lp->scb.rcvdt_err, lp->scb.short_err);
- cmd = lp->cmd_head;
- while (cmd != NULL) {
- printk("cmd at %p, .status = %04x, .command = %04x, .b_next = %08x\n",
- cmd, cmd->status, cmd->command, cmd->b_next);
- cmd = cmd->v_next;
- }
- rfd = lp->rfd_head;
- printk("rfd_head = %p\n", rfd);
- do {
- printk(" %p .stat %04x, .cmd %04x, b_next %08x, rbd %08x,"
- " count %04x\n",
- rfd, rfd->stat, rfd->cmd, rfd->b_next, rfd->rbd,
- rfd->count);
- rfd = rfd->v_next;
- } while (rfd != lp->rfd_head);
- rbd = lp->rbd_head;
- printk("rbd_head = %p\n", rbd);
- do {
- printk(" %p .count %04x, b_next %08x, b_data %08x, size %04x\n",
- rbd, rbd->count, rbd->b_next, rbd->b_data, rbd->size);
- rbd = rbd->v_next;
- } while (rbd != lp->rbd_head);
- CHECK_INV(lp, lp, sizeof(struct i596_private));
-}
-
-
-#if defined(ENABLE_MVME16x_NET) || defined(ENABLE_BVME6000_NET)
-static void i596_error(int irq, void *dev_id)
-{
- struct net_device *dev = dev_id;
- volatile unsigned char *pcc2 = (unsigned char *) 0xfff42000;
-
- pcc2[0x28] = 1;
- pcc2[0x2b] = 0x1d;
- printk("%s: Error interrupt\n", dev->name);
- i596_display_data(dev);
-}
-#endif
-
-#define virt_to_dma(lp,v) ((lp)->dma_addr + (dma_addr_t)((unsigned long)(v)-(unsigned long)(lp)))
-
-static inline void init_rx_bufs(struct net_device *dev)
-{
- struct i596_private *lp = dev->priv;
- int i;
- struct i596_rfd *rfd;
- struct i596_rbd *rbd;
-
- /* First build the Receive Buffer Descriptor List */
-
- for (i = 0, rbd = lp->rbds; i < rx_ring_size; i++, rbd++) {
- dma_addr_t dma_addr;
- struct sk_buff *skb = dev_alloc_skb(PKT_BUF_SZ + 4);
-
- if (skb == NULL)
- panic("%s: alloc_skb() failed", __FILE__);
- skb_reserve(skb, 2);
- dma_addr = dma_map_single(lp->dev, skb->data,PKT_BUF_SZ,
- DMA_FROM_DEVICE);
- skb->dev = dev;
- rbd->v_next = rbd+1;
- rbd->b_next = WSWAPrbd(virt_to_dma(lp,rbd+1));
- rbd->b_addr = WSWAPrbd(virt_to_dma(lp,rbd));
- rbd->skb = skb;
- rbd->v_data = skb->data;
- rbd->b_data = WSWAPchar(dma_addr);
- rbd->size = PKT_BUF_SZ;
- }
- lp->rbd_head = lp->rbds;
- rbd = lp->rbds + rx_ring_size - 1;
- rbd->v_next = lp->rbds;
- rbd->b_next = WSWAPrbd(virt_to_dma(lp,lp->rbds));
-
- /* Now build the Receive Frame Descriptor List */
-
- for (i = 0, rfd = lp->rfds; i < rx_ring_size; i++, rfd++) {
- rfd->rbd = I596_NULL;
- rfd->v_next = rfd+1;
- rfd->v_prev = rfd-1;
- rfd->b_next = WSWAPrfd(virt_to_dma(lp,rfd+1));
- rfd->cmd = CMD_FLEX;
- }
- lp->rfd_head = lp->rfds;
- lp->scb.rfd = WSWAPrfd(virt_to_dma(lp,lp->rfds));
- rfd = lp->rfds;
- rfd->rbd = WSWAPrbd(virt_to_dma(lp,lp->rbd_head));
- rfd->v_prev = lp->rfds + rx_ring_size - 1;
- rfd = lp->rfds + rx_ring_size - 1;
- rfd->v_next = lp->rfds;
- rfd->b_next = WSWAPrfd(virt_to_dma(lp,lp->rfds));
- rfd->cmd = CMD_EOL|CMD_FLEX;
-
- CHECK_WBACK_INV(lp, lp, sizeof(struct i596_private));
-}
-
-static inline void remove_rx_bufs(struct net_device *dev)
-{
- struct i596_private *lp = dev->priv;
- struct i596_rbd *rbd;
- int i;
-
- for (i = 0, rbd = lp->rbds; i < rx_ring_size; i++, rbd++) {
- if (rbd->skb == NULL)
- break;
- dma_unmap_single(lp->dev,
- (dma_addr_t)WSWAPchar(rbd->b_data),
- PKT_BUF_SZ, DMA_FROM_DEVICE);
- dev_kfree_skb(rbd->skb);
- }
-}
-
-
-static void rebuild_rx_bufs(struct net_device *dev)
-{
- struct i596_private *lp = dev->priv;
- int i;
-
- /* Ensure rx frame/buffer descriptors are tidy */
-
- for (i = 0; i < rx_ring_size; i++) {
- lp->rfds[i].rbd = I596_NULL;
- lp->rfds[i].cmd = CMD_FLEX;
- }
- lp->rfds[rx_ring_size-1].cmd = CMD_EOL|CMD_FLEX;
- lp->rfd_head = lp->rfds;
- lp->scb.rfd = WSWAPrfd(virt_to_dma(lp,lp->rfds));
- lp->rbd_head = lp->rbds;
- lp->rfds[0].rbd = WSWAPrbd(virt_to_dma(lp,lp->rbds));
-
- CHECK_WBACK_INV(lp, lp, sizeof(struct i596_private));
-}
-
-
-static int init_i596_mem(struct net_device *dev)
-{
- struct i596_private *lp = dev->priv;
- unsigned long flags;
-
- disable_irq(dev->irq); /* disable IRQs from LAN */
- DEB(DEB_INIT,
- printk("RESET 82596 port: %lx (with IRQ %d disabled)\n",
- (dev->base_addr + PA_I82596_RESET),
- dev->irq));
-
- gsc_writel(0, (dev->base_addr + PA_I82596_RESET)); /* Hard Reset */
- udelay(100); /* Wait 100us - seems to help */
-
- /* change the scp address */
-
- lp->last_cmd = jiffies;
-
-
- lp->scp.sysbus = 0x0000006c;
- lp->scp.iscp = WSWAPiscp(virt_to_dma(lp,&(lp->iscp)));
- lp->iscp.scb = WSWAPscb(virt_to_dma(lp,&(lp->scb)));
- lp->iscp.stat = ISCP_BUSY;
- lp->cmd_backlog = 0;
-
- lp->cmd_head = NULL;
- lp->scb.cmd = I596_NULL;
-
- DEB(DEB_INIT, printk("%s: starting i82596.\n", dev->name));
-
- CHECK_WBACK(lp, &(lp->scp), sizeof(struct i596_scp));
- CHECK_WBACK(lp, &(lp->iscp), sizeof(struct i596_iscp));
-
- MPU_PORT(dev, PORT_ALTSCP, virt_to_dma(lp,&lp->scp));
-
- CA(dev);
-
- if (wait_istat(dev, lp, 1000, "initialization timed out"))
- goto failed;
- DEB(DEB_INIT, printk("%s: i82596 initialization successful\n", dev->name));
-
- /* Ensure rx frame/buffer descriptors are tidy */
- rebuild_rx_bufs(dev);
-
- lp->scb.command = 0;
- CHECK_WBACK(lp, &(lp->scb), sizeof(struct i596_scb));
-
- enable_irq(dev->irq); /* enable IRQs from LAN */
-
- DEB(DEB_INIT, printk("%s: queuing CmdConfigure\n", dev->name));
- memcpy(lp->cf_cmd.i596_config, init_setup, sizeof(init_setup));
- lp->cf_cmd.cmd.command = CmdConfigure;
- CHECK_WBACK(lp, &(lp->cf_cmd), sizeof(struct cf_cmd));
- i596_add_cmd(dev, &lp->cf_cmd.cmd);
-
- DEB(DEB_INIT, printk("%s: queuing CmdSASetup\n", dev->name));
- memcpy(lp->sa_cmd.eth_addr, dev->dev_addr, 6);
- lp->sa_cmd.cmd.command = CmdSASetup;
- CHECK_WBACK(lp, &(lp->sa_cmd), sizeof(struct sa_cmd));
- i596_add_cmd(dev, &lp->sa_cmd.cmd);
-
- DEB(DEB_INIT, printk("%s: queuing CmdTDR\n", dev->name));
- lp->tdr_cmd.cmd.command = CmdTDR;
- CHECK_WBACK(lp, &(lp->tdr_cmd), sizeof(struct tdr_cmd));
- i596_add_cmd(dev, &lp->tdr_cmd.cmd);
-
- spin_lock_irqsave (&lp->lock, flags);
-
- if (wait_cmd(dev, lp, 1000, "timed out waiting to issue RX_START")) {
- spin_unlock_irqrestore (&lp->lock, flags);
- goto failed;
- }
- DEB(DEB_INIT, printk("%s: Issuing RX_START\n", dev->name));
- lp->scb.command = RX_START;
- lp->scb.rfd = WSWAPrfd(virt_to_dma(lp,lp->rfds));
- CHECK_WBACK(lp, &(lp->scb), sizeof(struct i596_scb));
-
- CA(dev);
-
- spin_unlock_irqrestore (&lp->lock, flags);
-
- if (wait_cmd(dev, lp, 1000, "RX_START not processed"))
- goto failed;
- DEB(DEB_INIT, printk("%s: Receive unit started OK\n", dev->name));
-
- return 0;
-
-failed:
- printk("%s: Failed to initialise 82596\n", dev->name);
- MPU_PORT(dev, PORT_RESET, 0);
- return -1;
-}
-
-
-static inline int i596_rx(struct net_device *dev)
-{
- struct i596_private *lp = dev->priv;
- struct i596_rfd *rfd;
- struct i596_rbd *rbd;
- int frames = 0;
-
- DEB(DEB_RXFRAME, printk("i596_rx(), rfd_head %p, rbd_head %p\n",
- lp->rfd_head, lp->rbd_head));
-
-
- rfd = lp->rfd_head; /* Ref next frame to check */
-
- CHECK_INV(lp, rfd, sizeof(struct i596_rfd));
- while ((rfd->stat) & STAT_C) { /* Loop while complete frames */
- if (rfd->rbd == I596_NULL)
- rbd = NULL;
- else if (rfd->rbd == lp->rbd_head->b_addr) {
- rbd = lp->rbd_head;
- CHECK_INV(lp, rbd, sizeof(struct i596_rbd));
- }
- else {
- printk("%s: rbd chain broken!\n", dev->name);
- /* XXX Now what? */
- rbd = NULL;
- }
- DEB(DEB_RXFRAME, printk(" rfd %p, rfd.rbd %08x, rfd.stat %04x\n",
- rfd, rfd->rbd, rfd->stat));
-
- if (rbd != NULL && ((rfd->stat) & STAT_OK)) {
- /* a good frame */
- int pkt_len = rbd->count & 0x3fff;
- struct sk_buff *skb = rbd->skb;
- int rx_in_place = 0;
-
- DEB(DEB_RXADDR,print_eth(rbd->v_data, "received"));
- frames++;
-
- /* Check if the packet is long enough to just accept
- * without copying to a properly sized skbuff.
- */
-
- if (pkt_len > rx_copybreak) {
- struct sk_buff *newskb;
- dma_addr_t dma_addr;
-
- dma_unmap_single(lp->dev,(dma_addr_t)WSWAPchar(rbd->b_data), PKT_BUF_SZ, DMA_FROM_DEVICE);
- /* Get fresh skbuff to replace filled one. */
- newskb = dev_alloc_skb(PKT_BUF_SZ + 4);
- if (newskb == NULL) {
- skb = NULL; /* drop pkt */
- goto memory_squeeze;
- }
- skb_reserve(newskb, 2);
-
- /* Pass up the skb already on the Rx ring. */
- skb_put(skb, pkt_len);
- rx_in_place = 1;
- rbd->skb = newskb;
- newskb->dev = dev;
- dma_addr = dma_map_single(lp->dev, newskb->data, PKT_BUF_SZ, DMA_FROM_DEVICE);
- rbd->v_data = newskb->data;
- rbd->b_data = WSWAPchar(dma_addr);
- CHECK_WBACK_INV(lp, rbd, sizeof(struct i596_rbd));
- }
- else
- skb = dev_alloc_skb(pkt_len + 2);
-memory_squeeze:
- if (skb == NULL) {
- /* XXX tulip.c can defer packets here!! */
- printk("%s: i596_rx Memory squeeze, dropping packet.\n", dev->name);
- lp->stats.rx_dropped++;
- }
- else {
- if (!rx_in_place) {
- /* 16 byte align the data fields */
- dma_sync_single_for_cpu(lp->dev, (dma_addr_t)WSWAPchar(rbd->b_data), PKT_BUF_SZ, DMA_FROM_DEVICE);
- skb_reserve(skb, 2);
- memcpy(skb_put(skb,pkt_len), rbd->v_data, pkt_len);
- dma_sync_single_for_device(lp->dev, (dma_addr_t)WSWAPchar(rbd->b_data), PKT_BUF_SZ, DMA_FROM_DEVICE);
- }
- skb->len = pkt_len;
- skb->protocol=eth_type_trans(skb,dev);
- netif_rx(skb);
- dev->last_rx = jiffies;
- lp->stats.rx_packets++;
- lp->stats.rx_bytes+=pkt_len;
- }
- }
- else {
- DEB(DEB_ERRORS, printk("%s: Error, rfd.stat = 0x%04x\n",
- dev->name, rfd->stat));
- lp->stats.rx_errors++;
- if ((rfd->stat) & 0x0001)
- lp->stats.collisions++;
- if ((rfd->stat) & 0x0080)
- lp->stats.rx_length_errors++;
- if ((rfd->stat) & 0x0100)
- lp->stats.rx_over_errors++;
- if ((rfd->stat) & 0x0200)
- lp->stats.rx_fifo_errors++;
- if ((rfd->stat) & 0x0400)
- lp->stats.rx_frame_errors++;
- if ((rfd->stat) & 0x0800)
- lp->stats.rx_crc_errors++;
- if ((rfd->stat) & 0x1000)
- lp->stats.rx_length_errors++;
- }
-
- /* Clear the buffer descriptor count and EOF + F flags */
-
- if (rbd != NULL && (rbd->count & 0x4000)) {
- rbd->count = 0;
- lp->rbd_head = rbd->v_next;
- CHECK_WBACK_INV(lp, rbd, sizeof(struct i596_rbd));
- }
-
- /* Tidy the frame descriptor, marking it as end of list */
-
- rfd->rbd = I596_NULL;
- rfd->stat = 0;
- rfd->cmd = CMD_EOL|CMD_FLEX;
- rfd->count = 0;
-
- /* Remove end-of-list from old end descriptor */
-
- rfd->v_prev->cmd = CMD_FLEX;
-
- /* Update record of next frame descriptor to process */
-
- lp->scb.rfd = rfd->b_next;
- lp->rfd_head = rfd->v_next;
- CHECK_WBACK_INV(lp, rfd->v_prev, sizeof(struct i596_rfd));
- CHECK_WBACK_INV(lp, rfd, sizeof(struct i596_rfd));
- rfd = lp->rfd_head;
- CHECK_INV(lp, rfd, sizeof(struct i596_rfd));
- }
-
- DEB(DEB_RXFRAME, printk("frames %d\n", frames));
-
- return 0;
-}
-
-
-static inline void i596_cleanup_cmd(struct net_device *dev, struct i596_private *lp)
-{
- struct i596_cmd *ptr;
-
- while (lp->cmd_head != NULL) {
- ptr = lp->cmd_head;
- lp->cmd_head = ptr->v_next;
- lp->cmd_backlog--;
-
- switch ((ptr->command) & 0x7) {
- case CmdTx:
- {
- struct tx_cmd *tx_cmd = (struct tx_cmd *) ptr;
- struct sk_buff *skb = tx_cmd->skb;
- dma_unmap_single(lp->dev, tx_cmd->dma_addr, skb->len, DMA_TO_DEVICE);
-
- dev_kfree_skb(skb);
-
- lp->stats.tx_errors++;
- lp->stats.tx_aborted_errors++;
-
- ptr->v_next = NULL;
- ptr->b_next = I596_NULL;
- tx_cmd->cmd.command = 0; /* Mark as free */
- break;
- }
- default:
- ptr->v_next = NULL;
- ptr->b_next = I596_NULL;
- }
- CHECK_WBACK_INV(lp, ptr, sizeof(struct i596_cmd));
- }
-
- wait_cmd(dev, lp, 100, "i596_cleanup_cmd timed out");
- lp->scb.cmd = I596_NULL;
- CHECK_WBACK(lp, &(lp->scb), sizeof(struct i596_scb));
-}
-
-
-static inline void i596_reset(struct net_device *dev, struct i596_private *lp)
-{
- unsigned long flags;
-
- DEB(DEB_RESET, printk("i596_reset\n"));
-
- spin_lock_irqsave (&lp->lock, flags);
-
- wait_cmd(dev, lp, 100, "i596_reset timed out");
-
- netif_stop_queue(dev);
-
- /* FIXME: this command might cause an lpmc */
- lp->scb.command = CUC_ABORT | RX_ABORT;
- CHECK_WBACK(lp, &(lp->scb), sizeof(struct i596_scb));
- CA(dev);
-
- /* wait for shutdown */
- wait_cmd(dev, lp, 1000, "i596_reset 2 timed out");
- spin_unlock_irqrestore (&lp->lock, flags);
-
- i596_cleanup_cmd(dev,lp);
- i596_rx(dev);
-
- netif_start_queue(dev);
- init_i596_mem(dev);
-}
-
-
-static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd)
-{
- struct i596_private *lp = dev->priv;
- unsigned long flags;
-
- DEB(DEB_ADDCMD, printk("i596_add_cmd cmd_head %p\n", lp->cmd_head));
-
- cmd->status = 0;
- cmd->command |= (CMD_EOL | CMD_INTR);
- cmd->v_next = NULL;
- cmd->b_next = I596_NULL;
- CHECK_WBACK(lp, cmd, sizeof(struct i596_cmd));
-
- spin_lock_irqsave (&lp->lock, flags);
-
- if (lp->cmd_head != NULL) {
- lp->cmd_tail->v_next = cmd;
- lp->cmd_tail->b_next = WSWAPcmd(virt_to_dma(lp,&cmd->status));
- CHECK_WBACK(lp, lp->cmd_tail, sizeof(struct i596_cmd));
- } else {
- lp->cmd_head = cmd;
- wait_cmd(dev, lp, 100, "i596_add_cmd timed out");
- lp->scb.cmd = WSWAPcmd(virt_to_dma(lp,&cmd->status));
- lp->scb.command = CUC_START;
- CHECK_WBACK(lp, &(lp->scb), sizeof(struct i596_scb));
- CA(dev);
- }
- lp->cmd_tail = cmd;
- lp->cmd_backlog++;
-
- spin_unlock_irqrestore (&lp->lock, flags);
-
- if (lp->cmd_backlog > max_cmd_backlog) {
- unsigned long tickssofar = jiffies - lp->last_cmd;
-
- if (tickssofar < ticks_limit)
- return;
-
- printk("%s: command unit timed out, status resetting.\n", dev->name);
-#if 1
- i596_reset(dev, lp);
-#endif
- }
-}
-
-#if 0
-/* this function makes a perfectly adequate probe... but we have a
- device list */
-static int i596_test(struct net_device *dev)
-{
- struct i596_private *lp = dev->priv;
- volatile int *tint;
- u32 data;
-
- tint = (volatile int *)(&(lp->scp));
- data = virt_to_dma(lp,tint);
-
- tint[1] = -1;
- CHECK_WBACK(lp, tint, PAGE_SIZE);
-
- MPU_PORT(dev, 1, data);
-
- for(data = 1000000; data; data--) {
- CHECK_INV(lp, tint, PAGE_SIZE);
- if(tint[1] != -1)
- break;
-
- }
-
- printk("i596_test result %d\n", tint[1]);
-
-}
-#endif
-
-
-static int i596_open(struct net_device *dev)
-{
- DEB(DEB_OPEN, printk("%s: i596_open() irq %d.\n", dev->name, dev->irq));
-
- if (request_irq(dev->irq, &i596_interrupt, 0, "i82596", dev)) {
- printk("%s: IRQ %d not free\n", dev->name, dev->irq);
- goto out;
- }
-
- init_rx_bufs(dev);
-
- if (init_i596_mem(dev)) {
- printk("%s: Failed to init memory\n", dev->name);
- goto out_remove_rx_bufs;
- }
-
- netif_start_queue(dev);
-
- return 0;
-
-out_remove_rx_bufs:
- remove_rx_bufs(dev);
- free_irq(dev->irq, dev);
-out:
- return -EAGAIN;
-}
-
-static void i596_tx_timeout (struct net_device *dev)
-{
- struct i596_private *lp = dev->priv;
-
- /* Transmitter timeout, serious problems. */
- DEB(DEB_ERRORS, printk("%s: transmit timed out, status resetting.\n",
- dev->name));
-
- lp->stats.tx_errors++;
-
- /* Try to restart the adaptor */
- if (lp->last_restart == lp->stats.tx_packets) {
- DEB(DEB_ERRORS, printk("Resetting board.\n"));
- /* Shutdown and restart */
- i596_reset (dev, lp);
- } else {
- /* Issue a channel attention signal */
- DEB(DEB_ERRORS, printk("Kicking board.\n"));
- lp->scb.command = CUC_START | RX_START;
- CHECK_WBACK_INV(lp, &(lp->scb), sizeof(struct i596_scb));
- CA (dev);
- lp->last_restart = lp->stats.tx_packets;
- }
-
- dev->trans_start = jiffies;
- netif_wake_queue (dev);
-}
-
-
-static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
- struct i596_private *lp = dev->priv;
- struct tx_cmd *tx_cmd;
- struct i596_tbd *tbd;
- short length = skb->len;
- dev->trans_start = jiffies;
-
- DEB(DEB_STARTTX, printk("%s: i596_start_xmit(%x,%p) called\n", dev->name,
- skb->len, skb->data));
-
- if (length < ETH_ZLEN) {
- if (skb_padto(skb, ETH_ZLEN))
- return 0;
- length = ETH_ZLEN;
- }
-
- netif_stop_queue(dev);
-
- tx_cmd = lp->tx_cmds + lp->next_tx_cmd;
- tbd = lp->tbds + lp->next_tx_cmd;
-
- if (tx_cmd->cmd.command) {
- DEB(DEB_ERRORS, printk("%s: xmit ring full, dropping packet.\n",
- dev->name));
- lp->stats.tx_dropped++;
-
- dev_kfree_skb(skb);
- } else {
- if (++lp->next_tx_cmd == TX_RING_SIZE)
- lp->next_tx_cmd = 0;
- tx_cmd->tbd = WSWAPtbd(virt_to_dma(lp,tbd));
- tbd->next = I596_NULL;
-
- tx_cmd->cmd.command = CMD_FLEX | CmdTx;
- tx_cmd->skb = skb;
-
- tx_cmd->pad = 0;
- tx_cmd->size = 0;
- tbd->pad = 0;
- tbd->size = EOF | length;
-
- tx_cmd->dma_addr = dma_map_single(lp->dev, skb->data, skb->len,
- DMA_TO_DEVICE);
- tbd->data = WSWAPchar(tx_cmd->dma_addr);
-
- DEB(DEB_TXADDR,print_eth(skb->data, "tx-queued"));
- CHECK_WBACK_INV(lp, tx_cmd, sizeof(struct tx_cmd));
- CHECK_WBACK_INV(lp, tbd, sizeof(struct i596_tbd));
- i596_add_cmd(dev, &tx_cmd->cmd);
-
- lp->stats.tx_packets++;
- lp->stats.tx_bytes += length;
- }
-
- netif_start_queue(dev);
-
- return 0;
-}
-
-static void print_eth(unsigned char *add, char *str)
-{
- int i;
-
- printk("i596 0x%p, ", add);
- for (i = 0; i < 6; i++)
- printk(" %02X", add[i + 6]);
- printk(" -->");
- for (i = 0; i < 6; i++)
- printk(" %02X", add[i]);
- printk(" %02X%02X, %s\n", add[12], add[13], str);
-}
-
-
#define LAN_PROM_ADDR 0xF0810000
-static int __devinit i82596_probe(struct net_device *dev,
- struct device *gen_dev)
-{
- int i;
- struct i596_private *lp;
- char eth_addr[6];
- dma_addr_t dma_addr;
-
- /* This lot is ensure things have been cache line aligned. */
- BUILD_BUG_ON(sizeof(struct i596_rfd) != 32);
- BUILD_BUG_ON(sizeof(struct i596_rbd) & 31);
- BUILD_BUG_ON(sizeof(struct tx_cmd) & 31);
- BUILD_BUG_ON(sizeof(struct i596_tbd) != 32);
-#ifndef __LP64__
- BUILD_BUG_ON(sizeof(struct i596_private) > 4096);
-#endif
-
- if (!dev->base_addr || !dev->irq)
- return -ENODEV;
-
- if (pdc_lan_station_id(eth_addr, dev->base_addr)) {
- for (i=0; i < 6; i++) {
- eth_addr[i] = gsc_readb(LAN_PROM_ADDR + i);
- }
- printk(KERN_INFO "%s: MAC of HP700 LAN read from EEPROM\n", __FILE__);
- }
-
- dev->mem_start = (unsigned long) dma_alloc_noncoherent(gen_dev,
- sizeof(struct i596_private), &dma_addr, GFP_KERNEL);
- if (!dev->mem_start) {
- printk(KERN_ERR "%s: Couldn't get shared memory\n", __FILE__);
- return -ENOMEM;
- }
-
- for (i = 0; i < 6; i++)
- dev->dev_addr[i] = eth_addr[i];
-
- /* The 82596-specific entries in the device structure. */
- dev->open = i596_open;
- dev->stop = i596_close;
- dev->hard_start_xmit = i596_start_xmit;
- dev->get_stats = i596_get_stats;
- dev->set_multicast_list = set_multicast_list;
- dev->tx_timeout = i596_tx_timeout;
- dev->watchdog_timeo = TX_TIMEOUT;
-#ifdef CONFIG_NET_POLL_CONTROLLER
- dev->poll_controller = i596_poll_controller;
-#endif
-
- dev->priv = (void *)(dev->mem_start);
-
- lp = dev->priv;
- memset(lp, 0, sizeof(struct i596_private));
-
- lp->scb.command = 0;
- lp->scb.cmd = I596_NULL;
- lp->scb.rfd = I596_NULL;
- spin_lock_init(&lp->lock);
- lp->dma_addr = dma_addr;
- lp->dev = gen_dev;
-
- CHECK_WBACK_INV(lp, dev->mem_start, sizeof(struct i596_private));
-
- i = register_netdev(dev);
- if (i) {
- lp = dev->priv;
- dma_free_noncoherent(lp->dev, sizeof(struct i596_private),
- (void *)dev->mem_start, lp->dma_addr);
- return i;
- };
-
- DEB(DEB_PROBE, printk(KERN_INFO "%s: 82596 at %#3lx,", dev->name, dev->base_addr));
- for (i = 0; i < 6; i++)
- DEB(DEB_PROBE, printk(" %2.2X", dev->dev_addr[i]));
- DEB(DEB_PROBE, printk(" IRQ %d.\n", dev->irq));
- DEB(DEB_INIT, printk(KERN_INFO "%s: lp at 0x%p (%d bytes), lp->scb at 0x%p\n",
- dev->name, lp, (int)sizeof(struct i596_private), &lp->scb));
-
- return 0;
-}
-
-#ifdef CONFIG_NET_POLL_CONTROLLER
-static void i596_poll_controller(struct net_device *dev)
-{
- disable_irq(dev->irq);
- i596_interrupt(dev->irq, dev);
- enable_irq(dev->irq);
-}
-#endif
-
-static irqreturn_t i596_interrupt(int irq, void *dev_id)
-{
- struct net_device *dev = dev_id;
- struct i596_private *lp;
- unsigned short status, ack_cmd = 0;
-
- if (dev == NULL) {
- printk("%s: irq %d for unknown device.\n", __FUNCTION__, irq);
- return IRQ_NONE;
- }
-
- lp = dev->priv;
-
- spin_lock (&lp->lock);
-
- wait_cmd(dev, lp, 100, "i596 interrupt, timeout");
- status = lp->scb.status;
-
- DEB(DEB_INTS, printk("%s: i596 interrupt, IRQ %d, status %4.4x.\n",
- dev->name, irq, status));
-
- ack_cmd = status & 0xf000;
-
- if (!ack_cmd) {
- DEB(DEB_ERRORS, printk("%s: interrupt with no events\n", dev->name));
- spin_unlock (&lp->lock);
- return IRQ_NONE;
- }
-
- if ((status & 0x8000) || (status & 0x2000)) {
- struct i596_cmd *ptr;
-
- if ((status & 0x8000))
- DEB(DEB_INTS, printk("%s: i596 interrupt completed command.\n", dev->name));
- if ((status & 0x2000))
- DEB(DEB_INTS, printk("%s: i596 interrupt command unit inactive %x.\n", dev->name, status & 0x0700));
-
- while (lp->cmd_head != NULL) {
- CHECK_INV(lp, lp->cmd_head, sizeof(struct i596_cmd));
- if (!(lp->cmd_head->status & STAT_C))
- break;
-
- ptr = lp->cmd_head;
-
- DEB(DEB_STATUS, printk("cmd_head->status = %04x, ->command = %04x\n",
- lp->cmd_head->status, lp->cmd_head->command));
- lp->cmd_head = ptr->v_next;
- lp->cmd_backlog--;
-
- switch ((ptr->command) & 0x7) {
- case CmdTx:
- {
- struct tx_cmd *tx_cmd = (struct tx_cmd *) ptr;
- struct sk_buff *skb = tx_cmd->skb;
-
- if ((ptr->status) & STAT_OK) {
- DEB(DEB_TXADDR, print_eth(skb->data, "tx-done"));
- } else {
- lp->stats.tx_errors++;
- if ((ptr->status) & 0x0020)
- lp->stats.collisions++;
- if (!((ptr->status) & 0x0040))
- lp->stats.tx_heartbeat_errors++;
- if ((ptr->status) & 0x0400)
- lp->stats.tx_carrier_errors++;
- if ((ptr->status) & 0x0800)
- lp->stats.collisions++;
- if ((ptr->status) & 0x1000)
- lp->stats.tx_aborted_errors++;
- }
- dma_unmap_single(lp->dev, tx_cmd->dma_addr, skb->len, DMA_TO_DEVICE);
- dev_kfree_skb_irq(skb);
-
- tx_cmd->cmd.command = 0; /* Mark free */
- break;
- }
- case CmdTDR:
- {
- unsigned short status = ((struct tdr_cmd *)ptr)->status;
-
- if (status & 0x8000) {
- DEB(DEB_ANY, printk("%s: link ok.\n", dev->name));
- } else {
- if (status & 0x4000)
- printk("%s: Transceiver problem.\n", dev->name);
- if (status & 0x2000)
- printk("%s: Termination problem.\n", dev->name);
- if (status & 0x1000)
- printk("%s: Short circuit.\n", dev->name);
-
- DEB(DEB_TDR, printk("%s: Time %d.\n", dev->name, status & 0x07ff));
- }
- break;
- }
- case CmdConfigure:
- /* Zap command so set_multicast_list() knows it is free */
- ptr->command = 0;
- break;
- }
- ptr->v_next = NULL;
- ptr->b_next = I596_NULL;
- CHECK_WBACK(lp, ptr, sizeof(struct i596_cmd));
- lp->last_cmd = jiffies;
- }
-
- /* This mess is arranging that only the last of any outstanding
- * commands has the interrupt bit set. Should probably really
- * only add to the cmd queue when the CU is stopped.
- */
- ptr = lp->cmd_head;
- while ((ptr != NULL) && (ptr != lp->cmd_tail)) {
- struct i596_cmd *prev = ptr;
-
- ptr->command &= 0x1fff;
- ptr = ptr->v_next;
- CHECK_WBACK_INV(lp, prev, sizeof(struct i596_cmd));
- }
-
- if ((lp->cmd_head != NULL))
- ack_cmd |= CUC_START;
- lp->scb.cmd = WSWAPcmd(virt_to_dma(lp,&lp->cmd_head->status));
- CHECK_WBACK_INV(lp, &lp->scb, sizeof(struct i596_scb));
- }
- if ((status & 0x1000) || (status & 0x4000)) {
- if ((status & 0x4000))
- DEB(DEB_INTS, printk("%s: i596 interrupt received a frame.\n", dev->name));
- i596_rx(dev);
- /* Only RX_START if stopped - RGH 07-07-96 */
- if (status & 0x1000) {
- if (netif_running(dev)) {
- DEB(DEB_ERRORS, printk("%s: i596 interrupt receive unit inactive, status 0x%x\n", dev->name, status));
- ack_cmd |= RX_START;
- lp->stats.rx_errors++;
- lp->stats.rx_fifo_errors++;
- rebuild_rx_bufs(dev);
- }
- }
- }
- wait_cmd(dev, lp, 100, "i596 interrupt, timeout");
- lp->scb.command = ack_cmd;
- CHECK_WBACK(lp, &lp->scb, sizeof(struct i596_scb));
-
- /* DANGER: I suspect that some kind of interrupt
- acknowledgement aside from acking the 82596 might be needed
- here... but it's running acceptably without */
-
- CA(dev);
-
- wait_cmd(dev, lp, 100, "i596 interrupt, exit timeout");
- DEB(DEB_INTS, printk("%s: exiting interrupt.\n", dev->name));
-
- spin_unlock (&lp->lock);
- return IRQ_HANDLED;
-}
-
-static int i596_close(struct net_device *dev)
-{
- struct i596_private *lp = dev->priv;
- unsigned long flags;
-
- netif_stop_queue(dev);
-
- DEB(DEB_INIT, printk("%s: Shutting down ethercard, status was %4.4x.\n",
- dev->name, lp->scb.status));
-
- spin_lock_irqsave(&lp->lock, flags);
-
- wait_cmd(dev, lp, 100, "close1 timed out");
- lp->scb.command = CUC_ABORT | RX_ABORT;
- CHECK_WBACK(lp, &lp->scb, sizeof(struct i596_scb));
-
- CA(dev);
-
- wait_cmd(dev, lp, 100, "close2 timed out");
- spin_unlock_irqrestore(&lp->lock, flags);
- DEB(DEB_STRUCT,i596_display_data(dev));
- i596_cleanup_cmd(dev,lp);
-
- disable_irq(dev->irq);
-
- free_irq(dev->irq, dev);
- remove_rx_bufs(dev);
-
- return 0;
-}
-
-static struct net_device_stats *
- i596_get_stats(struct net_device *dev)
-{
- struct i596_private *lp = dev->priv;
-
- return &lp->stats;
-}
-
-/*
- * Set or clear the multicast filter for this adaptor.
- */
-
-static void set_multicast_list(struct net_device *dev)
-{
- struct i596_private *lp = dev->priv;
- int config = 0, cnt;
-
- DEB(DEB_MULTI, printk("%s: set multicast list, %d entries, promisc %s, allmulti %s\n",
- dev->name, dev->mc_count, dev->flags & IFF_PROMISC ? "ON" : "OFF",
- dev->flags & IFF_ALLMULTI ? "ON" : "OFF"));
-
- if ((dev->flags & IFF_PROMISC) && !(lp->cf_cmd.i596_config[8] & 0x01)) {
- lp->cf_cmd.i596_config[8] |= 0x01;
- config = 1;
- }
- if (!(dev->flags & IFF_PROMISC) && (lp->cf_cmd.i596_config[8] & 0x01)) {
- lp->cf_cmd.i596_config[8] &= ~0x01;
- config = 1;
- }
- if ((dev->flags & IFF_ALLMULTI) && (lp->cf_cmd.i596_config[11] & 0x20)) {
- lp->cf_cmd.i596_config[11] &= ~0x20;
- config = 1;
- }
- if (!(dev->flags & IFF_ALLMULTI) && !(lp->cf_cmd.i596_config[11] & 0x20)) {
- lp->cf_cmd.i596_config[11] |= 0x20;
- config = 1;
- }
- if (config) {
- if (lp->cf_cmd.cmd.command)
- printk("%s: config change request already queued\n",
- dev->name);
- else {
- lp->cf_cmd.cmd.command = CmdConfigure;
- CHECK_WBACK_INV(lp, &lp->cf_cmd, sizeof(struct cf_cmd));
- i596_add_cmd(dev, &lp->cf_cmd.cmd);
- }
- }
-
- cnt = dev->mc_count;
- if (cnt > MAX_MC_CNT)
- {
- cnt = MAX_MC_CNT;
- printk("%s: Only %d multicast addresses supported",
- dev->name, cnt);
- }
-
- if (dev->mc_count > 0) {
- struct dev_mc_list *dmi;
- unsigned char *cp;
- struct mc_cmd *cmd;
-
- cmd = &lp->mc_cmd;
- cmd->cmd.command = CmdMulticastList;
- cmd->mc_cnt = dev->mc_count * 6;
- cp = cmd->mc_addrs;
- for (dmi = dev->mc_list; cnt && dmi != NULL; dmi = dmi->next, cnt--, cp += 6) {
- memcpy(cp, dmi->dmi_addr, 6);
- if (i596_debug > 1)
- DEB(DEB_MULTI, printk("%s: Adding address %02x:%02x:%02x:%02x:%02x:%02x\n",
- dev->name, cp[0],cp[1],cp[2],cp[3],cp[4],cp[5]));
- }
- CHECK_WBACK_INV(lp, &lp->mc_cmd, sizeof(struct mc_cmd));
- i596_add_cmd(dev, &cmd->cmd);
- }
-}
-
-static int debug = -1;
-module_param(debug, int, 0);
-MODULE_PARM_DESC(debug, "lasi_82596 debug mask");
-
-static int num_drivers;
-static struct net_device *netdevs[MAX_DRIVERS];
-
static int __devinit
lan_init_chip(struct parisc_device *dev)
{
struct net_device *netdevice;
+ struct i596_private *lp;
int retval;
-
- if (num_drivers >= MAX_DRIVERS) {
- /* max count of possible i82596 drivers reached */
- return -ENOMEM;
- }
-
- if (num_drivers == 0)
- printk(KERN_INFO LASI_82596_DRIVER_VERSION "\n");
+ int i;
if (!dev->irq) {
printk(KERN_ERR "%s: IRQ not found for i82596 at 0x%lx\n",
@@ -1528,28 +168,45 @@ lan_init_chip(struct parisc_device *dev)
printk(KERN_INFO "Found i82596 at 0x%lx, IRQ %d\n", dev->hpa.start,
dev->irq);
- netdevice = alloc_etherdev(0);
+ netdevice = alloc_etherdev(sizeof(struct i596_private));
if (!netdevice)
return -ENOMEM;
+ SET_NETDEV_DEV(netdevice, &dev->dev);
+ parisc_set_drvdata (dev, netdevice);
netdevice->base_addr = dev->hpa.start;
netdevice->irq = dev->irq;
- retval = i82596_probe(netdevice, &dev->dev);
+ if (pdc_lan_station_id(netdevice->dev_addr, netdevice->base_addr)) {
+ for (i = 0; i < 6; i++) {
+ netdevice->dev_addr[i] = gsc_readb(LAN_PROM_ADDR + i);
+ }
+ printk(KERN_INFO
+ "%s: MAC of HP700 LAN read from EEPROM\n", __FILE__);
+ }
+
+ lp = netdev_priv(netdevice);
+ lp->options = dev->id.sversion == 0x72 ? OPT_SWAP_PORT : 0;
+
+ retval = i82596_probe(netdevice);
if (retval) {
free_netdev(netdevice);
return -ENODEV;
}
-
- if (dev->id.sversion == 0x72) {
- ((struct i596_private *)netdevice->priv)->options = OPT_SWAP_PORT;
- }
-
- netdevs[num_drivers++] = netdevice;
-
return retval;
}
+static int __devexit lan_remove_chip (struct parisc_device *pdev)
+{
+ struct net_device *dev = parisc_get_drvdata(pdev);
+ struct i596_private *lp = netdev_priv(dev);
+
+ unregister_netdev (dev);
+ DMA_FREE(&pdev->dev, sizeof(struct i596_private),
+ (void *)lp->dma, lp->dma_addr);
+ free_netdev (dev);
+ return 0;
+}
static struct parisc_device_id lan_tbl[] = {
{ HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0008a },
@@ -1563,12 +220,12 @@ static struct parisc_driver lan_driver = {
.name = "lasi_82596",
.id_table = lan_tbl,
.probe = lan_init_chip,
+ .remove = __devexit_p(lan_remove_chip),
};
static int __devinit lasi_82596_init(void)
{
- if (debug >= 0)
- i596_debug = debug;
+ printk(KERN_INFO LASI_82596_DRIVER_VERSION "\n");
return register_parisc_driver(&lan_driver);
}
@@ -1576,25 +233,6 @@ module_init(lasi_82596_init);
static void __exit lasi_82596_exit(void)
{
- int i;
-
- for (i=0; i<MAX_DRIVERS; i++) {
- struct i596_private *lp;
- struct net_device *netdevice;
-
- netdevice = netdevs[i];
- if (!netdevice)
- continue;
-
- unregister_netdev(netdevice);
-
- lp = netdevice->priv;
- dma_free_noncoherent(lp->dev, sizeof(struct i596_private),
- (void *)netdevice->mem_start, lp->dma_addr);
- free_netdev(netdevice);
- }
- num_drivers = 0;
-
unregister_parisc_driver(&lan_driver);
}
diff --git a/drivers/net/lib82596.c b/drivers/net/lib82596.c
new file mode 100644
index 000000000000..5884f5bd04a4
--- /dev/null
+++ b/drivers/net/lib82596.c
@@ -0,0 +1,1434 @@
+/* lasi_82596.c -- driver for the intel 82596 ethernet controller, as
+ munged into HPPA boxen .
+
+ This driver is based upon 82596.c, original credits are below...
+ but there were too many hoops which HP wants jumped through to
+ keep this code in there in a sane manner.
+
+ 3 primary sources of the mess --
+ 1) hppa needs *lots* of cacheline flushing to keep this kind of
+ MMIO running.
+
+ 2) The 82596 needs to see all of its pointers as their physical
+ address. Thus virt_to_bus/bus_to_virt are *everywhere*.
+
+ 3) The implementation HP is using seems to be significantly pickier
+ about when and how the command and RX units are started. some
+ command ordering was changed.
+
+ Examination of the mach driver leads one to believe that there
+ might be a saner way to pull this off... anyone who feels like a
+ full rewrite can be my guest.
+
+ Split 02/13/2000 Sam Creasey (sammy@oh.verio.com)
+
+ 02/01/2000 Initial modifications for parisc by Helge Deller (deller@gmx.de)
+ 03/02/2000 changes for better/correct(?) cache-flushing (deller)
+*/
+
+/* 82596.c: A generic 82596 ethernet driver for linux. */
+/*
+ Based on Apricot.c
+ Written 1994 by Mark Evans.
+ This driver is for the Apricot 82596 bus-master interface
+
+ Modularised 12/94 Mark Evans
+
+
+ Modified to support the 82596 ethernet chips on 680x0 VME boards.
+ by Richard Hirst <richard@sleepie.demon.co.uk>
+ Renamed to be 82596.c
+
+ 980825: Changed to receive directly in to sk_buffs which are
+ allocated at open() time. Eliminates copy on incoming frames
+ (small ones are still copied). Shared data now held in a
+ non-cached page, so we can run on 68060 in copyback mode.
+
+ TBD:
+ * look at deferring rx frames rather than discarding (as per tulip)
+ * handle tx ring full as per tulip
+ * performace test to tune rx_copybreak
+
+ Most of my modifications relate to the braindead big-endian
+ implementation by Intel. When the i596 is operating in
+ 'big-endian' mode, it thinks a 32 bit value of 0x12345678
+ should be stored as 0x56781234. This is a real pain, when
+ you have linked lists which are shared by the 680x0 and the
+ i596.
+
+ Driver skeleton
+ Written 1993 by Donald Becker.
+ Copyright 1993 United States Government as represented by the Director,
+ National Security Agency. This software may only be used and distributed
+ according to the terms of the GNU General Public License as modified by SRC,
+ incorporated herein by reference.
+
+ The author may be reached as becker@scyld.com, or C/O
+ Scyld Computing Corporation, 410 Severn Ave., Suite 210, Annapolis MD 21403
+
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/bitops.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+
+/* DEBUG flags
+ */
+
+#define DEB_INIT 0x0001
+#define DEB_PROBE 0x0002
+#define DEB_SERIOUS 0x0004
+#define DEB_ERRORS 0x0008
+#define DEB_MULTI 0x0010
+#define DEB_TDR 0x0020
+#define DEB_OPEN 0x0040
+#define DEB_RESET 0x0080
+#define DEB_ADDCMD 0x0100
+#define DEB_STATUS 0x0200
+#define DEB_STARTTX 0x0400
+#define DEB_RXADDR 0x0800
+#define DEB_TXADDR 0x1000
+#define DEB_RXFRAME 0x2000
+#define DEB_INTS 0x4000
+#define DEB_STRUCT 0x8000
+#define DEB_ANY 0xffff
+
+
+#define DEB(x, y) if (i596_debug & (x)) { y; }
+
+
+/*
+ * The MPU_PORT command allows direct access to the 82596. With PORT access
+ * the following commands are available (p5-18). The 32-bit port command
+ * must be word-swapped with the most significant word written first.
+ * This only applies to VME boards.
+ */
+#define PORT_RESET 0x00 /* reset 82596 */
+#define PORT_SELFTEST 0x01 /* selftest */
+#define PORT_ALTSCP 0x02 /* alternate SCB address */
+#define PORT_ALTDUMP 0x03 /* Alternate DUMP address */
+
+static int i596_debug = (DEB_SERIOUS|DEB_PROBE);
+
+/* Copy frames shorter than rx_copybreak, otherwise pass on up in
+ * a full sized sk_buff. Value of 100 stolen from tulip.c (!alpha).
+ */
+static int rx_copybreak = 100;
+
+#define PKT_BUF_SZ 1536
+#define MAX_MC_CNT 64
+
+#define ISCP_BUSY 0x0001
+
+#define I596_NULL ((u32)0xffffffff)
+
+#define CMD_EOL 0x8000 /* The last command of the list, stop. */
+#define CMD_SUSP 0x4000 /* Suspend after doing cmd. */
+#define CMD_INTR 0x2000 /* Interrupt after doing cmd. */
+
+#define CMD_FLEX 0x0008 /* Enable flexible memory model */
+
+enum commands {
+ CmdNOp = 0, CmdSASetup = 1, CmdConfigure = 2, CmdMulticastList = 3,
+ CmdTx = 4, CmdTDR = 5, CmdDump = 6, CmdDiagnose = 7
+};
+
+#define STAT_C 0x8000 /* Set to 0 after execution */
+#define STAT_B 0x4000 /* Command being executed */
+#define STAT_OK 0x2000 /* Command executed ok */
+#define STAT_A 0x1000 /* Command aborted */
+
+#define CUC_START 0x0100
+#define CUC_RESUME 0x0200
+#define CUC_SUSPEND 0x0300
+#define CUC_ABORT 0x0400
+#define RX_START 0x0010
+#define RX_RESUME 0x0020
+#define RX_SUSPEND 0x0030
+#define RX_ABORT 0x0040
+
+#define TX_TIMEOUT 5
+
+
+struct i596_reg {
+ unsigned short porthi;
+ unsigned short portlo;
+ u32 ca;
+};
+
+#define EOF 0x8000
+#define SIZE_MASK 0x3fff
+
+struct i596_tbd {
+ unsigned short size;
+ unsigned short pad;
+ dma_addr_t next;
+ dma_addr_t data;
+ u32 cache_pad[5]; /* Total 32 bytes... */
+};
+
+/* The command structure has two 'next' pointers; v_next is the address of
+ * the next command as seen by the CPU, b_next is the address of the next
+ * command as seen by the 82596. The b_next pointer, as used by the 82596
+ * always references the status field of the next command, rather than the
+ * v_next field, because the 82596 is unaware of v_next. It may seem more
+ * logical to put v_next at the end of the structure, but we cannot do that
+ * because the 82596 expects other fields to be there, depending on command
+ * type.
+ */
+
+struct i596_cmd {
+ struct i596_cmd *v_next; /* Address from CPUs viewpoint */
+ unsigned short status;
+ unsigned short command;
+ dma_addr_t b_next; /* Address from i596 viewpoint */
+};
+
+struct tx_cmd {
+ struct i596_cmd cmd;
+ dma_addr_t tbd;
+ unsigned short size;
+ unsigned short pad;
+ struct sk_buff *skb; /* So we can free it after tx */
+ dma_addr_t dma_addr;
+#ifdef __LP64__
+ u32 cache_pad[6]; /* Total 64 bytes... */
+#else
+ u32 cache_pad[1]; /* Total 32 bytes... */
+#endif
+};
+
+struct tdr_cmd {
+ struct i596_cmd cmd;
+ unsigned short status;
+ unsigned short pad;
+};
+
+struct mc_cmd {
+ struct i596_cmd cmd;
+ short mc_cnt;
+ char mc_addrs[MAX_MC_CNT*6];
+};
+
+struct sa_cmd {
+ struct i596_cmd cmd;
+ char eth_addr[8];
+};
+
+struct cf_cmd {
+ struct i596_cmd cmd;
+ char i596_config[16];
+};
+
+struct i596_rfd {
+ unsigned short stat;
+ unsigned short cmd;
+ dma_addr_t b_next; /* Address from i596 viewpoint */
+ dma_addr_t rbd;
+ unsigned short count;
+ unsigned short size;
+ struct i596_rfd *v_next; /* Address from CPUs viewpoint */
+ struct i596_rfd *v_prev;
+#ifndef __LP64__
+ u32 cache_pad[2]; /* Total 32 bytes... */
+#endif
+};
+
+struct i596_rbd {
+ /* hardware data */
+ unsigned short count;
+ unsigned short zero1;
+ dma_addr_t b_next;
+ dma_addr_t b_data; /* Address from i596 viewpoint */
+ unsigned short size;
+ unsigned short zero2;
+ /* driver data */
+ struct sk_buff *skb;
+ struct i596_rbd *v_next;
+ dma_addr_t b_addr; /* This rbd addr from i596 view */
+ unsigned char *v_data; /* Address from CPUs viewpoint */
+ /* Total 32 bytes... */
+#ifdef __LP64__
+ u32 cache_pad[4];
+#endif
+};
+
+/* These values as chosen so struct i596_dma fits in one page... */
+
+#define TX_RING_SIZE 32
+#define RX_RING_SIZE 16
+
+struct i596_scb {
+ unsigned short status;
+ unsigned short command;
+ dma_addr_t cmd;
+ dma_addr_t rfd;
+ u32 crc_err;
+ u32 align_err;
+ u32 resource_err;
+ u32 over_err;
+ u32 rcvdt_err;
+ u32 short_err;
+ unsigned short t_on;
+ unsigned short t_off;
+};
+
+struct i596_iscp {
+ u32 stat;
+ dma_addr_t scb;
+};
+
+struct i596_scp {
+ u32 sysbus;
+ u32 pad;
+ dma_addr_t iscp;
+};
+
+struct i596_dma {
+ struct i596_scp scp __attribute__((aligned(32)));
+ volatile struct i596_iscp iscp __attribute__((aligned(32)));
+ volatile struct i596_scb scb __attribute__((aligned(32)));
+ struct sa_cmd sa_cmd __attribute__((aligned(32)));
+ struct cf_cmd cf_cmd __attribute__((aligned(32)));
+ struct tdr_cmd tdr_cmd __attribute__((aligned(32)));
+ struct mc_cmd mc_cmd __attribute__((aligned(32)));
+ struct i596_rfd rfds[RX_RING_SIZE] __attribute__((aligned(32)));
+ struct i596_rbd rbds[RX_RING_SIZE] __attribute__((aligned(32)));
+ struct tx_cmd tx_cmds[TX_RING_SIZE] __attribute__((aligned(32)));
+ struct i596_tbd tbds[TX_RING_SIZE] __attribute__((aligned(32)));
+};
+
+struct i596_private {
+ struct i596_dma *dma;
+ u32 stat;
+ int last_restart;
+ struct i596_rfd *rfd_head;
+ struct i596_rbd *rbd_head;
+ struct i596_cmd *cmd_tail;
+ struct i596_cmd *cmd_head;
+ int cmd_backlog;
+ u32 last_cmd;
+ struct net_device_stats stats;
+ int next_tx_cmd;
+ int options;
+ spinlock_t lock; /* serialize access to chip */
+ dma_addr_t dma_addr;
+ void __iomem *mpu_port;
+ void __iomem *ca;
+};
+
+static const char init_setup[] =
+{
+ 0x8E, /* length, prefetch on */
+ 0xC8, /* fifo to 8, monitor off */
+ 0x80, /* don't save bad frames */
+ 0x2E, /* No source address insertion, 8 byte preamble */
+ 0x00, /* priority and backoff defaults */
+ 0x60, /* interframe spacing */
+ 0x00, /* slot time LSB */
+ 0xf2, /* slot time and retries */
+ 0x00, /* promiscuous mode */
+ 0x00, /* collision detect */
+ 0x40, /* minimum frame length */
+ 0xff,
+ 0x00,
+ 0x7f /* *multi IA */ };
+
+static int i596_open(struct net_device *dev);
+static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static irqreturn_t i596_interrupt(int irq, void *dev_id);
+static int i596_close(struct net_device *dev);
+static struct net_device_stats *i596_get_stats(struct net_device *dev);
+static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd);
+static void i596_tx_timeout (struct net_device *dev);
+static void print_eth(unsigned char *buf, char *str);
+static void set_multicast_list(struct net_device *dev);
+static inline void ca(struct net_device *dev);
+static void mpu_port(struct net_device *dev, int c, dma_addr_t x);
+
+static int rx_ring_size = RX_RING_SIZE;
+static int ticks_limit = 100;
+static int max_cmd_backlog = TX_RING_SIZE-1;
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void i596_poll_controller(struct net_device *dev);
+#endif
+
+
+static inline int wait_istat(struct net_device *dev, struct i596_dma *dma, int delcnt, char *str)
+{
+ DMA_INV(dev, &(dma->iscp), sizeof(struct i596_iscp));
+ while (--delcnt && dma->iscp.stat) {
+ udelay(10);
+ DMA_INV(dev, &(dma->iscp), sizeof(struct i596_iscp));
+ }
+ if (!delcnt) {
+ printk(KERN_ERR "%s: %s, iscp.stat %04x, didn't clear\n",
+ dev->name, str, SWAP16(dma->iscp.stat));
+ return -1;
+ } else
+ return 0;
+}
+
+
+static inline int wait_cmd(struct net_device *dev, struct i596_dma *dma, int delcnt, char *str)
+{
+ DMA_INV(dev, &(dma->scb), sizeof(struct i596_scb));
+ while (--delcnt && dma->scb.command) {
+ udelay(10);
+ DMA_INV(dev, &(dma->scb), sizeof(struct i596_scb));
+ }
+ if (!delcnt) {
+ printk(KERN_ERR "%s: %s, status %4.4x, cmd %4.4x.\n",
+ dev->name, str,
+ SWAP16(dma->scb.status),
+ SWAP16(dma->scb.command));
+ return -1;
+ } else
+ return 0;
+}
+
+
+static void i596_display_data(struct net_device *dev)
+{
+ struct i596_private *lp = netdev_priv(dev);
+ struct i596_dma *dma = lp->dma;
+ struct i596_cmd *cmd;
+ struct i596_rfd *rfd;
+ struct i596_rbd *rbd;
+
+ printk(KERN_DEBUG "lp and scp at %p, .sysbus = %08x, .iscp = %08x\n",
+ &dma->scp, dma->scp.sysbus, SWAP32(dma->scp.iscp));
+ printk(KERN_DEBUG "iscp at %p, iscp.stat = %08x, .scb = %08x\n",
+ &dma->iscp, SWAP32(dma->iscp.stat), SWAP32(dma->iscp.scb));
+ printk(KERN_DEBUG "scb at %p, scb.status = %04x, .command = %04x,"
+ " .cmd = %08x, .rfd = %08x\n",
+ &dma->scb, SWAP16(dma->scb.status), SWAP16(dma->scb.command),
+ SWAP16(dma->scb.cmd), SWAP32(dma->scb.rfd));
+ printk(KERN_DEBUG " errors: crc %x, align %x, resource %x,"
+ " over %x, rcvdt %x, short %x\n",
+ SWAP32(dma->scb.crc_err), SWAP32(dma->scb.align_err),
+ SWAP32(dma->scb.resource_err), SWAP32(dma->scb.over_err),
+ SWAP32(dma->scb.rcvdt_err), SWAP32(dma->scb.short_err));
+ cmd = lp->cmd_head;
+ while (cmd != NULL) {
+ printk(KERN_DEBUG
+ "cmd at %p, .status = %04x, .command = %04x,"
+ " .b_next = %08x\n",
+ cmd, SWAP16(cmd->status), SWAP16(cmd->command),
+ SWAP32(cmd->b_next));
+ cmd = cmd->v_next;
+ }
+ rfd = lp->rfd_head;
+ printk(KERN_DEBUG "rfd_head = %p\n", rfd);
+ do {
+ printk(KERN_DEBUG
+ " %p .stat %04x, .cmd %04x, b_next %08x, rbd %08x,"
+ " count %04x\n",
+ rfd, SWAP16(rfd->stat), SWAP16(rfd->cmd),
+ SWAP32(rfd->b_next), SWAP32(rfd->rbd),
+ SWAP16(rfd->count));
+ rfd = rfd->v_next;
+ } while (rfd != lp->rfd_head);
+ rbd = lp->rbd_head;
+ printk(KERN_DEBUG "rbd_head = %p\n", rbd);
+ do {
+ printk(KERN_DEBUG
+ " %p .count %04x, b_next %08x, b_data %08x,"
+ " size %04x\n",
+ rbd, SWAP16(rbd->count), SWAP32(rbd->b_next),
+ SWAP32(rbd->b_data), SWAP16(rbd->size));
+ rbd = rbd->v_next;
+ } while (rbd != lp->rbd_head);
+ DMA_INV(dev, dma, sizeof(struct i596_dma));
+}
+
+
+#define virt_to_dma(lp, v) ((lp)->dma_addr + (dma_addr_t)((unsigned long)(v)-(unsigned long)((lp)->dma)))
+
+static inline int init_rx_bufs(struct net_device *dev)
+{
+ struct i596_private *lp = netdev_priv(dev);
+ struct i596_dma *dma = lp->dma;
+ int i;
+ struct i596_rfd *rfd;
+ struct i596_rbd *rbd;
+
+ /* First build the Receive Buffer Descriptor List */
+
+ for (i = 0, rbd = dma->rbds; i < rx_ring_size; i++, rbd++) {
+ dma_addr_t dma_addr;
+ struct sk_buff *skb = netdev_alloc_skb(dev, PKT_BUF_SZ + 4);
+
+ if (skb == NULL)
+ return -1;
+ skb_reserve(skb, 2);
+ dma_addr = dma_map_single(dev->dev.parent, skb->data,
+ PKT_BUF_SZ, DMA_FROM_DEVICE);
+ rbd->v_next = rbd+1;
+ rbd->b_next = SWAP32(virt_to_dma(lp, rbd+1));
+ rbd->b_addr = SWAP32(virt_to_dma(lp, rbd));
+ rbd->skb = skb;
+ rbd->v_data = skb->data;
+ rbd->b_data = SWAP32(dma_addr);
+ rbd->size = SWAP16(PKT_BUF_SZ);
+ }
+ lp->rbd_head = dma->rbds;
+ rbd = dma->rbds + rx_ring_size - 1;
+ rbd->v_next = dma->rbds;
+ rbd->b_next = SWAP32(virt_to_dma(lp, dma->rbds));
+
+ /* Now build the Receive Frame Descriptor List */
+
+ for (i = 0, rfd = dma->rfds; i < rx_ring_size; i++, rfd++) {
+ rfd->rbd = I596_NULL;
+ rfd->v_next = rfd+1;
+ rfd->v_prev = rfd-1;
+ rfd->b_next = SWAP32(virt_to_dma(lp, rfd+1));
+ rfd->cmd = SWAP16(CMD_FLEX);
+ }
+ lp->rfd_head = dma->rfds;
+ dma->scb.rfd = SWAP32(virt_to_dma(lp, dma->rfds));
+ rfd = dma->rfds;
+ rfd->rbd = SWAP32(virt_to_dma(lp, lp->rbd_head));
+ rfd->v_prev = dma->rfds + rx_ring_size - 1;
+ rfd = dma->rfds + rx_ring_size - 1;
+ rfd->v_next = dma->rfds;
+ rfd->b_next = SWAP32(virt_to_dma(lp, dma->rfds));
+ rfd->cmd = SWAP16(CMD_EOL|CMD_FLEX);
+
+ DMA_WBACK_INV(dev, dma, sizeof(struct i596_dma));
+ return 0;
+}
+
+static inline void remove_rx_bufs(struct net_device *dev)
+{
+ struct i596_private *lp = netdev_priv(dev);
+ struct i596_rbd *rbd;
+ int i;
+
+ for (i = 0, rbd = lp->dma->rbds; i < rx_ring_size; i++, rbd++) {
+ if (rbd->skb == NULL)
+ break;
+ dma_unmap_single(dev->dev.parent,
+ (dma_addr_t)SWAP32(rbd->b_data),
+ PKT_BUF_SZ, DMA_FROM_DEVICE);
+ dev_kfree_skb(rbd->skb);
+ }
+}
+
+
+static void rebuild_rx_bufs(struct net_device *dev)
+{
+ struct i596_private *lp = netdev_priv(dev);
+ struct i596_dma *dma = lp->dma;
+ int i;
+
+ /* Ensure rx frame/buffer descriptors are tidy */
+
+ for (i = 0; i < rx_ring_size; i++) {
+ dma->rfds[i].rbd = I596_NULL;
+ dma->rfds[i].cmd = SWAP16(CMD_FLEX);
+ }
+ dma->rfds[rx_ring_size-1].cmd = SWAP16(CMD_EOL|CMD_FLEX);
+ lp->rfd_head = dma->rfds;
+ dma->scb.rfd = SWAP32(virt_to_dma(lp, dma->rfds));
+ lp->rbd_head = dma->rbds;
+ dma->rfds[0].rbd = SWAP32(virt_to_dma(lp, dma->rbds));
+
+ DMA_WBACK_INV(dev, dma, sizeof(struct i596_dma));
+}
+
+
+static int init_i596_mem(struct net_device *dev)
+{
+ struct i596_private *lp = netdev_priv(dev);
+ struct i596_dma *dma = lp->dma;
+ unsigned long flags;
+
+ mpu_port(dev, PORT_RESET, 0);
+ udelay(100); /* Wait 100us - seems to help */
+
+ /* change the scp address */
+
+ lp->last_cmd = jiffies;
+
+ dma->scp.sysbus = SYSBUS;
+ dma->scp.iscp = SWAP32(virt_to_dma(lp, &(dma->iscp)));
+ dma->iscp.scb = SWAP32(virt_to_dma(lp, &(dma->scb)));
+ dma->iscp.stat = SWAP32(ISCP_BUSY);
+ lp->cmd_backlog = 0;
+
+ lp->cmd_head = NULL;
+ dma->scb.cmd = I596_NULL;
+
+ DEB(DEB_INIT, printk(KERN_DEBUG "%s: starting i82596.\n", dev->name));
+
+ DMA_WBACK(dev, &(dma->scp), sizeof(struct i596_scp));
+ DMA_WBACK(dev, &(dma->iscp), sizeof(struct i596_iscp));
+ DMA_WBACK(dev, &(dma->scb), sizeof(struct i596_scb));
+
+ mpu_port(dev, PORT_ALTSCP, virt_to_dma(lp, &dma->scp));
+ ca(dev);
+ if (wait_istat(dev, dma, 1000, "initialization timed out"))
+ goto failed;
+ DEB(DEB_INIT, printk(KERN_DEBUG
+ "%s: i82596 initialization successful\n",
+ dev->name));
+
+ if (request_irq(dev->irq, &i596_interrupt, 0, "i82596", dev)) {
+ printk(KERN_ERR "%s: IRQ %d not free\n", dev->name, dev->irq);
+ goto failed;
+ }
+
+ /* Ensure rx frame/buffer descriptors are tidy */
+ rebuild_rx_bufs(dev);
+
+ dma->scb.command = 0;
+ DMA_WBACK(dev, &(dma->scb), sizeof(struct i596_scb));
+
+ DEB(DEB_INIT, printk(KERN_DEBUG
+ "%s: queuing CmdConfigure\n", dev->name));
+ memcpy(dma->cf_cmd.i596_config, init_setup, 14);
+ dma->cf_cmd.cmd.command = SWAP16(CmdConfigure);
+ DMA_WBACK(dev, &(dma->cf_cmd), sizeof(struct cf_cmd));
+ i596_add_cmd(dev, &dma->cf_cmd.cmd);
+
+ DEB(DEB_INIT, printk(KERN_DEBUG "%s: queuing CmdSASetup\n", dev->name));
+ memcpy(dma->sa_cmd.eth_addr, dev->dev_addr, 6);
+ dma->sa_cmd.cmd.command = SWAP16(CmdSASetup);
+ DMA_WBACK(dev, &(dma->sa_cmd), sizeof(struct sa_cmd));
+ i596_add_cmd(dev, &dma->sa_cmd.cmd);
+
+ DEB(DEB_INIT, printk(KERN_DEBUG "%s: queuing CmdTDR\n", dev->name));
+ dma->tdr_cmd.cmd.command = SWAP16(CmdTDR);
+ DMA_WBACK(dev, &(dma->tdr_cmd), sizeof(struct tdr_cmd));
+ i596_add_cmd(dev, &dma->tdr_cmd.cmd);
+
+ spin_lock_irqsave (&lp->lock, flags);
+
+ if (wait_cmd(dev, dma, 1000, "timed out waiting to issue RX_START")) {
+ spin_unlock_irqrestore (&lp->lock, flags);
+ goto failed_free_irq;
+ }
+ DEB(DEB_INIT, printk(KERN_DEBUG "%s: Issuing RX_START\n", dev->name));
+ dma->scb.command = SWAP16(RX_START);
+ dma->scb.rfd = SWAP32(virt_to_dma(lp, dma->rfds));
+ DMA_WBACK(dev, &(dma->scb), sizeof(struct i596_scb));
+
+ ca(dev);
+
+ spin_unlock_irqrestore (&lp->lock, flags);
+ if (wait_cmd(dev, dma, 1000, "RX_START not processed"))
+ goto failed_free_irq;
+ DEB(DEB_INIT, printk(KERN_DEBUG
+ "%s: Receive unit started OK\n", dev->name));
+ return 0;
+
+failed_free_irq:
+ free_irq(dev->irq, dev);
+failed:
+ printk(KERN_ERR "%s: Failed to initialise 82596\n", dev->name);
+ mpu_port(dev, PORT_RESET, 0);
+ return -1;
+}
+
+
+static inline int i596_rx(struct net_device *dev)
+{
+ struct i596_private *lp = netdev_priv(dev);
+ struct i596_rfd *rfd;
+ struct i596_rbd *rbd;
+ int frames = 0;
+
+ DEB(DEB_RXFRAME, printk(KERN_DEBUG
+ "i596_rx(), rfd_head %p, rbd_head %p\n",
+ lp->rfd_head, lp->rbd_head));
+
+
+ rfd = lp->rfd_head; /* Ref next frame to check */
+
+ DMA_INV(dev, rfd, sizeof(struct i596_rfd));
+ while (rfd->stat & SWAP16(STAT_C)) { /* Loop while complete frames */
+ if (rfd->rbd == I596_NULL)
+ rbd = NULL;
+ else if (rfd->rbd == lp->rbd_head->b_addr) {
+ rbd = lp->rbd_head;
+ DMA_INV(dev, rbd, sizeof(struct i596_rbd));
+ } else {
+ printk(KERN_ERR "%s: rbd chain broken!\n", dev->name);
+ /* XXX Now what? */
+ rbd = NULL;
+ }
+ DEB(DEB_RXFRAME, printk(KERN_DEBUG
+ " rfd %p, rfd.rbd %08x, rfd.stat %04x\n",
+ rfd, rfd->rbd, rfd->stat));
+
+ if (rbd != NULL && (rfd->stat & SWAP16(STAT_OK))) {
+ /* a good frame */
+ int pkt_len = SWAP16(rbd->count) & 0x3fff;
+ struct sk_buff *skb = rbd->skb;
+ int rx_in_place = 0;
+
+ DEB(DEB_RXADDR, print_eth(rbd->v_data, "received"));
+ frames++;
+
+ /* Check if the packet is long enough to just accept
+ * without copying to a properly sized skbuff.
+ */
+
+ if (pkt_len > rx_copybreak) {
+ struct sk_buff *newskb;
+ dma_addr_t dma_addr;
+
+ dma_unmap_single(dev->dev.parent,
+ (dma_addr_t)SWAP32(rbd->b_data),
+ PKT_BUF_SZ, DMA_FROM_DEVICE);
+ /* Get fresh skbuff to replace filled one. */
+ newskb = netdev_alloc_skb(dev, PKT_BUF_SZ + 4);
+ if (newskb == NULL) {
+ skb = NULL; /* drop pkt */
+ goto memory_squeeze;
+ }
+ skb_reserve(newskb, 2);
+
+ /* Pass up the skb already on the Rx ring. */
+ skb_put(skb, pkt_len);
+ rx_in_place = 1;
+ rbd->skb = newskb;
+ dma_addr = dma_map_single(dev->dev.parent,
+ newskb->data,
+ PKT_BUF_SZ,
+ DMA_FROM_DEVICE);
+ rbd->v_data = newskb->data;
+ rbd->b_data = SWAP32(dma_addr);
+ DMA_WBACK_INV(dev, rbd, sizeof(struct i596_rbd));
+ } else
+ skb = netdev_alloc_skb(dev, pkt_len + 2);
+memory_squeeze:
+ if (skb == NULL) {
+ /* XXX tulip.c can defer packets here!! */
+ printk(KERN_ERR
+ "%s: i596_rx Memory squeeze, dropping packet.\n",
+ dev->name);
+ lp->stats.rx_dropped++;
+ } else {
+ if (!rx_in_place) {
+ /* 16 byte align the data fields */
+ dma_sync_single_for_cpu(dev->dev.parent,
+ (dma_addr_t)SWAP32(rbd->b_data),
+ PKT_BUF_SZ, DMA_FROM_DEVICE);
+ skb_reserve(skb, 2);
+ memcpy(skb_put(skb, pkt_len), rbd->v_data, pkt_len);
+ dma_sync_single_for_device(dev->dev.parent,
+ (dma_addr_t)SWAP32(rbd->b_data),
+ PKT_BUF_SZ, DMA_FROM_DEVICE);
+ }
+ skb->len = pkt_len;
+ skb->protocol = eth_type_trans(skb, dev);
+ netif_rx(skb);
+ dev->last_rx = jiffies;
+ lp->stats.rx_packets++;
+ lp->stats.rx_bytes += pkt_len;
+ }
+ } else {
+ DEB(DEB_ERRORS, printk(KERN_DEBUG
+ "%s: Error, rfd.stat = 0x%04x\n",
+ dev->name, rfd->stat));
+ lp->stats.rx_errors++;
+ if (rfd->stat & SWAP16(0x0100))
+ lp->stats.collisions++;
+ if (rfd->stat & SWAP16(0x8000))
+ lp->stats.rx_length_errors++;
+ if (rfd->stat & SWAP16(0x0001))
+ lp->stats.rx_over_errors++;
+ if (rfd->stat & SWAP16(0x0002))
+ lp->stats.rx_fifo_errors++;
+ if (rfd->stat & SWAP16(0x0004))
+ lp->stats.rx_frame_errors++;
+ if (rfd->stat & SWAP16(0x0008))
+ lp->stats.rx_crc_errors++;
+ if (rfd->stat & SWAP16(0x0010))
+ lp->stats.rx_length_errors++;
+ }
+
+ /* Clear the buffer descriptor count and EOF + F flags */
+
+ if (rbd != NULL && (rbd->count & SWAP16(0x4000))) {
+ rbd->count = 0;
+ lp->rbd_head = rbd->v_next;
+ DMA_WBACK_INV(dev, rbd, sizeof(struct i596_rbd));
+ }
+
+ /* Tidy the frame descriptor, marking it as end of list */
+
+ rfd->rbd = I596_NULL;
+ rfd->stat = 0;
+ rfd->cmd = SWAP16(CMD_EOL|CMD_FLEX);
+ rfd->count = 0;
+
+ /* Update record of next frame descriptor to process */
+
+ lp->dma->scb.rfd = rfd->b_next;
+ lp->rfd_head = rfd->v_next;
+ DMA_WBACK_INV(dev, rfd, sizeof(struct i596_rfd));
+
+ /* Remove end-of-list from old end descriptor */
+
+ rfd->v_prev->cmd = SWAP16(CMD_FLEX);
+ DMA_WBACK_INV(dev, rfd->v_prev, sizeof(struct i596_rfd));
+ rfd = lp->rfd_head;
+ DMA_INV(dev, rfd, sizeof(struct i596_rfd));
+ }
+
+ DEB(DEB_RXFRAME, printk(KERN_DEBUG "frames %d\n", frames));
+
+ return 0;
+}
+
+
+static inline void i596_cleanup_cmd(struct net_device *dev, struct i596_private *lp)
+{
+ struct i596_cmd *ptr;
+
+ while (lp->cmd_head != NULL) {
+ ptr = lp->cmd_head;
+ lp->cmd_head = ptr->v_next;
+ lp->cmd_backlog--;
+
+ switch (SWAP16(ptr->command) & 0x7) {
+ case CmdTx:
+ {
+ struct tx_cmd *tx_cmd = (struct tx_cmd *) ptr;
+ struct sk_buff *skb = tx_cmd->skb;
+ dma_unmap_single(dev->dev.parent,
+ tx_cmd->dma_addr,
+ skb->len, DMA_TO_DEVICE);
+
+ dev_kfree_skb(skb);
+
+ lp->stats.tx_errors++;
+ lp->stats.tx_aborted_errors++;
+
+ ptr->v_next = NULL;
+ ptr->b_next = I596_NULL;
+ tx_cmd->cmd.command = 0; /* Mark as free */
+ break;
+ }
+ default:
+ ptr->v_next = NULL;
+ ptr->b_next = I596_NULL;
+ }
+ DMA_WBACK_INV(dev, ptr, sizeof(struct i596_cmd));
+ }
+
+ wait_cmd(dev, lp->dma, 100, "i596_cleanup_cmd timed out");
+ lp->dma->scb.cmd = I596_NULL;
+ DMA_WBACK(dev, &(lp->dma->scb), sizeof(struct i596_scb));
+}
+
+
+static inline void i596_reset(struct net_device *dev, struct i596_private *lp)
+{
+ unsigned long flags;
+
+ DEB(DEB_RESET, printk(KERN_DEBUG "i596_reset\n"));
+
+ spin_lock_irqsave (&lp->lock, flags);
+
+ wait_cmd(dev, lp->dma, 100, "i596_reset timed out");
+
+ netif_stop_queue(dev);
+
+ /* FIXME: this command might cause an lpmc */
+ lp->dma->scb.command = SWAP16(CUC_ABORT | RX_ABORT);
+ DMA_WBACK(dev, &(lp->dma->scb), sizeof(struct i596_scb));
+ ca(dev);
+
+ /* wait for shutdown */
+ wait_cmd(dev, lp->dma, 1000, "i596_reset 2 timed out");
+ spin_unlock_irqrestore (&lp->lock, flags);
+
+ i596_cleanup_cmd(dev, lp);
+ i596_rx(dev);
+
+ netif_start_queue(dev);
+ init_i596_mem(dev);
+}
+
+
+static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd)
+{
+ struct i596_private *lp = netdev_priv(dev);
+ struct i596_dma *dma = lp->dma;
+ unsigned long flags;
+
+ DEB(DEB_ADDCMD, printk(KERN_DEBUG "i596_add_cmd cmd_head %p\n",
+ lp->cmd_head));
+
+ cmd->status = 0;
+ cmd->command |= SWAP16(CMD_EOL | CMD_INTR);
+ cmd->v_next = NULL;
+ cmd->b_next = I596_NULL;
+ DMA_WBACK(dev, cmd, sizeof(struct i596_cmd));
+
+ spin_lock_irqsave (&lp->lock, flags);
+
+ if (lp->cmd_head != NULL) {
+ lp->cmd_tail->v_next = cmd;
+ lp->cmd_tail->b_next = SWAP32(virt_to_dma(lp, &cmd->status));
+ DMA_WBACK(dev, lp->cmd_tail, sizeof(struct i596_cmd));
+ } else {
+ lp->cmd_head = cmd;
+ wait_cmd(dev, dma, 100, "i596_add_cmd timed out");
+ dma->scb.cmd = SWAP32(virt_to_dma(lp, &cmd->status));
+ dma->scb.command = SWAP16(CUC_START);
+ DMA_WBACK(dev, &(dma->scb), sizeof(struct i596_scb));
+ ca(dev);
+ }
+ lp->cmd_tail = cmd;
+ lp->cmd_backlog++;
+
+ spin_unlock_irqrestore (&lp->lock, flags);
+
+ if (lp->cmd_backlog > max_cmd_backlog) {
+ unsigned long tickssofar = jiffies - lp->last_cmd;
+
+ if (tickssofar < ticks_limit)
+ return;
+
+ printk(KERN_ERR
+ "%s: command unit timed out, status resetting.\n",
+ dev->name);
+#if 1
+ i596_reset(dev, lp);
+#endif
+ }
+}
+
+static int i596_open(struct net_device *dev)
+{
+ DEB(DEB_OPEN, printk(KERN_DEBUG
+ "%s: i596_open() irq %d.\n", dev->name, dev->irq));
+
+ if (init_rx_bufs(dev)) {
+ printk(KERN_ERR "%s: Failed to init rx bufs\n", dev->name);
+ return -EAGAIN;
+ }
+ if (init_i596_mem(dev)) {
+ printk(KERN_ERR "%s: Failed to init memory\n", dev->name);
+ goto out_remove_rx_bufs;
+ }
+ netif_start_queue(dev);
+
+ return 0;
+
+out_remove_rx_bufs:
+ remove_rx_bufs(dev);
+ return -EAGAIN;
+}
+
+static void i596_tx_timeout (struct net_device *dev)
+{
+ struct i596_private *lp = netdev_priv(dev);
+
+ /* Transmitter timeout, serious problems. */
+ DEB(DEB_ERRORS, printk(KERN_DEBUG
+ "%s: transmit timed out, status resetting.\n",
+ dev->name));
+
+ lp->stats.tx_errors++;
+
+ /* Try to restart the adaptor */
+ if (lp->last_restart == lp->stats.tx_packets) {
+ DEB(DEB_ERRORS, printk(KERN_DEBUG "Resetting board.\n"));
+ /* Shutdown and restart */
+ i596_reset (dev, lp);
+ } else {
+ /* Issue a channel attention signal */
+ DEB(DEB_ERRORS, printk(KERN_DEBUG "Kicking board.\n"));
+ lp->dma->scb.command = SWAP16(CUC_START | RX_START);
+ DMA_WBACK_INV(dev, &(lp->dma->scb), sizeof(struct i596_scb));
+ ca (dev);
+ lp->last_restart = lp->stats.tx_packets;
+ }
+
+ dev->trans_start = jiffies;
+ netif_wake_queue (dev);
+}
+
+
+static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct i596_private *lp = netdev_priv(dev);
+ struct tx_cmd *tx_cmd;
+ struct i596_tbd *tbd;
+ short length = skb->len;
+ dev->trans_start = jiffies;
+
+ DEB(DEB_STARTTX, printk(KERN_DEBUG
+ "%s: i596_start_xmit(%x,%p) called\n",
+ dev->name, skb->len, skb->data));
+
+ if (length < ETH_ZLEN) {
+ if (skb_padto(skb, ETH_ZLEN))
+ return 0;
+ length = ETH_ZLEN;
+ }
+
+ netif_stop_queue(dev);
+
+ tx_cmd = lp->dma->tx_cmds + lp->next_tx_cmd;
+ tbd = lp->dma->tbds + lp->next_tx_cmd;
+
+ if (tx_cmd->cmd.command) {
+ DEB(DEB_ERRORS, printk(KERN_DEBUG
+ "%s: xmit ring full, dropping packet.\n",
+ dev->name));
+ lp->stats.tx_dropped++;
+
+ dev_kfree_skb(skb);
+ } else {
+ if (++lp->next_tx_cmd == TX_RING_SIZE)
+ lp->next_tx_cmd = 0;
+ tx_cmd->tbd = SWAP32(virt_to_dma(lp, tbd));
+ tbd->next = I596_NULL;
+
+ tx_cmd->cmd.command = SWAP16(CMD_FLEX | CmdTx);
+ tx_cmd->skb = skb;
+
+ tx_cmd->pad = 0;
+ tx_cmd->size = 0;
+ tbd->pad = 0;
+ tbd->size = SWAP16(EOF | length);
+
+ tx_cmd->dma_addr = dma_map_single(dev->dev.parent, skb->data,
+ skb->len, DMA_TO_DEVICE);
+ tbd->data = SWAP32(tx_cmd->dma_addr);
+
+ DEB(DEB_TXADDR, print_eth(skb->data, "tx-queued"));
+ DMA_WBACK_INV(dev, tx_cmd, sizeof(struct tx_cmd));
+ DMA_WBACK_INV(dev, tbd, sizeof(struct i596_tbd));
+ i596_add_cmd(dev, &tx_cmd->cmd);
+
+ lp->stats.tx_packets++;
+ lp->stats.tx_bytes += length;
+ }
+
+ netif_start_queue(dev);
+
+ return 0;
+}
+
+static void print_eth(unsigned char *add, char *str)
+{
+ int i;
+
+ printk(KERN_DEBUG "i596 0x%p, ", add);
+ for (i = 0; i < 6; i++)
+ printk(" %02X", add[i + 6]);
+ printk(" -->");
+ for (i = 0; i < 6; i++)
+ printk(" %02X", add[i]);
+ printk(" %02X%02X, %s\n", add[12], add[13], str);
+}
+
+static int __devinit i82596_probe(struct net_device *dev)
+{
+ int i;
+ struct i596_private *lp = netdev_priv(dev);
+ struct i596_dma *dma;
+
+ /* This lot is ensure things have been cache line aligned. */
+ BUILD_BUG_ON(sizeof(struct i596_rfd) != 32);
+ BUILD_BUG_ON(sizeof(struct i596_rbd) & 31);
+ BUILD_BUG_ON(sizeof(struct tx_cmd) & 31);
+ BUILD_BUG_ON(sizeof(struct i596_tbd) != 32);
+#ifndef __LP64__
+ BUILD_BUG_ON(sizeof(struct i596_dma) > 4096);
+#endif
+
+ if (!dev->base_addr || !dev->irq)
+ return -ENODEV;
+
+ dma = (struct i596_dma *) DMA_ALLOC(dev->dev.parent,
+ sizeof(struct i596_dma), &lp->dma_addr, GFP_KERNEL);
+ if (!dma) {
+ printk(KERN_ERR "%s: Couldn't get shared memory\n", __FILE__);
+ return -ENOMEM;
+ }
+
+ /* The 82596-specific entries in the device structure. */
+ dev->open = i596_open;
+ dev->stop = i596_close;
+ dev->hard_start_xmit = i596_start_xmit;
+ dev->get_stats = i596_get_stats;
+ dev->set_multicast_list = set_multicast_list;
+ dev->tx_timeout = i596_tx_timeout;
+ dev->watchdog_timeo = TX_TIMEOUT;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ dev->poll_controller = i596_poll_controller;
+#endif
+
+ memset(dma, 0, sizeof(struct i596_dma));
+ lp->dma = dma;
+
+ dma->scb.command = 0;
+ dma->scb.cmd = I596_NULL;
+ dma->scb.rfd = I596_NULL;
+ spin_lock_init(&lp->lock);
+
+ DMA_WBACK_INV(dev, dma, sizeof(struct i596_dma));
+
+ i = register_netdev(dev);
+ if (i) {
+ DMA_FREE(dev->dev.parent, sizeof(struct i596_dma),
+ (void *)dma, lp->dma_addr);
+ return i;
+ };
+
+ DEB(DEB_PROBE, printk(KERN_INFO "%s: 82596 at %#3lx,",
+ dev->name, dev->base_addr));
+ for (i = 0; i < 6; i++)
+ DEB(DEB_PROBE, printk(" %2.2X", dev->dev_addr[i]));
+ DEB(DEB_PROBE, printk(" IRQ %d.\n", dev->irq));
+ DEB(DEB_INIT, printk(KERN_INFO
+ "%s: dma at 0x%p (%d bytes), lp->scb at 0x%p\n",
+ dev->name, dma, (int)sizeof(struct i596_dma),
+ &dma->scb));
+
+ return 0;
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void i596_poll_controller(struct net_device *dev)
+{
+ disable_irq(dev->irq);
+ i596_interrupt(dev->irq, dev);
+ enable_irq(dev->irq);
+}
+#endif
+
+static irqreturn_t i596_interrupt(int irq, void *dev_id)
+{
+ struct net_device *dev = dev_id;
+ struct i596_private *lp;
+ struct i596_dma *dma;
+ unsigned short status, ack_cmd = 0;
+
+ if (dev == NULL) {
+ printk(KERN_WARNING "%s: irq %d for unknown device.\n",
+ __FUNCTION__, irq);
+ return IRQ_NONE;
+ }
+
+ lp = netdev_priv(dev);
+ dma = lp->dma;
+
+ spin_lock (&lp->lock);
+
+ wait_cmd(dev, dma, 100, "i596 interrupt, timeout");
+ status = SWAP16(dma->scb.status);
+
+ DEB(DEB_INTS, printk(KERN_DEBUG
+ "%s: i596 interrupt, IRQ %d, status %4.4x.\n",
+ dev->name, irq, status));
+
+ ack_cmd = status & 0xf000;
+
+ if (!ack_cmd) {
+ DEB(DEB_ERRORS, printk(KERN_DEBUG
+ "%s: interrupt with no events\n",
+ dev->name));
+ spin_unlock (&lp->lock);
+ return IRQ_NONE;
+ }
+
+ if ((status & 0x8000) || (status & 0x2000)) {
+ struct i596_cmd *ptr;
+
+ if ((status & 0x8000))
+ DEB(DEB_INTS,
+ printk(KERN_DEBUG
+ "%s: i596 interrupt completed command.\n",
+ dev->name));
+ if ((status & 0x2000))
+ DEB(DEB_INTS,
+ printk(KERN_DEBUG
+ "%s: i596 interrupt command unit inactive %x.\n",
+ dev->name, status & 0x0700));
+
+ while (lp->cmd_head != NULL) {
+ DMA_INV(dev, lp->cmd_head, sizeof(struct i596_cmd));
+ if (!(lp->cmd_head->status & SWAP16(STAT_C)))
+ break;
+
+ ptr = lp->cmd_head;
+
+ DEB(DEB_STATUS,
+ printk(KERN_DEBUG
+ "cmd_head->status = %04x, ->command = %04x\n",
+ SWAP16(lp->cmd_head->status),
+ SWAP16(lp->cmd_head->command)));
+ lp->cmd_head = ptr->v_next;
+ lp->cmd_backlog--;
+
+ switch (SWAP16(ptr->command) & 0x7) {
+ case CmdTx:
+ {
+ struct tx_cmd *tx_cmd = (struct tx_cmd *) ptr;
+ struct sk_buff *skb = tx_cmd->skb;
+
+ if (ptr->status & SWAP16(STAT_OK)) {
+ DEB(DEB_TXADDR,
+ print_eth(skb->data, "tx-done"));
+ } else {
+ lp->stats.tx_errors++;
+ if (ptr->status & SWAP16(0x0020))
+ lp->stats.collisions++;
+ if (!(ptr->status & SWAP16(0x0040)))
+ lp->stats.tx_heartbeat_errors++;
+ if (ptr->status & SWAP16(0x0400))
+ lp->stats.tx_carrier_errors++;
+ if (ptr->status & SWAP16(0x0800))
+ lp->stats.collisions++;
+ if (ptr->status & SWAP16(0x1000))
+ lp->stats.tx_aborted_errors++;
+ }
+ dma_unmap_single(dev->dev.parent,
+ tx_cmd->dma_addr,
+ skb->len, DMA_TO_DEVICE);
+ dev_kfree_skb_irq(skb);
+
+ tx_cmd->cmd.command = 0; /* Mark free */
+ break;
+ }
+ case CmdTDR:
+ {
+ unsigned short status = SWAP16(((struct tdr_cmd *)ptr)->status);
+
+ if (status & 0x8000) {
+ DEB(DEB_ANY,
+ printk(KERN_DEBUG "%s: link ok.\n",
+ dev->name));
+ } else {
+ if (status & 0x4000)
+ printk(KERN_ERR
+ "%s: Transceiver problem.\n",
+ dev->name);
+ if (status & 0x2000)
+ printk(KERN_ERR
+ "%s: Termination problem.\n",
+ dev->name);
+ if (status & 0x1000)
+ printk(KERN_ERR
+ "%s: Short circuit.\n",
+ dev->name);
+
+ DEB(DEB_TDR,
+ printk(KERN_DEBUG "%s: Time %d.\n",
+ dev->name, status & 0x07ff));
+ }
+ break;
+ }
+ case CmdConfigure:
+ /*
+ * Zap command so set_multicast_list() know
+ * it is free
+ */
+ ptr->command = 0;
+ break;
+ }
+ ptr->v_next = NULL;
+ ptr->b_next = I596_NULL;
+ DMA_WBACK(dev, ptr, sizeof(struct i596_cmd));
+ lp->last_cmd = jiffies;
+ }
+
+ /* This mess is arranging that only the last of any outstanding
+ * commands has the interrupt bit set. Should probably really
+ * only add to the cmd queue when the CU is stopped.
+ */
+ ptr = lp->cmd_head;
+ while ((ptr != NULL) && (ptr != lp->cmd_tail)) {
+ struct i596_cmd *prev = ptr;
+
+ ptr->command &= SWAP16(0x1fff);
+ ptr = ptr->v_next;
+ DMA_WBACK_INV(dev, prev, sizeof(struct i596_cmd));
+ }
+
+ if (lp->cmd_head != NULL)
+ ack_cmd |= CUC_START;
+ dma->scb.cmd = SWAP32(virt_to_dma(lp, &lp->cmd_head->status));
+ DMA_WBACK_INV(dev, &dma->scb, sizeof(struct i596_scb));
+ }
+ if ((status & 0x1000) || (status & 0x4000)) {
+ if ((status & 0x4000))
+ DEB(DEB_INTS,
+ printk(KERN_DEBUG
+ "%s: i596 interrupt received a frame.\n",
+ dev->name));
+ i596_rx(dev);
+ /* Only RX_START if stopped - RGH 07-07-96 */
+ if (status & 0x1000) {
+ if (netif_running(dev)) {
+ DEB(DEB_ERRORS,
+ printk(KERN_DEBUG
+ "%s: i596 interrupt receive unit inactive, status 0x%x\n",
+ dev->name, status));
+ ack_cmd |= RX_START;
+ lp->stats.rx_errors++;
+ lp->stats.rx_fifo_errors++;
+ rebuild_rx_bufs(dev);
+ }
+ }
+ }
+ wait_cmd(dev, dma, 100, "i596 interrupt, timeout");
+ dma->scb.command = SWAP16(ack_cmd);
+ DMA_WBACK(dev, &dma->scb, sizeof(struct i596_scb));
+
+ /* DANGER: I suspect that some kind of interrupt
+ acknowledgement aside from acking the 82596 might be needed
+ here... but it's running acceptably without */
+
+ ca(dev);
+
+ wait_cmd(dev, dma, 100, "i596 interrupt, exit timeout");
+ DEB(DEB_INTS, printk(KERN_DEBUG "%s: exiting interrupt.\n", dev->name));
+
+ spin_unlock (&lp->lock);
+ return IRQ_HANDLED;
+}
+
+static int i596_close(struct net_device *dev)
+{
+ struct i596_private *lp = netdev_priv(dev);
+ unsigned long flags;
+
+ netif_stop_queue(dev);
+
+ DEB(DEB_INIT,
+ printk(KERN_DEBUG
+ "%s: Shutting down ethercard, status was %4.4x.\n",
+ dev->name, SWAP16(lp->dma->scb.status)));
+
+ spin_lock_irqsave(&lp->lock, flags);
+
+ wait_cmd(dev, lp->dma, 100, "close1 timed out");
+ lp->dma->scb.command = SWAP16(CUC_ABORT | RX_ABORT);
+ DMA_WBACK(dev, &lp->dma->scb, sizeof(struct i596_scb));
+
+ ca(dev);
+
+ wait_cmd(dev, lp->dma, 100, "close2 timed out");
+ spin_unlock_irqrestore(&lp->lock, flags);
+ DEB(DEB_STRUCT, i596_display_data(dev));
+ i596_cleanup_cmd(dev, lp);
+
+ free_irq(dev->irq, dev);
+ remove_rx_bufs(dev);
+
+ return 0;
+}
+
+static struct net_device_stats *i596_get_stats(struct net_device *dev)
+{
+ struct i596_private *lp = netdev_priv(dev);
+
+ return &lp->stats;
+}
+
+/*
+ * Set or clear the multicast filter for this adaptor.
+ */
+
+static void set_multicast_list(struct net_device *dev)
+{
+ struct i596_private *lp = netdev_priv(dev);
+ struct i596_dma *dma = lp->dma;
+ int config = 0, cnt;
+
+ DEB(DEB_MULTI,
+ printk(KERN_DEBUG
+ "%s: set multicast list, %d entries, promisc %s, allmulti %s\n",
+ dev->name, dev->mc_count,
+ dev->flags & IFF_PROMISC ? "ON" : "OFF",
+ dev->flags & IFF_ALLMULTI ? "ON" : "OFF"));
+
+ if ((dev->flags & IFF_PROMISC) &&
+ !(dma->cf_cmd.i596_config[8] & 0x01)) {
+ dma->cf_cmd.i596_config[8] |= 0x01;
+ config = 1;
+ }
+ if (!(dev->flags & IFF_PROMISC) &&
+ (dma->cf_cmd.i596_config[8] & 0x01)) {
+ dma->cf_cmd.i596_config[8] &= ~0x01;
+ config = 1;
+ }
+ if ((dev->flags & IFF_ALLMULTI) &&
+ (dma->cf_cmd.i596_config[11] & 0x20)) {
+ dma->cf_cmd.i596_config[11] &= ~0x20;
+ config = 1;
+ }
+ if (!(dev->flags & IFF_ALLMULTI) &&
+ !(dma->cf_cmd.i596_config[11] & 0x20)) {
+ dma->cf_cmd.i596_config[11] |= 0x20;
+ config = 1;
+ }
+ if (config) {
+ if (dma->cf_cmd.cmd.command)
+ printk(KERN_INFO
+ "%s: config change request already queued\n",
+ dev->name);
+ else {
+ dma->cf_cmd.cmd.command = SWAP16(CmdConfigure);
+ DMA_WBACK_INV(dev, &dma->cf_cmd, sizeof(struct cf_cmd));
+ i596_add_cmd(dev, &dma->cf_cmd.cmd);
+ }
+ }
+
+ cnt = dev->mc_count;
+ if (cnt > MAX_MC_CNT) {
+ cnt = MAX_MC_CNT;
+ printk(KERN_NOTICE "%s: Only %d multicast addresses supported",
+ dev->name, cnt);
+ }
+
+ if (dev->mc_count > 0) {
+ struct dev_mc_list *dmi;
+ unsigned char *cp;
+ struct mc_cmd *cmd;
+
+ cmd = &dma->mc_cmd;
+ cmd->cmd.command = SWAP16(CmdMulticastList);
+ cmd->mc_cnt = SWAP16(dev->mc_count * 6);
+ cp = cmd->mc_addrs;
+ for (dmi = dev->mc_list;
+ cnt && dmi != NULL;
+ dmi = dmi->next, cnt--, cp += 6) {
+ memcpy(cp, dmi->dmi_addr, 6);
+ if (i596_debug > 1)
+ DEB(DEB_MULTI,
+ printk(KERN_DEBUG
+ "%s: Adding address %02x:%02x:%02x:%02x:%02x:%02x\n",
+ dev->name, cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]));
+ }
+ DMA_WBACK_INV(dev, &dma->mc_cmd, sizeof(struct mc_cmd));
+ i596_add_cmd(dev, &cmd->cmd);
+ }
+}
diff --git a/drivers/net/mlx4/qp.c b/drivers/net/mlx4/qp.c
index 7f8b7d55b6e1..492cfaaaa75c 100644
--- a/drivers/net/mlx4/qp.c
+++ b/drivers/net/mlx4/qp.c
@@ -113,8 +113,7 @@ int mlx4_qp_modify(struct mlx4_dev *dev, struct mlx4_mtt *mtt,
struct mlx4_cmd_mailbox *mailbox;
int ret = 0;
- if (cur_state < 0 || cur_state >= MLX4_QP_NUM_STATE ||
- new_state < 0 || cur_state >= MLX4_QP_NUM_STATE ||
+ if (cur_state >= MLX4_QP_NUM_STATE || cur_state >= MLX4_QP_NUM_STATE ||
!op[cur_state][new_state])
return -EINVAL;
diff --git a/drivers/net/netxen/netxen_nic_niu.c b/drivers/net/netxen/netxen_nic_niu.c
index 75102d30730f..05e0577a0e10 100644
--- a/drivers/net/netxen/netxen_nic_niu.c
+++ b/drivers/net/netxen/netxen_nic_niu.c
@@ -724,7 +724,7 @@ int netxen_niu_disable_gbe_port(struct netxen_adapter *adapter)
__u32 mac_cfg0;
u32 port = physical_port[adapter->portnum];
- if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS))
+ if (port > NETXEN_NIU_MAX_GBE_PORTS)
return -EINVAL;
mac_cfg0 = 0;
netxen_gb_soft_reset(mac_cfg0);
@@ -757,7 +757,7 @@ int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter,
__u32 reg;
u32 port = physical_port[adapter->portnum];
- if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS))
+ if (port > NETXEN_NIU_MAX_GBE_PORTS)
return -EINVAL;
/* save previous contents */
@@ -894,7 +894,7 @@ int netxen_niu_xg_set_promiscuous_mode(struct netxen_adapter *adapter,
__u32 reg;
u32 port = physical_port[adapter->portnum];
- if ((port < 0) || (port > NETXEN_NIU_MAX_XG_PORTS))
+ if (port > NETXEN_NIU_MAX_XG_PORTS)
return -EINVAL;
if (netxen_nic_hw_read_wx(adapter,
diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c
index 8d38425e46c3..0b3066a6fe40 100644
--- a/drivers/net/pasemi_mac.c
+++ b/drivers/net/pasemi_mac.c
@@ -755,7 +755,7 @@ static int pasemi_mac_open(struct net_device *dev)
flags |= PAS_MAC_CFG_PCFG_TSR_1G | PAS_MAC_CFG_PCFG_SPD_1G;
pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_RXCH_CFG(mac->dma_rxch),
- PAS_IOB_DMA_RXCH_CFG_CNTTH(1));
+ PAS_IOB_DMA_RXCH_CFG_CNTTH(0));
pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_TXCH_CFG(mac->dma_txch),
PAS_IOB_DMA_TXCH_CFG_CNTTH(32));
diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c
index 808fae1577e0..50dff1b81d34 100644
--- a/drivers/net/pcmcia/axnet_cs.c
+++ b/drivers/net/pcmcia/axnet_cs.c
@@ -521,6 +521,7 @@ static void mdio_write(kio_addr_t addr, int phy_id, int loc, int value)
static int axnet_open(struct net_device *dev)
{
+ int ret;
axnet_dev_t *info = PRIV(dev);
struct pcmcia_device *link = info->p_dev;
@@ -529,9 +530,11 @@ static int axnet_open(struct net_device *dev)
if (!pcmcia_dev_present(link))
return -ENODEV;
- link->open++;
+ ret = request_irq(dev->irq, ei_irq_wrapper, IRQF_SHARED, "axnet_cs", dev);
+ if (ret)
+ return ret;
- request_irq(dev->irq, ei_irq_wrapper, IRQF_SHARED, "axnet_cs", dev);
+ link->open++;
info->link_status = 0x00;
init_timer(&info->watchdog);
diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c
index 3f93d4933235..85d5f2ca4bb5 100644
--- a/drivers/net/pcmcia/fmvj18x_cs.c
+++ b/drivers/net/pcmcia/fmvj18x_cs.c
@@ -109,7 +109,7 @@ static const struct ethtool_ops netdev_ethtool_ops;
card type
*/
typedef enum { MBH10302, MBH10304, TDK, CONTEC, LA501, UNGERMANN,
- XXX10304
+ XXX10304, NEC, KME
} cardtype_t;
/*
@@ -374,6 +374,18 @@ static int fmvj18x_config(struct pcmcia_device *link)
link->io.NumPorts2 = 8;
}
break;
+ case MANFID_NEC:
+ cardtype = NEC; /* MultiFunction Card */
+ link->conf.ConfigBase = 0x800;
+ link->conf.ConfigIndex = 0x47;
+ link->io.NumPorts2 = 8;
+ break;
+ case MANFID_KME:
+ cardtype = KME; /* MultiFunction Card */
+ link->conf.ConfigBase = 0x800;
+ link->conf.ConfigIndex = 0x47;
+ link->io.NumPorts2 = 8;
+ break;
case MANFID_CONTEC:
cardtype = CONTEC;
break;
@@ -450,6 +462,8 @@ static int fmvj18x_config(struct pcmcia_device *link)
case TDK:
case LA501:
case CONTEC:
+ case NEC:
+ case KME:
tuple.DesiredTuple = CISTPL_FUNCE;
tuple.TupleOffset = 0;
CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
@@ -469,6 +483,10 @@ static int fmvj18x_config(struct pcmcia_device *link)
card_name = "TDK LAK-CD021";
} else if( cardtype == LA501 ) {
card_name = "LA501";
+ } else if( cardtype == NEC ) {
+ card_name = "PK-UG-J001";
+ } else if( cardtype == KME ) {
+ card_name = "Panasonic";
} else {
card_name = "C-NET(PC)C";
}
@@ -678,8 +696,11 @@ static struct pcmcia_device_id fmvj18x_ids[] = {
PCMCIA_DEVICE_PROD_ID1("PCMCIA MBH10302", 0x8f4005da),
PCMCIA_DEVICE_PROD_ID1("UBKK,V2.0", 0x90888080),
PCMCIA_PFC_DEVICE_PROD_ID12(0, "TDK", "GlobalNetworker 3410/3412", 0x1eae9475, 0xd9a93bed),
+ PCMCIA_PFC_DEVICE_PROD_ID12(0, "NEC", "PK-UG-J001" ,0x18df0ba0 ,0x831b1064),
PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0105, 0x0d0a),
PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0105, 0x0e0a),
+ PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0032, 0x0a05),
+ PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0032, 0x1101),
PCMCIA_DEVICE_NULL,
};
MODULE_DEVICE_TABLE(pcmcia, fmvj18x_ids);
diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c
index d88e9b2e93cf..f2613c29b008 100644
--- a/drivers/net/pcmcia/pcnet_cs.c
+++ b/drivers/net/pcmcia/pcnet_cs.c
@@ -960,6 +960,7 @@ static void mii_phy_probe(struct net_device *dev)
static int pcnet_open(struct net_device *dev)
{
+ int ret;
pcnet_dev_t *info = PRIV(dev);
struct pcmcia_device *link = info->p_dev;
@@ -968,10 +969,12 @@ static int pcnet_open(struct net_device *dev)
if (!pcmcia_dev_present(link))
return -ENODEV;
- link->open++;
-
set_misc_reg(dev);
- request_irq(dev->irq, ei_irq_wrapper, IRQF_SHARED, dev_info, dev);
+ ret = request_irq(dev->irq, ei_irq_wrapper, IRQF_SHARED, dev_info, dev);
+ if (ret)
+ return ret;
+
+ link->open++;
info->phy_id = info->eth_phy;
info->link_status = 0x00;
@@ -1552,6 +1555,7 @@ static struct pcmcia_device_id pcnet_ids[] = {
PCMCIA_PFC_DEVICE_PROD_ID12(0, "Grey Cell", "GCS3000", 0x2a151fac, 0x48b932ae),
PCMCIA_PFC_DEVICE_PROD_ID12(0, "Linksys", "EtherFast 10&100 + 56K PC Card (PCMLM56)", 0x0733cc81, 0xb3765033),
PCMCIA_PFC_DEVICE_PROD_ID12(0, "LINKSYS", "PCMLM336", 0xf7cb0b07, 0x7a821b58),
+ PCMCIA_PFC_DEVICE_PROD_ID12(0, "MICRO RESEARCH", "COMBO-L/M-336", 0xb2ced065, 0x3ced0555),
PCMCIA_PFC_DEVICE_PROD_ID12(0, "PCMCIAs", "ComboCard", 0xdcfe12d3, 0xcd8906cc),
PCMCIA_PFC_DEVICE_PROD_ID12(0, "PCMCIAs", "LanModem", 0xdcfe12d3, 0xc67c648f),
PCMCIA_MFC_DEVICE_PROD_ID12(0, "IBM", "Home and Away 28.8 PC Card ", 0xb569a6e5, 0x5bd4ff2c),
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 09b6f259eb92..dd09011c7ee5 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -55,6 +55,11 @@ config BROADCOM_PHY
---help---
Currently supports the BCM5411, BCM5421 and BCM5461 PHYs.
+config ICPLUS_PHY
+ tristate "Drivers for ICPlus PHYs"
+ ---help---
+ Currently supports the IP175C PHY.
+
config FIXED_PHY
tristate "Drivers for PHY emulation on fixed speed/link"
---help---
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index bcd1efbd2a18..8885650647ff 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -11,4 +11,5 @@ obj-$(CONFIG_QSEMI_PHY) += qsemi.o
obj-$(CONFIG_SMSC_PHY) += smsc.o
obj-$(CONFIG_VITESSE_PHY) += vitesse.o
obj-$(CONFIG_BROADCOM_PHY) += broadcom.o
+obj-$(CONFIG_ICPLUS_PHY) += icplus.o
obj-$(CONFIG_FIXED_PHY) += fixed.o
diff --git a/drivers/net/phy/icplus.c b/drivers/net/phy/icplus.c
new file mode 100644
index 000000000000..af3f1f2a9f87
--- /dev/null
+++ b/drivers/net/phy/icplus.c
@@ -0,0 +1,134 @@
+/*
+ * Driver for ICPlus PHYs
+ *
+ * Copyright (c) 2007 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/phy.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+MODULE_DESCRIPTION("ICPlus IP175C PHY driver");
+MODULE_AUTHOR("Michael Barkowski");
+MODULE_LICENSE("GPL");
+
+static int ip175c_config_init(struct phy_device *phydev)
+{
+ int err, i;
+ static int full_reset_performed = 0;
+
+ if (full_reset_performed == 0) {
+
+ /* master reset */
+ err = phydev->bus->write(phydev->bus, 30, 0, 0x175c);
+ if (err < 0)
+ return err;
+
+ /* ensure no bus delays overlap reset period */
+ err = phydev->bus->read(phydev->bus, 30, 0);
+
+ /* data sheet specifies reset period is 2 msec */
+ mdelay(2);
+
+ /* enable IP175C mode */
+ err = phydev->bus->write(phydev->bus, 29, 31, 0x175c);
+ if (err < 0)
+ return err;
+
+ /* Set MII0 speed and duplex (in PHY mode) */
+ err = phydev->bus->write(phydev->bus, 29, 22, 0x420);
+ if (err < 0)
+ return err;
+
+ /* reset switch ports */
+ for (i = 0; i < 5; i++) {
+ err = phydev->bus->write(phydev->bus, i,
+ MII_BMCR, BMCR_RESET);
+ if (err < 0)
+ return err;
+ }
+
+ for (i = 0; i < 5; i++)
+ err = phydev->bus->read(phydev->bus, i, MII_BMCR);
+
+ mdelay(2);
+
+ full_reset_performed = 1;
+ }
+
+ if (phydev->addr != 4) {
+ phydev->state = PHY_RUNNING;
+ phydev->speed = SPEED_100;
+ phydev->duplex = DUPLEX_FULL;
+ phydev->link = 1;
+ netif_carrier_on(phydev->attached_dev);
+ }
+
+ return 0;
+}
+
+static int ip175c_read_status(struct phy_device *phydev)
+{
+ if (phydev->addr == 4) /* WAN port */
+ genphy_read_status(phydev);
+ else
+ /* Don't need to read status for switch ports */
+ phydev->irq = PHY_IGNORE_INTERRUPT;
+
+ return 0;
+}
+
+static int ip175c_config_aneg(struct phy_device *phydev)
+{
+ if (phydev->addr == 4) /* WAN port */
+ genphy_config_aneg(phydev);
+
+ return 0;
+}
+
+static struct phy_driver ip175c_driver = {
+ .phy_id = 0x02430d80,
+ .name = "ICPlus IP175C",
+ .phy_id_mask = 0x0ffffff0,
+ .features = PHY_BASIC_FEATURES,
+ .config_init = &ip175c_config_init,
+ .config_aneg = &ip175c_config_aneg,
+ .read_status = &ip175c_read_status,
+ .driver = { .owner = THIS_MODULE,},
+};
+
+static int __init ip175c_init(void)
+{
+ return phy_driver_register(&ip175c_driver);
+}
+
+static void __exit ip175c_exit(void)
+{
+ phy_driver_unregister(&ip175c_driver);
+}
+
+module_init(ip175c_init);
+module_exit(ip175c_exit);
diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c
index b87f8d2a888b..fbe1104e9a07 100644
--- a/drivers/net/phy/marvell.c
+++ b/drivers/net/phy/marvell.c
@@ -60,6 +60,7 @@
#define MII_M1111_PHY_EXT_SR 0x1b
#define MII_M1111_HWCFG_MODE_MASK 0xf
#define MII_M1111_HWCFG_MODE_RGMII 0xb
+#define MII_M1111_HWCFG_MODE_SGMII_NO_CLK 0x4
MODULE_DESCRIPTION("Marvell PHY driver");
MODULE_AUTHOR("Andy Fleming");
@@ -169,6 +170,21 @@ static int m88e1111_config_init(struct phy_device *phydev)
return err;
}
+ if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
+ int temp;
+
+ temp = phy_read(phydev, MII_M1111_PHY_EXT_SR);
+ if (temp < 0)
+ return temp;
+
+ temp &= ~(MII_M1111_HWCFG_MODE_MASK);
+ temp |= MII_M1111_HWCFG_MODE_SGMII_NO_CLK;
+
+ err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp);
+ if (err < 0)
+ return err;
+ }
+
err = phy_write(phydev, MII_BMCR, BMCR_RESET);
if (err < 0)
return err;
diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c
index 585be044ebbb..8be8be451ada 100755
--- a/drivers/net/qla3xxx.c
+++ b/drivers/net/qla3xxx.c
@@ -2433,37 +2433,22 @@ static int ql_get_seg_count(struct ql3_adapter *qdev,
return -1;
}
-static void ql_hw_csum_setup(struct sk_buff *skb,
+static void ql_hw_csum_setup(const struct sk_buff *skb,
struct ob_mac_iocb_req *mac_iocb_ptr)
{
- struct ethhdr *eth;
- struct iphdr *ip = NULL;
- u8 offset = ETH_HLEN;
+ const struct iphdr *ip = ip_hdr(skb);
- eth = (struct ethhdr *)(skb->data);
+ mac_iocb_ptr->ip_hdr_off = skb_network_offset(skb);
+ mac_iocb_ptr->ip_hdr_len = ip->ihl;
- if (eth->h_proto == __constant_htons(ETH_P_IP)) {
- ip = (struct iphdr *)&skb->data[ETH_HLEN];
- } else if (eth->h_proto == htons(ETH_P_8021Q) &&
- ((struct vlan_ethhdr *)skb->data)->
- h_vlan_encapsulated_proto == __constant_htons(ETH_P_IP)) {
- ip = (struct iphdr *)&skb->data[VLAN_ETH_HLEN];
- offset = VLAN_ETH_HLEN;
- }
-
- if (ip) {
- if (ip->protocol == IPPROTO_TCP) {
- mac_iocb_ptr->flags1 |= OB_3032MAC_IOCB_REQ_TC |
+ if (ip->protocol == IPPROTO_TCP) {
+ mac_iocb_ptr->flags1 |= OB_3032MAC_IOCB_REQ_TC |
OB_3032MAC_IOCB_REQ_IC;
- mac_iocb_ptr->ip_hdr_off = offset;
- mac_iocb_ptr->ip_hdr_len = ip->ihl;
- } else if (ip->protocol == IPPROTO_UDP) {
- mac_iocb_ptr->flags1 |= OB_3032MAC_IOCB_REQ_UC |
+ } else {
+ mac_iocb_ptr->flags1 |= OB_3032MAC_IOCB_REQ_UC |
OB_3032MAC_IOCB_REQ_IC;
- mac_iocb_ptr->ip_hdr_off = offset;
- mac_iocb_ptr->ip_hdr_len = ip->ihl;
- }
}
+
}
/*
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
index 5ec7752caa48..982a9010c7a9 100644
--- a/drivers/net/r8169.c
+++ b/drivers/net/r8169.c
@@ -1,53 +1,11 @@
/*
-=========================================================================
- r8169.c: A RealTek RTL-8169 Gigabit Ethernet driver for Linux kernel 2.4.x.
- --------------------------------------------------------------------
-
- History:
- Feb 4 2002 - created initially by ShuChen <shuchen@realtek.com.tw>.
- May 20 2002 - Add link status force-mode and TBI mode support.
- 2004 - Massive updates. See kernel SCM system for details.
-=========================================================================
- 1. [DEPRECATED: use ethtool instead] The media can be forced in 5 modes.
- Command: 'insmod r8169 media = SET_MEDIA'
- Ex: 'insmod r8169 media = 0x04' will force PHY to operate in 100Mpbs Half-duplex.
-
- SET_MEDIA can be:
- _10_Half = 0x01
- _10_Full = 0x02
- _100_Half = 0x04
- _100_Full = 0x08
- _1000_Full = 0x10
-
- 2. Support TBI mode.
-=========================================================================
-VERSION 1.1 <2002/10/4>
-
- The bit4:0 of MII register 4 is called "selector field", and have to be
- 00001b to indicate support of IEEE std 802.3 during NWay process of
- exchanging Link Code Word (FLP).
-
-VERSION 1.2 <2002/11/30>
-
- - Large style cleanup
- - Use ether_crc in stock kernel (linux/crc32.h)
- - Copy mc_filter setup code from 8139cp
- (includes an optimization, and avoids set_bit use)
-
-VERSION 1.6LK <2004/04/14>
-
- - Merge of Realtek's version 1.6
- - Conversion to DMA API
- - Suspend/resume
- - Endianness
- - Misc Rx/Tx bugs
-
-VERSION 2.2LK <2005/01/25>
-
- - RX csum, TX csum/SG, TSO
- - VLAN
- - baby (< 7200) Jumbo frames support
- - Merge of Realtek's version 2.2 (new phy)
+ * r8169.c: RealTek 8169/8168/8101 ethernet driver.
+ *
+ * Copyright (c) 2002 ShuChen <shuchen@realtek.com.tw>
+ * Copyright (c) 2003 - 2007 Francois Romieu <romieu@fr.zoreil.com>
+ * Copyright (c) a lot of people too. Please respect their work.
+ *
+ * See MAINTAINERS file for support contact information.
*/
#include <linux/module.h>
@@ -108,11 +66,6 @@ VERSION 2.2LK <2005/01/25>
#define rtl8169_rx_quota(count, quota) count
#endif
-/* media options */
-#define MAX_UNITS 8
-static int media[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1 };
-static int num_media = 0;
-
/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
static const int max_interrupt_work = 20;
@@ -126,7 +79,7 @@ static const int multicast_filter_limit = 32;
#define RX_FIFO_THRESH 7 /* 7 means NO threshold, Rx buffer level before first PCI xfer. */
#define RX_DMA_BURST 6 /* Maximum PCI burst, '6' is 1024 */
#define TX_DMA_BURST 6 /* Maximum PCI burst, '6' is 1024 */
-#define EarlyTxThld 0x3F /* 0x3F means NO early transmit */
+#define EarlyTxThld 0x3F /* 0x3F means NO early transmit */
#define RxPacketMaxSize 0x3FE8 /* 16K - 1 - ETH_HLEN - VLAN - CRC... */
#define SafeMtu 0x1c20 /* ... actually life sucks beyond ~7k */
#define InterFrameGap 0x03 /* 3 means InterFrameGap = the shortest one */
@@ -151,16 +104,17 @@ static const int multicast_filter_limit = 32;
#define RTL_R32(reg) ((unsigned long) readl (ioaddr + (reg)))
enum mac_version {
- RTL_GIGA_MAC_VER_01 = 0x00,
- RTL_GIGA_MAC_VER_02 = 0x01,
- RTL_GIGA_MAC_VER_03 = 0x02,
- RTL_GIGA_MAC_VER_04 = 0x03,
- RTL_GIGA_MAC_VER_05 = 0x04,
- RTL_GIGA_MAC_VER_11 = 0x0b,
- RTL_GIGA_MAC_VER_12 = 0x0c,
- RTL_GIGA_MAC_VER_13 = 0x0d,
- RTL_GIGA_MAC_VER_14 = 0x0e,
- RTL_GIGA_MAC_VER_15 = 0x0f
+ RTL_GIGA_MAC_VER_01 = 0x01, // 8169
+ RTL_GIGA_MAC_VER_02 = 0x02, // 8169S
+ RTL_GIGA_MAC_VER_03 = 0x03, // 8110S
+ RTL_GIGA_MAC_VER_04 = 0x04, // 8169SB
+ RTL_GIGA_MAC_VER_05 = 0x05, // 8110SCd
+ RTL_GIGA_MAC_VER_06 = 0x06, // 8110SCe
+ RTL_GIGA_MAC_VER_11 = 0x0b, // 8168Bb
+ RTL_GIGA_MAC_VER_12 = 0x0c, // 8168Be 8168Bf
+ RTL_GIGA_MAC_VER_13 = 0x0d, // 8101Eb 8101Ec
+ RTL_GIGA_MAC_VER_14 = 0x0e, // 8101
+ RTL_GIGA_MAC_VER_15 = 0x0f // 8101
};
enum phy_version {
@@ -180,11 +134,12 @@ static const struct {
u8 mac_version;
u32 RxConfigMask; /* Clears the bits supported by this chip */
} rtl_chip_info[] = {
- _R("RTL8169", RTL_GIGA_MAC_VER_01, 0xff7e1880),
- _R("RTL8169s/8110s", RTL_GIGA_MAC_VER_02, 0xff7e1880),
- _R("RTL8169s/8110s", RTL_GIGA_MAC_VER_03, 0xff7e1880),
- _R("RTL8169sb/8110sb", RTL_GIGA_MAC_VER_04, 0xff7e1880),
- _R("RTL8169sc/8110sc", RTL_GIGA_MAC_VER_05, 0xff7e1880),
+ _R("RTL8169", RTL_GIGA_MAC_VER_01, 0xff7e1880), // 8169
+ _R("RTL8169s", RTL_GIGA_MAC_VER_02, 0xff7e1880), // 8169S
+ _R("RTL8110s", RTL_GIGA_MAC_VER_03, 0xff7e1880), // 8110S
+ _R("RTL8169sb/8110sb", RTL_GIGA_MAC_VER_04, 0xff7e1880), // 8169SB
+ _R("RTL8169sc/8110sc", RTL_GIGA_MAC_VER_05, 0xff7e1880), // 8110SCd
+ _R("RTL8169sc/8110sc", RTL_GIGA_MAC_VER_06, 0xff7e1880), // 8110SCe
_R("RTL8168b/8111b", RTL_GIGA_MAC_VER_11, 0xff7e1880), // PCI-E
_R("RTL8168b/8111b", RTL_GIGA_MAC_VER_12, 0xff7e1880), // PCI-E
_R("RTL8101e", RTL_GIGA_MAC_VER_13, 0xff7e1880), // PCI-E 8139
@@ -199,20 +154,15 @@ enum cfg_version {
RTL_CFG_2
};
-static const struct {
- unsigned int region;
- unsigned int align;
-} rtl_cfg_info[] = {
- [RTL_CFG_0] = { 1, NET_IP_ALIGN },
- [RTL_CFG_1] = { 2, NET_IP_ALIGN },
- [RTL_CFG_2] = { 2, 8 }
-};
+static void rtl_hw_start_8169(struct net_device *);
+static void rtl_hw_start_8168(struct net_device *);
+static void rtl_hw_start_8101(struct net_device *);
static struct pci_device_id rtl8169_pci_tbl[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8129), 0, 0, RTL_CFG_0 },
{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8136), 0, 0, RTL_CFG_2 },
{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8167), 0, 0, RTL_CFG_0 },
- { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8168), 0, 0, RTL_CFG_2 },
+ { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8168), 0, 0, RTL_CFG_1 },
{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8169), 0, 0, RTL_CFG_0 },
{ PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4300), 0, 0, RTL_CFG_0 },
{ PCI_DEVICE(0x1259, 0xc107), 0, 0, RTL_CFG_0 },
@@ -230,62 +180,63 @@ static struct {
u32 msg_enable;
} debug = { -1 };
-enum RTL8169_registers {
- MAC0 = 0, /* Ethernet hardware address. */
- MAR0 = 8, /* Multicast filter. */
- CounterAddrLow = 0x10,
- CounterAddrHigh = 0x14,
- TxDescStartAddrLow = 0x20,
- TxDescStartAddrHigh = 0x24,
- TxHDescStartAddrLow = 0x28,
- TxHDescStartAddrHigh = 0x2c,
- FLASH = 0x30,
- ERSR = 0x36,
- ChipCmd = 0x37,
- TxPoll = 0x38,
- IntrMask = 0x3C,
- IntrStatus = 0x3E,
- TxConfig = 0x40,
- RxConfig = 0x44,
- RxMissed = 0x4C,
- Cfg9346 = 0x50,
- Config0 = 0x51,
- Config1 = 0x52,
- Config2 = 0x53,
- Config3 = 0x54,
- Config4 = 0x55,
- Config5 = 0x56,
- MultiIntr = 0x5C,
- PHYAR = 0x60,
- TBICSR = 0x64,
- TBI_ANAR = 0x68,
- TBI_LPAR = 0x6A,
- PHYstatus = 0x6C,
- RxMaxSize = 0xDA,
- CPlusCmd = 0xE0,
- IntrMitigate = 0xE2,
- RxDescAddrLow = 0xE4,
- RxDescAddrHigh = 0xE8,
- EarlyTxThres = 0xEC,
- FuncEvent = 0xF0,
- FuncEventMask = 0xF4,
- FuncPresetState = 0xF8,
- FuncForceEvent = 0xFC,
+enum rtl_registers {
+ MAC0 = 0, /* Ethernet hardware address. */
+ MAC4 = 4,
+ MAR0 = 8, /* Multicast filter. */
+ CounterAddrLow = 0x10,
+ CounterAddrHigh = 0x14,
+ TxDescStartAddrLow = 0x20,
+ TxDescStartAddrHigh = 0x24,
+ TxHDescStartAddrLow = 0x28,
+ TxHDescStartAddrHigh = 0x2c,
+ FLASH = 0x30,
+ ERSR = 0x36,
+ ChipCmd = 0x37,
+ TxPoll = 0x38,
+ IntrMask = 0x3c,
+ IntrStatus = 0x3e,
+ TxConfig = 0x40,
+ RxConfig = 0x44,
+ RxMissed = 0x4c,
+ Cfg9346 = 0x50,
+ Config0 = 0x51,
+ Config1 = 0x52,
+ Config2 = 0x53,
+ Config3 = 0x54,
+ Config4 = 0x55,
+ Config5 = 0x56,
+ MultiIntr = 0x5c,
+ PHYAR = 0x60,
+ TBICSR = 0x64,
+ TBI_ANAR = 0x68,
+ TBI_LPAR = 0x6a,
+ PHYstatus = 0x6c,
+ RxMaxSize = 0xda,
+ CPlusCmd = 0xe0,
+ IntrMitigate = 0xe2,
+ RxDescAddrLow = 0xe4,
+ RxDescAddrHigh = 0xe8,
+ EarlyTxThres = 0xec,
+ FuncEvent = 0xf0,
+ FuncEventMask = 0xf4,
+ FuncPresetState = 0xf8,
+ FuncForceEvent = 0xfc,
};
-enum RTL8169_register_content {
+enum rtl_register_content {
/* InterruptStatusBits */
- SYSErr = 0x8000,
- PCSTimeout = 0x4000,
- SWInt = 0x0100,
- TxDescUnavail = 0x80,
- RxFIFOOver = 0x40,
- LinkChg = 0x20,
- RxOverflow = 0x10,
- TxErr = 0x08,
- TxOK = 0x04,
- RxErr = 0x02,
- RxOK = 0x01,
+ SYSErr = 0x8000,
+ PCSTimeout = 0x4000,
+ SWInt = 0x0100,
+ TxDescUnavail = 0x0080,
+ RxFIFOOver = 0x0040,
+ LinkChg = 0x0020,
+ RxOverflow = 0x0010,
+ TxErr = 0x0008,
+ TxOK = 0x0004,
+ RxErr = 0x0002,
+ RxOK = 0x0001,
/* RxStatusDesc */
RxFOVF = (1 << 23),
@@ -295,26 +246,31 @@ enum RTL8169_register_content {
RxCRC = (1 << 19),
/* ChipCmdBits */
- CmdReset = 0x10,
- CmdRxEnb = 0x08,
- CmdTxEnb = 0x04,
- RxBufEmpty = 0x01,
+ CmdReset = 0x10,
+ CmdRxEnb = 0x08,
+ CmdTxEnb = 0x04,
+ RxBufEmpty = 0x01,
+
+ /* TXPoll register p.5 */
+ HPQ = 0x80, /* Poll cmd on the high prio queue */
+ NPQ = 0x40, /* Poll cmd on the low prio queue */
+ FSWInt = 0x01, /* Forced software interrupt */
/* Cfg9346Bits */
- Cfg9346_Lock = 0x00,
- Cfg9346_Unlock = 0xC0,
+ Cfg9346_Lock = 0x00,
+ Cfg9346_Unlock = 0xc0,
/* rx_mode_bits */
- AcceptErr = 0x20,
- AcceptRunt = 0x10,
- AcceptBroadcast = 0x08,
- AcceptMulticast = 0x04,
- AcceptMyPhys = 0x02,
- AcceptAllPhys = 0x01,
+ AcceptErr = 0x20,
+ AcceptRunt = 0x10,
+ AcceptBroadcast = 0x08,
+ AcceptMulticast = 0x04,
+ AcceptMyPhys = 0x02,
+ AcceptAllPhys = 0x01,
/* RxConfigBits */
- RxCfgFIFOShift = 13,
- RxCfgDMAShift = 8,
+ RxCfgFIFOShift = 13,
+ RxCfgDMAShift = 8,
/* TxConfigBits */
TxInterFrameGapShift = 24,
@@ -323,6 +279,10 @@ enum RTL8169_register_content {
/* Config1 register p.24 */
PMEnable = (1 << 0), /* Power Management Enable */
+ /* Config2 register p. 25 */
+ PCI_Clock_66MHz = 0x01,
+ PCI_Clock_33MHz = 0x00,
+
/* Config3 register p.25 */
MagicPacket = (1 << 5), /* Wake up when receives a Magic Packet */
LinkUp = (1 << 4), /* Wake up when the cable connection is re-established */
@@ -343,36 +303,34 @@ enum RTL8169_register_content {
TBINwComplete = 0x01000000,
/* CPlusCmd p.31 */
+ PktCntrDisable = (1 << 7), // 8168
RxVlan = (1 << 6),
RxChkSum = (1 << 5),
PCIDAC = (1 << 4),
PCIMulRW = (1 << 3),
+ INTT_0 = 0x0000, // 8168
+ INTT_1 = 0x0001, // 8168
+ INTT_2 = 0x0002, // 8168
+ INTT_3 = 0x0003, // 8168
/* rtl8169_PHYstatus */
- TBI_Enable = 0x80,
- TxFlowCtrl = 0x40,
- RxFlowCtrl = 0x20,
- _1000bpsF = 0x10,
- _100bps = 0x08,
- _10bps = 0x04,
- LinkStatus = 0x02,
- FullDup = 0x01,
-
- /* _MediaType */
- _10_Half = 0x01,
- _10_Full = 0x02,
- _100_Half = 0x04,
- _100_Full = 0x08,
- _1000_Full = 0x10,
+ TBI_Enable = 0x80,
+ TxFlowCtrl = 0x40,
+ RxFlowCtrl = 0x20,
+ _1000bpsF = 0x10,
+ _100bps = 0x08,
+ _10bps = 0x04,
+ LinkStatus = 0x02,
+ FullDup = 0x01,
/* _TBICSRBit */
- TBILinkOK = 0x02000000,
+ TBILinkOK = 0x02000000,
/* DumpCounterCommand */
- CounterDump = 0x8,
+ CounterDump = 0x8,
};
-enum _DescStatusBit {
+enum desc_status_bit {
DescOwn = (1 << 31), /* Descriptor is owned by NIC */
RingEnd = (1 << 30), /* End of descriptor ring */
FirstFrag = (1 << 29), /* First segment of a packet */
@@ -405,15 +363,15 @@ enum _DescStatusBit {
#define RsvdMask 0x3fffc000
struct TxDesc {
- u32 opts1;
- u32 opts2;
- u64 addr;
+ __le32 opts1;
+ __le32 opts2;
+ __le64 addr;
};
struct RxDesc {
- u32 opts1;
- u32 opts2;
- u64 addr;
+ __le32 opts1;
+ __le32 opts2;
+ __le64 addr;
};
struct ring_info {
@@ -446,6 +404,8 @@ struct rtl8169_private {
unsigned rx_buf_sz;
struct timer_list timer;
u16 cp_cmd;
+ u16 intr_event;
+ u16 napi_event;
u16 intr_mask;
int phy_auto_nego_reg;
int phy_1000_ctrl_reg;
@@ -455,6 +415,7 @@ struct rtl8169_private {
int (*set_speed)(struct net_device *, u8 autoneg, u16 speed, u8 duplex);
void (*get_settings)(struct net_device *, struct ethtool_cmd *);
void (*phy_reset_enable)(void __iomem *);
+ void (*hw_start)(struct net_device *);
unsigned int (*phy_reset_pending)(void __iomem *);
unsigned int (*link_ok)(void __iomem *);
struct delayed_work task;
@@ -463,8 +424,6 @@ struct rtl8169_private {
MODULE_AUTHOR("Realtek and the Linux r8169 crew <netdev@vger.kernel.org>");
MODULE_DESCRIPTION("RealTek RTL-8169 Gigabit Ethernet driver");
-module_param_array(media, int, &num_media, 0);
-MODULE_PARM_DESC(media, "force phy operation. Deprecated by ethtool (8).");
module_param(rx_copybreak, int, 0);
MODULE_PARM_DESC(rx_copybreak, "Copy breakpoint for copy-only-tiny-frames");
module_param(use_dac, int, 0);
@@ -478,9 +437,9 @@ static int rtl8169_open(struct net_device *dev);
static int rtl8169_start_xmit(struct sk_buff *skb, struct net_device *dev);
static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance);
static int rtl8169_init_ring(struct net_device *dev);
-static void rtl8169_hw_start(struct net_device *dev);
+static void rtl_hw_start(struct net_device *dev);
static int rtl8169_close(struct net_device *dev);
-static void rtl8169_set_rx_mode(struct net_device *dev);
+static void rtl_set_rx_mode(struct net_device *dev);
static void rtl8169_tx_timeout(struct net_device *dev);
static struct net_device_stats *rtl8169_get_stats(struct net_device *dev);
static int rtl8169_rx_interrupt(struct net_device *, struct rtl8169_private *,
@@ -493,35 +452,37 @@ static void rtl8169_rx_clear(struct rtl8169_private *tp);
static int rtl8169_poll(struct net_device *dev, int *budget);
#endif
-static const u16 rtl8169_intr_mask =
- SYSErr | LinkChg | RxOverflow | RxFIFOOver | TxErr | TxOK | RxErr | RxOK;
-static const u16 rtl8169_napi_event =
- RxOK | RxOverflow | RxFIFOOver | TxOK | TxErr;
static const unsigned int rtl8169_rx_config =
(RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift);
-static void mdio_write(void __iomem *ioaddr, int RegAddr, int value)
+static void mdio_write(void __iomem *ioaddr, int reg_addr, int value)
{
int i;
- RTL_W32(PHYAR, 0x80000000 | (RegAddr & 0xFF) << 16 | value);
+ RTL_W32(PHYAR, 0x80000000 | (reg_addr & 0xFF) << 16 | value);
for (i = 20; i > 0; i--) {
- /* Check if the RTL8169 has completed writing to the specified MII register */
+ /*
+ * Check if the RTL8169 has completed writing to the specified
+ * MII register.
+ */
if (!(RTL_R32(PHYAR) & 0x80000000))
break;
udelay(25);
}
}
-static int mdio_read(void __iomem *ioaddr, int RegAddr)
+static int mdio_read(void __iomem *ioaddr, int reg_addr)
{
int i, value = -1;
- RTL_W32(PHYAR, 0x0 | (RegAddr & 0xFF) << 16);
+ RTL_W32(PHYAR, 0x0 | (reg_addr & 0xFF) << 16);
for (i = 20; i > 0; i--) {
- /* Check if the RTL8169 has completed retrieving data from the specified MII register */
+ /*
+ * Check if the RTL8169 has completed retrieving data from
+ * the specified MII register.
+ */
if (RTL_R32(PHYAR) & 0x80000000) {
value = (int) (RTL_R32(PHYAR) & 0xFFFF);
break;
@@ -579,7 +540,8 @@ static void rtl8169_xmii_reset_enable(void __iomem *ioaddr)
}
static void rtl8169_check_link_status(struct net_device *dev,
- struct rtl8169_private *tp, void __iomem *ioaddr)
+ struct rtl8169_private *tp,
+ void __iomem *ioaddr)
{
unsigned long flags;
@@ -596,38 +558,6 @@ static void rtl8169_check_link_status(struct net_device *dev,
spin_unlock_irqrestore(&tp->lock, flags);
}
-static void rtl8169_link_option(int idx, u8 *autoneg, u16 *speed, u8 *duplex)
-{
- struct {
- u16 speed;
- u8 duplex;
- u8 autoneg;
- u8 media;
- } link_settings[] = {
- { SPEED_10, DUPLEX_HALF, AUTONEG_DISABLE, _10_Half },
- { SPEED_10, DUPLEX_FULL, AUTONEG_DISABLE, _10_Full },
- { SPEED_100, DUPLEX_HALF, AUTONEG_DISABLE, _100_Half },
- { SPEED_100, DUPLEX_FULL, AUTONEG_DISABLE, _100_Full },
- { SPEED_1000, DUPLEX_FULL, AUTONEG_DISABLE, _1000_Full },
- /* Make TBI happy */
- { SPEED_1000, DUPLEX_FULL, AUTONEG_ENABLE, 0xff }
- }, *p;
- unsigned char option;
-
- option = ((idx < MAX_UNITS) && (idx >= 0)) ? media[idx] : 0xff;
-
- if ((option != 0xff) && !idx && netif_msg_drv(&debug))
- printk(KERN_WARNING PFX "media option is deprecated.\n");
-
- for (p = link_settings; p->media != 0xff; p++) {
- if (p->media == option)
- break;
- }
- *autoneg = p->autoneg;
- *speed = p->speed;
- *duplex = p->duplex;
-}
-
static void rtl8169_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
{
struct rtl8169_private *tp = netdev_priv(dev);
@@ -667,7 +597,7 @@ static int rtl8169_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
{
struct rtl8169_private *tp = netdev_priv(dev);
void __iomem *ioaddr = tp->mmio_addr;
- int i;
+ unsigned int i;
static struct {
u32 opt;
u16 reg;
@@ -893,8 +823,7 @@ static int rtl8169_rx_vlan_skb(struct rtl8169_private *tp, struct RxDesc *desc,
int ret;
if (tp->vlgrp && (opts2 & RxVlanTag)) {
- rtl8169_rx_hwaccel_skb(skb, tp->vlgrp,
- swab16(opts2 & 0xffff));
+ rtl8169_rx_hwaccel_skb(skb, tp->vlgrp, swab16(opts2 & 0xffff));
ret = 0;
} else
ret = -1;
@@ -1115,7 +1044,6 @@ static void rtl8169_get_strings(struct net_device *dev, u32 stringset, u8 *data)
}
}
-
static const struct ethtool_ops rtl8169_ethtool_ops = {
.get_drvinfo = rtl8169_get_drvinfo,
.get_regs_len = rtl8169_get_regs_len,
@@ -1141,8 +1069,8 @@ static const struct ethtool_ops rtl8169_ethtool_ops = {
.get_perm_addr = ethtool_op_get_perm_addr,
};
-static void rtl8169_write_gmii_reg_bit(void __iomem *ioaddr, int reg, int bitnum,
- int bitval)
+static void rtl8169_write_gmii_reg_bit(void __iomem *ioaddr, int reg,
+ int bitnum, int bitval)
{
int val;
@@ -1152,8 +1080,20 @@ static void rtl8169_write_gmii_reg_bit(void __iomem *ioaddr, int reg, int bitnum
mdio_write(ioaddr, reg, val & 0xffff);
}
-static void rtl8169_get_mac_version(struct rtl8169_private *tp, void __iomem *ioaddr)
+static void rtl8169_get_mac_version(struct rtl8169_private *tp,
+ void __iomem *ioaddr)
{
+ /*
+ * The driver currently handles the 8168Bf and the 8168Be identically
+ * but they can be identified more specifically through the test below
+ * if needed:
+ *
+ * (RTL_R32(TxConfig) & 0x700000) == 0x500000 ? 8168Bf : 8168Be
+ *
+ * Same thing for the 8101Eb and the 8101Ec:
+ *
+ * (RTL_R32(TxConfig) & 0x700000) == 0x200000 ? 8101Eb : 8101Ec
+ */
const struct {
u32 mask;
int mac_version;
@@ -1163,6 +1103,7 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp, void __iomem *io
{ 0x34000000, RTL_GIGA_MAC_VER_13 },
{ 0x30800000, RTL_GIGA_MAC_VER_14 },
{ 0x30000000, RTL_GIGA_MAC_VER_11 },
+ { 0x98000000, RTL_GIGA_MAC_VER_06 },
{ 0x18000000, RTL_GIGA_MAC_VER_05 },
{ 0x10000000, RTL_GIGA_MAC_VER_04 },
{ 0x04000000, RTL_GIGA_MAC_VER_03 },
@@ -1171,7 +1112,7 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp, void __iomem *io
}, *p = mac_info;
u32 reg;
- reg = RTL_R32(TxConfig) & 0x7c800000;
+ reg = RTL_R32(TxConfig) & 0xfc800000;
while ((reg & p->mask) != p->mask)
p++;
tp->mac_version = p->mac_version;
@@ -1182,7 +1123,8 @@ static void rtl8169_print_mac_version(struct rtl8169_private *tp)
dprintk("mac_version = 0x%02x\n", tp->mac_version);
}
-static void rtl8169_get_phy_version(struct rtl8169_private *tp, void __iomem *ioaddr)
+static void rtl8169_get_phy_version(struct rtl8169_private *tp,
+ void __iomem *ioaddr)
{
const struct {
u16 mask;
@@ -1259,7 +1201,7 @@ static void rtl8169_hw_phy_config(struct net_device *dev)
0xbf00 } //w 0 15 0 bf00
}
}, *p = phy_magic;
- int i;
+ unsigned int i;
rtl8169_print_mac_version(tp);
rtl8169_print_phy_version(tp);
@@ -1393,7 +1335,7 @@ static void rtl8169_phy_reset(struct net_device *dev,
struct rtl8169_private *tp)
{
void __iomem *ioaddr = tp->mmio_addr;
- int i;
+ unsigned int i;
tp->phy_reset_enable(ioaddr);
for (i = 0; i < 100; i++) {
@@ -1408,21 +1350,16 @@ static void rtl8169_phy_reset(struct net_device *dev,
static void rtl8169_init_phy(struct net_device *dev, struct rtl8169_private *tp)
{
void __iomem *ioaddr = tp->mmio_addr;
- static int board_idx = -1;
- u8 autoneg, duplex;
- u16 speed;
-
- board_idx++;
rtl8169_hw_phy_config(dev);
dprintk("Set MAC Reg C+CR Offset 0x82h = 0x01h\n");
RTL_W8(0x82, 0x01);
- if (tp->mac_version < RTL_GIGA_MAC_VER_03) {
- dprintk("Set PCI Latency=0x40\n");
- pci_write_config_byte(tp->pci_dev, PCI_LATENCY_TIMER, 0x40);
- }
+ pci_write_config_byte(tp->pci_dev, PCI_LATENCY_TIMER, 0x40);
+
+ if (tp->mac_version <= RTL_GIGA_MAC_VER_06)
+ pci_write_config_byte(tp->pci_dev, PCI_CACHE_LINE_SIZE, 0x08);
if (tp->mac_version == RTL_GIGA_MAC_VER_02) {
dprintk("Set MAC Reg C+CR Offset 0x82h = 0x01h\n");
@@ -1431,16 +1368,52 @@ static void rtl8169_init_phy(struct net_device *dev, struct rtl8169_private *tp)
mdio_write(ioaddr, 0x0b, 0x0000); //w 0x0b 15 0 0
}
- rtl8169_link_option(board_idx, &autoneg, &speed, &duplex);
-
rtl8169_phy_reset(dev, tp);
- rtl8169_set_speed(dev, autoneg, speed, duplex);
+ /*
+ * rtl8169_set_speed_xmii takes good care of the Fast Ethernet
+ * only 8101. Don't panic.
+ */
+ rtl8169_set_speed(dev, AUTONEG_ENABLE, SPEED_1000, DUPLEX_FULL);
if ((RTL_R8(PHYstatus) & TBI_Enable) && netif_msg_link(tp))
printk(KERN_INFO PFX "%s: TBI auto-negotiating\n", dev->name);
}
+static void rtl_rar_set(struct rtl8169_private *tp, u8 *addr)
+{
+ void __iomem *ioaddr = tp->mmio_addr;
+ u32 high;
+ u32 low;
+
+ low = addr[0] | (addr[1] << 8) | (addr[2] << 16) | (addr[3] << 24);
+ high = addr[4] | (addr[5] << 8);
+
+ spin_lock_irq(&tp->lock);
+
+ RTL_W8(Cfg9346, Cfg9346_Unlock);
+ RTL_W32(MAC0, low);
+ RTL_W32(MAC4, high);
+ RTL_W8(Cfg9346, Cfg9346_Lock);
+
+ spin_unlock_irq(&tp->lock);
+}
+
+static int rtl_set_mac_address(struct net_device *dev, void *p)
+{
+ struct rtl8169_private *tp = netdev_priv(dev);
+ struct sockaddr *addr = p;
+
+ if (!is_valid_ether_addr(addr->sa_data))
+ return -EADDRNOTAVAIL;
+
+ memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+
+ rtl_rar_set(tp, dev->dev_addr);
+
+ return 0;
+}
+
static int rtl8169_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
struct rtl8169_private *tp = netdev_priv(dev);
@@ -1467,15 +1440,49 @@ static int rtl8169_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
return -EOPNOTSUPP;
}
+static const struct rtl_cfg_info {
+ void (*hw_start)(struct net_device *);
+ unsigned int region;
+ unsigned int align;
+ u16 intr_event;
+ u16 napi_event;
+} rtl_cfg_infos [] = {
+ [RTL_CFG_0] = {
+ .hw_start = rtl_hw_start_8169,
+ .region = 1,
+ .align = 0,
+ .intr_event = SYSErr | LinkChg | RxOverflow |
+ RxFIFOOver | TxErr | TxOK | RxOK | RxErr,
+ .napi_event = RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow
+ },
+ [RTL_CFG_1] = {
+ .hw_start = rtl_hw_start_8168,
+ .region = 2,
+ .align = 8,
+ .intr_event = SYSErr | LinkChg | RxOverflow |
+ TxErr | TxOK | RxOK | RxErr,
+ .napi_event = TxErr | TxOK | RxOK | RxOverflow
+ },
+ [RTL_CFG_2] = {
+ .hw_start = rtl_hw_start_8101,
+ .region = 2,
+ .align = 8,
+ .intr_event = SYSErr | LinkChg | RxOverflow | PCSTimeout |
+ RxFIFOOver | TxErr | TxOK | RxOK | RxErr,
+ .napi_event = RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow
+ }
+};
+
static int __devinit
rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
- const unsigned int region = rtl_cfg_info[ent->driver_data].region;
+ const struct rtl_cfg_info *cfg = rtl_cfg_infos + ent->driver_data;
+ const unsigned int region = cfg->region;
struct rtl8169_private *tp;
struct net_device *dev;
void __iomem *ioaddr;
- unsigned int pm_cap;
- int i, rc;
+ unsigned int i;
+ int rc;
if (netif_msg_drv(&debug)) {
printk(KERN_INFO "%s Gigabit Ethernet driver %s loaded\n",
@@ -1508,20 +1515,6 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (rc < 0)
goto err_out_disable_2;
- /* save power state before pci_enable_device overwrites it */
- pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
- if (pm_cap) {
- u16 pwr_command, acpi_idle_state;
-
- pci_read_config_word(pdev, pm_cap + PCI_PM_CTRL, &pwr_command);
- acpi_idle_state = pwr_command & PCI_PM_CTRL_STATE_MASK;
- } else {
- if (netif_msg_probe(tp)) {
- dev_err(&pdev->dev,
- "PowerManagement capability not found.\n");
- }
- }
-
/* make sure PCI base addr 1 is MMIO */
if (!(pci_resource_flags(pdev, region) & IORESOURCE_MEM)) {
if (netif_msg_probe(tp)) {
@@ -1585,7 +1578,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
RTL_W8(ChipCmd, CmdReset);
/* Check that the chip has finished the reset. */
- for (i = 100; i > 0; i--) {
+ for (i = 0; i < 100; i++) {
if ((RTL_R8(ChipCmd) & CmdReset) == 0)
break;
msleep_interruptible(1);
@@ -1647,11 +1640,12 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
SET_ETHTOOL_OPS(dev, &rtl8169_ethtool_ops);
dev->stop = rtl8169_close;
dev->tx_timeout = rtl8169_tx_timeout;
- dev->set_multicast_list = rtl8169_set_rx_mode;
+ dev->set_multicast_list = rtl_set_rx_mode;
dev->watchdog_timeo = RTL8169_TX_TIMEOUT;
dev->irq = pdev->irq;
dev->base_addr = (unsigned long) ioaddr;
dev->change_mtu = rtl8169_change_mtu;
+ dev->set_mac_address = rtl_set_mac_address;
#ifdef CONFIG_R8169_NAPI
dev->poll = rtl8169_poll;
@@ -1670,7 +1664,10 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
tp->intr_mask = 0xffff;
tp->pci_dev = pdev;
tp->mmio_addr = ioaddr;
- tp->align = rtl_cfg_info[ent->driver_data].align;
+ tp->align = cfg->align;
+ tp->hw_start = cfg->hw_start;
+ tp->intr_event = cfg->intr_event;
+ tp->napi_event = cfg->napi_event;
init_timer(&tp->timer);
tp->timer.data = (unsigned long) dev;
@@ -1685,15 +1682,17 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
pci_set_drvdata(pdev, dev);
if (netif_msg_probe(tp)) {
+ u32 xid = RTL_R32(TxConfig) & 0x7cf0f8ff;
+
printk(KERN_INFO "%s: %s at 0x%lx, "
"%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
- "IRQ %d\n",
+ "XID %08x IRQ %d\n",
dev->name,
rtl_chip_info[tp->chipset].name,
dev->base_addr,
dev->dev_addr[0], dev->dev_addr[1],
dev->dev_addr[2], dev->dev_addr[3],
- dev->dev_addr[4], dev->dev_addr[5], dev->irq);
+ dev->dev_addr[4], dev->dev_addr[5], xid, dev->irq);
}
rtl8169_init_phy(dev, tp);
@@ -1714,15 +1713,11 @@ err_out_free_dev_1:
goto out;
}
-static void __devexit
-rtl8169_remove_one(struct pci_dev *pdev)
+static void __devexit rtl8169_remove_one(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
struct rtl8169_private *tp = netdev_priv(dev);
- assert(dev != NULL);
- assert(tp != NULL);
-
flush_scheduled_work();
unregister_netdev(dev);
@@ -1774,7 +1769,7 @@ static int rtl8169_open(struct net_device *dev)
if (retval < 0)
goto err_release_ring_2;
- rtl8169_hw_start(dev);
+ rtl_hw_start(dev);
rtl8169_request_timer(dev);
@@ -1805,7 +1800,7 @@ static void rtl8169_hw_reset(void __iomem *ioaddr)
RTL_R8(ChipCmd);
}
-static void rtl8169_set_rx_tx_config_registers(struct rtl8169_private *tp)
+static void rtl_set_rx_tx_config_registers(struct rtl8169_private *tp)
{
void __iomem *ioaddr = tp->mmio_addr;
u32 cfg = rtl8169_rx_config;
@@ -1818,45 +1813,90 @@ static void rtl8169_set_rx_tx_config_registers(struct rtl8169_private *tp)
(InterFrameGap << TxInterFrameGapShift));
}
-static void rtl8169_hw_start(struct net_device *dev)
+static void rtl_hw_start(struct net_device *dev)
{
struct rtl8169_private *tp = netdev_priv(dev);
void __iomem *ioaddr = tp->mmio_addr;
- struct pci_dev *pdev = tp->pci_dev;
- u16 cmd;
- u32 i;
+ unsigned int i;
/* Soft reset the chip. */
RTL_W8(ChipCmd, CmdReset);
/* Check that the chip has finished the reset. */
- for (i = 100; i > 0; i--) {
+ for (i = 0; i < 100; i++) {
if ((RTL_R8(ChipCmd) & CmdReset) == 0)
break;
msleep_interruptible(1);
}
- if (tp->mac_version == RTL_GIGA_MAC_VER_05) {
- RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) | PCIMulRW);
- pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x08);
- }
+ tp->hw_start(dev);
- if (tp->mac_version == RTL_GIGA_MAC_VER_13) {
- pci_write_config_word(pdev, 0x68, 0x00);
- pci_write_config_word(pdev, 0x69, 0x08);
- }
+ netif_start_queue(dev);
+}
- /* Undocumented stuff. */
- if (tp->mac_version == RTL_GIGA_MAC_VER_05) {
- /* Realtek's r1000_n.c driver uses '&& 0x01' here. Well... */
- if ((RTL_R8(Config2) & 0x07) & 0x01)
- RTL_W32(0x7c, 0x0007ffff);
- RTL_W32(0x7c, 0x0007ff00);
+static void rtl_set_rx_tx_desc_registers(struct rtl8169_private *tp,
+ void __iomem *ioaddr)
+{
+ /*
+ * Magic spell: some iop3xx ARM board needs the TxDescAddrHigh
+ * register to be written before TxDescAddrLow to work.
+ * Switching from MMIO to I/O access fixes the issue as well.
+ */
+ RTL_W32(TxDescStartAddrHigh, ((u64) tp->TxPhyAddr) >> 32);
+ RTL_W32(TxDescStartAddrLow, ((u64) tp->TxPhyAddr) & DMA_32BIT_MASK);
+ RTL_W32(RxDescAddrHigh, ((u64) tp->RxPhyAddr) >> 32);
+ RTL_W32(RxDescAddrLow, ((u64) tp->RxPhyAddr) & DMA_32BIT_MASK);
+}
+
+static u16 rtl_rw_cpluscmd(void __iomem *ioaddr)
+{
+ u16 cmd;
+
+ cmd = RTL_R16(CPlusCmd);
+ RTL_W16(CPlusCmd, cmd);
+ return cmd;
+}
+
+static void rtl_set_rx_max_size(void __iomem *ioaddr)
+{
+ /* Low hurts. Let's disable the filtering. */
+ RTL_W16(RxMaxSize, 16383);
+}
+
+static void rtl8169_set_magic_reg(void __iomem *ioaddr, unsigned mac_version)
+{
+ struct {
+ u32 mac_version;
+ u32 clk;
+ u32 val;
+ } cfg2_info [] = {
+ { RTL_GIGA_MAC_VER_05, PCI_Clock_33MHz, 0x000fff00 }, // 8110SCd
+ { RTL_GIGA_MAC_VER_05, PCI_Clock_66MHz, 0x000fffff },
+ { RTL_GIGA_MAC_VER_06, PCI_Clock_33MHz, 0x00ffff00 }, // 8110SCe
+ { RTL_GIGA_MAC_VER_06, PCI_Clock_66MHz, 0x00ffffff }
+ }, *p = cfg2_info;
+ unsigned int i;
+ u32 clk;
- pci_read_config_word(pdev, PCI_COMMAND, &cmd);
- cmd = cmd & 0xef;
- pci_write_config_word(pdev, PCI_COMMAND, cmd);
+ clk = RTL_R8(Config2) & PCI_Clock_66MHz;
+ for (i = 0; i < ARRAY_SIZE(cfg2_info); i++) {
+ if ((p->mac_version == mac_version) && (p->clk == clk)) {
+ RTL_W32(0x7c, p->val);
+ break;
+ }
+ }
+}
+
+static void rtl_hw_start_8169(struct net_device *dev)
+{
+ struct rtl8169_private *tp = netdev_priv(dev);
+ void __iomem *ioaddr = tp->mmio_addr;
+ struct pci_dev *pdev = tp->pci_dev;
+
+ if (tp->mac_version == RTL_GIGA_MAC_VER_05) {
+ RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) | PCIMulRW);
+ pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x08);
}
RTL_W8(Cfg9346, Cfg9346_Unlock);
@@ -1868,19 +1908,11 @@ static void rtl8169_hw_start(struct net_device *dev)
RTL_W8(EarlyTxThres, EarlyTxThld);
- /* Low hurts. Let's disable the filtering. */
- RTL_W16(RxMaxSize, 16383);
-
- if ((tp->mac_version == RTL_GIGA_MAC_VER_01) ||
- (tp->mac_version == RTL_GIGA_MAC_VER_02) ||
- (tp->mac_version == RTL_GIGA_MAC_VER_03) ||
- (tp->mac_version == RTL_GIGA_MAC_VER_04))
- rtl8169_set_rx_tx_config_registers(tp);
+ rtl_set_rx_max_size(ioaddr);
- cmd = RTL_R16(CPlusCmd);
- RTL_W16(CPlusCmd, cmd);
+ rtl_set_rx_tx_config_registers(tp);
- tp->cp_cmd |= cmd | PCIMulRW;
+ tp->cp_cmd |= rtl_rw_cpluscmd(ioaddr) | PCIMulRW;
if ((tp->mac_version == RTL_GIGA_MAC_VER_02) ||
(tp->mac_version == RTL_GIGA_MAC_VER_03)) {
@@ -1891,29 +1923,15 @@ static void rtl8169_hw_start(struct net_device *dev)
RTL_W16(CPlusCmd, tp->cp_cmd);
+ rtl8169_set_magic_reg(ioaddr, tp->mac_version);
+
/*
* Undocumented corner. Supposedly:
* (TxTimer << 12) | (TxPackets << 8) | (RxTimer << 4) | RxPackets
*/
RTL_W16(IntrMitigate, 0x0000);
- /*
- * Magic spell: some iop3xx ARM board needs the TxDescAddrHigh
- * register to be written before TxDescAddrLow to work.
- * Switching from MMIO to I/O access fixes the issue as well.
- */
- RTL_W32(TxDescStartAddrHigh, ((u64) tp->TxPhyAddr >> 32));
- RTL_W32(TxDescStartAddrLow, ((u64) tp->TxPhyAddr & DMA_32BIT_MASK));
- RTL_W32(RxDescAddrHigh, ((u64) tp->RxPhyAddr >> 32));
- RTL_W32(RxDescAddrLow, ((u64) tp->RxPhyAddr & DMA_32BIT_MASK));
-
- if ((tp->mac_version != RTL_GIGA_MAC_VER_01) &&
- (tp->mac_version != RTL_GIGA_MAC_VER_02) &&
- (tp->mac_version != RTL_GIGA_MAC_VER_03) &&
- (tp->mac_version != RTL_GIGA_MAC_VER_04)) {
- RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
- rtl8169_set_rx_tx_config_registers(tp);
- }
+ rtl_set_rx_tx_desc_registers(tp, ioaddr);
RTL_W8(Cfg9346, Cfg9346_Lock);
@@ -1922,15 +1940,107 @@ static void rtl8169_hw_start(struct net_device *dev)
RTL_W32(RxMissed, 0);
- rtl8169_set_rx_mode(dev);
+ rtl_set_rx_mode(dev);
/* no early-rx interrupts */
RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xF000);
/* Enable all known interrupts by setting the interrupt mask. */
- RTL_W16(IntrMask, rtl8169_intr_mask);
+ RTL_W16(IntrMask, tp->intr_event);
- netif_start_queue(dev);
+ RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
+}
+
+static void rtl_hw_start_8168(struct net_device *dev)
+{
+ struct rtl8169_private *tp = netdev_priv(dev);
+ void __iomem *ioaddr = tp->mmio_addr;
+ struct pci_dev *pdev = tp->pci_dev;
+ u8 ctl;
+
+ RTL_W8(Cfg9346, Cfg9346_Unlock);
+
+ RTL_W8(EarlyTxThres, EarlyTxThld);
+
+ rtl_set_rx_max_size(ioaddr);
+
+ rtl_set_rx_tx_config_registers(tp);
+
+ tp->cp_cmd |= RTL_R16(CPlusCmd) | PktCntrDisable | INTT_1;
+
+ RTL_W16(CPlusCmd, tp->cp_cmd);
+
+ /* Tx performance tweak. */
+ pci_read_config_byte(pdev, 0x69, &ctl);
+ ctl = (ctl & ~0x70) | 0x50;
+ pci_write_config_byte(pdev, 0x69, ctl);
+
+ RTL_W16(IntrMitigate, 0x5151);
+
+ /* Work around for RxFIFO overflow. */
+ if (tp->mac_version == RTL_GIGA_MAC_VER_11) {
+ tp->intr_event |= RxFIFOOver | PCSTimeout;
+ tp->intr_event &= ~RxOverflow;
+ }
+
+ rtl_set_rx_tx_desc_registers(tp, ioaddr);
+
+ RTL_W8(Cfg9346, Cfg9346_Lock);
+
+ RTL_R8(IntrMask);
+
+ RTL_W32(RxMissed, 0);
+
+ rtl_set_rx_mode(dev);
+
+ RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
+
+ RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xF000);
+
+ RTL_W16(IntrMask, tp->intr_event);
+}
+
+static void rtl_hw_start_8101(struct net_device *dev)
+{
+ struct rtl8169_private *tp = netdev_priv(dev);
+ void __iomem *ioaddr = tp->mmio_addr;
+ struct pci_dev *pdev = tp->pci_dev;
+
+ if (tp->mac_version == RTL_GIGA_MAC_VER_13) {
+ pci_write_config_word(pdev, 0x68, 0x00);
+ pci_write_config_word(pdev, 0x69, 0x08);
+ }
+
+ RTL_W8(Cfg9346, Cfg9346_Unlock);
+
+ RTL_W8(EarlyTxThres, EarlyTxThld);
+
+ rtl_set_rx_max_size(ioaddr);
+
+ tp->cp_cmd |= rtl_rw_cpluscmd(ioaddr) | PCIMulRW;
+
+ RTL_W16(CPlusCmd, tp->cp_cmd);
+
+ RTL_W16(IntrMitigate, 0x0000);
+
+ rtl_set_rx_tx_desc_registers(tp, ioaddr);
+
+ RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
+ rtl_set_rx_tx_config_registers(tp);
+
+ RTL_W8(Cfg9346, Cfg9346_Lock);
+
+ RTL_R8(IntrMask);
+
+ RTL_W32(RxMissed, 0);
+
+ rtl_set_rx_mode(dev);
+
+ RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
+
+ RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xf000);
+
+ RTL_W16(IntrMask, tp->intr_event);
}
static int rtl8169_change_mtu(struct net_device *dev, int new_mtu)
@@ -1956,7 +2066,7 @@ static int rtl8169_change_mtu(struct net_device *dev, int new_mtu)
netif_poll_enable(dev);
- rtl8169_hw_start(dev);
+ rtl_hw_start(dev);
rtl8169_request_timer(dev);
@@ -1997,38 +2107,38 @@ static inline void rtl8169_map_to_asic(struct RxDesc *desc, dma_addr_t mapping,
rtl8169_mark_to_asic(desc, rx_buf_sz);
}
-static int rtl8169_alloc_rx_skb(struct pci_dev *pdev, struct sk_buff **sk_buff,
- struct RxDesc *desc, int rx_buf_sz,
- unsigned int align)
+static struct sk_buff *rtl8169_alloc_rx_skb(struct pci_dev *pdev,
+ struct net_device *dev,
+ struct RxDesc *desc, int rx_buf_sz,
+ unsigned int align)
{
struct sk_buff *skb;
dma_addr_t mapping;
- int ret = 0;
+ unsigned int pad;
- skb = dev_alloc_skb(rx_buf_sz + align);
+ pad = align ? align : NET_IP_ALIGN;
+
+ skb = netdev_alloc_skb(dev, rx_buf_sz + pad);
if (!skb)
goto err_out;
- skb_reserve(skb, (align - 1) & (unsigned long)skb->data);
- *sk_buff = skb;
+ skb_reserve(skb, align ? ((pad - 1) & (unsigned long)skb->data) : pad);
mapping = pci_map_single(pdev, skb->data, rx_buf_sz,
PCI_DMA_FROMDEVICE);
rtl8169_map_to_asic(desc, mapping, rx_buf_sz);
-
out:
- return ret;
+ return skb;
err_out:
- ret = -ENOMEM;
rtl8169_make_unusable_by_asic(desc);
goto out;
}
static void rtl8169_rx_clear(struct rtl8169_private *tp)
{
- int i;
+ unsigned int i;
for (i = 0; i < NUM_RX_DESC; i++) {
if (tp->Rx_skbuff[i]) {
@@ -2043,16 +2153,22 @@ static u32 rtl8169_rx_fill(struct rtl8169_private *tp, struct net_device *dev,
{
u32 cur;
- for (cur = start; end - cur > 0; cur++) {
- int ret, i = cur % NUM_RX_DESC;
+ for (cur = start; end - cur != 0; cur++) {
+ struct sk_buff *skb;
+ unsigned int i = cur % NUM_RX_DESC;
+
+ WARN_ON((s32)(end - cur) < 0);
if (tp->Rx_skbuff[i])
continue;
- ret = rtl8169_alloc_rx_skb(tp->pci_dev, tp->Rx_skbuff + i,
- tp->RxDescArray + i, tp->rx_buf_sz, tp->align);
- if (ret < 0)
+ skb = rtl8169_alloc_rx_skb(tp->pci_dev, dev,
+ tp->RxDescArray + i,
+ tp->rx_buf_sz, tp->align);
+ if (!skb)
break;
+
+ tp->Rx_skbuff[i] = skb;
}
return cur - start;
}
@@ -2164,14 +2280,9 @@ static void rtl8169_reinit_task(struct work_struct *work)
ret = rtl8169_open(dev);
if (unlikely(ret < 0)) {
- if (net_ratelimit()) {
- struct rtl8169_private *tp = netdev_priv(dev);
-
- if (netif_msg_drv(tp)) {
- printk(PFX KERN_ERR
- "%s: reinit failure (status = %d)."
- " Rescheduling.\n", dev->name, ret);
- }
+ if (net_ratelimit() && netif_msg_drv(tp)) {
+ printk(PFX KERN_ERR "%s: reinit failure (status = %d)."
+ " Rescheduling.\n", dev->name, ret);
}
rtl8169_schedule_work(dev, rtl8169_reinit_task);
}
@@ -2198,16 +2309,12 @@ static void rtl8169_reset_task(struct work_struct *work)
if (tp->dirty_rx == tp->cur_rx) {
rtl8169_init_ring_indexes(tp);
- rtl8169_hw_start(dev);
+ rtl_hw_start(dev);
netif_wake_queue(dev);
} else {
- if (net_ratelimit()) {
- struct rtl8169_private *tp = netdev_priv(dev);
-
- if (netif_msg_intr(tp)) {
- printk(PFX KERN_EMERG
- "%s: Rx buffers shortage\n", dev->name);
- }
+ if (net_ratelimit() && netif_msg_intr(tp)) {
+ printk(PFX KERN_EMERG "%s: Rx buffers shortage\n",
+ dev->name);
}
rtl8169_schedule_work(dev, rtl8169_reset_task);
}
@@ -2344,7 +2451,7 @@ static int rtl8169_start_xmit(struct sk_buff *skb, struct net_device *dev)
smp_wmb();
- RTL_W8(TxPoll, 0x40); /* set polling bit */
+ RTL_W8(TxPoll, NPQ); /* set polling bit */
if (TX_BUFFS_AVAIL(tp) < MAX_SKB_FRAGS) {
netif_stop_queue(dev);
@@ -2414,16 +2521,12 @@ static void rtl8169_pcierr_interrupt(struct net_device *dev)
rtl8169_schedule_work(dev, rtl8169_reinit_task);
}
-static void
-rtl8169_tx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
- void __iomem *ioaddr)
+static void rtl8169_tx_interrupt(struct net_device *dev,
+ struct rtl8169_private *tp,
+ void __iomem *ioaddr)
{
unsigned int dirty_tx, tx_left;
- assert(dev != NULL);
- assert(tp != NULL);
- assert(ioaddr != NULL);
-
dirty_tx = tp->dirty_tx;
smp_rmb();
tx_left = tp->cur_tx - dirty_tx;
@@ -2480,38 +2583,37 @@ static inline void rtl8169_rx_csum(struct sk_buff *skb, struct RxDesc *desc)
skb->ip_summed = CHECKSUM_NONE;
}
-static inline int rtl8169_try_rx_copy(struct sk_buff **sk_buff, int pkt_size,
- struct RxDesc *desc, int rx_buf_sz,
- unsigned int align)
+static inline bool rtl8169_try_rx_copy(struct sk_buff **sk_buff,
+ struct rtl8169_private *tp, int pkt_size,
+ dma_addr_t addr)
{
- int ret = -1;
+ struct sk_buff *skb;
+ bool done = false;
- if (pkt_size < rx_copybreak) {
- struct sk_buff *skb;
+ if (pkt_size >= rx_copybreak)
+ goto out;
- skb = dev_alloc_skb(pkt_size + align);
- if (skb) {
- skb_reserve(skb, (align - 1) & (unsigned long)skb->data);
- eth_copy_and_sum(skb, sk_buff[0]->data, pkt_size, 0);
- *sk_buff = skb;
- rtl8169_mark_to_asic(desc, rx_buf_sz);
- ret = 0;
- }
- }
- return ret;
+ skb = netdev_alloc_skb(tp->dev, pkt_size + NET_IP_ALIGN);
+ if (!skb)
+ goto out;
+
+ pci_dma_sync_single_for_cpu(tp->pci_dev, addr, pkt_size,
+ PCI_DMA_FROMDEVICE);
+ skb_reserve(skb, NET_IP_ALIGN);
+ skb_copy_from_linear_data(*sk_buff, skb->data, pkt_size);
+ *sk_buff = skb;
+ done = true;
+out:
+ return done;
}
-static int
-rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
- void __iomem *ioaddr)
+static int rtl8169_rx_interrupt(struct net_device *dev,
+ struct rtl8169_private *tp,
+ void __iomem *ioaddr)
{
unsigned int cur_rx, rx_left;
unsigned int delta, count;
- assert(dev != NULL);
- assert(tp != NULL);
- assert(ioaddr != NULL);
-
cur_rx = tp->cur_rx;
rx_left = NUM_RX_DESC + tp->dirty_rx - cur_rx;
rx_left = rtl8169_rx_quota(rx_left, (u32) dev->quota);
@@ -2544,9 +2646,9 @@ rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
rtl8169_mark_to_asic(desc, tp->rx_buf_sz);
} else {
struct sk_buff *skb = tp->Rx_skbuff[entry];
+ dma_addr_t addr = le64_to_cpu(desc->addr);
int pkt_size = (status & 0x00001FFF) - 4;
- void (*pci_action)(struct pci_dev *, dma_addr_t,
- size_t, int) = pci_dma_sync_single_for_device;
+ struct pci_dev *pdev = tp->pci_dev;
/*
* The driver does not support incoming fragmented
@@ -2562,19 +2664,16 @@ rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
rtl8169_rx_csum(skb, desc);
- pci_dma_sync_single_for_cpu(tp->pci_dev,
- le64_to_cpu(desc->addr), tp->rx_buf_sz,
- PCI_DMA_FROMDEVICE);
-
- if (rtl8169_try_rx_copy(&skb, pkt_size, desc,
- tp->rx_buf_sz, tp->align)) {
- pci_action = pci_unmap_single;
+ if (rtl8169_try_rx_copy(&skb, tp, pkt_size, addr)) {
+ pci_dma_sync_single_for_device(pdev, addr,
+ pkt_size, PCI_DMA_FROMDEVICE);
+ rtl8169_mark_to_asic(desc, tp->rx_buf_sz);
+ } else {
+ pci_unmap_single(pdev, addr, pkt_size,
+ PCI_DMA_FROMDEVICE);
tp->Rx_skbuff[entry] = NULL;
}
- pci_action(tp->pci_dev, le64_to_cpu(desc->addr),
- tp->rx_buf_sz, PCI_DMA_FROMDEVICE);
-
skb_put(skb, pkt_size);
skb->protocol = eth_type_trans(skb, dev);
@@ -2585,6 +2684,13 @@ rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
tp->stats.rx_bytes += pkt_size;
tp->stats.rx_packets++;
}
+
+ /* Work around for AMD plateform. */
+ if ((desc->opts2 & 0xfffe000) &&
+ (tp->mac_version == RTL_GIGA_MAC_VER_05)) {
+ desc->opts2 = 0;
+ cur_rx++;
+ }
}
count = cur_rx - tp->cur_rx;
@@ -2608,11 +2714,9 @@ rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
return count;
}
-/* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */
-static irqreturn_t
-rtl8169_interrupt(int irq, void *dev_instance)
+static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance)
{
- struct net_device *dev = (struct net_device *) dev_instance;
+ struct net_device *dev = dev_instance;
struct rtl8169_private *tp = netdev_priv(dev);
int boguscnt = max_interrupt_work;
void __iomem *ioaddr = tp->mmio_addr;
@@ -2637,9 +2741,17 @@ rtl8169_interrupt(int irq, void *dev_instance)
RTL_W16(IntrStatus,
(status & RxFIFOOver) ? (status | RxOverflow) : status);
- if (!(status & rtl8169_intr_mask))
+ if (!(status & tp->intr_event))
break;
+ /* Work around for rx fifo overflow */
+ if (unlikely(status & RxFIFOOver) &&
+ (tp->mac_version == RTL_GIGA_MAC_VER_11)) {
+ netif_stop_queue(dev);
+ rtl8169_tx_timeout(dev);
+ break;
+ }
+
if (unlikely(status & SYSErr)) {
rtl8169_pcierr_interrupt(dev);
break;
@@ -2649,8 +2761,8 @@ rtl8169_interrupt(int irq, void *dev_instance)
rtl8169_check_link_status(dev, tp, ioaddr);
#ifdef CONFIG_R8169_NAPI
- RTL_W16(IntrMask, rtl8169_intr_mask & ~rtl8169_napi_event);
- tp->intr_mask = ~rtl8169_napi_event;
+ RTL_W16(IntrMask, tp->intr_event & ~tp->napi_event);
+ tp->intr_mask = ~tp->napi_event;
if (likely(netif_rx_schedule_prep(dev)))
__netif_rx_schedule(dev);
@@ -2661,9 +2773,9 @@ rtl8169_interrupt(int irq, void *dev_instance)
break;
#else
/* Rx interrupt */
- if (status & (RxOK | RxOverflow | RxFIFOOver)) {
+ if (status & (RxOK | RxOverflow | RxFIFOOver))
rtl8169_rx_interrupt(dev, tp, ioaddr);
- }
+
/* Tx interrupt */
if (status & (TxOK | TxErr))
rtl8169_tx_interrupt(dev, tp, ioaddr);
@@ -2707,7 +2819,7 @@ static int rtl8169_poll(struct net_device *dev, int *budget)
* write is safe - FR
*/
smp_wmb();
- RTL_W16(IntrMask, rtl8169_intr_mask);
+ RTL_W16(IntrMask, tp->intr_event);
}
return (work_done >= work_to_do);
@@ -2789,14 +2901,13 @@ static int rtl8169_close(struct net_device *dev)
return 0;
}
-static void
-rtl8169_set_rx_mode(struct net_device *dev)
+static void rtl_set_rx_mode(struct net_device *dev)
{
struct rtl8169_private *tp = netdev_priv(dev);
void __iomem *ioaddr = tp->mmio_addr;
unsigned long flags;
u32 mc_filter[2]; /* Multicast hash filter */
- int i, rx_mode;
+ int rx_mode;
u32 tmp = 0;
if (dev->flags & IFF_PROMISC) {
@@ -2816,6 +2927,8 @@ rtl8169_set_rx_mode(struct net_device *dev)
mc_filter[1] = mc_filter[0] = 0xffffffff;
} else {
struct dev_mc_list *mclist;
+ unsigned int i;
+
rx_mode = AcceptBroadcast | AcceptMyPhys;
mc_filter[1] = mc_filter[0] = 0;
for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
@@ -2840,10 +2953,11 @@ rtl8169_set_rx_mode(struct net_device *dev)
mc_filter[1] = 0xffffffff;
}
- RTL_W32(RxConfig, tmp);
RTL_W32(MAR0 + 0, mc_filter[0]);
RTL_W32(MAR0 + 4, mc_filter[1]);
+ RTL_W32(RxConfig, tmp);
+
spin_unlock_irqrestore(&tp->lock, flags);
}
@@ -2931,14 +3045,12 @@ static struct pci_driver rtl8169_pci_driver = {
#endif
};
-static int __init
-rtl8169_init_module(void)
+static int __init rtl8169_init_module(void)
{
return pci_register_driver(&rtl8169_pci_driver);
}
-static void __exit
-rtl8169_cleanup_module(void)
+static void __exit rtl8169_cleanup_module(void)
{
pci_unregister_driver(&rtl8169_pci_driver);
}
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c
index 09078ff84cd2..2d826fff7e2e 100644
--- a/drivers/net/s2io.c
+++ b/drivers/net/s2io.c
@@ -469,11 +469,18 @@ static struct pci_device_id s2io_tbl[] __devinitdata = {
MODULE_DEVICE_TABLE(pci, s2io_tbl);
+static struct pci_error_handlers s2io_err_handler = {
+ .error_detected = s2io_io_error_detected,
+ .slot_reset = s2io_io_slot_reset,
+ .resume = s2io_io_resume,
+};
+
static struct pci_driver s2io_driver = {
.name = "S2IO",
.id_table = s2io_tbl,
.probe = s2io_init_nic,
.remove = __devexit_p(s2io_rem_nic),
+ .err_handler = &s2io_err_handler,
};
/* A simplifier macro used both by init and free shared_mem Fns(). */
@@ -2689,6 +2696,9 @@ static void s2io_netpoll(struct net_device *dev)
u64 val64 = 0xFFFFFFFFFFFFFFFFULL;
int i;
+ if (pci_channel_offline(nic->pdev))
+ return;
+
disable_irq(dev->irq);
atomic_inc(&nic->isr_cnt);
@@ -3215,6 +3225,8 @@ static void alarm_intr_handler(struct s2io_nic *nic)
int i;
if (atomic_read(&nic->card_state) == CARD_DOWN)
return;
+ if (pci_channel_offline(nic->pdev))
+ return;
nic->mac_control.stats_info->sw_stat.ring_full_cnt = 0;
/* Handling the XPAK counters update */
if(nic->mac_control.stats_info->xpak_stat.xpak_timer_count < 72000) {
@@ -3958,7 +3970,6 @@ static int s2io_close(struct net_device *dev)
/* Reset card, kill tasklet and free Tx and Rx buffers. */
s2io_card_down(sp);
- sp->device_close_flag = TRUE; /* Device is shut down. */
return 0;
}
@@ -4314,6 +4325,10 @@ static irqreturn_t s2io_isr(int irq, void *dev_id)
struct mac_info *mac_control;
struct config_param *config;
+ /* Pretend we handled any irq's from a disconnected card */
+ if (pci_channel_offline(sp->pdev))
+ return IRQ_NONE;
+
atomic_inc(&sp->isr_cnt);
mac_control = &sp->mac_control;
config = &sp->config;
@@ -6569,7 +6584,7 @@ static void s2io_rem_isr(struct s2io_nic * sp)
} while(cnt < 5);
}
-static void s2io_card_down(struct s2io_nic * sp)
+static void do_s2io_card_down(struct s2io_nic * sp, int do_io)
{
int cnt = 0;
struct XENA_dev_config __iomem *bar0 = sp->bar0;
@@ -6584,7 +6599,8 @@ static void s2io_card_down(struct s2io_nic * sp)
atomic_set(&sp->card_state, CARD_DOWN);
/* disable Tx and Rx traffic on the NIC */
- stop_nic(sp);
+ if (do_io)
+ stop_nic(sp);
s2io_rem_isr(sp);
@@ -6592,7 +6608,7 @@ static void s2io_card_down(struct s2io_nic * sp)
tasklet_kill(&sp->task);
/* Check if the device is Quiescent and then Reset the NIC */
- do {
+ while(do_io) {
/* As per the HW requirement we need to replenish the
* receive buffer to avoid the ring bump. Since there is
* no intention of processing the Rx frame at this pointwe are
@@ -6617,8 +6633,9 @@ static void s2io_card_down(struct s2io_nic * sp)
(unsigned long long) val64);
break;
}
- } while (1);
- s2io_reset(sp);
+ }
+ if (do_io)
+ s2io_reset(sp);
spin_lock_irqsave(&sp->tx_lock, flags);
/* Free all Tx buffers */
@@ -6633,6 +6650,11 @@ static void s2io_card_down(struct s2io_nic * sp)
clear_bit(0, &(sp->link_state));
}
+static void s2io_card_down(struct s2io_nic * sp)
+{
+ do_s2io_card_down(sp, 1);
+}
+
static int s2io_card_up(struct s2io_nic * sp)
{
int i, ret = 0;
@@ -8010,3 +8032,85 @@ static void lro_append_pkt(struct s2io_nic *sp, struct lro *lro,
sp->mac_control.stats_info->sw_stat.clubbed_frms_cnt++;
return;
}
+
+/**
+ * s2io_io_error_detected - called when PCI error is detected
+ * @pdev: Pointer to PCI device
+ * @state: The current pci conneection state
+ *
+ * This function is called after a PCI bus error affecting
+ * this device has been detected.
+ */
+static pci_ers_result_t s2io_io_error_detected(struct pci_dev *pdev,
+ pci_channel_state_t state)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct s2io_nic *sp = netdev->priv;
+
+ netif_device_detach(netdev);
+
+ if (netif_running(netdev)) {
+ /* Bring down the card, while avoiding PCI I/O */
+ do_s2io_card_down(sp, 0);
+ }
+ pci_disable_device(pdev);
+
+ return PCI_ERS_RESULT_NEED_RESET;
+}
+
+/**
+ * s2io_io_slot_reset - called after the pci bus has been reset.
+ * @pdev: Pointer to PCI device
+ *
+ * Restart the card from scratch, as if from a cold-boot.
+ * At this point, the card has exprienced a hard reset,
+ * followed by fixups by BIOS, and has its config space
+ * set up identically to what it was at cold boot.
+ */
+static pci_ers_result_t s2io_io_slot_reset(struct pci_dev *pdev)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct s2io_nic *sp = netdev->priv;
+
+ if (pci_enable_device(pdev)) {
+ printk(KERN_ERR "s2io: "
+ "Cannot re-enable PCI device after reset.\n");
+ return PCI_ERS_RESULT_DISCONNECT;
+ }
+
+ pci_set_master(pdev);
+ s2io_reset(sp);
+
+ return PCI_ERS_RESULT_RECOVERED;
+}
+
+/**
+ * s2io_io_resume - called when traffic can start flowing again.
+ * @pdev: Pointer to PCI device
+ *
+ * This callback is called when the error recovery driver tells
+ * us that its OK to resume normal operation.
+ */
+static void s2io_io_resume(struct pci_dev *pdev)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct s2io_nic *sp = netdev->priv;
+
+ if (netif_running(netdev)) {
+ if (s2io_card_up(sp)) {
+ printk(KERN_ERR "s2io: "
+ "Can't bring device back up after reset.\n");
+ return;
+ }
+
+ if (s2io_set_mac_addr(netdev, netdev->dev_addr) == FAILURE) {
+ s2io_card_down(sp);
+ printk(KERN_ERR "s2io: "
+ "Can't resetore mac addr after reset.\n");
+ return;
+ }
+ }
+
+ netif_device_attach(netdev);
+ netif_wake_queue(netdev);
+}
diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h
index 54baa0b8ec7c..58592780f519 100644
--- a/drivers/net/s2io.h
+++ b/drivers/net/s2io.h
@@ -794,7 +794,6 @@ struct s2io_nic {
struct net_device_stats stats;
int high_dma_flag;
- int device_close_flag;
int device_enabled_once;
char name[60];
@@ -1052,6 +1051,11 @@ static void lro_append_pkt(struct s2io_nic *sp, struct lro *lro,
struct sk_buff *skb, u32 tcp_len);
static int rts_ds_steer(struct s2io_nic *nic, u8 ds_codepoint, u8 ring);
+static pci_ers_result_t s2io_io_error_detected(struct pci_dev *pdev,
+ pci_channel_state_t state);
+static pci_ers_result_t s2io_io_slot_reset(struct pci_dev *pdev);
+static void s2io_io_resume(struct pci_dev *pdev);
+
#define s2io_tcp_mss(skb) skb_shinfo(skb)->gso_size
#define s2io_udp_mss(skb) skb_shinfo(skb)->gso_size
#define s2io_offload_type(skb) skb_shinfo(skb)->gso_type
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index fe01b961b597..b51d73c8f817 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -50,7 +50,7 @@
#include "sky2.h"
#define DRV_NAME "sky2"
-#define DRV_VERSION "1.14"
+#define DRV_VERSION "1.15"
#define PFX DRV_NAME " "
/*
@@ -130,7 +130,7 @@ static const struct pci_device_id sky2_id_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4368) }, /* 88EC034 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4369) }, /* 88EC042 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x436A) }, /* 88E8058 */
-// { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x436B) }, /* 88E8071 */
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x436B) }, /* 88E8071 */
{ 0 }
};
@@ -217,13 +217,24 @@ static void sky2_power_on(struct sky2_hw *hw)
sky2_write8(hw, B2_Y2_CLK_GATE, 0);
if (hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_EX) {
- u32 reg1;
+ u32 reg;
- sky2_pci_write32(hw, PCI_DEV_REG3, 0);
- reg1 = sky2_pci_read32(hw, PCI_DEV_REG4);
- reg1 &= P_ASPM_CONTROL_MSK;
- sky2_pci_write32(hw, PCI_DEV_REG4, reg1);
- sky2_pci_write32(hw, PCI_DEV_REG5, 0);
+ reg = sky2_pci_read32(hw, PCI_DEV_REG4);
+ /* set all bits to 0 except bits 15..12 and 8 */
+ reg &= P_ASPM_CONTROL_MSK;
+ sky2_pci_write32(hw, PCI_DEV_REG4, reg);
+
+ reg = sky2_pci_read32(hw, PCI_DEV_REG5);
+ /* set all bits to 0 except bits 28 & 27 */
+ reg &= P_CTL_TIM_VMAIN_AV_MSK;
+ sky2_pci_write32(hw, PCI_DEV_REG5, reg);
+
+ sky2_pci_write32(hw, PCI_CFG_REG_1, 0);
+
+ /* Enable workaround for dev 4.107 on Yukon-Ultra & Extreme */
+ reg = sky2_read32(hw, B2_GP_IO);
+ reg |= GLB_GPIO_STAT_RACE_DIS;
+ sky2_write32(hw, B2_GP_IO, reg);
}
}
@@ -650,6 +661,30 @@ static void sky2_wol_init(struct sky2_port *sky2)
}
+static void sky2_set_tx_stfwd(struct sky2_hw *hw, unsigned port)
+{
+ if (hw->chip_id == CHIP_ID_YUKON_EX && hw->chip_rev != CHIP_REV_YU_EX_A0) {
+ sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
+ TX_STFW_ENA |
+ (hw->dev[port]->mtu > ETH_DATA_LEN) ? TX_JUMBO_ENA : TX_JUMBO_DIS);
+ } else {
+ if (hw->dev[port]->mtu > ETH_DATA_LEN) {
+ /* set Tx GMAC FIFO Almost Empty Threshold */
+ sky2_write32(hw, SK_REG(port, TX_GMF_AE_THR),
+ (ECU_JUMBO_WM << 16) | ECU_AE_THR);
+
+ sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
+ TX_JUMBO_ENA | TX_STFW_DIS);
+
+ /* Can't do offload because of lack of store/forward */
+ hw->dev[port]->features &= ~(NETIF_F_TSO | NETIF_F_SG
+ | NETIF_F_ALL_CSUM);
+ } else
+ sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
+ TX_JUMBO_DIS | TX_STFW_ENA);
+ }
+}
+
static void sky2_mac_init(struct sky2_hw *hw, unsigned port)
{
struct sky2_port *sky2 = netdev_priv(hw->dev[port]);
@@ -730,8 +765,11 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port)
/* Configure Rx MAC FIFO */
sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_CLR);
- sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T),
- GMF_OPER_ON | GMF_RX_F_FL_ON);
+ reg = GMF_OPER_ON | GMF_RX_F_FL_ON;
+ if (hw->chip_id == CHIP_ID_YUKON_EX)
+ reg |= GMF_RX_OVER_ON;
+
+ sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T), reg);
/* Flush Rx MAC FIFO on any flow control or error */
sky2_write16(hw, SK_REG(port, RX_GMF_FL_MSK), GMR_FS_ANY_ERR);
@@ -747,16 +785,7 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port)
sky2_write8(hw, SK_REG(port, RX_GMF_LP_THR), 768/8);
sky2_write8(hw, SK_REG(port, RX_GMF_UP_THR), 1024/8);
- /* set Tx GMAC FIFO Almost Empty Threshold */
- sky2_write32(hw, SK_REG(port, TX_GMF_AE_THR),
- (ECU_JUMBO_WM << 16) | ECU_AE_THR);
-
- if (hw->dev[port]->mtu > ETH_DATA_LEN)
- sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
- TX_JUMBO_ENA | TX_STFW_DIS);
- else
- sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
- TX_JUMBO_DIS | TX_STFW_ENA);
+ sky2_set_tx_stfwd(hw, port);
}
}
@@ -939,14 +968,16 @@ static void rx_set_checksum(struct sky2_port *sky2)
{
struct sky2_rx_le *le;
- le = sky2_next_rx(sky2);
- le->addr = cpu_to_le32((ETH_HLEN << 16) | ETH_HLEN);
- le->ctrl = 0;
- le->opcode = OP_TCPSTART | HW_OWNER;
+ if (sky2->hw->chip_id != CHIP_ID_YUKON_EX) {
+ le = sky2_next_rx(sky2);
+ le->addr = cpu_to_le32((ETH_HLEN << 16) | ETH_HLEN);
+ le->ctrl = 0;
+ le->opcode = OP_TCPSTART | HW_OWNER;
- sky2_write32(sky2->hw,
- Q_ADDR(rxqaddr[sky2->port], Q_CSR),
- sky2->rx_csum ? BMU_ENA_RX_CHKSUM : BMU_DIS_RX_CHKSUM);
+ sky2_write32(sky2->hw,
+ Q_ADDR(rxqaddr[sky2->port], Q_CSR),
+ sky2->rx_csum ? BMU_ENA_RX_CHKSUM : BMU_DIS_RX_CHKSUM);
+ }
}
@@ -1134,7 +1165,7 @@ static int sky2_rx_start(struct sky2_port *sky2)
if (hw->chip_id == CHIP_ID_YUKON_EC_U &&
(hw->chip_rev == CHIP_REV_YU_EC_U_A1
|| hw->chip_rev == CHIP_REV_YU_EC_U_B0))
- sky2_write32(hw, Q_ADDR(rxq, Q_F), F_M_RX_RAM_DIS);
+ sky2_write32(hw, Q_ADDR(rxq, Q_TEST), F_M_RX_RAM_DIS);
sky2_prefetch_init(hw, rxq, sky2->rx_le_map, RX_LE_SIZE - 1);
@@ -1285,6 +1316,10 @@ static int sky2_up(struct net_device *dev)
sky2_qset(hw, txqaddr[port]);
+ /* This is copied from sk98lin 10.0.5.3; no one tells me about erratta's */
+ if (hw->chip_id == CHIP_ID_YUKON_EX && hw->chip_rev == CHIP_REV_YU_EX_B0)
+ sky2_write32(hw, Q_ADDR(txqaddr[port], Q_TEST), F_TX_CHK_AUTO_OFF);
+
/* Set almost empty threshold */
if (hw->chip_id == CHIP_ID_YUKON_EC_U
&& hw->chip_rev == CHIP_REV_YU_EC_U_A0)
@@ -1393,14 +1428,16 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev)
/* Check for TCP Segmentation Offload */
mss = skb_shinfo(skb)->gso_size;
if (mss != 0) {
- mss += tcp_optlen(skb); /* TCP options */
- mss += ip_hdrlen(skb) + sizeof(struct tcphdr);
- mss += ETH_HLEN;
-
- if (mss != sky2->tx_last_mss) {
- le = get_tx_le(sky2);
- le->addr = cpu_to_le32(mss);
- le->opcode = OP_LRGLEN | HW_OWNER;
+ if (hw->chip_id != CHIP_ID_YUKON_EX)
+ mss += ETH_HLEN + ip_hdrlen(skb) + tcp_hdrlen(skb);
+
+ if (mss != sky2->tx_last_mss) {
+ le = get_tx_le(sky2);
+ le->addr = cpu_to_le32(mss);
+ if (hw->chip_id == CHIP_ID_YUKON_EX)
+ le->opcode = OP_MSS | HW_OWNER;
+ else
+ le->opcode = OP_LRGLEN | HW_OWNER;
sky2->tx_last_mss = mss;
}
}
@@ -1422,24 +1459,30 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev)
/* Handle TCP checksum offload */
if (skb->ip_summed == CHECKSUM_PARTIAL) {
- const unsigned offset = skb_transport_offset(skb);
- u32 tcpsum;
-
- tcpsum = offset << 16; /* sum start */
- tcpsum |= offset + skb->csum_offset; /* sum write */
-
- ctrl |= CALSUM | WR_SUM | INIT_SUM | LOCK_SUM;
- if (ip_hdr(skb)->protocol == IPPROTO_UDP)
- ctrl |= UDPTCP;
-
- if (tcpsum != sky2->tx_tcpsum) {
- sky2->tx_tcpsum = tcpsum;
-
- le = get_tx_le(sky2);
- le->addr = cpu_to_le32(tcpsum);
- le->length = 0; /* initial checksum value */
- le->ctrl = 1; /* one packet */
- le->opcode = OP_TCPLISW | HW_OWNER;
+ /* On Yukon EX (some versions) encoding change. */
+ if (hw->chip_id == CHIP_ID_YUKON_EX
+ && hw->chip_rev != CHIP_REV_YU_EX_B0)
+ ctrl |= CALSUM; /* auto checksum */
+ else {
+ const unsigned offset = skb_transport_offset(skb);
+ u32 tcpsum;
+
+ tcpsum = offset << 16; /* sum start */
+ tcpsum |= offset + skb->csum_offset; /* sum write */
+
+ ctrl |= CALSUM | WR_SUM | INIT_SUM | LOCK_SUM;
+ if (ip_hdr(skb)->protocol == IPPROTO_UDP)
+ ctrl |= UDPTCP;
+
+ if (tcpsum != sky2->tx_tcpsum) {
+ sky2->tx_tcpsum = tcpsum;
+
+ le = get_tx_le(sky2);
+ le->addr = cpu_to_le32(tcpsum);
+ le->length = 0; /* initial checksum value */
+ le->ctrl = 1; /* one packet */
+ le->opcode = OP_TCPLISW | HW_OWNER;
+ }
}
}
@@ -1913,15 +1956,8 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu)
synchronize_irq(hw->pdev->irq);
- if (hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_EX) {
- if (new_mtu > ETH_DATA_LEN) {
- sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
- TX_JUMBO_ENA | TX_STFW_DIS);
- dev->features &= NETIF_F_TSO | NETIF_F_SG | NETIF_F_IP_CSUM;
- } else
- sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
- TX_JUMBO_DIS | TX_STFW_ENA);
- }
+ if (hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_EX)
+ sky2_set_tx_stfwd(hw, port);
ctl = gma_read16(hw, port, GM_GP_CTRL);
gma_write16(hw, port, GM_GP_CTRL, ctl & ~GM_GPCR_RX_ENA);
@@ -2118,6 +2154,7 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do)
while (hw->st_idx != hwidx) {
struct sky2_status_le *le = hw->st_le + hw->st_idx;
+ unsigned port = le->css & CSS_LINK_BIT;
struct net_device *dev;
struct sk_buff *skb;
u32 status;
@@ -2125,9 +2162,7 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do)
hw->st_idx = RING_NEXT(hw->st_idx, STATUS_RING_SIZE);
- BUG_ON(le->link >= 2);
- dev = hw->dev[le->link];
-
+ dev = hw->dev[port];
sky2 = netdev_priv(dev);
length = le16_to_cpu(le->length);
status = le32_to_cpu(le->status);
@@ -2140,6 +2175,16 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do)
goto force_update;
}
+ /* This chip reports checksum status differently */
+ if (hw->chip_id == CHIP_ID_YUKON_EX) {
+ if (sky2->rx_csum &&
+ (le->css & (CSS_ISIPV4 | CSS_ISIPV6)) &&
+ (le->css & CSS_TCPUDPCSOK))
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ else
+ skb->ip_summed = CHECKSUM_NONE;
+ }
+
skb->protocol = eth_type_trans(skb, dev);
sky2->net_stats.rx_packets++;
sky2->net_stats.rx_bytes += skb->len;
@@ -2155,10 +2200,10 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do)
netif_receive_skb(skb);
/* Update receiver after 16 frames */
- if (++buf_write[le->link] == RX_BUF_WRITE) {
+ if (++buf_write[port] == RX_BUF_WRITE) {
force_update:
- sky2_put_idx(hw, rxqaddr[le->link], sky2->rx_put);
- buf_write[le->link] = 0;
+ sky2_put_idx(hw, rxqaddr[port], sky2->rx_put);
+ buf_write[port] = 0;
}
/* Stop after net poll weight */
@@ -2179,6 +2224,9 @@ force_update:
if (!sky2->rx_csum)
break;
+ if (hw->chip_id == CHIP_ID_YUKON_EX)
+ break;
+
/* Both checksum counters are programmed to start at
* the same offset, so unless there is a problem they
* should match. This failure is an early indication that
@@ -2194,7 +2242,7 @@ force_update:
dev->name, status);
sky2->rx_csum = 0;
sky2_write32(sky2->hw,
- Q_ADDR(rxqaddr[le->link], Q_CSR),
+ Q_ADDR(rxqaddr[port], Q_CSR),
BMU_DIS_RX_CHKSUM);
}
break;
@@ -2513,6 +2561,9 @@ static int __devinit sky2_init(struct sky2_hw *hw)
{
u8 t8;
+ /* Enable all clocks */
+ sky2_pci_write32(hw, PCI_DEV_REG3, 0);
+
sky2_write8(hw, B0_CTST, CS_RST_CLR);
hw->chip_id = sky2_read8(hw, B2_CHIP_ID);
@@ -2522,14 +2573,6 @@ static int __devinit sky2_init(struct sky2_hw *hw)
return -EOPNOTSUPP;
}
- if (hw->chip_id == CHIP_ID_YUKON_EX)
- dev_warn(&hw->pdev->dev, "this driver not yet tested on this chip type\n"
- "Please report success or failure to <netdev@vger.kernel.org>\n");
-
- /* Make sure and enable all clocks */
- if (hw->chip_id == CHIP_ID_YUKON_EX || hw->chip_id == CHIP_ID_YUKON_EC_U)
- sky2_pci_write32(hw, PCI_DEV_REG3, 0);
-
hw->chip_rev = (sky2_read8(hw, B2_MAC_CFG) & CFG_CHIP_R_MSK) >> 4;
/* This rev is really old, and requires untested workarounds */
@@ -2589,6 +2632,11 @@ static void sky2_reset(struct sky2_hw *hw)
for (i = 0; i < hw->ports; i++) {
sky2_write8(hw, SK_REG(i, GMAC_LINK_CTRL), GMLC_RST_SET);
sky2_write8(hw, SK_REG(i, GMAC_LINK_CTRL), GMLC_RST_CLR);
+
+ if (hw->chip_id == CHIP_ID_YUKON_EX)
+ sky2_write16(hw, SK_REG(i, GMAC_CTRL),
+ GMC_BYP_MACSECRX_ON | GMC_BYP_MACSECTX_ON
+ | GMC_BYP_RETR_ON);
}
sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
@@ -2735,7 +2783,7 @@ static int sky2_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
sky2->wol = wol->wolopts;
- if (hw->chip_id == CHIP_ID_YUKON_EC_U)
+ if (hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_EX)
sky2_write32(hw, B0_CTST, sky2->wol
? Y2_HW_WOL_ON : Y2_HW_WOL_OFF);
@@ -3330,7 +3378,7 @@ static int sky2_get_regs_len(struct net_device *dev)
/*
* Returns copy of control register region
- * Note: access to the RAM address register set will cause timeouts.
+ * Note: ethtool_get_regs always provides full size (16k) buffer
*/
static void sky2_get_regs(struct net_device *dev, struct ethtool_regs *regs,
void *p)
@@ -3338,15 +3386,19 @@ static void sky2_get_regs(struct net_device *dev, struct ethtool_regs *regs,
const struct sky2_port *sky2 = netdev_priv(dev);
const void __iomem *io = sky2->hw->regs;
- BUG_ON(regs->len < B3_RI_WTO_R1);
regs->version = 1;
memset(p, 0, regs->len);
memcpy_fromio(p, io, B3_RAM_ADDR);
- memcpy_fromio(p + B3_RI_WTO_R1,
- io + B3_RI_WTO_R1,
- regs->len - B3_RI_WTO_R1);
+ /* skip diagnostic ram region */
+ memcpy_fromio(p + B3_RI_WTO_R1, io + B3_RI_WTO_R1, 0x2000 - B3_RI_WTO_R1);
+
+ /* copy GMAC registers */
+ memcpy_fromio(p + BASE_GMAC_1, io + BASE_GMAC_1, 0x1000);
+ if (sky2->hw->ports > 1)
+ memcpy_fromio(p + BASE_GMAC_2, io + BASE_GMAC_2, 0x1000);
+
}
/* In order to do Jumbo packets on these chips, need to turn off the
@@ -3357,9 +3409,7 @@ static int no_tx_offload(struct net_device *dev)
const struct sky2_port *sky2 = netdev_priv(dev);
const struct sky2_hw *hw = sky2->hw;
- return dev->mtu > ETH_DATA_LEN &&
- (hw->chip_id == CHIP_ID_YUKON_EX
- || hw->chip_id == CHIP_ID_YUKON_EC_U);
+ return dev->mtu > ETH_DATA_LEN && hw->chip_id == CHIP_ID_YUKON_EC_U;
}
static int sky2_set_tx_csum(struct net_device *dev, u32 data)
diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h
index b8c4a3b5eadf..8df4643493d1 100644
--- a/drivers/net/sky2.h
+++ b/drivers/net/sky2.h
@@ -14,6 +14,8 @@ enum {
PCI_DEV_REG3 = 0x80,
PCI_DEV_REG4 = 0x84,
PCI_DEV_REG5 = 0x88,
+ PCI_CFG_REG_0 = 0x90,
+ PCI_CFG_REG_1 = 0x94,
};
enum {
@@ -28,6 +30,7 @@ enum {
enum pci_dev_reg_1 {
PCI_Y2_PIG_ENA = 1<<31, /* Enable Plug-in-Go (YUKON-2) */
PCI_Y2_DLL_DIS = 1<<30, /* Disable PCI DLL (YUKON-2) */
+ PCI_SW_PWR_ON_RST= 1<<30, /* SW Power on Reset (Yukon-EX) */
PCI_Y2_PHY2_COMA = 1<<29, /* Set PHY 2 to Coma Mode (YUKON-2) */
PCI_Y2_PHY1_COMA = 1<<28, /* Set PHY 1 to Coma Mode (YUKON-2) */
PCI_Y2_PHY2_POWD = 1<<27, /* Set PHY 2 to Power Down (YUKON-2) */
@@ -67,6 +70,80 @@ enum pci_dev_reg_4 {
| P_ASPM_CLKRUN_REQUEST | P_ASPM_INT_FIFO_EMPTY,
};
+/* PCI_OUR_REG_5 32 bit Our Register 5 (Yukon-ECU only) */
+enum pci_dev_reg_5 {
+ /* Bit 31..27: for A3 & later */
+ P_CTL_DIV_CORE_CLK_ENA = 1<<31, /* Divide Core Clock Enable */
+ P_CTL_SRESET_VMAIN_AV = 1<<30, /* Soft Reset for Vmain_av De-Glitch */
+ P_CTL_BYPASS_VMAIN_AV = 1<<29, /* Bypass En. for Vmain_av De-Glitch */
+ P_CTL_TIM_VMAIN_AV_MSK = 3<<27, /* Bit 28..27: Timer Vmain_av Mask */
+ /* Bit 26..16: Release Clock on Event */
+ P_REL_PCIE_RST_DE_ASS = 1<<26, /* PCIe Reset De-Asserted */
+ P_REL_GPHY_REC_PACKET = 1<<25, /* GPHY Received Packet */
+ P_REL_INT_FIFO_N_EMPTY = 1<<24, /* Internal FIFO Not Empty */
+ P_REL_MAIN_PWR_AVAIL = 1<<23, /* Main Power Available */
+ P_REL_CLKRUN_REQ_REL = 1<<22, /* CLKRUN Request Release */
+ P_REL_PCIE_RESET_ASS = 1<<21, /* PCIe Reset Asserted */
+ P_REL_PME_ASSERTED = 1<<20, /* PME Asserted */
+ P_REL_PCIE_EXIT_L1_ST = 1<<19, /* PCIe Exit L1 State */
+ P_REL_LOADER_NOT_FIN = 1<<18, /* EPROM Loader Not Finished */
+ P_REL_PCIE_RX_EX_IDLE = 1<<17, /* PCIe Rx Exit Electrical Idle State */
+ P_REL_GPHY_LINK_UP = 1<<16, /* GPHY Link Up */
+
+ /* Bit 10.. 0: Mask for Gate Clock */
+ P_GAT_PCIE_RST_ASSERTED = 1<<10,/* PCIe Reset Asserted */
+ P_GAT_GPHY_N_REC_PACKET = 1<<9, /* GPHY Not Received Packet */
+ P_GAT_INT_FIFO_EMPTY = 1<<8, /* Internal FIFO Empty */
+ P_GAT_MAIN_PWR_N_AVAIL = 1<<7, /* Main Power Not Available */
+ P_GAT_CLKRUN_REQ_REL = 1<<6, /* CLKRUN Not Requested */
+ P_GAT_PCIE_RESET_ASS = 1<<5, /* PCIe Reset Asserted */
+ P_GAT_PME_DE_ASSERTED = 1<<4, /* PME De-Asserted */
+ P_GAT_PCIE_ENTER_L1_ST = 1<<3, /* PCIe Enter L1 State */
+ P_GAT_LOADER_FINISHED = 1<<2, /* EPROM Loader Finished */
+ P_GAT_PCIE_RX_EL_IDLE = 1<<1, /* PCIe Rx Electrical Idle State */
+ P_GAT_GPHY_LINK_DOWN = 1<<0, /* GPHY Link Down */
+
+ PCIE_OUR5_EVENT_CLK_D3_SET = P_REL_GPHY_REC_PACKET |
+ P_REL_INT_FIFO_N_EMPTY |
+ P_REL_PCIE_EXIT_L1_ST |
+ P_REL_PCIE_RX_EX_IDLE |
+ P_GAT_GPHY_N_REC_PACKET |
+ P_GAT_INT_FIFO_EMPTY |
+ P_GAT_PCIE_ENTER_L1_ST |
+ P_GAT_PCIE_RX_EL_IDLE,
+};
+
+#/* PCI_CFG_REG_1 32 bit Config Register 1 (Yukon-Ext only) */
+enum pci_cfg_reg1 {
+ P_CF1_DIS_REL_EVT_RST = 1<<24, /* Dis. Rel. Event during PCIE reset */
+ /* Bit 23..21: Release Clock on Event */
+ P_CF1_REL_LDR_NOT_FIN = 1<<23, /* EEPROM Loader Not Finished */
+ P_CF1_REL_VMAIN_AVLBL = 1<<22, /* Vmain available */
+ P_CF1_REL_PCIE_RESET = 1<<21, /* PCI-E reset */
+ /* Bit 20..18: Gate Clock on Event */
+ P_CF1_GAT_LDR_NOT_FIN = 1<<20, /* EEPROM Loader Finished */
+ P_CF1_GAT_PCIE_RX_IDLE = 1<<19, /* PCI-E Rx Electrical idle */
+ P_CF1_GAT_PCIE_RESET = 1<<18, /* PCI-E Reset */
+ P_CF1_PRST_PHY_CLKREQ = 1<<17, /* Enable PCI-E rst & PM2PHY gen. CLKREQ */
+ P_CF1_PCIE_RST_CLKREQ = 1<<16, /* Enable PCI-E rst generate CLKREQ */
+
+ P_CF1_ENA_CFG_LDR_DONE = 1<<8, /* Enable core level Config loader done */
+
+ P_CF1_ENA_TXBMU_RD_IDLE = 1<<1, /* Enable TX BMU Read IDLE for ASPM */
+ P_CF1_ENA_TXBMU_WR_IDLE = 1<<0, /* Enable TX BMU Write IDLE for ASPM */
+
+ PCIE_CFG1_EVENT_CLK_D3_SET = P_CF1_DIS_REL_EVT_RST |
+ P_CF1_REL_LDR_NOT_FIN |
+ P_CF1_REL_VMAIN_AVLBL |
+ P_CF1_REL_PCIE_RESET |
+ P_CF1_GAT_LDR_NOT_FIN |
+ P_CF1_GAT_PCIE_RESET |
+ P_CF1_PRST_PHY_CLKREQ |
+ P_CF1_ENA_CFG_LDR_DONE |
+ P_CF1_ENA_TXBMU_RD_IDLE |
+ P_CF1_ENA_TXBMU_WR_IDLE,
+};
+
#define PCI_STATUS_ERROR_BITS (PCI_STATUS_DETECTED_PARITY | \
PCI_STATUS_SIG_SYSTEM_ERROR | \
@@ -364,6 +441,20 @@ enum {
TST_CFG_WRITE_OFF= 1<<0, /* Disable Config Reg WR */
};
+/* B2_GPIO */
+enum {
+ GLB_GPIO_CLK_DEB_ENA = 1<<31, /* Clock Debug Enable */
+ GLB_GPIO_CLK_DBG_MSK = 0xf<<26, /* Clock Debug */
+
+ GLB_GPIO_INT_RST_D3_DIS = 1<<15, /* Disable Internal Reset After D3 to D0 */
+ GLB_GPIO_LED_PAD_SPEED_UP = 1<<14, /* LED PAD Speed Up */
+ GLB_GPIO_STAT_RACE_DIS = 1<<13, /* Status Race Disable */
+ GLB_GPIO_TEST_SEL_MSK = 3<<11, /* Testmode Select */
+ GLB_GPIO_TEST_SEL_BASE = 1<<11,
+ GLB_GPIO_RAND_ENA = 1<<10, /* Random Enable */
+ GLB_GPIO_RAND_BIT_1 = 1<<9, /* Random Bit 1 */
+};
+
/* B2_MAC_CFG 8 bit MAC Configuration / Chip Revision */
enum {
CFG_CHIP_R_MSK = 0xf<<4, /* Bit 7.. 4: Chip Revision */
@@ -392,6 +483,11 @@ enum {
CHIP_REV_YU_FE_A2 = 2,
};
+enum yukon_ex_rev {
+ CHIP_REV_YU_EX_A0 = 1,
+ CHIP_REV_YU_EX_B0 = 2,
+};
+
/* B2_Y2_CLK_GATE 8 bit Clock Gating (Yukon-2 only) */
enum {
@@ -515,23 +611,15 @@ enum {
enum {
B8_Q_REGS = 0x0400, /* base of Queue registers */
Q_D = 0x00, /* 8*32 bit Current Descriptor */
- Q_DA_L = 0x20, /* 32 bit Current Descriptor Address Low dWord */
- Q_DA_H = 0x24, /* 32 bit Current Descriptor Address High dWord */
+ Q_VLAN = 0x20, /* 16 bit Current VLAN Tag */
+ Q_DONE = 0x24, /* 16 bit Done Index */
Q_AC_L = 0x28, /* 32 bit Current Address Counter Low dWord */
Q_AC_H = 0x2c, /* 32 bit Current Address Counter High dWord */
Q_BC = 0x30, /* 32 bit Current Byte Counter */
Q_CSR = 0x34, /* 32 bit BMU Control/Status Register */
- Q_F = 0x38, /* 32 bit Flag Register */
- Q_T1 = 0x3c, /* 32 bit Test Register 1 */
- Q_T1_TR = 0x3c, /* 8 bit Test Register 1 Transfer SM */
- Q_T1_WR = 0x3d, /* 8 bit Test Register 1 Write Descriptor SM */
- Q_T1_RD = 0x3e, /* 8 bit Test Register 1 Read Descriptor SM */
- Q_T1_SV = 0x3f, /* 8 bit Test Register 1 Supervisor SM */
- Q_T2 = 0x40, /* 32 bit Test Register 2 */
- Q_T3 = 0x44, /* 32 bit Test Register 3 */
+ Q_TEST = 0x38, /* 32 bit Test/Control Register */
/* Yukon-2 */
- Q_DONE = 0x24, /* 16 bit Done Index (Yukon-2 only) */
Q_WM = 0x40, /* 16 bit FIFO Watermark */
Q_AL = 0x42, /* 8 bit FIFO Alignment */
Q_RSP = 0x44, /* 16 bit FIFO Read Shadow Pointer */
@@ -545,15 +633,16 @@ enum {
};
#define Q_ADDR(reg, offs) (B8_Q_REGS + (reg) + (offs))
-/* Q_F 32 bit Flag Register */
+/* Q_TEST 32 bit Test Register */
enum {
- F_ALM_FULL = 1<<27, /* Rx FIFO: almost full */
- F_EMPTY = 1<<27, /* Tx FIFO: empty flag */
- F_FIFO_EOF = 1<<26, /* Tag (EOF Flag) bit in FIFO */
- F_WM_REACHED = 1<<25, /* Watermark reached */
+ /* Transmit */
+ F_TX_CHK_AUTO_OFF = 1<<31, /* Tx checksum auto calc off (Yukon EX) */
+ F_TX_CHK_AUTO_ON = 1<<30, /* Tx checksum auto calc off (Yukon EX) */
+
+ /* Receive */
F_M_RX_RAM_DIS = 1<<24, /* MAC Rx RAM Read Port disable */
- F_FIFO_LEVEL = 0x1fL<<16, /* Bit 23..16: # of Qwords in FIFO */
- F_WATER_MARK = 0x0007ffL, /* Bit 10.. 0: Watermark */
+
+ /* Hardware testbits not used */
};
/* Queue Prefetch Unit Offsets, use Y2_QADDR() to address (Yukon-2 only)*/
@@ -1608,6 +1697,16 @@ enum {
RX_VLAN_STRIP_ON = 1<<25, /* enable VLAN stripping */
RX_VLAN_STRIP_OFF = 1<<24, /* disable VLAN stripping */
+ RX_MACSEC_FLUSH_ON = 1<<23,
+ RX_MACSEC_FLUSH_OFF = 1<<22,
+ RX_MACSEC_ASF_FLUSH_ON = 1<<21,
+ RX_MACSEC_ASF_FLUSH_OFF = 1<<20,
+
+ GMF_RX_OVER_ON = 1<<19, /* enable flushing on receive overrun */
+ GMF_RX_OVER_OFF = 1<<18, /* disable flushing on receive overrun */
+ GMF_ASF_RX_OVER_ON = 1<<17, /* enable flushing of ASF when overrun */
+ GMF_ASF_RX_OVER_OFF = 1<<16, /* disable flushing of ASF when overrun */
+
GMF_WP_TST_ON = 1<<14, /* Write Pointer Test On */
GMF_WP_TST_OFF = 1<<13, /* Write Pointer Test Off */
GMF_WP_STEP = 1<<12, /* Write Pointer Step/Increment */
@@ -1720,6 +1819,15 @@ enum {
/* GMAC_CTRL 32 bit GMAC Control Reg (YUKON only) */
enum {
+ GMC_SET_RST = 1<<15,/* MAC SEC RST */
+ GMC_SEC_RST_OFF = 1<<14,/* MAC SEC RSt OFF */
+ GMC_BYP_MACSECRX_ON = 1<<13,/* Bypass macsec RX */
+ GMC_BYP_MACSECRX_OFF= 1<<12,/* Bypass macsec RX off */
+ GMC_BYP_MACSECTX_ON = 1<<11,/* Bypass macsec TX */
+ GMC_BYP_MACSECTX_OFF= 1<<10,/* Bypass macsec TX off*/
+ GMC_BYP_RETR_ON = 1<<9, /* Bypass retransmit FIFO On */
+ GMC_BYP_RETR_OFF= 1<<8, /* Bypass retransmit FIFO Off */
+
GMC_H_BURST_ON = 1<<7, /* Half Duplex Burst Mode On */
GMC_H_BURST_OFF = 1<<6, /* Half Duplex Burst Mode Off */
GMC_F_LOOPB_ON = 1<<5, /* FIFO Loopback On */
@@ -1805,9 +1913,13 @@ enum {
OP_ADDR64VLAN = OP_ADDR64 | OP_VLAN,
OP_LRGLEN = 0x24,
OP_LRGLENVLAN = OP_LRGLEN | OP_VLAN,
+ OP_MSS = 0x28,
+ OP_MSSVLAN = OP_MSS | OP_VLAN,
+
OP_BUFFER = 0x40,
OP_PACKET = 0x41,
OP_LARGESEND = 0x43,
+ OP_LSOV2 = 0x45,
/* YUKON-2 STATUS opcodes defines */
OP_RXSTAT = 0x60,
@@ -1818,6 +1930,19 @@ enum {
OP_RXTIMEVLAN = OP_RXTIMESTAMP | OP_RXVLAN,
OP_RSS_HASH = 0x65,
OP_TXINDEXLE = 0x68,
+ OP_MACSEC = 0x6c,
+ OP_PUTIDX = 0x70,
+};
+
+enum status_css {
+ CSS_TCPUDPCSOK = 1<<7, /* TCP / UDP checksum is ok */
+ CSS_ISUDP = 1<<6, /* packet is a UDP packet */
+ CSS_ISTCP = 1<<5, /* packet is a TCP packet */
+ CSS_ISIPFRAG = 1<<4, /* packet is a TCP/UDP frag, CS calc not done */
+ CSS_ISIPV6 = 1<<3, /* packet is a IPv6 packet */
+ CSS_IPV4CSUMOK = 1<<2, /* IP v4: TCP header checksum is ok */
+ CSS_ISIPV4 = 1<<1, /* packet is a IPv4 packet */
+ CSS_LINK_BIT = 1<<0, /* port number (legacy) */
};
/* Yukon 2 hardware interface */
@@ -1838,7 +1963,7 @@ struct sky2_rx_le {
struct sky2_status_le {
__le32 status; /* also checksum */
__le16 length; /* also vlan tag */
- u8 link;
+ u8 css;
u8 opcode;
} __attribute((packed));
diff --git a/drivers/net/sni_82596.c b/drivers/net/sni_82596.c
new file mode 100644
index 000000000000..2cf6794acb4f
--- /dev/null
+++ b/drivers/net/sni_82596.c
@@ -0,0 +1,185 @@
+/*
+ * sni_82596.c -- driver for intel 82596 ethernet controller, as
+ * used in older SNI RM machines
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/bitops.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+
+#define SNI_82596_DRIVER_VERSION "SNI RM 82596 driver - Revision: 0.01"
+
+static const char sni_82596_string[] = "snirm_82596";
+
+#define DMA_ALLOC dma_alloc_coherent
+#define DMA_FREE dma_free_coherent
+#define DMA_WBACK(priv, addr, len) do { } while (0)
+#define DMA_INV(priv, addr, len) do { } while (0)
+#define DMA_WBACK_INV(priv, addr, len) do { } while (0)
+
+#define SYSBUS 0x00004400
+
+/* big endian CPU, 82596 little endian */
+#define SWAP32(x) cpu_to_le32((u32)(x))
+#define SWAP16(x) cpu_to_le16((u16)(x))
+
+#define OPT_MPU_16BIT 0x01
+
+#include "lib82596.c"
+
+MODULE_AUTHOR("Thomas Bogendoerfer");
+MODULE_DESCRIPTION("i82596 driver");
+MODULE_LICENSE("GPL");
+module_param(i596_debug, int, 0);
+MODULE_PARM_DESC(i596_debug, "82596 debug mask");
+
+static inline void ca(struct net_device *dev)
+{
+ struct i596_private *lp = netdev_priv(dev);
+
+ writel(0, lp->ca);
+}
+
+
+static void mpu_port(struct net_device *dev, int c, dma_addr_t x)
+{
+ struct i596_private *lp = netdev_priv(dev);
+
+ u32 v = (u32) (c) | (u32) (x);
+
+ if (lp->options & OPT_MPU_16BIT) {
+ writew(v & 0xffff, lp->mpu_port);
+ wmb(); /* order writes to MPU port */
+ udelay(1);
+ writew(v >> 16, lp->mpu_port);
+ } else {
+ writel(v, lp->mpu_port);
+ wmb(); /* order writes to MPU port */
+ udelay(1);
+ writel(v, lp->mpu_port);
+ }
+}
+
+
+static int __devinit sni_82596_probe(struct platform_device *dev)
+{
+ struct net_device *netdevice;
+ struct i596_private *lp;
+ struct resource *res, *ca, *idprom, *options;
+ int retval = -ENOMEM;
+ void __iomem *mpu_addr;
+ void __iomem *ca_addr;
+ u8 __iomem *eth_addr;
+
+ res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ ca = platform_get_resource(dev, IORESOURCE_MEM, 1);
+ options = platform_get_resource(dev, 0, 0);
+ idprom = platform_get_resource(dev, IORESOURCE_MEM, 2);
+ if (!res || !ca || !options || !idprom)
+ return -ENODEV;
+ mpu_addr = ioremap_nocache(res->start, 4);
+ if (!mpu_addr)
+ return -ENOMEM;
+ ca_addr = ioremap_nocache(ca->start, 4);
+ if (!ca_addr)
+ goto probe_failed_free_mpu;
+
+ printk(KERN_INFO "Found i82596 at 0x%x\n", res->start);
+
+ netdevice = alloc_etherdev(sizeof(struct i596_private));
+ if (!netdevice)
+ goto probe_failed_free_ca;
+
+ SET_NETDEV_DEV(netdevice, &dev->dev);
+ platform_set_drvdata (dev, netdevice);
+
+ netdevice->base_addr = res->start;
+ netdevice->irq = platform_get_irq(dev, 0);
+
+ eth_addr = ioremap_nocache(idprom->start, 0x10);
+ if (!eth_addr)
+ goto probe_failed;
+
+ /* someone seems to like messed up stuff */
+ netdevice->dev_addr[0] = readb(eth_addr + 0x0b);
+ netdevice->dev_addr[1] = readb(eth_addr + 0x0a);
+ netdevice->dev_addr[2] = readb(eth_addr + 0x09);
+ netdevice->dev_addr[3] = readb(eth_addr + 0x08);
+ netdevice->dev_addr[4] = readb(eth_addr + 0x07);
+ netdevice->dev_addr[5] = readb(eth_addr + 0x06);
+ iounmap(eth_addr);
+
+ if (!netdevice->irq) {
+ printk(KERN_ERR "%s: IRQ not found for i82596 at 0x%lx\n",
+ __FILE__, netdevice->base_addr);
+ goto probe_failed;
+ }
+
+ lp = netdev_priv(netdevice);
+ lp->options = options->flags & IORESOURCE_BITS;
+ lp->ca = ca_addr;
+ lp->mpu_port = mpu_addr;
+
+ retval = i82596_probe(netdevice);
+ if (retval == 0)
+ return 0;
+
+probe_failed:
+ free_netdev(netdevice);
+probe_failed_free_ca:
+ iounmap(ca_addr);
+probe_failed_free_mpu:
+ iounmap(mpu_addr);
+ return retval;
+}
+
+static int __devexit sni_82596_driver_remove(struct platform_device *pdev)
+{
+ struct net_device *dev = platform_get_drvdata(pdev);
+ struct i596_private *lp = netdev_priv(dev);
+
+ unregister_netdev(dev);
+ DMA_FREE(dev->dev.parent, sizeof(struct i596_private),
+ lp->dma, lp->dma_addr);
+ iounmap(lp->ca);
+ iounmap(lp->mpu_port);
+ free_netdev (dev);
+ return 0;
+}
+
+static struct platform_driver sni_82596_driver = {
+ .probe = sni_82596_probe,
+ .remove = __devexit_p(sni_82596_driver_remove),
+ .driver = {
+ .name = sni_82596_string,
+ },
+};
+
+static int __devinit sni_82596_init(void)
+{
+ printk(KERN_INFO SNI_82596_DRIVER_VERSION "\n");
+ return platform_driver_register(&sni_82596_driver);
+}
+
+
+static void __exit sni_82596_exit(void)
+{
+ platform_driver_unregister(&sni_82596_driver);
+}
+
+module_init(sni_82596_init);
+module_exit(sni_82596_exit);
diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c
index 7a4aa6a9f949..f5abb5279d4d 100644
--- a/drivers/net/spider_net.c
+++ b/drivers/net/spider_net.c
@@ -434,7 +434,8 @@ spider_net_prepare_rx_descr(struct spider_net_card *card,
bufsize + SPIDER_NET_RXBUF_ALIGN - 1);
if (!descr->skb) {
if (netif_msg_rx_err(card) && net_ratelimit())
- pr_err("Not enough memory to allocate rx buffer\n");
+ dev_err(&card->netdev->dev,
+ "Not enough memory to allocate rx buffer\n");
card->spider_stats.alloc_rx_skb_error++;
return -ENOMEM;
}
@@ -455,7 +456,7 @@ spider_net_prepare_rx_descr(struct spider_net_card *card,
dev_kfree_skb_any(descr->skb);
descr->skb = NULL;
if (netif_msg_rx_err(card) && net_ratelimit())
- pr_err("Could not iommu-map rx buffer\n");
+ dev_err(&card->netdev->dev, "Could not iommu-map rx buffer\n");
card->spider_stats.rx_iommu_map_error++;
hwdescr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
} else {
@@ -500,6 +501,20 @@ spider_net_enable_rxdmac(struct spider_net_card *card)
}
/**
+ * spider_net_disable_rxdmac - disables the receive DMA controller
+ * @card: card structure
+ *
+ * spider_net_disable_rxdmac terminates processing on the DMA controller
+ * by turing off the DMA controller, with the force-end flag set.
+ */
+static inline void
+spider_net_disable_rxdmac(struct spider_net_card *card)
+{
+ spider_net_write_reg(card, SPIDER_NET_GDADMACCNTR,
+ SPIDER_NET_DMA_RX_FEND_VALUE);
+}
+
+/**
* spider_net_refill_rx_chain - refills descriptors/skbs in the rx chains
* @card: card structure
*
@@ -655,20 +670,6 @@ write_hash:
}
/**
- * spider_net_disable_rxdmac - disables the receive DMA controller
- * @card: card structure
- *
- * spider_net_disable_rxdmac terminates processing on the DMA controller by
- * turing off DMA and issueing a force end
- */
-static void
-spider_net_disable_rxdmac(struct spider_net_card *card)
-{
- spider_net_write_reg(card, SPIDER_NET_GDADMACCNTR,
- SPIDER_NET_DMA_RX_FEND_VALUE);
-}
-
-/**
* spider_net_prepare_tx_descr - fill tx descriptor with skb data
* @card: card structure
* @descr: descriptor structure to fill out
@@ -692,7 +693,7 @@ spider_net_prepare_tx_descr(struct spider_net_card *card,
buf = pci_map_single(card->pdev, skb->data, skb->len, PCI_DMA_TODEVICE);
if (pci_dma_mapping_error(buf)) {
if (netif_msg_tx_err(card) && net_ratelimit())
- pr_err("could not iommu-map packet (%p, %i). "
+ dev_err(&card->netdev->dev, "could not iommu-map packet (%p, %i). "
"Dropping packet\n", skb->data, skb->len);
card->spider_stats.tx_iommu_map_error++;
return -ENOMEM;
@@ -715,7 +716,7 @@ spider_net_prepare_tx_descr(struct spider_net_card *card,
hwdescr->data_status = 0;
hwdescr->dmac_cmd_status =
- SPIDER_NET_DESCR_CARDOWNED | SPIDER_NET_DMAC_NOCS;
+ SPIDER_NET_DESCR_CARDOWNED | SPIDER_NET_DMAC_TXFRMTL;
spin_unlock_irqrestore(&chain->lock, flags);
if (skb->ip_summed == CHECKSUM_PARTIAL)
@@ -832,9 +833,8 @@ spider_net_release_tx_chain(struct spider_net_card *card, int brutal)
case SPIDER_NET_DESCR_PROTECTION_ERROR:
case SPIDER_NET_DESCR_FORCE_END:
if (netif_msg_tx_err(card))
- pr_err("%s: forcing end of tx descriptor "
- "with status x%02x\n",
- card->netdev->name, status);
+ dev_err(&card->netdev->dev, "forcing end of tx descriptor "
+ "with status x%02x\n", status);
card->netdev_stats.tx_errors++;
break;
@@ -1022,34 +1022,94 @@ spider_net_pass_skb_up(struct spider_net_descr *descr,
netif_receive_skb(skb);
}
-#ifdef DEBUG
static void show_rx_chain(struct spider_net_card *card)
{
struct spider_net_descr_chain *chain = &card->rx_chain;
struct spider_net_descr *start= chain->tail;
struct spider_net_descr *descr= start;
+ struct spider_net_hw_descr *hwd = start->hwdescr;
+ struct device *dev = &card->netdev->dev;
+ u32 curr_desc, next_desc;
int status;
+ int tot = 0;
int cnt = 0;
- int cstat = spider_net_get_descr_status(descr);
- printk(KERN_INFO "RX chain tail at descr=%ld\n",
- (start - card->descr) - card->tx_chain.num_desc);
+ int off = start - chain->ring;
+ int cstat = hwd->dmac_cmd_status;
+
+ dev_info(dev, "Total number of descrs=%d\n",
+ chain->num_desc);
+ dev_info(dev, "Chain tail located at descr=%d, status=0x%x\n",
+ off, cstat);
+
+ curr_desc = spider_net_read_reg(card, SPIDER_NET_GDACTDPA);
+ next_desc = spider_net_read_reg(card, SPIDER_NET_GDACNEXTDA);
+
status = cstat;
do
{
- status = spider_net_get_descr_status(descr);
+ hwd = descr->hwdescr;
+ off = descr - chain->ring;
+ status = hwd->dmac_cmd_status;
+
+ if (descr == chain->head)
+ dev_info(dev, "Chain head is at %d, head status=0x%x\n",
+ off, status);
+
+ if (curr_desc == descr->bus_addr)
+ dev_info(dev, "HW curr desc (GDACTDPA) is at %d, status=0x%x\n",
+ off, status);
+
+ if (next_desc == descr->bus_addr)
+ dev_info(dev, "HW next desc (GDACNEXTDA) is at %d, status=0x%x\n",
+ off, status);
+
+ if (hwd->next_descr_addr == 0)
+ dev_info(dev, "chain is cut at %d\n", off);
+
if (cstat != status) {
- printk(KERN_INFO "Have %d descrs with stat=x%08x\n", cnt, cstat);
+ int from = (chain->num_desc + off - cnt) % chain->num_desc;
+ int to = (chain->num_desc + off - 1) % chain->num_desc;
+ dev_info(dev, "Have %d (from %d to %d) descrs "
+ "with stat=0x%08x\n", cnt, from, to, cstat);
cstat = status;
cnt = 0;
}
+
cnt ++;
+ tot ++;
+ descr = descr->next;
+ } while (descr != start);
+
+ dev_info(dev, "Last %d descrs with stat=0x%08x "
+ "for a total of %d descrs\n", cnt, cstat, tot);
+
+#ifdef DEBUG
+ /* Now dump the whole ring */
+ descr = start;
+ do
+ {
+ struct spider_net_hw_descr *hwd = descr->hwdescr;
+ status = spider_net_get_descr_status(hwd);
+ cnt = descr - chain->ring;
+ dev_info(dev, "Descr %d stat=0x%08x skb=%p\n",
+ cnt, status, descr->skb);
+ dev_info(dev, "bus addr=%08x buf addr=%08x sz=%d\n",
+ descr->bus_addr, hwd->buf_addr, hwd->buf_size);
+ dev_info(dev, "next=%08x result sz=%d valid sz=%d\n",
+ hwd->next_descr_addr, hwd->result_size,
+ hwd->valid_size);
+ dev_info(dev, "dmac=%08x data stat=%08x data err=%08x\n",
+ hwd->dmac_cmd_status, hwd->data_status,
+ hwd->data_error);
+ dev_info(dev, "\n");
+
descr = descr->next;
} while (descr != start);
- printk(KERN_INFO "Last %d descrs with stat=x%08x\n", cnt, cstat);
-}
#endif
+}
+
/**
* spider_net_resync_head_ptr - Advance head ptr past empty descrs
*
@@ -1127,6 +1187,7 @@ spider_net_decode_one_descr(struct spider_net_card *card)
struct spider_net_descr_chain *chain = &card->rx_chain;
struct spider_net_descr *descr = chain->tail;
struct spider_net_hw_descr *hwdescr = descr->hwdescr;
+ u32 hw_buf_addr;
int status;
status = spider_net_get_descr_status(hwdescr);
@@ -1140,15 +1201,17 @@ spider_net_decode_one_descr(struct spider_net_card *card)
chain->tail = descr->next;
/* unmap descriptor */
- pci_unmap_single(card->pdev, hwdescr->buf_addr,
+ hw_buf_addr = hwdescr->buf_addr;
+ hwdescr->buf_addr = 0xffffffff;
+ pci_unmap_single(card->pdev, hw_buf_addr,
SPIDER_NET_MAX_FRAME, PCI_DMA_FROMDEVICE);
if ( (status == SPIDER_NET_DESCR_RESPONSE_ERROR) ||
(status == SPIDER_NET_DESCR_PROTECTION_ERROR) ||
(status == SPIDER_NET_DESCR_FORCE_END) ) {
if (netif_msg_rx_err(card))
- pr_err("%s: dropping RX descriptor with state %d\n",
- card->netdev->name, status);
+ dev_err(&card->netdev->dev,
+ "dropping RX descriptor with state %d\n", status);
card->netdev_stats.rx_dropped++;
goto bad_desc;
}
@@ -1156,8 +1219,8 @@ spider_net_decode_one_descr(struct spider_net_card *card)
if ( (status != SPIDER_NET_DESCR_COMPLETE) &&
(status != SPIDER_NET_DESCR_FRAME_END) ) {
if (netif_msg_rx_err(card))
- pr_err("%s: RX descriptor with unknown state %d\n",
- card->netdev->name, status);
+ dev_err(&card->netdev->dev,
+ "RX descriptor with unknown state %d\n", status);
card->spider_stats.rx_desc_unk_state++;
goto bad_desc;
}
@@ -1165,18 +1228,17 @@ spider_net_decode_one_descr(struct spider_net_card *card)
/* The cases we'll throw away the packet immediately */
if (hwdescr->data_error & SPIDER_NET_DESTROY_RX_FLAGS) {
if (netif_msg_rx_err(card))
- pr_err("%s: error in received descriptor found, "
+ dev_err(&card->netdev->dev,
+ "error in received descriptor found, "
"data_status=x%08x, data_error=x%08x\n",
- card->netdev->name,
hwdescr->data_status, hwdescr->data_error);
goto bad_desc;
}
- if (hwdescr->dmac_cmd_status & 0xfcf4) {
- pr_err("%s: bad status, cmd_status=x%08x\n",
- card->netdev->name,
+ if (hwdescr->dmac_cmd_status & SPIDER_NET_DESCR_BAD_STATUS) {
+ dev_err(&card->netdev->dev, "bad status, cmd_status=x%08x\n",
hwdescr->dmac_cmd_status);
- pr_err("buf_addr=x%08x\n", hwdescr->buf_addr);
+ pr_err("buf_addr=x%08x\n", hw_buf_addr);
pr_err("buf_size=x%08x\n", hwdescr->buf_size);
pr_err("next_descr_addr=x%08x\n", hwdescr->next_descr_addr);
pr_err("result_size=x%08x\n", hwdescr->result_size);
@@ -1196,6 +1258,8 @@ spider_net_decode_one_descr(struct spider_net_card *card)
return 1;
bad_desc:
+ if (netif_msg_rx_err(card))
+ show_rx_chain(card);
dev_kfree_skb_irq(descr->skb);
descr->skb = NULL;
hwdescr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
@@ -1221,7 +1285,6 @@ spider_net_poll(struct net_device *netdev, int *budget)
int packets_to_do, packets_done = 0;
int no_more_packets = 0;
- spider_net_cleanup_tx_ring(card);
packets_to_do = min(*budget, netdev->quota);
while (packets_to_do) {
@@ -1246,6 +1309,8 @@ spider_net_poll(struct net_device *netdev, int *budget)
spider_net_refill_rx_chain(card);
spider_net_enable_rxdmac(card);
+ spider_net_cleanup_tx_ring(card);
+
/* if all packets are in the stack, enable interrupts and return 0 */
/* if not, return 1 */
if (no_more_packets) {
@@ -1415,7 +1480,7 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg)
case SPIDER_NET_GPWFFINT:
/* PHY command queue full */
if (netif_msg_intr(card))
- pr_err("PHY write queue full\n");
+ dev_err(&card->netdev->dev, "PHY write queue full\n");
show_error = 0;
break;
@@ -1582,9 +1647,8 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg)
}
if ((show_error) && (netif_msg_intr(card)) && net_ratelimit())
- pr_err("Got error interrupt on %s, GHIINT0STS = 0x%08x, "
+ dev_err(&card->netdev->dev, "Error interrupt, GHIINT0STS = 0x%08x, "
"GHIINT1STS = 0x%08x, GHIINT2STS = 0x%08x\n",
- card->netdev->name,
status_reg, error_reg1, error_reg2);
/* clear interrupt sources */
@@ -1849,7 +1913,8 @@ spider_net_init_firmware(struct spider_net_card *card)
SPIDER_NET_FIRMWARE_NAME, &card->pdev->dev) == 0) {
if ( (firmware->size != SPIDER_NET_FIRMWARE_LEN) &&
netif_msg_probe(card) ) {
- pr_err("Incorrect size of spidernet firmware in " \
+ dev_err(&card->netdev->dev,
+ "Incorrect size of spidernet firmware in " \
"filesystem. Looking in host firmware...\n");
goto try_host_fw;
}
@@ -1873,8 +1938,8 @@ try_host_fw:
if ( (fw_size != SPIDER_NET_FIRMWARE_LEN) &&
netif_msg_probe(card) ) {
- pr_err("Incorrect size of spidernet firmware in " \
- "host firmware\n");
+ dev_err(&card->netdev->dev,
+ "Incorrect size of spidernet firmware in host firmware\n");
goto done;
}
@@ -1884,7 +1949,8 @@ done:
return err;
out_err:
if (netif_msg_probe(card))
- pr_err("Couldn't find spidernet firmware in filesystem " \
+ dev_err(&card->netdev->dev,
+ "Couldn't find spidernet firmware in filesystem " \
"or host firmware\n");
return err;
}
@@ -2279,13 +2345,14 @@ spider_net_setup_netdev(struct spider_net_card *card)
result = spider_net_set_mac(netdev, &addr);
if ((result) && (netif_msg_probe(card)))
- pr_err("Failed to set MAC address: %i\n", result);
+ dev_err(&card->netdev->dev,
+ "Failed to set MAC address: %i\n", result);
result = register_netdev(netdev);
if (result) {
if (netif_msg_probe(card))
- pr_err("Couldn't register net_device: %i\n",
- result);
+ dev_err(&card->netdev->dev,
+ "Couldn't register net_device: %i\n", result);
return result;
}
@@ -2363,17 +2430,19 @@ spider_net_setup_pci_dev(struct pci_dev *pdev)
unsigned long mmio_start, mmio_len;
if (pci_enable_device(pdev)) {
- pr_err("Couldn't enable PCI device\n");
+ dev_err(&pdev->dev, "Couldn't enable PCI device\n");
return NULL;
}
if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
- pr_err("Couldn't find proper PCI device base address.\n");
+ dev_err(&pdev->dev,
+ "Couldn't find proper PCI device base address.\n");
goto out_disable_dev;
}
if (pci_request_regions(pdev, spider_net_driver_name)) {
- pr_err("Couldn't obtain PCI resources, aborting.\n");
+ dev_err(&pdev->dev,
+ "Couldn't obtain PCI resources, aborting.\n");
goto out_disable_dev;
}
@@ -2381,8 +2450,8 @@ spider_net_setup_pci_dev(struct pci_dev *pdev)
card = spider_net_alloc_card();
if (!card) {
- pr_err("Couldn't allocate net_device structure, "
- "aborting.\n");
+ dev_err(&pdev->dev,
+ "Couldn't allocate net_device structure, aborting.\n");
goto out_release_regions;
}
card->pdev = pdev;
@@ -2396,7 +2465,8 @@ spider_net_setup_pci_dev(struct pci_dev *pdev)
card->regs = ioremap(mmio_start, mmio_len);
if (!card->regs) {
- pr_err("Couldn't obtain PCI resources, aborting.\n");
+ dev_err(&pdev->dev,
+ "Couldn't obtain PCI resources, aborting.\n");
goto out_release_regions;
}
diff --git a/drivers/net/spider_net.h b/drivers/net/spider_net.h
index 1d054aa71504..dbbdb8cee3c6 100644
--- a/drivers/net/spider_net.h
+++ b/drivers/net/spider_net.h
@@ -349,11 +349,23 @@ enum spider_net_int2_status {
#define SPIDER_NET_GPRDAT_MASK 0x0000ffff
#define SPIDER_NET_DMAC_NOINTR_COMPLETE 0x00800000
-#define SPIDER_NET_DMAC_NOCS 0x00040000
+#define SPIDER_NET_DMAC_TXFRMTL 0x00040000
#define SPIDER_NET_DMAC_TCP 0x00020000
#define SPIDER_NET_DMAC_UDP 0x00030000
#define SPIDER_NET_TXDCEST 0x08000000
+#define SPIDER_NET_DESCR_RXFDIS 0x00000001
+#define SPIDER_NET_DESCR_RXDCEIS 0x00000002
+#define SPIDER_NET_DESCR_RXDEN0IS 0x00000004
+#define SPIDER_NET_DESCR_RXINVDIS 0x00000008
+#define SPIDER_NET_DESCR_RXRERRIS 0x00000010
+#define SPIDER_NET_DESCR_RXFDCIMS 0x00000100
+#define SPIDER_NET_DESCR_RXDCEIMS 0x00000200
+#define SPIDER_NET_DESCR_RXDEN0IMS 0x00000400
+#define SPIDER_NET_DESCR_RXINVDIMS 0x00000800
+#define SPIDER_NET_DESCR_RXRERRMIS 0x00001000
+#define SPIDER_NET_DESCR_UNUSED 0x077fe0e0
+
#define SPIDER_NET_DESCR_IND_PROC_MASK 0xF0000000
#define SPIDER_NET_DESCR_COMPLETE 0x00000000 /* used in rx and tx */
#define SPIDER_NET_DESCR_RESPONSE_ERROR 0x10000000 /* used in rx and tx */
@@ -364,6 +376,13 @@ enum spider_net_int2_status {
#define SPIDER_NET_DESCR_NOT_IN_USE 0xF0000000
#define SPIDER_NET_DESCR_TXDESFLG 0x00800000
+#define SPIDER_NET_DESCR_BAD_STATUS (SPIDER_NET_DESCR_RXDEN0IS | \
+ SPIDER_NET_DESCR_RXRERRIS | \
+ SPIDER_NET_DESCR_RXDEN0IMS | \
+ SPIDER_NET_DESCR_RXINVDIMS | \
+ SPIDER_NET_DESCR_RXRERRMIS | \
+ SPIDER_NET_DESCR_UNUSED)
+
/* Descriptor, as defined by the hardware */
struct spider_net_hw_descr {
u32 buf_addr;
diff --git a/drivers/net/tulip/Kconfig b/drivers/net/tulip/Kconfig
index 8c9634a98c11..1c537d5a3062 100644
--- a/drivers/net/tulip/Kconfig
+++ b/drivers/net/tulip/Kconfig
@@ -2,17 +2,17 @@
# Tulip family network device configuration
#
-menu "Tulip family network device support"
- depends on NET_ETHERNET && (PCI || EISA || CARDBUS)
-
-config NET_TULIP
+menuconfig NET_TULIP
bool "\"Tulip\" family network device support"
+ depends on PCI || EISA || CARDBUS
help
This selects the "Tulip" family of EISA/PCI network cards.
+if NET_TULIP
+
config DE2104X
tristate "Early DECchip Tulip (dc2104x) PCI support (EXPERIMENTAL)"
- depends on NET_TULIP && PCI && EXPERIMENTAL
+ depends on PCI && EXPERIMENTAL
select CRC32
---help---
This driver is developed for the SMC EtherPower series Ethernet
@@ -30,7 +30,7 @@ config DE2104X
config TULIP
tristate "DECchip Tulip (dc2114x) PCI support"
- depends on NET_TULIP && PCI
+ depends on PCI
select CRC32
---help---
This driver is developed for the SMC EtherPower series Ethernet
@@ -95,7 +95,7 @@ config TULIP_NAPI_HW_MITIGATION
config DE4X5
tristate "Generic DECchip & DIGITAL EtherWORKS PCI/EISA"
- depends on NET_TULIP && (PCI || EISA)
+ depends on PCI || EISA
select CRC32
---help---
This is support for the DIGITAL series of PCI/EISA Ethernet cards.
@@ -112,7 +112,7 @@ config DE4X5
config WINBOND_840
tristate "Winbond W89c840 Ethernet support"
- depends on NET_TULIP && PCI
+ depends on PCI
select CRC32
select MII
help
@@ -123,7 +123,7 @@ config WINBOND_840
config DM9102
tristate "Davicom DM910x/DM980x support"
- depends on NET_TULIP && PCI
+ depends on PCI
select CRC32
---help---
This driver is for DM9102(A)/DM9132/DM9801 compatible PCI cards from
@@ -137,7 +137,7 @@ config DM9102
config ULI526X
tristate "ULi M526x controller support"
- depends on NET_TULIP && PCI
+ depends on PCI
select CRC32
---help---
This driver is for ULi M5261/M5263 10/100M Ethernet Controller
@@ -149,7 +149,7 @@ config ULI526X
config PCMCIA_XIRCOM
tristate "Xircom CardBus support (new driver)"
- depends on NET_TULIP && CARDBUS
+ depends on CARDBUS
---help---
This driver is for the Digital "Tulip" Ethernet CardBus adapters.
It should work with most DEC 21*4*-based chips/ethercards, as well
@@ -162,7 +162,7 @@ config PCMCIA_XIRCOM
config PCMCIA_XIRTULIP
tristate "Xircom Tulip-like CardBus support (old driver)"
- depends on NET_TULIP && CARDBUS && BROKEN_ON_SMP
+ depends on CARDBUS && BROKEN_ON_SMP
select CRC32
---help---
This driver is for the Digital "Tulip" Ethernet CardBus adapters.
@@ -174,5 +174,4 @@ config PCMCIA_XIRTULIP
<file:Documentation/networking/net-modules.txt>. The module will
be called xircom_tulip_cb. If unsure, say N.
-endmenu
-
+endif # NET_TULIP
diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c
index 861729806dc1..d380e0b3f05a 100644
--- a/drivers/net/tulip/de2104x.c
+++ b/drivers/net/tulip/de2104x.c
@@ -785,7 +785,6 @@ static void __de_set_rx_mode (struct net_device *dev)
de->tx_head = NEXT_TX(entry);
- BUG_ON(TX_BUFFS_AVAIL(de) < 0);
if (TX_BUFFS_AVAIL(de) == 0)
netif_stop_queue(dev);
diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c
index 62143f92c231..42fca26afc50 100644
--- a/drivers/net/tulip/de4x5.c
+++ b/drivers/net/tulip/de4x5.c
@@ -597,7 +597,7 @@ static char *args;
#endif
struct parameters {
- int fdx;
+ bool fdx;
int autosense;
};
@@ -809,10 +809,10 @@ struct de4x5_private {
s32 irq_en; /* Summary interrupt bits */
int media; /* Media (eg TP), mode (eg 100B)*/
int c_media; /* Remember the last media conn */
- int fdx; /* media full duplex flag */
+ bool fdx; /* media full duplex flag */
int linkOK; /* Link is OK */
int autosense; /* Allow/disallow autosensing */
- int tx_enable; /* Enable descriptor polling */
+ bool tx_enable; /* Enable descriptor polling */
int setup_f; /* Setup frame filtering type */
int local_state; /* State within a 'media' state */
struct mii_phy phy[DE4X5_MAX_PHY]; /* List of attached PHY devices */
@@ -838,8 +838,8 @@ struct de4x5_private {
struct de4x5_srom srom; /* A copy of the SROM */
int cfrv; /* Card CFRV copy */
int rx_ovf; /* Check for 'RX overflow' tag */
- int useSROM; /* For non-DEC card use SROM */
- int useMII; /* Infoblock using the MII */
+ bool useSROM; /* For non-DEC card use SROM */
+ bool useMII; /* Infoblock using the MII */
int asBitValid; /* Autosense bits in GEP? */
int asPolarity; /* 0 => asserted high */
int asBit; /* Autosense bit number in GEP */
@@ -928,7 +928,7 @@ static int dc21040_state(struct net_device *dev, int csr13, int csr14, int c
static int test_media(struct net_device *dev, s32 irqs, s32 irq_mask, s32 csr13, s32 csr14, s32 csr15, s32 msec);
static int test_for_100Mb(struct net_device *dev, int msec);
static int wait_for_link(struct net_device *dev);
-static int test_mii_reg(struct net_device *dev, int reg, int mask, int pol, long msec);
+static int test_mii_reg(struct net_device *dev, int reg, int mask, bool pol, long msec);
static int is_spd_100(struct net_device *dev);
static int is_100_up(struct net_device *dev);
static int is_10_up(struct net_device *dev);
@@ -1109,7 +1109,7 @@ de4x5_hw_init(struct net_device *dev, u_long iobase, struct device *gendev)
/*
** Now find out what kind of DC21040/DC21041/DC21140 board we have.
*/
- lp->useSROM = FALSE;
+ lp->useSROM = false;
if (lp->bus == PCI) {
PCI_signature(name, lp);
} else {
@@ -1137,7 +1137,7 @@ de4x5_hw_init(struct net_device *dev, u_long iobase, struct device *gendev)
lp->cache.gepc = GEP_INIT;
lp->asBit = GEP_SLNK;
lp->asPolarity = GEP_SLNK;
- lp->asBitValid = TRUE;
+ lp->asBitValid = ~0;
lp->timeout = -1;
lp->gendev = gendev;
spin_lock_init(&lp->lock);
@@ -1463,7 +1463,7 @@ de4x5_queue_pkt(struct sk_buff *skb, struct net_device *dev)
u_long flags = 0;
netif_stop_queue(dev);
- if (lp->tx_enable == NO) { /* Cannot send for now */
+ if (!lp->tx_enable) { /* Cannot send for now */
return -1;
}
@@ -2424,7 +2424,7 @@ dc21040_autoconf(struct net_device *dev)
switch (lp->media) {
case INIT:
DISABLE_IRQs;
- lp->tx_enable = NO;
+ lp->tx_enable = false;
lp->timeout = -1;
de4x5_save_skbs(dev);
if ((lp->autosense == AUTO) || (lp->autosense == TP)) {
@@ -2477,7 +2477,7 @@ dc21040_autoconf(struct net_device *dev)
lp->c_media = lp->media;
}
lp->media = INIT;
- lp->tx_enable = NO;
+ lp->tx_enable = false;
break;
}
@@ -2578,7 +2578,7 @@ dc21041_autoconf(struct net_device *dev)
switch (lp->media) {
case INIT:
DISABLE_IRQs;
- lp->tx_enable = NO;
+ lp->tx_enable = false;
lp->timeout = -1;
de4x5_save_skbs(dev); /* Save non transmitted skb's */
if ((lp->autosense == AUTO) || (lp->autosense == TP_NW)) {
@@ -2757,7 +2757,7 @@ dc21041_autoconf(struct net_device *dev)
lp->c_media = lp->media;
}
lp->media = INIT;
- lp->tx_enable = NO;
+ lp->tx_enable = false;
break;
}
@@ -2781,7 +2781,7 @@ dc21140m_autoconf(struct net_device *dev)
case INIT:
if (lp->timeout < 0) {
DISABLE_IRQs;
- lp->tx_enable = FALSE;
+ lp->tx_enable = false;
lp->linkOK = 0;
de4x5_save_skbs(dev); /* Save non transmitted skb's */
}
@@ -2830,7 +2830,7 @@ dc21140m_autoconf(struct net_device *dev)
if (lp->timeout < 0) {
mii_wr(MII_CR_ASSE | MII_CR_RAN, MII_CR, lp->phy[lp->active].addr, DE4X5_MII);
}
- cr = test_mii_reg(dev, MII_CR, MII_CR_RAN, FALSE, 500);
+ cr = test_mii_reg(dev, MII_CR, MII_CR_RAN, false, 500);
if (cr < 0) {
next_tick = cr & ~TIMER_CB;
} else {
@@ -2845,7 +2845,7 @@ dc21140m_autoconf(struct net_device *dev)
break;
case 1:
- if ((sr=test_mii_reg(dev, MII_SR, MII_SR_ASSC, TRUE, 2000)) < 0) {
+ if ((sr=test_mii_reg(dev, MII_SR, MII_SR_ASSC, true, 2000)) < 0) {
next_tick = sr & ~TIMER_CB;
} else {
lp->media = SPD_DET;
@@ -2857,10 +2857,10 @@ dc21140m_autoconf(struct net_device *dev)
if (!(anlpa & MII_ANLPA_RF) &&
(cap = anlpa & MII_ANLPA_TAF & ana)) {
if (cap & MII_ANA_100M) {
- lp->fdx = ((ana & anlpa & MII_ANA_FDAM & MII_ANA_100M) ? TRUE : FALSE);
+ lp->fdx = (ana & anlpa & MII_ANA_FDAM & MII_ANA_100M) != 0;
lp->media = _100Mb;
} else if (cap & MII_ANA_10M) {
- lp->fdx = ((ana & anlpa & MII_ANA_FDAM & MII_ANA_10M) ? TRUE : FALSE);
+ lp->fdx = (ana & anlpa & MII_ANA_FDAM & MII_ANA_10M) != 0;
lp->media = _10Mb;
}
@@ -2932,7 +2932,7 @@ dc21140m_autoconf(struct net_device *dev)
lp->c_media = lp->media;
}
lp->media = INIT;
- lp->tx_enable = FALSE;
+ lp->tx_enable = false;
break;
}
@@ -2965,7 +2965,7 @@ dc2114x_autoconf(struct net_device *dev)
case INIT:
if (lp->timeout < 0) {
DISABLE_IRQs;
- lp->tx_enable = FALSE;
+ lp->tx_enable = false;
lp->linkOK = 0;
lp->timeout = -1;
de4x5_save_skbs(dev); /* Save non transmitted skb's */
@@ -3013,7 +3013,7 @@ dc2114x_autoconf(struct net_device *dev)
if (lp->timeout < 0) {
mii_wr(MII_CR_ASSE | MII_CR_RAN, MII_CR, lp->phy[lp->active].addr, DE4X5_MII);
}
- cr = test_mii_reg(dev, MII_CR, MII_CR_RAN, FALSE, 500);
+ cr = test_mii_reg(dev, MII_CR, MII_CR_RAN, false, 500);
if (cr < 0) {
next_tick = cr & ~TIMER_CB;
} else {
@@ -3028,7 +3028,8 @@ dc2114x_autoconf(struct net_device *dev)
break;
case 1:
- if ((sr=test_mii_reg(dev, MII_SR, MII_SR_ASSC, TRUE, 2000)) < 0) {
+ sr = test_mii_reg(dev, MII_SR, MII_SR_ASSC, true, 2000);
+ if (sr < 0) {
next_tick = sr & ~TIMER_CB;
} else {
lp->media = SPD_DET;
@@ -3040,10 +3041,10 @@ dc2114x_autoconf(struct net_device *dev)
if (!(anlpa & MII_ANLPA_RF) &&
(cap = anlpa & MII_ANLPA_TAF & ana)) {
if (cap & MII_ANA_100M) {
- lp->fdx = ((ana & anlpa & MII_ANA_FDAM & MII_ANA_100M) ? TRUE : FALSE);
+ lp->fdx = (ana & anlpa & MII_ANA_FDAM & MII_ANA_100M) != 0;
lp->media = _100Mb;
} else if (cap & MII_ANA_10M) {
- lp->fdx = ((ana & anlpa & MII_ANA_FDAM & MII_ANA_10M) ? TRUE : FALSE);
+ lp->fdx = (ana & anlpa & MII_ANA_FDAM & MII_ANA_10M) != 0;
lp->media = _10Mb;
}
}
@@ -3222,14 +3223,14 @@ srom_map_media(struct net_device *dev)
{
struct de4x5_private *lp = netdev_priv(dev);
- lp->fdx = 0;
+ lp->fdx = false;
if (lp->infoblock_media == lp->media)
return 0;
switch(lp->infoblock_media) {
case SROM_10BASETF:
if (!lp->params.fdx) return -1;
- lp->fdx = TRUE;
+ lp->fdx = true;
case SROM_10BASET:
if (lp->params.fdx && !lp->fdx) return -1;
if ((lp->chipset == DC21140) || ((lp->chipset & ~0x00ff) == DC2114x)) {
@@ -3249,7 +3250,7 @@ srom_map_media(struct net_device *dev)
case SROM_100BASETF:
if (!lp->params.fdx) return -1;
- lp->fdx = TRUE;
+ lp->fdx = true;
case SROM_100BASET:
if (lp->params.fdx && !lp->fdx) return -1;
lp->media = _100Mb;
@@ -3261,7 +3262,7 @@ srom_map_media(struct net_device *dev)
case SROM_100BASEFF:
if (!lp->params.fdx) return -1;
- lp->fdx = TRUE;
+ lp->fdx = true;
case SROM_100BASEF:
if (lp->params.fdx && !lp->fdx) return -1;
lp->media = _100Mb;
@@ -3297,7 +3298,7 @@ de4x5_init_connection(struct net_device *dev)
spin_lock_irqsave(&lp->lock, flags);
de4x5_rst_desc_ring(dev);
de4x5_setup_intr(dev);
- lp->tx_enable = YES;
+ lp->tx_enable = true;
spin_unlock_irqrestore(&lp->lock, flags);
outl(POLL_DEMAND, DE4X5_TPD);
@@ -3336,7 +3337,7 @@ de4x5_reset_phy(struct net_device *dev)
}
}
if (lp->useMII) {
- next_tick = test_mii_reg(dev, MII_CR, MII_CR_RST, FALSE, 500);
+ next_tick = test_mii_reg(dev, MII_CR, MII_CR_RST, false, 500);
}
} else if (lp->chipset == DC21140) {
PHY_HARD_RESET;
@@ -3466,7 +3467,7 @@ wait_for_link(struct net_device *dev)
**
*/
static int
-test_mii_reg(struct net_device *dev, int reg, int mask, int pol, long msec)
+test_mii_reg(struct net_device *dev, int reg, int mask, bool pol, long msec)
{
struct de4x5_private *lp = netdev_priv(dev);
int test;
@@ -3476,9 +3477,8 @@ test_mii_reg(struct net_device *dev, int reg, int mask, int pol, long msec)
lp->timeout = msec/100;
}
- if (pol) pol = ~0;
reg = mii_rd((u_char)reg, lp->phy[lp->active].addr, DE4X5_MII) & mask;
- test = (reg ^ pol) & mask;
+ test = (reg ^ (pol ? ~0 : 0)) & mask;
if (test && --lp->timeout) {
reg = 100 | TIMER_CB;
@@ -3992,10 +3992,10 @@ PCI_signature(char *name, struct de4x5_private *lp)
)))))));
}
if (lp->chipset != DC21041) {
- lp->useSROM = TRUE; /* card is not recognisably DEC */
+ lp->useSROM = true; /* card is not recognisably DEC */
}
} else if ((lp->chipset & ~0x00ff) == DC2114x) {
- lp->useSROM = TRUE;
+ lp->useSROM = true;
}
return status;
@@ -4216,7 +4216,7 @@ srom_repair(struct net_device *dev, int card)
memset((char *)&lp->srom, 0, sizeof(struct de4x5_srom));
memcpy(lp->srom.ieee_addr, (char *)dev->dev_addr, ETH_ALEN);
memcpy(lp->srom.info, (char *)&srom_repair_info[SMC-1], 100);
- lp->useSROM = TRUE;
+ lp->useSROM = true;
break;
}
@@ -4392,7 +4392,7 @@ srom_infoleaf_info(struct net_device *dev)
if (lp->chipset == infoleaf_array[i].chipset) break;
}
if (i == INFOLEAF_SIZE) {
- lp->useSROM = FALSE;
+ lp->useSROM = false;
printk("%s: Cannot find correct chipset for SROM decoding!\n",
dev->name);
return -ENXIO;
@@ -4409,7 +4409,7 @@ srom_infoleaf_info(struct net_device *dev)
if (lp->device == *p) break;
}
if (i == 0) {
- lp->useSROM = FALSE;
+ lp->useSROM = false;
printk("%s: Cannot find correct PCI device [%d] for SROM decoding!\n",
dev->name, lp->device);
return -ENXIO;
@@ -4542,7 +4542,7 @@ dc21140_infoleaf(struct net_device *dev)
}
lp->media = INIT;
lp->tcount = 0;
- lp->tx_enable = FALSE;
+ lp->tx_enable = false;
}
return next_tick & ~TIMER_CB;
@@ -4577,7 +4577,7 @@ dc21142_infoleaf(struct net_device *dev)
}
lp->media = INIT;
lp->tcount = 0;
- lp->tx_enable = FALSE;
+ lp->tx_enable = false;
}
return next_tick & ~TIMER_CB;
@@ -4611,7 +4611,7 @@ dc21143_infoleaf(struct net_device *dev)
}
lp->media = INIT;
lp->tcount = 0;
- lp->tx_enable = FALSE;
+ lp->tx_enable = false;
}
return next_tick & ~TIMER_CB;
@@ -4650,7 +4650,7 @@ compact_infoblock(struct net_device *dev, u_char count, u_char *p)
lp->asBit = 1 << ((csr6 >> 1) & 0x07);
lp->asPolarity = ((csr6 & 0x80) ? -1 : 0) & lp->asBit;
lp->infoblock_csr6 = OMR_DEF | ((csr6 & 0x71) << 18);
- lp->useMII = FALSE;
+ lp->useMII = false;
de4x5_switch_mac_port(dev);
}
@@ -4691,7 +4691,7 @@ type0_infoblock(struct net_device *dev, u_char count, u_char *p)
lp->asBit = 1 << ((csr6 >> 1) & 0x07);
lp->asPolarity = ((csr6 & 0x80) ? -1 : 0) & lp->asBit;
lp->infoblock_csr6 = OMR_DEF | ((csr6 & 0x71) << 18);
- lp->useMII = FALSE;
+ lp->useMII = false;
de4x5_switch_mac_port(dev);
}
@@ -4731,7 +4731,7 @@ type1_infoblock(struct net_device *dev, u_char count, u_char *p)
lp->ibn = 1;
lp->active = *p;
lp->infoblock_csr6 = OMR_MII_100;
- lp->useMII = TRUE;
+ lp->useMII = true;
lp->infoblock_media = ANS;
de4x5_switch_mac_port(dev);
@@ -4773,7 +4773,7 @@ type2_infoblock(struct net_device *dev, u_char count, u_char *p)
lp->cache.gepc = ((s32)(TWIDDLE(p)) << 16); p += 2;
lp->cache.gep = ((s32)(TWIDDLE(p)) << 16);
lp->infoblock_csr6 = OMR_SIA;
- lp->useMII = FALSE;
+ lp->useMII = false;
de4x5_switch_mac_port(dev);
}
@@ -4814,7 +4814,7 @@ type3_infoblock(struct net_device *dev, u_char count, u_char *p)
lp->active = *p;
if (MOTO_SROM_BUG) lp->active = 0;
lp->infoblock_csr6 = OMR_MII_100;
- lp->useMII = TRUE;
+ lp->useMII = true;
lp->infoblock_media = ANS;
de4x5_switch_mac_port(dev);
@@ -4856,7 +4856,7 @@ type4_infoblock(struct net_device *dev, u_char count, u_char *p)
lp->asBit = 1 << ((csr6 >> 1) & 0x07);
lp->asPolarity = ((csr6 & 0x80) ? -1 : 0) & lp->asBit;
lp->infoblock_csr6 = OMR_DEF | ((csr6 & 0x71) << 18);
- lp->useMII = FALSE;
+ lp->useMII = false;
de4x5_switch_mac_port(dev);
}
@@ -5077,7 +5077,7 @@ mii_get_phy(struct net_device *dev)
int id;
lp->active = 0;
- lp->useMII = TRUE;
+ lp->useMII = true;
/* Search the MII address space for possible PHY devices */
for (n=0, lp->mii_cnt=0, i=1; !((i==1) && (n==1)); i=(i+1)%DE4X5_MAX_MII) {
@@ -5127,7 +5127,7 @@ mii_get_phy(struct net_device *dev)
de4x5_dbg_mii(dev, k);
}
}
- if (!lp->mii_cnt) lp->useMII = FALSE;
+ if (!lp->mii_cnt) lp->useMII = false;
return lp->mii_cnt;
}
diff --git a/drivers/net/tulip/de4x5.h b/drivers/net/tulip/de4x5.h
index 57226e5eb8a6..12af0cc037fb 100644
--- a/drivers/net/tulip/de4x5.h
+++ b/drivers/net/tulip/de4x5.h
@@ -893,15 +893,6 @@
#define PHYS_ADDR_ONLY 1 /* Update the physical address only */
/*
-** Booleans
-*/
-#define NO 0
-#define FALSE 0
-
-#define YES ~0
-#define TRUE ~0
-
-/*
** Adapter state
*/
#define INITIALISED 0 /* After h/w initialised and mem alloc'd */
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index a12f576391cf..86b690843362 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -192,7 +192,7 @@ static int init_status (struct usbnet *dev, struct usb_interface *intf)
usb_pipeendpoint(pipe), maxp, period);
}
}
- return 0;
+ return 0;
}
/* Passes this packet up the stack, updating its accounting.
@@ -326,7 +326,7 @@ static void rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags)
if (netif_running (dev->net)
&& netif_device_present (dev->net)
&& !test_bit (EVENT_RX_HALT, &dev->flags)) {
- switch (retval = usb_submit_urb (urb, GFP_ATOMIC)){
+ switch (retval = usb_submit_urb (urb, GFP_ATOMIC)) {
case -EPIPE:
usbnet_defer_kevent (dev, EVENT_RX_HALT);
break;
@@ -393,8 +393,8 @@ static void rx_complete (struct urb *urb)
entry->urb = NULL;
switch (urb_status) {
- // success
- case 0:
+ /* success */
+ case 0:
if (skb->len < dev->net->hard_header_len) {
entry->state = rx_cleanup;
dev->stats.rx_errors++;
@@ -404,28 +404,30 @@ static void rx_complete (struct urb *urb)
}
break;
- // stalls need manual reset. this is rare ... except that
- // when going through USB 2.0 TTs, unplug appears this way.
- // we avoid the highspeed version of the ETIMEOUT/EILSEQ
- // storm, recovering as needed.
- case -EPIPE:
+ /* stalls need manual reset. this is rare ... except that
+ * when going through USB 2.0 TTs, unplug appears this way.
+ * we avoid the highspeed version of the ETIMEOUT/EILSEQ
+ * storm, recovering as needed.
+ */
+ case -EPIPE:
dev->stats.rx_errors++;
usbnet_defer_kevent (dev, EVENT_RX_HALT);
// FALLTHROUGH
- // software-driven interface shutdown
- case -ECONNRESET: // async unlink
- case -ESHUTDOWN: // hardware gone
+ /* software-driven interface shutdown */
+ case -ECONNRESET: /* async unlink */
+ case -ESHUTDOWN: /* hardware gone */
if (netif_msg_ifdown (dev))
devdbg (dev, "rx shutdown, code %d", urb_status);
goto block;
- // we get controller i/o faults during khubd disconnect() delays.
- // throttle down resubmits, to avoid log floods; just temporarily,
- // so we still recover when the fault isn't a khubd delay.
- case -EPROTO:
- case -ETIME:
- case -EILSEQ:
+ /* we get controller i/o faults during khubd disconnect() delays.
+ * throttle down resubmits, to avoid log floods; just temporarily,
+ * so we still recover when the fault isn't a khubd delay.
+ */
+ case -EPROTO:
+ case -ETIME:
+ case -EILSEQ:
dev->stats.rx_errors++;
if (!timer_pending (&dev->delay)) {
mod_timer (&dev->delay, jiffies + THROTTLE_JIFFIES);
@@ -438,12 +440,12 @@ block:
urb = NULL;
break;
- // data overrun ... flush fifo?
- case -EOVERFLOW:
+ /* data overrun ... flush fifo? */
+ case -EOVERFLOW:
dev->stats.rx_over_errors++;
// FALLTHROUGH
- default:
+ default:
entry->state = rx_cleanup;
dev->stats.rx_errors++;
if (netif_msg_rx_err (dev))
@@ -471,22 +473,22 @@ static void intr_complete (struct urb *urb)
int status = urb->status;
switch (status) {
- /* success */
- case 0:
+ /* success */
+ case 0:
dev->driver_info->status(dev, urb);
break;
- /* software-driven interface shutdown */
- case -ENOENT: // urb killed
- case -ESHUTDOWN: // hardware gone
+ /* software-driven interface shutdown */
+ case -ENOENT: /* urb killed */
+ case -ESHUTDOWN: /* hardware gone */
if (netif_msg_ifdown (dev))
devdbg (dev, "intr shutdown, code %d", status);
return;
- /* NOTE: not throttling like RX/TX, since this endpoint
- * already polls infrequently
- */
- default:
+ /* NOTE: not throttling like RX/TX, since this endpoint
+ * already polls infrequently
+ */
+ default:
devdbg (dev, "intr status %d", status);
break;
}
@@ -569,9 +571,9 @@ static int usbnet_stop (struct net_device *net)
temp = unlink_urbs (dev, &dev->txq) + unlink_urbs (dev, &dev->rxq);
// maybe wait for deletions to finish.
- while (!skb_queue_empty(&dev->rxq) &&
- !skb_queue_empty(&dev->txq) &&
- !skb_queue_empty(&dev->done)) {
+ while (!skb_queue_empty(&dev->rxq)
+ && !skb_queue_empty(&dev->txq)
+ && !skb_queue_empty(&dev->done)) {
msleep(UNLINK_TIMEOUT_MS);
if (netif_msg_ifdown (dev))
devdbg (dev, "waited for %d urb completions", temp);
@@ -1011,16 +1013,16 @@ static void usbnet_bh (unsigned long param)
while ((skb = skb_dequeue (&dev->done))) {
entry = (struct skb_data *) skb->cb;
switch (entry->state) {
- case rx_done:
+ case rx_done:
entry->state = rx_cleanup;
rx_process (dev, skb);
continue;
- case tx_done:
- case rx_cleanup:
+ case tx_done:
+ case rx_cleanup:
usb_free_urb (entry->urb);
dev_kfree_skb (skb);
continue;
- default:
+ default:
devdbg (dev, "bogus skb state %d", entry->state);
}
}
diff --git a/drivers/net/usb/usbnet.h b/drivers/net/usb/usbnet.h
index a3f8b9e7bc00..a6c5820767de 100644
--- a/drivers/net/usb/usbnet.h
+++ b/drivers/net/usb/usbnet.h
@@ -47,7 +47,7 @@ struct usbnet {
unsigned long data [5];
u32 xid;
u32 hard_mtu; /* count any extra framing */
- size_t rx_urb_size; /* size for rx urbs */
+ size_t rx_urb_size; /* size for rx urbs */
struct mii_if_info mii;
/* various kinds of pending driver work */
@@ -85,7 +85,7 @@ struct driver_info {
#define FLAG_NO_SETINT 0x0010 /* device can't set_interface() */
#define FLAG_ETHER 0x0020 /* maybe use "eth%d" names */
-#define FLAG_FRAMING_AX 0x0040 /* AX88772/178 packets */
+#define FLAG_FRAMING_AX 0x0040 /* AX88772/178 packets */
/* init device ... can sleep, or cause probe() failure */
int (*bind)(struct usbnet *, struct usb_interface *);
@@ -146,9 +146,9 @@ extern void usbnet_cdc_unbind (struct usbnet *, struct usb_interface *);
/* CDC and RNDIS support the same host-chosen packet filters for IN transfers */
#define DEFAULT_FILTER (USB_CDC_PACKET_TYPE_BROADCAST \
- |USB_CDC_PACKET_TYPE_ALL_MULTICAST \
- |USB_CDC_PACKET_TYPE_PROMISCUOUS \
- |USB_CDC_PACKET_TYPE_DIRECTED)
+ |USB_CDC_PACKET_TYPE_ALL_MULTICAST \
+ |USB_CDC_PACKET_TYPE_PROMISCUOUS \
+ |USB_CDC_PACKET_TYPE_DIRECTED)
/* we record the state for each of our queued skbs */
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index fa2399cbd5ca..ae27af0141c0 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -546,6 +546,18 @@ config USB_ZD1201
To compile this driver as a module, choose M here: the
module will be called zd1201.
+config RTL8187
+ tristate "Realtek 8187 USB support"
+ depends on MAC80211 && USB && WLAN_80211 && EXPERIMENTAL
+ select EEPROM_93CX6
+ ---help---
+ This is a driver for RTL8187 based cards.
+ These are USB based chips found in cards such as:
+
+ Netgear WG111v2
+
+ Thanks to Realtek for their support!
+
source "drivers/net/wireless/hostap/Kconfig"
source "drivers/net/wireless/bcm43xx/Kconfig"
source "drivers/net/wireless/zd1211rw/Kconfig"
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index d2124602263b..ef35bc6c4a22 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -44,3 +44,6 @@ obj-$(CONFIG_PCMCIA_WL3501) += wl3501_cs.o
obj-$(CONFIG_USB_ZD1201) += zd1201.o
obj-$(CONFIG_LIBERTAS_USB) += libertas/
+
+rtl8187-objs := rtl8187_dev.o rtl8187_rtl8225.o
+obj-$(CONFIG_RTL8187) += rtl8187.o
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
index b37f1e348700..d779199c30d0 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
@@ -1638,7 +1638,7 @@ void bcm43xx_phy_set_baseband_attenuation(struct bcm43xx_private *bcm,
return;
}
- if (phy->analog > 1) {
+ if (phy->analog == 1) {
value = bcm43xx_phy_read(bcm, 0x0060) & ~0x003C;
value |= (baseband_attenuation << 2) & 0x003C;
} else {
diff --git a/drivers/net/wireless/hostap/hostap_ap.c b/drivers/net/wireless/hostap/hostap_ap.c
index 5b3abd54d0e5..90900525379c 100644
--- a/drivers/net/wireless/hostap/hostap_ap.c
+++ b/drivers/net/wireless/hostap/hostap_ap.c
@@ -326,7 +326,6 @@ static int ap_control_proc_read(char *page, char **start, off_t off,
char *p = page;
struct ap_data *ap = (struct ap_data *) data;
char *policy_txt;
- struct list_head *ptr;
struct mac_entry *entry;
if (off != 0) {
@@ -352,14 +351,12 @@ static int ap_control_proc_read(char *page, char **start, off_t off,
p += sprintf(p, "MAC entries: %u\n", ap->mac_restrictions.entries);
p += sprintf(p, "MAC list:\n");
spin_lock_bh(&ap->mac_restrictions.lock);
- for (ptr = ap->mac_restrictions.mac_list.next;
- ptr != &ap->mac_restrictions.mac_list; ptr = ptr->next) {
+ list_for_each_entry(entry, &ap->mac_restrictions.mac_list, list) {
if (p - page > PAGE_SIZE - 80) {
p += sprintf(p, "All entries did not fit one page.\n");
break;
}
- entry = list_entry(ptr, struct mac_entry, list);
p += sprintf(p, MACSTR "\n", MAC2STR(entry->addr));
}
spin_unlock_bh(&ap->mac_restrictions.lock);
@@ -413,7 +410,6 @@ int ap_control_del_mac(struct mac_restrictions *mac_restrictions, u8 *mac)
static int ap_control_mac_deny(struct mac_restrictions *mac_restrictions,
u8 *mac)
{
- struct list_head *ptr;
struct mac_entry *entry;
int found = 0;
@@ -421,10 +417,7 @@ static int ap_control_mac_deny(struct mac_restrictions *mac_restrictions,
return 0;
spin_lock_bh(&mac_restrictions->lock);
- for (ptr = mac_restrictions->mac_list.next;
- ptr != &mac_restrictions->mac_list; ptr = ptr->next) {
- entry = list_entry(ptr, struct mac_entry, list);
-
+ list_for_each_entry(entry, &mac_restrictions->mac_list, list) {
if (memcmp(entry->addr, mac, ETH_ALEN) == 0) {
found = 1;
break;
@@ -519,7 +512,7 @@ static int prism2_ap_proc_read(char *page, char **start, off_t off,
{
char *p = page;
struct ap_data *ap = (struct ap_data *) data;
- struct list_head *ptr;
+ struct sta_info *sta;
int i;
if (off > PROC_LIMIT) {
@@ -529,9 +522,7 @@ static int prism2_ap_proc_read(char *page, char **start, off_t off,
p += sprintf(p, "# BSSID CHAN SIGNAL NOISE RATE SSID FLAGS\n");
spin_lock_bh(&ap->sta_table_lock);
- for (ptr = ap->sta_list.next; ptr != &ap->sta_list; ptr = ptr->next) {
- struct sta_info *sta = (struct sta_info *) ptr;
-
+ list_for_each_entry(sta, &ap->sta_list, list) {
if (!sta->ap)
continue;
@@ -861,7 +852,7 @@ void hostap_init_ap_proc(local_info_t *local)
void hostap_free_data(struct ap_data *ap)
{
- struct list_head *n, *ptr;
+ struct sta_info *n, *sta;
if (ap == NULL || !ap->initialized) {
printk(KERN_DEBUG "hostap_free_data: ap has not yet been "
@@ -875,8 +866,7 @@ void hostap_free_data(struct ap_data *ap)
ap->crypt = ap->crypt_priv = NULL;
#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
- list_for_each_safe(ptr, n, &ap->sta_list) {
- struct sta_info *sta = list_entry(ptr, struct sta_info, list);
+ list_for_each_entry_safe(sta, n, &ap->sta_list, list) {
ap_sta_hash_del(ap, sta);
list_del(&sta->list);
if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap && sta->local)
@@ -2704,6 +2694,8 @@ ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx)
if (hdr->addr1[0] & 0x01) {
/* broadcast/multicast frame - no AP related processing */
+ if (local->ap->num_sta <= 0)
+ ret = AP_TX_DROP;
goto out;
}
@@ -3198,15 +3190,14 @@ int hostap_update_rx_stats(struct ap_data *ap,
void hostap_update_rates(local_info_t *local)
{
- struct list_head *ptr;
+ struct sta_info *sta;
struct ap_data *ap = local->ap;
if (!ap)
return;
spin_lock_bh(&ap->sta_table_lock);
- for (ptr = ap->sta_list.next; ptr != &ap->sta_list; ptr = ptr->next) {
- struct sta_info *sta = (struct sta_info *) ptr;
+ list_for_each_entry(sta, &ap->sta_list, list) {
prism2_check_tx_rates(sta);
}
spin_unlock_bh(&ap->sta_table_lock);
@@ -3242,11 +3233,10 @@ void * ap_crypt_get_ptrs(struct ap_data *ap, u8 *addr, int permanent,
void hostap_add_wds_links(local_info_t *local)
{
struct ap_data *ap = local->ap;
- struct list_head *ptr;
+ struct sta_info *sta;
spin_lock_bh(&ap->sta_table_lock);
- list_for_each(ptr, &ap->sta_list) {
- struct sta_info *sta = list_entry(ptr, struct sta_info, list);
+ list_for_each_entry(sta, &ap->sta_list, list) {
if (sta->ap)
hostap_wds_link_oper(local, sta->addr, WDS_ADD);
}
diff --git a/drivers/net/wireless/hostap/hostap_config.h b/drivers/net/wireless/hostap/hostap_config.h
index c090a5aebb58..30acd39d76a2 100644
--- a/drivers/net/wireless/hostap/hostap_config.h
+++ b/drivers/net/wireless/hostap/hostap_config.h
@@ -1,8 +1,6 @@
#ifndef HOSTAP_CONFIG_H
#define HOSTAP_CONFIG_H
-#define PRISM2_VERSION "0.4.4-kernel"
-
/* In the previous versions of Host AP driver, support for user space version
* of IEEE 802.11 management (hostapd) used to be disabled in the default
* configuration. From now on, support for hostapd is always included and it is
diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c
index ee1532b62e42..30e723f65979 100644
--- a/drivers/net/wireless/hostap/hostap_cs.c
+++ b/drivers/net/wireless/hostap/hostap_cs.c
@@ -22,7 +22,6 @@
#include "hostap_wlan.h"
-static char *version = PRISM2_VERSION " (Jouni Malinen <j@w1.fi>)";
static dev_info_t dev_info = "hostap_cs";
MODULE_AUTHOR("Jouni Malinen");
@@ -30,7 +29,6 @@ MODULE_DESCRIPTION("Support for Intersil Prism2-based 802.11 wireless LAN "
"cards (PC Card).");
MODULE_SUPPORTED_DEVICE("Intersil Prism2-based WLAN cards (PC Card)");
MODULE_LICENSE("GPL");
-MODULE_VERSION(PRISM2_VERSION);
static int ignore_cis_vcc;
@@ -910,14 +908,12 @@ static struct pcmcia_driver hostap_driver = {
static int __init init_prism2_pccard(void)
{
- printk(KERN_INFO "%s: %s\n", dev_info, version);
return pcmcia_register_driver(&hostap_driver);
}
static void __exit exit_prism2_pccard(void)
{
pcmcia_unregister_driver(&hostap_driver);
- printk(KERN_INFO "%s: Driver unloaded\n", dev_info);
}
diff --git a/drivers/net/wireless/hostap/hostap_ioctl.c b/drivers/net/wireless/hostap/hostap_ioctl.c
index cdea7f71b9eb..8c71077d653c 100644
--- a/drivers/net/wireless/hostap/hostap_ioctl.c
+++ b/drivers/net/wireless/hostap/hostap_ioctl.c
@@ -3893,8 +3893,6 @@ static void prism2_get_drvinfo(struct net_device *dev,
local = iface->local;
strncpy(info->driver, "hostap", sizeof(info->driver) - 1);
- strncpy(info->version, PRISM2_VERSION,
- sizeof(info->version) - 1);
snprintf(info->fw_version, sizeof(info->fw_version) - 1,
"%d.%d.%d", (local->sta_fw_ver >> 16) & 0xff,
(local->sta_fw_ver >> 8) & 0xff,
diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c
index 4743426cf6ad..446de51bab74 100644
--- a/drivers/net/wireless/hostap/hostap_main.c
+++ b/drivers/net/wireless/hostap/hostap_main.c
@@ -37,7 +37,6 @@
MODULE_AUTHOR("Jouni Malinen");
MODULE_DESCRIPTION("Host AP common routines");
MODULE_LICENSE("GPL");
-MODULE_VERSION(PRISM2_VERSION);
#define TX_TIMEOUT (2 * HZ)
diff --git a/drivers/net/wireless/hostap/hostap_pci.c b/drivers/net/wireless/hostap/hostap_pci.c
index db4899ed4bb1..0cd48d151f5e 100644
--- a/drivers/net/wireless/hostap/hostap_pci.c
+++ b/drivers/net/wireless/hostap/hostap_pci.c
@@ -20,7 +20,6 @@
#include "hostap_wlan.h"
-static char *version = PRISM2_VERSION " (Jouni Malinen <j@w1.fi>)";
static char *dev_info = "hostap_pci";
@@ -29,7 +28,6 @@ MODULE_DESCRIPTION("Support for Intersil Prism2.5-based 802.11 wireless LAN "
"PCI cards.");
MODULE_SUPPORTED_DEVICE("Intersil Prism2.5-based WLAN PCI cards");
MODULE_LICENSE("GPL");
-MODULE_VERSION(PRISM2_VERSION);
/* struct local_info::hw_priv */
@@ -462,8 +460,6 @@ static struct pci_driver prism2_pci_drv_id = {
static int __init init_prism2_pci(void)
{
- printk(KERN_INFO "%s: %s\n", dev_info, version);
-
return pci_register_driver(&prism2_pci_drv_id);
}
@@ -471,7 +467,6 @@ static int __init init_prism2_pci(void)
static void __exit exit_prism2_pci(void)
{
pci_unregister_driver(&prism2_pci_drv_id);
- printk(KERN_INFO "%s: Driver unloaded\n", dev_info);
}
diff --git a/drivers/net/wireless/hostap/hostap_plx.c b/drivers/net/wireless/hostap/hostap_plx.c
index f0fd5ecdb24d..0183df757b3e 100644
--- a/drivers/net/wireless/hostap/hostap_plx.c
+++ b/drivers/net/wireless/hostap/hostap_plx.c
@@ -23,7 +23,6 @@
#include "hostap_wlan.h"
-static char *version = PRISM2_VERSION " (Jouni Malinen <j@w1.fi>)";
static char *dev_info = "hostap_plx";
@@ -32,7 +31,6 @@ MODULE_DESCRIPTION("Support for Intersil Prism2-based 802.11 wireless LAN "
"cards (PLX).");
MODULE_SUPPORTED_DEVICE("Intersil Prism2-based WLAN cards (PLX)");
MODULE_LICENSE("GPL");
-MODULE_VERSION(PRISM2_VERSION);
static int ignore_cis;
@@ -623,8 +621,6 @@ static struct pci_driver prism2_plx_drv_id = {
static int __init init_prism2_plx(void)
{
- printk(KERN_INFO "%s: %s\n", dev_info, version);
-
return pci_register_driver(&prism2_plx_drv_id);
}
@@ -632,7 +628,6 @@ static int __init init_prism2_plx(void)
static void __exit exit_prism2_plx(void)
{
pci_unregister_driver(&prism2_plx_drv_id);
- printk(KERN_INFO "%s: Driver unloaded\n", dev_info);
}
diff --git a/drivers/net/wireless/rtl8187.h b/drivers/net/wireless/rtl8187.h
new file mode 100644
index 000000000000..6124e467b156
--- /dev/null
+++ b/drivers/net/wireless/rtl8187.h
@@ -0,0 +1,145 @@
+/*
+ * Definitions for RTL8187 hardware
+ *
+ * Copyright 2007 Michael Wu <flamingice@sourmilk.net>
+ * Copyright 2007 Andrea Merello <andreamrl@tiscali.it>
+ *
+ * Based on the r8187 driver, which is:
+ * Copyright 2005 Andrea Merello <andreamrl@tiscali.it>, et al.
+ *
+ * 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.
+ */
+
+#ifndef RTL8187_H
+#define RTL8187_H
+
+#include "rtl818x.h"
+
+#define RTL8187_EEPROM_TXPWR_BASE 0x05
+#define RTL8187_EEPROM_MAC_ADDR 0x07
+#define RTL8187_EEPROM_TXPWR_CHAN_1 0x16 /* 3 channels */
+#define RTL8187_EEPROM_TXPWR_CHAN_6 0x1B /* 2 channels */
+#define RTL8187_EEPROM_TXPWR_CHAN_4 0x3D /* 2 channels */
+
+#define RTL8187_REQT_READ 0xC0
+#define RTL8187_REQT_WRITE 0x40
+#define RTL8187_REQ_GET_REG 0x05
+#define RTL8187_REQ_SET_REG 0x05
+
+#define RTL8187_MAX_RX 0x9C4
+
+struct rtl8187_rx_info {
+ struct urb *urb;
+ struct ieee80211_hw *dev;
+};
+
+struct rtl8187_rx_hdr {
+ __le16 len;
+ __le16 rate;
+ u8 noise;
+ u8 signal;
+ u8 agc;
+ u8 reserved;
+ __le64 mac_time;
+} __attribute__((packed));
+
+struct rtl8187_tx_info {
+ struct ieee80211_tx_control *control;
+ struct urb *urb;
+ struct ieee80211_hw *dev;
+};
+
+struct rtl8187_tx_hdr {
+ __le32 flags;
+#define RTL8187_TX_FLAG_NO_ENCRYPT (1 << 15)
+#define RTL8187_TX_FLAG_MORE_FRAG (1 << 17)
+#define RTL8187_TX_FLAG_CTS (1 << 18)
+#define RTL8187_TX_FLAG_RTS (1 << 23)
+ __le16 rts_duration;
+ __le16 len;
+ __le32 retry;
+} __attribute__((packed));
+
+struct rtl8187_priv {
+ /* common between rtl818x drivers */
+ struct rtl818x_csr *map;
+ void (*rf_init)(struct ieee80211_hw *);
+ int mode;
+
+ /* rtl8187 specific */
+ struct ieee80211_channel channels[14];
+ struct ieee80211_rate rates[12];
+ struct ieee80211_hw_mode modes[2];
+ struct usb_device *udev;
+ u8 *hwaddr;
+ u16 txpwr_base;
+ u8 asic_rev;
+ struct sk_buff_head rx_queue;
+};
+
+void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data);
+
+static inline u8 rtl818x_ioread8(struct rtl8187_priv *priv, u8 *addr)
+{
+ u8 val;
+
+ usb_control_msg(priv->udev, usb_rcvctrlpipe(priv->udev, 0),
+ RTL8187_REQ_GET_REG, RTL8187_REQT_READ,
+ (unsigned long)addr, 0, &val, sizeof(val), HZ / 2);
+
+ return val;
+}
+
+static inline u16 rtl818x_ioread16(struct rtl8187_priv *priv, __le16 *addr)
+{
+ __le16 val;
+
+ usb_control_msg(priv->udev, usb_rcvctrlpipe(priv->udev, 0),
+ RTL8187_REQ_GET_REG, RTL8187_REQT_READ,
+ (unsigned long)addr, 0, &val, sizeof(val), HZ / 2);
+
+ return le16_to_cpu(val);
+}
+
+static inline u32 rtl818x_ioread32(struct rtl8187_priv *priv, __le32 *addr)
+{
+ __le32 val;
+
+ usb_control_msg(priv->udev, usb_rcvctrlpipe(priv->udev, 0),
+ RTL8187_REQ_GET_REG, RTL8187_REQT_READ,
+ (unsigned long)addr, 0, &val, sizeof(val), HZ / 2);
+
+ return le32_to_cpu(val);
+}
+
+static inline void rtl818x_iowrite8(struct rtl8187_priv *priv,
+ u8 *addr, u8 val)
+{
+ usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0),
+ RTL8187_REQ_SET_REG, RTL8187_REQT_WRITE,
+ (unsigned long)addr, 0, &val, sizeof(val), HZ / 2);
+}
+
+static inline void rtl818x_iowrite16(struct rtl8187_priv *priv,
+ __le16 *addr, u16 val)
+{
+ __le16 buf = cpu_to_le16(val);
+
+ usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0),
+ RTL8187_REQ_SET_REG, RTL8187_REQT_WRITE,
+ (unsigned long)addr, 0, &buf, sizeof(buf), HZ / 2);
+}
+
+static inline void rtl818x_iowrite32(struct rtl8187_priv *priv,
+ __le32 *addr, u32 val)
+{
+ __le32 buf = cpu_to_le32(val);
+
+ usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0),
+ RTL8187_REQ_SET_REG, RTL8187_REQT_WRITE,
+ (unsigned long)addr, 0, &buf, sizeof(buf), HZ / 2);
+}
+
+#endif /* RTL8187_H */
diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c
new file mode 100644
index 000000000000..cea85894b7f2
--- /dev/null
+++ b/drivers/net/wireless/rtl8187_dev.c
@@ -0,0 +1,731 @@
+/*
+ * Linux device driver for RTL8187
+ *
+ * Copyright 2007 Michael Wu <flamingice@sourmilk.net>
+ * Copyright 2007 Andrea Merello <andreamrl@tiscali.it>
+ *
+ * Based on the r8187 driver, which is:
+ * Copyright 2005 Andrea Merello <andreamrl@tiscali.it>, et al.
+ *
+ * Magic delays and register offsets below are taken from the original
+ * r8187 driver sources. Thanks to Realtek for their support!
+ *
+ * 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/init.h>
+#include <linux/usb.h>
+#include <linux/delay.h>
+#include <linux/etherdevice.h>
+#include <linux/eeprom_93cx6.h>
+#include <net/mac80211.h>
+
+#include "rtl8187.h"
+#include "rtl8187_rtl8225.h"
+
+MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
+MODULE_AUTHOR("Andrea Merello <andreamrl@tiscali.it>");
+MODULE_DESCRIPTION("RTL8187 USB wireless driver");
+MODULE_LICENSE("GPL");
+
+static struct usb_device_id rtl8187_table[] __devinitdata = {
+ /* Realtek */
+ {USB_DEVICE(0x0bda, 0x8187)},
+ /* Netgear */
+ {USB_DEVICE(0x0846, 0x6100)},
+ {USB_DEVICE(0x0846, 0x6a00)},
+ {}
+};
+
+MODULE_DEVICE_TABLE(usb, rtl8187_table);
+
+void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data)
+{
+ struct rtl8187_priv *priv = dev->priv;
+
+ data <<= 8;
+ data |= addr | 0x80;
+
+ rtl818x_iowrite8(priv, &priv->map->PHY[3], (data >> 24) & 0xFF);
+ rtl818x_iowrite8(priv, &priv->map->PHY[2], (data >> 16) & 0xFF);
+ rtl818x_iowrite8(priv, &priv->map->PHY[1], (data >> 8) & 0xFF);
+ rtl818x_iowrite8(priv, &priv->map->PHY[0], data & 0xFF);
+
+ msleep(1);
+}
+
+static void rtl8187_tx_cb(struct urb *urb)
+{
+ struct ieee80211_tx_status status = { {0} };
+ struct sk_buff *skb = (struct sk_buff *)urb->context;
+ struct rtl8187_tx_info *info = (struct rtl8187_tx_info *)skb->cb;
+
+ usb_free_urb(info->urb);
+ if (info->control)
+ memcpy(&status.control, info->control, sizeof(status.control));
+ kfree(info->control);
+ skb_pull(skb, sizeof(struct rtl8187_tx_hdr));
+ status.flags |= IEEE80211_TX_STATUS_ACK;
+ ieee80211_tx_status_irqsafe(info->dev, skb, &status);
+}
+
+static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb,
+ struct ieee80211_tx_control *control)
+{
+ struct rtl8187_priv *priv = dev->priv;
+ struct rtl8187_tx_hdr *hdr;
+ struct rtl8187_tx_info *info;
+ struct urb *urb;
+ u32 tmp;
+
+ urb = usb_alloc_urb(0, GFP_ATOMIC);
+ if (!urb) {
+ kfree_skb(skb);
+ return 0;
+ }
+
+ hdr = (struct rtl8187_tx_hdr *)skb_push(skb, sizeof(*hdr));
+ tmp = skb->len - sizeof(*hdr);
+ tmp |= RTL8187_TX_FLAG_NO_ENCRYPT;
+ tmp |= control->rts_cts_rate << 19;
+ tmp |= control->tx_rate << 24;
+ if (ieee80211_get_morefrag((struct ieee80211_hdr *)skb))
+ tmp |= RTL8187_TX_FLAG_MORE_FRAG;
+ if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS) {
+ tmp |= RTL8187_TX_FLAG_RTS;
+ hdr->rts_duration =
+ ieee80211_rts_duration(dev, skb->len, control);
+ }
+ if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)
+ tmp |= RTL8187_TX_FLAG_CTS;
+ hdr->flags = cpu_to_le32(tmp);
+ hdr->len = 0;
+ tmp = control->retry_limit << 8;
+ hdr->retry = cpu_to_le32(tmp);
+
+ info = (struct rtl8187_tx_info *)skb->cb;
+ info->control = kmemdup(control, sizeof(*control), GFP_ATOMIC);
+ info->urb = urb;
+ info->dev = dev;
+ usb_fill_bulk_urb(urb, priv->udev, usb_sndbulkpipe(priv->udev, 2),
+ hdr, skb->len, rtl8187_tx_cb, skb);
+ usb_submit_urb(urb, GFP_ATOMIC);
+
+ return 0;
+}
+
+static void rtl8187_rx_cb(struct urb *urb)
+{
+ struct sk_buff *skb = (struct sk_buff *)urb->context;
+ struct rtl8187_rx_info *info = (struct rtl8187_rx_info *)skb->cb;
+ struct ieee80211_hw *dev = info->dev;
+ struct rtl8187_priv *priv = dev->priv;
+ struct rtl8187_rx_hdr *hdr;
+ struct ieee80211_rx_status rx_status = { 0 };
+ int rate, signal;
+
+ spin_lock(&priv->rx_queue.lock);
+ if (skb->next)
+ __skb_unlink(skb, &priv->rx_queue);
+ else {
+ spin_unlock(&priv->rx_queue.lock);
+ return;
+ }
+ spin_unlock(&priv->rx_queue.lock);
+
+ if (unlikely(urb->status)) {
+ usb_free_urb(urb);
+ dev_kfree_skb_irq(skb);
+ return;
+ }
+
+ skb_put(skb, urb->actual_length);
+ hdr = (struct rtl8187_rx_hdr *)(skb_tail_pointer(skb) - sizeof(*hdr));
+ skb_trim(skb, le16_to_cpu(hdr->len) & 0x0FFF);
+
+ signal = hdr->agc >> 1;
+ rate = (le16_to_cpu(hdr->rate) >> 4) & 0xF;
+ if (rate > 3) { /* OFDM rate */
+ if (signal > 90)
+ signal = 90;
+ else if (signal < 25)
+ signal = 25;
+ signal = 90 - signal;
+ } else { /* CCK rate */
+ if (signal > 95)
+ signal = 95;
+ else if (signal < 30)
+ signal = 30;
+ signal = 95 - signal;
+ }
+
+ rx_status.antenna = (hdr->signal >> 7) & 1;
+ rx_status.signal = 64 - min(hdr->noise, (u8)64);
+ rx_status.ssi = signal;
+ rx_status.rate = rate;
+ rx_status.freq = dev->conf.freq;
+ rx_status.channel = dev->conf.channel;
+ rx_status.phymode = dev->conf.phymode;
+ rx_status.mactime = le64_to_cpu(hdr->mac_time);
+ ieee80211_rx_irqsafe(dev, skb, &rx_status);
+
+ skb = dev_alloc_skb(RTL8187_MAX_RX);
+ if (unlikely(!skb)) {
+ usb_free_urb(urb);
+ /* TODO check rx queue length and refill *somewhere* */
+ return;
+ }
+
+ info = (struct rtl8187_rx_info *)skb->cb;
+ info->urb = urb;
+ info->dev = dev;
+ urb->transfer_buffer = skb_tail_pointer(skb);
+ urb->context = skb;
+ skb_queue_tail(&priv->rx_queue, skb);
+
+ usb_submit_urb(urb, GFP_ATOMIC);
+}
+
+static int rtl8187_init_urbs(struct ieee80211_hw *dev)
+{
+ struct rtl8187_priv *priv = dev->priv;
+ struct urb *entry;
+ struct sk_buff *skb;
+ struct rtl8187_rx_info *info;
+
+ while (skb_queue_len(&priv->rx_queue) < 8) {
+ skb = __dev_alloc_skb(RTL8187_MAX_RX, GFP_KERNEL);
+ if (!skb)
+ break;
+ entry = usb_alloc_urb(0, GFP_KERNEL);
+ if (!entry) {
+ kfree_skb(skb);
+ break;
+ }
+ usb_fill_bulk_urb(entry, priv->udev,
+ usb_rcvbulkpipe(priv->udev, 1),
+ skb_tail_pointer(skb),
+ RTL8187_MAX_RX, rtl8187_rx_cb, skb);
+ info = (struct rtl8187_rx_info *)skb->cb;
+ info->urb = entry;
+ info->dev = dev;
+ skb_queue_tail(&priv->rx_queue, skb);
+ usb_submit_urb(entry, GFP_KERNEL);
+ }
+
+ return 0;
+}
+
+static int rtl8187_init_hw(struct ieee80211_hw *dev)
+{
+ struct rtl8187_priv *priv = dev->priv;
+ u8 reg;
+ int i;
+
+ /* reset */
+ rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
+ reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
+ rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
+ rtl818x_iowrite32(priv, &priv->map->ANAPARAM, RTL8225_ANAPARAM_ON);
+ rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_ON);
+ rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
+ rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
+
+ rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0);
+
+ msleep(200);
+ rtl818x_iowrite8(priv, (u8 *)0xFE18, 0x10);
+ rtl818x_iowrite8(priv, (u8 *)0xFE18, 0x11);
+ rtl818x_iowrite8(priv, (u8 *)0xFE18, 0x00);
+ msleep(200);
+
+ reg = rtl818x_ioread8(priv, &priv->map->CMD);
+ reg &= (1 << 1);
+ reg |= RTL818X_CMD_RESET;
+ rtl818x_iowrite8(priv, &priv->map->CMD, reg);
+
+ i = 10;
+ do {
+ msleep(2);
+ if (!(rtl818x_ioread8(priv, &priv->map->CMD) &
+ RTL818X_CMD_RESET))
+ break;
+ } while (--i);
+
+ if (!i) {
+ printk(KERN_ERR "%s: Reset timeout!\n", wiphy_name(dev->wiphy));
+ return -ETIMEDOUT;
+ }
+
+ /* reload registers from eeprom */
+ rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_LOAD);
+
+ i = 10;
+ do {
+ msleep(4);
+ if (!(rtl818x_ioread8(priv, &priv->map->EEPROM_CMD) &
+ RTL818X_EEPROM_CMD_CONFIG))
+ break;
+ } while (--i);
+
+ if (!i) {
+ printk(KERN_ERR "%s: eeprom reset timeout!\n",
+ wiphy_name(dev->wiphy));
+ return -ETIMEDOUT;
+ }
+
+ rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
+ reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
+ rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
+ rtl818x_iowrite32(priv, &priv->map->ANAPARAM, RTL8225_ANAPARAM_ON);
+ rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_ON);
+ rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
+ rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
+
+ /* setup card */
+ rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0);
+ rtl818x_iowrite8(priv, &priv->map->GPIO, 0);
+
+ rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, (4 << 8));
+ rtl818x_iowrite8(priv, &priv->map->GPIO, 1);
+ rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0);
+
+ rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
+ for (i = 0; i < ETH_ALEN; i++)
+ rtl818x_iowrite8(priv, &priv->map->MAC[i], priv->hwaddr[i]);
+
+ rtl818x_iowrite16(priv, (__le16 *)0xFFF4, 0xFFFF);
+ reg = rtl818x_ioread8(priv, &priv->map->CONFIG1);
+ reg &= 0x3F;
+ reg |= 0x80;
+ rtl818x_iowrite8(priv, &priv->map->CONFIG1, reg);
+
+ rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
+
+ rtl818x_iowrite32(priv, &priv->map->INT_TIMEOUT, 0);
+ rtl818x_iowrite8(priv, &priv->map->WPA_CONF, 0);
+ rtl818x_iowrite8(priv, &priv->map->RATE_FALLBACK, 0x81);
+
+ // TODO: set RESP_RATE and BRSR properly
+ rtl818x_iowrite8(priv, &priv->map->RESP_RATE, (8 << 4) | 0);
+ rtl818x_iowrite16(priv, &priv->map->BRSR, 0x01F3);
+
+ /* host_usb_init */
+ rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0);
+ rtl818x_iowrite8(priv, &priv->map->GPIO, 0);
+ reg = rtl818x_ioread8(priv, (u8 *)0xFE53);
+ rtl818x_iowrite8(priv, (u8 *)0xFE53, reg | (1 << 7));
+ rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, (4 << 8));
+ rtl818x_iowrite8(priv, &priv->map->GPIO, 0x20);
+ rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0);
+ rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x80);
+ rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x80);
+ rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x80);
+ msleep(100);
+
+ rtl818x_iowrite32(priv, &priv->map->RF_TIMING, 0x000a8008);
+ rtl818x_iowrite16(priv, &priv->map->BRSR, 0xFFFF);
+ rtl818x_iowrite32(priv, &priv->map->RF_PARA, 0x00100044);
+ rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
+ rtl818x_iowrite8(priv, &priv->map->CONFIG3, 0x44);
+ rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
+ rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FF7);
+ msleep(100);
+
+ priv->rf_init(dev);
+
+ rtl818x_iowrite16(priv, &priv->map->BRSR, 0x01F3);
+ reg = rtl818x_ioread16(priv, &priv->map->PGSELECT) & 0xfffe;
+ rtl818x_iowrite16(priv, &priv->map->PGSELECT, reg | 0x1);
+ rtl818x_iowrite16(priv, (__le16 *)0xFFFE, 0x10);
+ rtl818x_iowrite8(priv, &priv->map->TALLY_SEL, 0x80);
+ rtl818x_iowrite8(priv, (u8 *)0xFFFF, 0x60);
+ rtl818x_iowrite16(priv, &priv->map->PGSELECT, reg);
+
+ return 0;
+}
+
+static void rtl8187_set_channel(struct ieee80211_hw *dev, int channel)
+{
+ u32 reg;
+ struct rtl8187_priv *priv = dev->priv;
+
+ reg = rtl818x_ioread32(priv, &priv->map->TX_CONF);
+ /* Enable TX loopback on MAC level to avoid TX during channel
+ * changes, as this has be seen to causes problems and the
+ * card will stop work until next reset
+ */
+ rtl818x_iowrite32(priv, &priv->map->TX_CONF,
+ reg | RTL818X_TX_CONF_LOOPBACK_MAC);
+ msleep(10);
+ rtl8225_rf_set_channel(dev, channel);
+ msleep(10);
+ rtl818x_iowrite32(priv, &priv->map->TX_CONF, reg);
+}
+
+static int rtl8187_open(struct ieee80211_hw *dev)
+{
+ struct rtl8187_priv *priv = dev->priv;
+ u32 reg;
+ int ret;
+
+ ret = rtl8187_init_hw(dev);
+ if (ret)
+ return ret;
+
+ rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0xFFFF);
+
+ rtl8187_init_urbs(dev);
+
+ reg = RTL818X_RX_CONF_ONLYERLPKT |
+ RTL818X_RX_CONF_RX_AUTORESETPHY |
+ RTL818X_RX_CONF_BSSID |
+ RTL818X_RX_CONF_MGMT |
+ RTL818X_RX_CONF_CTRL |
+ RTL818X_RX_CONF_DATA |
+ (7 << 13 /* RX FIFO threshold NONE */) |
+ (7 << 10 /* MAX RX DMA */) |
+ RTL818X_RX_CONF_BROADCAST |
+ RTL818X_RX_CONF_MULTICAST |
+ RTL818X_RX_CONF_NICMAC;
+ if (priv->mode == IEEE80211_IF_TYPE_MNTR)
+ reg |= RTL818X_RX_CONF_MONITOR;
+
+ rtl818x_iowrite32(priv, &priv->map->RX_CONF, reg);
+
+ reg = rtl818x_ioread8(priv, &priv->map->CW_CONF);
+ reg &= ~RTL818X_CW_CONF_PERPACKET_CW_SHIFT;
+ reg |= RTL818X_CW_CONF_PERPACKET_RETRY_SHIFT;
+ rtl818x_iowrite8(priv, &priv->map->CW_CONF, reg);
+
+ reg = rtl818x_ioread8(priv, &priv->map->TX_AGC_CTL);
+ reg &= ~RTL818X_TX_AGC_CTL_PERPACKET_GAIN_SHIFT;
+ reg &= ~RTL818X_TX_AGC_CTL_PERPACKET_ANTSEL_SHIFT;
+ reg &= ~RTL818X_TX_AGC_CTL_FEEDBACK_ANT;
+ rtl818x_iowrite8(priv, &priv->map->TX_AGC_CTL, reg);
+
+ reg = RTL818X_TX_CONF_CW_MIN |
+ (7 << 21 /* MAX TX DMA */) |
+ RTL818X_TX_CONF_NO_ICV;
+ rtl818x_iowrite32(priv, &priv->map->TX_CONF, reg);
+
+ reg = rtl818x_ioread8(priv, &priv->map->CMD);
+ reg |= RTL818X_CMD_TX_ENABLE;
+ reg |= RTL818X_CMD_RX_ENABLE;
+ rtl818x_iowrite8(priv, &priv->map->CMD, reg);
+
+ return 0;
+}
+
+static int rtl8187_stop(struct ieee80211_hw *dev)
+{
+ struct rtl8187_priv *priv = dev->priv;
+ struct rtl8187_rx_info *info;
+ struct sk_buff *skb;
+ u32 reg;
+
+ rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0);
+
+ reg = rtl818x_ioread8(priv, &priv->map->CMD);
+ reg &= ~RTL818X_CMD_TX_ENABLE;
+ reg &= ~RTL818X_CMD_RX_ENABLE;
+ rtl818x_iowrite8(priv, &priv->map->CMD, reg);
+
+ rtl8225_rf_stop(dev);
+
+ rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
+ reg = rtl818x_ioread8(priv, &priv->map->CONFIG4);
+ rtl818x_iowrite8(priv, &priv->map->CONFIG4, reg | RTL818X_CONFIG4_VCOOFF);
+ rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
+
+ while ((skb = skb_dequeue(&priv->rx_queue))) {
+ info = (struct rtl8187_rx_info *)skb->cb;
+ usb_kill_urb(info->urb);
+ kfree_skb(skb);
+ }
+ return 0;
+}
+
+static int rtl8187_add_interface(struct ieee80211_hw *dev,
+ struct ieee80211_if_init_conf *conf)
+{
+ struct rtl8187_priv *priv = dev->priv;
+
+ /* NOTE: using IEEE80211_IF_TYPE_MGMT to indicate no mode selected */
+ if (priv->mode != IEEE80211_IF_TYPE_MGMT)
+ return -1;
+
+ switch (conf->type) {
+ case IEEE80211_IF_TYPE_STA:
+ case IEEE80211_IF_TYPE_MNTR:
+ priv->mode = conf->type;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ priv->hwaddr = conf->mac_addr;
+
+ return 0;
+}
+
+static void rtl8187_remove_interface(struct ieee80211_hw *dev,
+ struct ieee80211_if_init_conf *conf)
+{
+ struct rtl8187_priv *priv = dev->priv;
+ priv->mode = IEEE80211_IF_TYPE_MGMT;
+}
+
+static int rtl8187_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
+{
+ struct rtl8187_priv *priv = dev->priv;
+ rtl8187_set_channel(dev, conf->channel);
+
+ rtl818x_iowrite8(priv, &priv->map->SIFS, 0x22);
+
+ if (conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME) {
+ rtl818x_iowrite8(priv, &priv->map->SLOT, 0x9);
+ rtl818x_iowrite8(priv, &priv->map->DIFS, 0x14);
+ rtl818x_iowrite8(priv, &priv->map->EIFS, 91 - 0x14);
+ rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0x73);
+ } else {
+ rtl818x_iowrite8(priv, &priv->map->SLOT, 0x14);
+ rtl818x_iowrite8(priv, &priv->map->DIFS, 0x24);
+ rtl818x_iowrite8(priv, &priv->map->EIFS, 91 - 0x24);
+ rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0xa5);
+ }
+
+ rtl818x_iowrite16(priv, &priv->map->ATIM_WND, 2);
+ rtl818x_iowrite16(priv, &priv->map->ATIMTR_INTERVAL, 100);
+ rtl818x_iowrite16(priv, &priv->map->BEACON_INTERVAL, 100);
+ rtl818x_iowrite16(priv, &priv->map->BEACON_INTERVAL_TIME, 100);
+ return 0;
+}
+
+static int rtl8187_config_interface(struct ieee80211_hw *dev, int if_id,
+ struct ieee80211_if_conf *conf)
+{
+ struct rtl8187_priv *priv = dev->priv;
+ int i;
+
+ for (i = 0; i < ETH_ALEN; i++)
+ rtl818x_iowrite8(priv, &priv->map->BSSID[i], conf->bssid[i]);
+
+ if (is_valid_ether_addr(conf->bssid))
+ rtl818x_iowrite8(priv, &priv->map->MSR, RTL818X_MSR_INFRA);
+ else
+ rtl818x_iowrite8(priv, &priv->map->MSR, RTL818X_MSR_NO_LINK);
+
+ return 0;
+}
+
+static const struct ieee80211_ops rtl8187_ops = {
+ .tx = rtl8187_tx,
+ .open = rtl8187_open,
+ .stop = rtl8187_stop,
+ .add_interface = rtl8187_add_interface,
+ .remove_interface = rtl8187_remove_interface,
+ .config = rtl8187_config,
+ .config_interface = rtl8187_config_interface,
+};
+
+static void rtl8187_eeprom_register_read(struct eeprom_93cx6 *eeprom)
+{
+ struct ieee80211_hw *dev = eeprom->data;
+ struct rtl8187_priv *priv = dev->priv;
+ u8 reg = rtl818x_ioread8(priv, &priv->map->EEPROM_CMD);
+
+ eeprom->reg_data_in = reg & RTL818X_EEPROM_CMD_WRITE;
+ eeprom->reg_data_out = reg & RTL818X_EEPROM_CMD_READ;
+ eeprom->reg_data_clock = reg & RTL818X_EEPROM_CMD_CK;
+ eeprom->reg_chip_select = reg & RTL818X_EEPROM_CMD_CS;
+}
+
+static void rtl8187_eeprom_register_write(struct eeprom_93cx6 *eeprom)
+{
+ struct ieee80211_hw *dev = eeprom->data;
+ struct rtl8187_priv *priv = dev->priv;
+ u8 reg = RTL818X_EEPROM_CMD_PROGRAM;
+
+ if (eeprom->reg_data_in)
+ reg |= RTL818X_EEPROM_CMD_WRITE;
+ if (eeprom->reg_data_out)
+ reg |= RTL818X_EEPROM_CMD_READ;
+ if (eeprom->reg_data_clock)
+ reg |= RTL818X_EEPROM_CMD_CK;
+ if (eeprom->reg_chip_select)
+ reg |= RTL818X_EEPROM_CMD_CS;
+
+ rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, reg);
+ udelay(10);
+}
+
+static int __devinit rtl8187_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct usb_device *udev = interface_to_usbdev(intf);
+ struct ieee80211_hw *dev;
+ struct rtl8187_priv *priv;
+ struct eeprom_93cx6 eeprom;
+ struct ieee80211_channel *channel;
+ u16 txpwr, reg;
+ int err, i;
+
+ dev = ieee80211_alloc_hw(sizeof(*priv), &rtl8187_ops);
+ if (!dev) {
+ printk(KERN_ERR "rtl8187: ieee80211 alloc failed\n");
+ return -ENOMEM;
+ }
+
+ priv = dev->priv;
+
+ SET_IEEE80211_DEV(dev, &intf->dev);
+ usb_set_intfdata(intf, dev);
+ priv->udev = udev;
+
+ usb_get_dev(udev);
+
+ skb_queue_head_init(&priv->rx_queue);
+ memcpy(priv->channels, rtl818x_channels, sizeof(rtl818x_channels));
+ memcpy(priv->rates, rtl818x_rates, sizeof(rtl818x_rates));
+ priv->map = (struct rtl818x_csr *)0xFF00;
+ priv->modes[0].mode = MODE_IEEE80211G;
+ priv->modes[0].num_rates = ARRAY_SIZE(rtl818x_rates);
+ priv->modes[0].rates = priv->rates;
+ priv->modes[0].num_channels = ARRAY_SIZE(rtl818x_channels);
+ priv->modes[0].channels = priv->channels;
+ priv->modes[1].mode = MODE_IEEE80211B;
+ priv->modes[1].num_rates = 4;
+ priv->modes[1].rates = priv->rates;
+ priv->modes[1].num_channels = ARRAY_SIZE(rtl818x_channels);
+ priv->modes[1].channels = priv->channels;
+ priv->mode = IEEE80211_IF_TYPE_MGMT;
+ dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
+ IEEE80211_HW_RX_INCLUDES_FCS |
+ IEEE80211_HW_WEP_INCLUDE_IV |
+ IEEE80211_HW_DATA_NULLFUNC_ACK;
+ dev->extra_tx_headroom = sizeof(struct rtl8187_tx_hdr);
+ dev->queues = 1;
+ dev->max_rssi = 65;
+ dev->max_signal = 64;
+
+ for (i = 0; i < 2; i++)
+ if ((err = ieee80211_register_hwmode(dev, &priv->modes[i])))
+ goto err_free_dev;
+
+ eeprom.data = dev;
+ eeprom.register_read = rtl8187_eeprom_register_read;
+ eeprom.register_write = rtl8187_eeprom_register_write;
+ if (rtl818x_ioread32(priv, &priv->map->RX_CONF) & (1 << 6))
+ eeprom.width = PCI_EEPROM_WIDTH_93C66;
+ else
+ eeprom.width = PCI_EEPROM_WIDTH_93C46;
+
+ rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
+ udelay(10);
+
+ eeprom_93cx6_multiread(&eeprom, RTL8187_EEPROM_MAC_ADDR,
+ (__le16 __force *)dev->wiphy->perm_addr, 3);
+ if (!is_valid_ether_addr(dev->wiphy->perm_addr)) {
+ printk(KERN_WARNING "rtl8187: Invalid hwaddr! Using randomly "
+ "generated MAC address\n");
+ random_ether_addr(dev->wiphy->perm_addr);
+ }
+
+ channel = priv->channels;
+ for (i = 0; i < 3; i++) {
+ eeprom_93cx6_read(&eeprom, RTL8187_EEPROM_TXPWR_CHAN_1 + i,
+ &txpwr);
+ (*channel++).val = txpwr & 0xFF;
+ (*channel++).val = txpwr >> 8;
+ }
+ for (i = 0; i < 2; i++) {
+ eeprom_93cx6_read(&eeprom, RTL8187_EEPROM_TXPWR_CHAN_4 + i,
+ &txpwr);
+ (*channel++).val = txpwr & 0xFF;
+ (*channel++).val = txpwr >> 8;
+ }
+ for (i = 0; i < 2; i++) {
+ eeprom_93cx6_read(&eeprom, RTL8187_EEPROM_TXPWR_CHAN_6 + i,
+ &txpwr);
+ (*channel++).val = txpwr & 0xFF;
+ (*channel++).val = txpwr >> 8;
+ }
+
+ eeprom_93cx6_read(&eeprom, RTL8187_EEPROM_TXPWR_BASE,
+ &priv->txpwr_base);
+
+ reg = rtl818x_ioread16(priv, &priv->map->PGSELECT) & ~1;
+ rtl818x_iowrite16(priv, &priv->map->PGSELECT, reg | 1);
+ /* 0 means asic B-cut, we should use SW 3 wire
+ * bit-by-bit banging for radio. 1 means we can use
+ * USB specific request to write radio registers */
+ priv->asic_rev = rtl818x_ioread8(priv, (u8 *)0xFFFE) & 0x3;
+ rtl818x_iowrite16(priv, &priv->map->PGSELECT, reg);
+ rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
+
+ rtl8225_write(dev, 0, 0x1B7);
+
+ if (rtl8225_read(dev, 8) != 0x588 || rtl8225_read(dev, 9) != 0x700)
+ priv->rf_init = rtl8225_rf_init;
+ else
+ priv->rf_init = rtl8225z2_rf_init;
+
+ rtl8225_write(dev, 0, 0x0B7);
+
+ err = ieee80211_register_hw(dev);
+ if (err) {
+ printk(KERN_ERR "rtl8187: Cannot register device\n");
+ goto err_free_dev;
+ }
+
+ printk(KERN_INFO "%s: hwaddr " MAC_FMT ", rtl8187 V%d + %s\n",
+ wiphy_name(dev->wiphy), MAC_ARG(dev->wiphy->perm_addr),
+ priv->asic_rev, priv->rf_init == rtl8225_rf_init ?
+ "rtl8225" : "rtl8225z2");
+
+ return 0;
+
+ err_free_dev:
+ ieee80211_free_hw(dev);
+ usb_set_intfdata(intf, NULL);
+ usb_put_dev(udev);
+ return err;
+}
+
+static void __devexit rtl8187_disconnect(struct usb_interface *intf)
+{
+ struct ieee80211_hw *dev = usb_get_intfdata(intf);
+ struct rtl8187_priv *priv;
+
+ if (!dev)
+ return;
+
+ ieee80211_unregister_hw(dev);
+
+ priv = dev->priv;
+ usb_put_dev(interface_to_usbdev(intf));
+ ieee80211_free_hw(dev);
+}
+
+static struct usb_driver rtl8187_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = rtl8187_table,
+ .probe = rtl8187_probe,
+ .disconnect = rtl8187_disconnect,
+};
+
+static int __init rtl8187_init(void)
+{
+ return usb_register(&rtl8187_driver);
+}
+
+static void __exit rtl8187_exit(void)
+{
+ usb_deregister(&rtl8187_driver);
+}
+
+module_init(rtl8187_init);
+module_exit(rtl8187_exit);
diff --git a/drivers/net/wireless/rtl8187_rtl8225.c b/drivers/net/wireless/rtl8187_rtl8225.c
new file mode 100644
index 000000000000..e25a09f1b068
--- /dev/null
+++ b/drivers/net/wireless/rtl8187_rtl8225.c
@@ -0,0 +1,745 @@
+/*
+ * Radio tuning for RTL8225 on RTL8187
+ *
+ * Copyright 2007 Michael Wu <flamingice@sourmilk.net>
+ * Copyright 2007 Andrea Merello <andreamrl@tiscali.it>
+ *
+ * Based on the r8187 driver, which is:
+ * Copyright 2005 Andrea Merello <andreamrl@tiscali.it>, et al.
+ *
+ * Magic delays, register offsets, and phy value tables below are
+ * taken from the original r8187 driver sources. Thanks to Realtek
+ * for their support!
+ *
+ * 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/init.h>
+#include <linux/usb.h>
+#include <net/mac80211.h>
+
+#include "rtl8187.h"
+#include "rtl8187_rtl8225.h"
+
+static void rtl8225_write_bitbang(struct ieee80211_hw *dev, u8 addr, u16 data)
+{
+ struct rtl8187_priv *priv = dev->priv;
+ u16 reg80, reg84, reg82;
+ u32 bangdata;
+ int i;
+
+ bangdata = (data << 4) | (addr & 0xf);
+
+ reg80 = rtl818x_ioread16(priv, &priv->map->RFPinsOutput) & 0xfff3;
+ reg82 = rtl818x_ioread16(priv, &priv->map->RFPinsEnable);
+
+ rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82 | 0x7);
+
+ reg84 = rtl818x_ioread16(priv, &priv->map->RFPinsSelect);
+ rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84 | 0x7);
+ udelay(10);
+
+ rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
+ udelay(2);
+ rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80);
+ udelay(10);
+
+ for (i = 15; i >= 0; i--) {
+ u16 reg = reg80 | (bangdata & (1 << i)) >> i;
+
+ if (i & 1)
+ rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg);
+
+ rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg | (1 << 1));
+ rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg | (1 << 1));
+
+ if (!(i & 1))
+ rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg);
+ }
+
+ rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
+ udelay(10);
+
+ rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
+ rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84);
+ msleep(2);
+}
+
+static void rtl8225_write_8051(struct ieee80211_hw *dev, u8 addr, u16 data)
+{
+ struct rtl8187_priv *priv = dev->priv;
+ u16 reg80, reg82, reg84;
+
+ reg80 = rtl818x_ioread16(priv, &priv->map->RFPinsOutput);
+ reg82 = rtl818x_ioread16(priv, &priv->map->RFPinsEnable);
+ reg84 = rtl818x_ioread16(priv, &priv->map->RFPinsSelect);
+
+ reg80 &= ~(0x3 << 2);
+ reg84 &= ~0xF;
+
+ rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82 | 0x0007);
+ rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84 | 0x0007);
+ udelay(10);
+
+ rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
+ udelay(2);
+
+ rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80);
+ udelay(10);
+
+ usb_control_msg(priv->udev, usb_sndctrlpipe(priv->udev, 0),
+ RTL8187_REQ_SET_REG, RTL8187_REQT_WRITE,
+ addr, 0x8225, &data, sizeof(data), HZ / 2);
+
+ rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
+ udelay(10);
+
+ rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
+ rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84);
+ msleep(2);
+}
+
+void rtl8225_write(struct ieee80211_hw *dev, u8 addr, u16 data)
+{
+ struct rtl8187_priv *priv = dev->priv;
+
+ if (priv->asic_rev)
+ rtl8225_write_8051(dev, addr, data);
+ else
+ rtl8225_write_bitbang(dev, addr, data);
+}
+
+u16 rtl8225_read(struct ieee80211_hw *dev, u8 addr)
+{
+ struct rtl8187_priv *priv = dev->priv;
+ u16 reg80, reg82, reg84, out;
+ int i;
+
+ reg80 = rtl818x_ioread16(priv, &priv->map->RFPinsOutput);
+ reg82 = rtl818x_ioread16(priv, &priv->map->RFPinsEnable);
+ reg84 = rtl818x_ioread16(priv, &priv->map->RFPinsSelect);
+
+ reg80 &= ~0xF;
+
+ rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82 | 0x000F);
+ rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84 | 0x000F);
+
+ rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2));
+ udelay(4);
+ rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80);
+ udelay(5);
+
+ for (i = 4; i >= 0; i--) {
+ u16 reg = reg80 | ((addr >> i) & 1);
+
+ if (!(i & 1)) {
+ rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg);
+ udelay(1);
+ }
+
+ rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
+ reg | (1 << 1));
+ udelay(2);
+ rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
+ reg | (1 << 1));
+ udelay(2);
+
+ if (i & 1) {
+ rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg);
+ udelay(1);
+ }
+ }
+
+ rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
+ reg80 | (1 << 3) | (1 << 1));
+ udelay(2);
+ rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
+ reg80 | (1 << 3));
+ udelay(2);
+ rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
+ reg80 | (1 << 3));
+ udelay(2);
+
+ out = 0;
+ for (i = 11; i >= 0; i--) {
+ rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
+ reg80 | (1 << 3));
+ udelay(1);
+ rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
+ reg80 | (1 << 3) | (1 << 1));
+ udelay(2);
+ rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
+ reg80 | (1 << 3) | (1 << 1));
+ udelay(2);
+ rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
+ reg80 | (1 << 3) | (1 << 1));
+ udelay(2);
+
+ if (rtl818x_ioread16(priv, &priv->map->RFPinsInput) & (1 << 1))
+ out |= 1 << i;
+
+ rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
+ reg80 | (1 << 3));
+ udelay(2);
+ }
+
+ rtl818x_iowrite16(priv, &priv->map->RFPinsOutput,
+ reg80 | (1 << 3) | (1 << 2));
+ udelay(2);
+
+ rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82);
+ rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84);
+ rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x03A0);
+
+ return out;
+}
+
+static const u16 rtl8225bcd_rxgain[] = {
+ 0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409,
+ 0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541,
+ 0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583,
+ 0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644,
+ 0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688,
+ 0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745,
+ 0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789,
+ 0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793,
+ 0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d,
+ 0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9,
+ 0x07aa, 0x07ab, 0x07ac, 0x07ad, 0x07b0, 0x07b1, 0x07b2, 0x07b3,
+ 0x07b4, 0x07b5, 0x07b8, 0x07b9, 0x07ba, 0x07bb, 0x07bb
+};
+
+static const u8 rtl8225_agc[] = {
+ 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e,
+ 0x9d, 0x9c, 0x9b, 0x9a, 0x99, 0x98, 0x97, 0x96,
+ 0x95, 0x94, 0x93, 0x92, 0x91, 0x90, 0x8f, 0x8e,
+ 0x8d, 0x8c, 0x8b, 0x8a, 0x89, 0x88, 0x87, 0x86,
+ 0x85, 0x84, 0x83, 0x82, 0x81, 0x80, 0x3f, 0x3e,
+ 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x37, 0x36,
+ 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x2f, 0x2e,
+ 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26,
+ 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x1f, 0x1e,
+ 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x17, 0x16,
+ 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0x0e,
+ 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06,
+ 0x05, 0x04, 0x03, 0x02, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01
+};
+
+static const u8 rtl8225_gain[] = {
+ 0x23, 0x88, 0x7c, 0xa5, /* -82dBm */
+ 0x23, 0x88, 0x7c, 0xb5, /* -82dBm */
+ 0x23, 0x88, 0x7c, 0xc5, /* -82dBm */
+ 0x33, 0x80, 0x79, 0xc5, /* -78dBm */
+ 0x43, 0x78, 0x76, 0xc5, /* -74dBm */
+ 0x53, 0x60, 0x73, 0xc5, /* -70dBm */
+ 0x63, 0x58, 0x70, 0xc5, /* -66dBm */
+};
+
+static const u8 rtl8225_threshold[] = {
+ 0x8d, 0x8d, 0x8d, 0x8d, 0x9d, 0xad, 0xbd
+};
+
+static const u8 rtl8225_tx_gain_cck_ofdm[] = {
+ 0x02, 0x06, 0x0e, 0x1e, 0x3e, 0x7e
+};
+
+static const u8 rtl8225_tx_power_cck[] = {
+ 0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02,
+ 0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02,
+ 0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02,
+ 0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02,
+ 0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03,
+ 0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03
+};
+
+static const u8 rtl8225_tx_power_cck_ch14[] = {
+ 0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00,
+ 0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00,
+ 0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00,
+ 0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00,
+ 0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00,
+ 0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00
+};
+
+static const u8 rtl8225_tx_power_ofdm[] = {
+ 0x80, 0x90, 0xa2, 0xb5, 0xcb, 0xe4
+};
+
+static const u32 rtl8225_chan[] = {
+ 0x085c, 0x08dc, 0x095c, 0x09dc, 0x0a5c, 0x0adc, 0x0b5c,
+ 0x0bdc, 0x0c5c, 0x0cdc, 0x0d5c, 0x0ddc, 0x0e5c, 0x0f72
+};
+
+static void rtl8225_rf_set_tx_power(struct ieee80211_hw *dev, int channel)
+{
+ struct rtl8187_priv *priv = dev->priv;
+ u8 cck_power, ofdm_power;
+ const u8 *tmp;
+ u32 reg;
+ int i;
+
+ cck_power = priv->channels[channel - 1].val & 0xF;
+ ofdm_power = priv->channels[channel - 1].val >> 4;
+
+ cck_power = min(cck_power, (u8)11);
+ ofdm_power = min(ofdm_power, (u8)35);
+
+ rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK,
+ rtl8225_tx_gain_cck_ofdm[cck_power / 6] >> 1);
+
+ if (channel == 14)
+ tmp = &rtl8225_tx_power_cck_ch14[(cck_power % 6) * 8];
+ else
+ tmp = &rtl8225_tx_power_cck[(cck_power % 6) * 8];
+
+ for (i = 0; i < 8; i++)
+ rtl8225_write_phy_cck(dev, 0x44 + i, *tmp++);
+
+ msleep(1); // FIXME: optional?
+
+ /* anaparam2 on */
+ rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
+ reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
+ rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
+ rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_ON);
+ rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
+ rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
+
+ rtl8225_write_phy_ofdm(dev, 2, 0x42);
+ rtl8225_write_phy_ofdm(dev, 6, 0x00);
+ rtl8225_write_phy_ofdm(dev, 8, 0x00);
+
+ rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM,
+ rtl8225_tx_gain_cck_ofdm[ofdm_power / 6] >> 1);
+
+ tmp = &rtl8225_tx_power_ofdm[ofdm_power % 6];
+
+ rtl8225_write_phy_ofdm(dev, 5, *tmp);
+ rtl8225_write_phy_ofdm(dev, 7, *tmp);
+
+ msleep(1);
+}
+
+void rtl8225_rf_init(struct ieee80211_hw *dev)
+{
+ struct rtl8187_priv *priv = dev->priv;
+ int i;
+
+ rtl8225_write(dev, 0x0, 0x067); msleep(1);
+ rtl8225_write(dev, 0x1, 0xFE0); msleep(1);
+ rtl8225_write(dev, 0x2, 0x44D); msleep(1);
+ rtl8225_write(dev, 0x3, 0x441); msleep(1);
+ rtl8225_write(dev, 0x4, 0x486); msleep(1);
+ rtl8225_write(dev, 0x5, 0xBC0); msleep(1);
+ rtl8225_write(dev, 0x6, 0xAE6); msleep(1);
+ rtl8225_write(dev, 0x7, 0x82A); msleep(1);
+ rtl8225_write(dev, 0x8, 0x01F); msleep(1);
+ rtl8225_write(dev, 0x9, 0x334); msleep(1);
+ rtl8225_write(dev, 0xA, 0xFD4); msleep(1);
+ rtl8225_write(dev, 0xB, 0x391); msleep(1);
+ rtl8225_write(dev, 0xC, 0x050); msleep(1);
+ rtl8225_write(dev, 0xD, 0x6DB); msleep(1);
+ rtl8225_write(dev, 0xE, 0x029); msleep(1);
+ rtl8225_write(dev, 0xF, 0x914); msleep(100);
+
+ rtl8225_write(dev, 0x2, 0xC4D); msleep(200);
+ rtl8225_write(dev, 0x2, 0x44D); msleep(200);
+
+ if (!(rtl8225_read(dev, 6) & (1 << 7))) {
+ rtl8225_write(dev, 0x02, 0x0c4d);
+ msleep(200);
+ rtl8225_write(dev, 0x02, 0x044d);
+ msleep(100);
+ if (!(rtl8225_read(dev, 6) & (1 << 7)))
+ printk(KERN_WARNING "%s: RF Calibration Failed! %x\n",
+ wiphy_name(dev->wiphy), rtl8225_read(dev, 6));
+ }
+
+ rtl8225_write(dev, 0x0, 0x127);
+
+ for (i = 0; i < ARRAY_SIZE(rtl8225bcd_rxgain); i++) {
+ rtl8225_write(dev, 0x1, i + 1);
+ rtl8225_write(dev, 0x2, rtl8225bcd_rxgain[i]);
+ }
+
+ rtl8225_write(dev, 0x0, 0x027);
+ rtl8225_write(dev, 0x0, 0x22F);
+
+ for (i = 0; i < ARRAY_SIZE(rtl8225_agc); i++) {
+ rtl8225_write_phy_ofdm(dev, 0xB, rtl8225_agc[i]);
+ msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0xA, 0x80 + i);
+ msleep(1);
+ }
+
+ msleep(1);
+
+ rtl8225_write_phy_ofdm(dev, 0x00, 0x01); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x01, 0x02); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x02, 0x42); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x03, 0x00); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x04, 0x00); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x05, 0x00); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x06, 0x40); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x07, 0x00); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x08, 0x40); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x09, 0xfe); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x0a, 0x09); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x0b, 0x80); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x0c, 0x01); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x0f, 0x38); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x10, 0x84); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x11, 0x06); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x12, 0x20); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x13, 0x20); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x14, 0x00); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x15, 0x40); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x16, 0x00); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x17, 0x40); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x18, 0xef); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x19, 0x19); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x1a, 0x20); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x1b, 0x76); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x1c, 0x04); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x1e, 0x95); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x1f, 0x75); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x20, 0x1f); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x21, 0x27); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x22, 0x16); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x24, 0x46); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x25, 0x20); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x27, 0x88); msleep(1);
+
+ rtl8225_write_phy_ofdm(dev, 0x0d, rtl8225_gain[2 * 4]);
+ rtl8225_write_phy_ofdm(dev, 0x1b, rtl8225_gain[2 * 4 + 2]);
+ rtl8225_write_phy_ofdm(dev, 0x1d, rtl8225_gain[2 * 4 + 3]);
+ rtl8225_write_phy_ofdm(dev, 0x23, rtl8225_gain[2 * 4 + 1]);
+
+ rtl8225_write_phy_cck(dev, 0x00, 0x98); msleep(1);
+ rtl8225_write_phy_cck(dev, 0x03, 0x20); msleep(1);
+ rtl8225_write_phy_cck(dev, 0x04, 0x7e); msleep(1);
+ rtl8225_write_phy_cck(dev, 0x05, 0x12); msleep(1);
+ rtl8225_write_phy_cck(dev, 0x06, 0xfc); msleep(1);
+ rtl8225_write_phy_cck(dev, 0x07, 0x78); msleep(1);
+ rtl8225_write_phy_cck(dev, 0x08, 0x2e); msleep(1);
+ rtl8225_write_phy_cck(dev, 0x10, 0x9b); msleep(1);
+ rtl8225_write_phy_cck(dev, 0x11, 0x88); msleep(1);
+ rtl8225_write_phy_cck(dev, 0x12, 0x47); msleep(1);
+ rtl8225_write_phy_cck(dev, 0x13, 0xd0);
+ rtl8225_write_phy_cck(dev, 0x19, 0x00);
+ rtl8225_write_phy_cck(dev, 0x1a, 0xa0);
+ rtl8225_write_phy_cck(dev, 0x1b, 0x08);
+ rtl8225_write_phy_cck(dev, 0x40, 0x86);
+ rtl8225_write_phy_cck(dev, 0x41, 0x8d); msleep(1);
+ rtl8225_write_phy_cck(dev, 0x42, 0x15); msleep(1);
+ rtl8225_write_phy_cck(dev, 0x43, 0x18); msleep(1);
+ rtl8225_write_phy_cck(dev, 0x44, 0x1f); msleep(1);
+ rtl8225_write_phy_cck(dev, 0x45, 0x1e); msleep(1);
+ rtl8225_write_phy_cck(dev, 0x46, 0x1a); msleep(1);
+ rtl8225_write_phy_cck(dev, 0x47, 0x15); msleep(1);
+ rtl8225_write_phy_cck(dev, 0x48, 0x10); msleep(1);
+ rtl8225_write_phy_cck(dev, 0x49, 0x0a); msleep(1);
+ rtl8225_write_phy_cck(dev, 0x4a, 0x05); msleep(1);
+ rtl8225_write_phy_cck(dev, 0x4b, 0x02); msleep(1);
+ rtl8225_write_phy_cck(dev, 0x4c, 0x05); msleep(1);
+
+ rtl818x_iowrite8(priv, &priv->map->TESTR, 0x0D);
+
+ rtl8225_rf_set_tx_power(dev, 1);
+
+ /* RX antenna default to A */
+ rtl8225_write_phy_cck(dev, 0x10, 0x9b); msleep(1); /* B: 0xDB */
+ rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1); /* B: 0x10 */
+
+ rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03); /* B: 0x00 */
+ msleep(1);
+ rtl818x_iowrite32(priv, (__le32 *)0xFF94, 0x3dc00002);
+
+ /* set sensitivity */
+ rtl8225_write(dev, 0x0c, 0x50);
+ rtl8225_write_phy_ofdm(dev, 0x0d, rtl8225_gain[2 * 4]);
+ rtl8225_write_phy_ofdm(dev, 0x1b, rtl8225_gain[2 * 4 + 2]);
+ rtl8225_write_phy_ofdm(dev, 0x1d, rtl8225_gain[2 * 4 + 3]);
+ rtl8225_write_phy_ofdm(dev, 0x23, rtl8225_gain[2 * 4 + 1]);
+ rtl8225_write_phy_cck(dev, 0x41, rtl8225_threshold[2]);
+}
+
+static const u8 rtl8225z2_tx_power_cck_ch14[] = {
+ 0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00
+};
+
+static const u8 rtl8225z2_tx_power_cck[] = {
+ 0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04
+};
+
+static const u8 rtl8225z2_tx_power_ofdm[] = {
+ 0x42, 0x00, 0x40, 0x00, 0x40
+};
+
+static const u8 rtl8225z2_tx_gain_cck_ofdm[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
+ 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
+ 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11,
+ 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
+ 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23
+};
+
+static void rtl8225z2_rf_set_tx_power(struct ieee80211_hw *dev, int channel)
+{
+ struct rtl8187_priv *priv = dev->priv;
+ u8 cck_power, ofdm_power;
+ const u8 *tmp;
+ u32 reg;
+ int i;
+
+ cck_power = priv->channels[channel - 1].val & 0xF;
+ ofdm_power = priv->channels[channel - 1].val >> 4;
+
+ cck_power = min(cck_power, (u8)15);
+ cck_power += priv->txpwr_base & 0xF;
+ cck_power = min(cck_power, (u8)35);
+
+ ofdm_power = min(ofdm_power, (u8)15);
+ ofdm_power += priv->txpwr_base >> 4;
+ ofdm_power = min(ofdm_power, (u8)35);
+
+ if (channel == 14)
+ tmp = rtl8225z2_tx_power_cck_ch14;
+ else
+ tmp = rtl8225z2_tx_power_cck;
+
+ for (i = 0; i < 8; i++)
+ rtl8225_write_phy_cck(dev, 0x44 + i, *tmp++);
+
+ rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK,
+ rtl8225z2_tx_gain_cck_ofdm[cck_power]);
+ msleep(1);
+
+ /* anaparam2 on */
+ rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
+ reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
+ rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
+ rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_ON);
+ rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
+ rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
+
+ rtl8225_write_phy_ofdm(dev, 2, 0x42);
+ rtl8225_write_phy_ofdm(dev, 5, 0x00);
+ rtl8225_write_phy_ofdm(dev, 6, 0x40);
+ rtl8225_write_phy_ofdm(dev, 7, 0x00);
+ rtl8225_write_phy_ofdm(dev, 8, 0x40);
+
+ rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM,
+ rtl8225z2_tx_gain_cck_ofdm[ofdm_power]);
+ msleep(1);
+}
+
+static const u16 rtl8225z2_rxgain[] = {
+ 0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409,
+ 0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541,
+ 0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583,
+ 0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644,
+ 0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688,
+ 0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745,
+ 0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789,
+ 0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793,
+ 0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d,
+ 0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9,
+ 0x03aa, 0x03ab, 0x03ac, 0x03ad, 0x03b0, 0x03b1, 0x03b2, 0x03b3,
+ 0x03b4, 0x03b5, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bb
+};
+
+static const u8 rtl8225z2_gain_bg[] = {
+ 0x23, 0x15, 0xa5, /* -82-1dBm */
+ 0x23, 0x15, 0xb5, /* -82-2dBm */
+ 0x23, 0x15, 0xc5, /* -82-3dBm */
+ 0x33, 0x15, 0xc5, /* -78dBm */
+ 0x43, 0x15, 0xc5, /* -74dBm */
+ 0x53, 0x15, 0xc5, /* -70dBm */
+ 0x63, 0x15, 0xc5 /* -66dBm */
+};
+
+void rtl8225z2_rf_init(struct ieee80211_hw *dev)
+{
+ struct rtl8187_priv *priv = dev->priv;
+ int i;
+
+ rtl8225_write(dev, 0x0, 0x2BF); msleep(1);
+ rtl8225_write(dev, 0x1, 0xEE0); msleep(1);
+ rtl8225_write(dev, 0x2, 0x44D); msleep(1);
+ rtl8225_write(dev, 0x3, 0x441); msleep(1);
+ rtl8225_write(dev, 0x4, 0x8C3); msleep(1);
+ rtl8225_write(dev, 0x5, 0xC72); msleep(1);
+ rtl8225_write(dev, 0x6, 0x0E6); msleep(1);
+ rtl8225_write(dev, 0x7, 0x82A); msleep(1);
+ rtl8225_write(dev, 0x8, 0x03F); msleep(1);
+ rtl8225_write(dev, 0x9, 0x335); msleep(1);
+ rtl8225_write(dev, 0xa, 0x9D4); msleep(1);
+ rtl8225_write(dev, 0xb, 0x7BB); msleep(1);
+ rtl8225_write(dev, 0xc, 0x850); msleep(1);
+ rtl8225_write(dev, 0xd, 0xCDF); msleep(1);
+ rtl8225_write(dev, 0xe, 0x02B); msleep(1);
+ rtl8225_write(dev, 0xf, 0x114); msleep(100);
+
+ rtl8225_write(dev, 0x0, 0x1B7);
+
+ for (i = 0; i < ARRAY_SIZE(rtl8225z2_rxgain); i++) {
+ rtl8225_write(dev, 0x1, i + 1);
+ rtl8225_write(dev, 0x2, rtl8225z2_rxgain[i]);
+ }
+
+ rtl8225_write(dev, 0x3, 0x080);
+ rtl8225_write(dev, 0x5, 0x004);
+ rtl8225_write(dev, 0x0, 0x0B7);
+ rtl8225_write(dev, 0x2, 0xc4D);
+
+ msleep(200);
+ rtl8225_write(dev, 0x2, 0x44D);
+ msleep(100);
+
+ if (!(rtl8225_read(dev, 6) & (1 << 7))) {
+ rtl8225_write(dev, 0x02, 0x0C4D);
+ msleep(200);
+ rtl8225_write(dev, 0x02, 0x044D);
+ msleep(100);
+ if (!(rtl8225_read(dev, 6) & (1 << 7)))
+ printk(KERN_WARNING "%s: RF Calibration Failed! %x\n",
+ wiphy_name(dev->wiphy), rtl8225_read(dev, 6));
+ }
+
+ msleep(200);
+
+ rtl8225_write(dev, 0x0, 0x2BF);
+
+ for (i = 0; i < ARRAY_SIZE(rtl8225_agc); i++) {
+ rtl8225_write_phy_ofdm(dev, 0xB, rtl8225_agc[i]);
+ msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0xA, 0x80 + i);
+ msleep(1);
+ }
+
+ msleep(1);
+
+ rtl8225_write_phy_ofdm(dev, 0x00, 0x01); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x01, 0x02); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x02, 0x42); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x03, 0x00); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x04, 0x00); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x05, 0x00); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x06, 0x40); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x07, 0x00); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x08, 0x40); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x09, 0xfe); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x0a, 0x08); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x0b, 0x80); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x0c, 0x01); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x0d, 0x43);
+ rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x0f, 0x38); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x10, 0x84); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x11, 0x07); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x12, 0x20); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x13, 0x20); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x14, 0x00); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x15, 0x40); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x16, 0x00); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x17, 0x40); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x18, 0xef); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x19, 0x19); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x1a, 0x20); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x1b, 0x15); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x1c, 0x04); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x1d, 0xc5); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x1e, 0x95); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x1f, 0x75); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x20, 0x1f); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x21, 0x17); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x22, 0x16); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x23, 0x80); msleep(1); //FIXME: not needed?
+ rtl8225_write_phy_ofdm(dev, 0x24, 0x46); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x25, 0x00); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1);
+ rtl8225_write_phy_ofdm(dev, 0x27, 0x88); msleep(1);
+
+ rtl8225_write_phy_ofdm(dev, 0x0b, rtl8225z2_gain_bg[4 * 3]);
+ rtl8225_write_phy_ofdm(dev, 0x1b, rtl8225z2_gain_bg[4 * 3 + 1]);
+ rtl8225_write_phy_ofdm(dev, 0x1d, rtl8225z2_gain_bg[4 * 3 + 2]);
+ rtl8225_write_phy_ofdm(dev, 0x21, 0x37);
+
+ rtl8225_write_phy_cck(dev, 0x00, 0x98); msleep(1);
+ rtl8225_write_phy_cck(dev, 0x03, 0x20); msleep(1);
+ rtl8225_write_phy_cck(dev, 0x04, 0x7e); msleep(1);
+ rtl8225_write_phy_cck(dev, 0x05, 0x12); msleep(1);
+ rtl8225_write_phy_cck(dev, 0x06, 0xfc); msleep(1);
+ rtl8225_write_phy_cck(dev, 0x07, 0x78); msleep(1);
+ rtl8225_write_phy_cck(dev, 0x08, 0x2e); msleep(1);
+ rtl8225_write_phy_cck(dev, 0x10, 0x9b); msleep(1);
+ rtl8225_write_phy_cck(dev, 0x11, 0x88); msleep(1);
+ rtl8225_write_phy_cck(dev, 0x12, 0x47); msleep(1);
+ rtl8225_write_phy_cck(dev, 0x13, 0xd0);
+ rtl8225_write_phy_cck(dev, 0x19, 0x00);
+ rtl8225_write_phy_cck(dev, 0x1a, 0xa0);
+ rtl8225_write_phy_cck(dev, 0x1b, 0x08);
+ rtl8225_write_phy_cck(dev, 0x40, 0x86);
+ rtl8225_write_phy_cck(dev, 0x41, 0x8d); msleep(1);
+ rtl8225_write_phy_cck(dev, 0x42, 0x15); msleep(1);
+ rtl8225_write_phy_cck(dev, 0x43, 0x18); msleep(1);
+ rtl8225_write_phy_cck(dev, 0x44, 0x36); msleep(1);
+ rtl8225_write_phy_cck(dev, 0x45, 0x35); msleep(1);
+ rtl8225_write_phy_cck(dev, 0x46, 0x2e); msleep(1);
+ rtl8225_write_phy_cck(dev, 0x47, 0x25); msleep(1);
+ rtl8225_write_phy_cck(dev, 0x48, 0x1c); msleep(1);
+ rtl8225_write_phy_cck(dev, 0x49, 0x12); msleep(1);
+ rtl8225_write_phy_cck(dev, 0x4a, 0x09); msleep(1);
+ rtl8225_write_phy_cck(dev, 0x4b, 0x04); msleep(1);
+ rtl8225_write_phy_cck(dev, 0x4c, 0x05); msleep(1);
+
+ rtl818x_iowrite8(priv, (u8 *)0xFF5B, 0x0D); msleep(1);
+
+ rtl8225z2_rf_set_tx_power(dev, 1);
+
+ /* RX antenna default to A */
+ rtl8225_write_phy_cck(dev, 0x10, 0x9b); msleep(1); /* B: 0xDB */
+ rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1); /* B: 0x10 */
+
+ rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03); /* B: 0x00 */
+ msleep(1);
+ rtl818x_iowrite32(priv, (__le32 *)0xFF94, 0x3dc00002);
+}
+
+void rtl8225_rf_stop(struct ieee80211_hw *dev)
+{
+ u8 reg;
+ struct rtl8187_priv *priv = dev->priv;
+
+ rtl8225_write(dev, 0x4, 0x1f); msleep(1);
+
+ rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
+ reg = rtl818x_ioread8(priv, &priv->map->CONFIG3);
+ rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE);
+ rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_OFF);
+ rtl818x_iowrite32(priv, &priv->map->ANAPARAM, RTL8225_ANAPARAM_OFF);
+ rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE);
+ rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
+}
+
+void rtl8225_rf_set_channel(struct ieee80211_hw *dev, int channel)
+{
+ struct rtl8187_priv *priv = dev->priv;
+
+ if (priv->rf_init == rtl8225_rf_init)
+ rtl8225_rf_set_tx_power(dev, channel);
+ else
+ rtl8225z2_rf_set_tx_power(dev, channel);
+
+ rtl8225_write(dev, 0x7, rtl8225_chan[channel - 1]);
+ msleep(10);
+}
diff --git a/drivers/net/wireless/rtl8187_rtl8225.h b/drivers/net/wireless/rtl8187_rtl8225.h
new file mode 100644
index 000000000000..798ba4a97376
--- /dev/null
+++ b/drivers/net/wireless/rtl8187_rtl8225.h
@@ -0,0 +1,44 @@
+/*
+ * Radio tuning definitions for RTL8225 on RTL8187
+ *
+ * Copyright 2007 Michael Wu <flamingice@sourmilk.net>
+ * Copyright 2007 Andrea Merello <andreamrl@tiscali.it>
+ *
+ * Based on the r8187 driver, which is:
+ * Copyright 2005 Andrea Merello <andreamrl@tiscali.it>, et al.
+ *
+ * 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.
+ */
+
+#ifndef RTL8187_RTL8225_H
+#define RTL8187_RTL8225_H
+
+#define RTL8225_ANAPARAM_ON 0xa0000a59
+#define RTL8225_ANAPARAM2_ON 0x860c7312
+#define RTL8225_ANAPARAM_OFF 0xa00beb59
+#define RTL8225_ANAPARAM2_OFF 0x840dec11
+
+void rtl8225_write(struct ieee80211_hw *, u8 addr, u16 data);
+u16 rtl8225_read(struct ieee80211_hw *, u8 addr);
+
+void rtl8225_rf_init(struct ieee80211_hw *);
+void rtl8225z2_rf_init(struct ieee80211_hw *);
+void rtl8225_rf_stop(struct ieee80211_hw *);
+void rtl8225_rf_set_channel(struct ieee80211_hw *, int);
+
+
+static inline void rtl8225_write_phy_ofdm(struct ieee80211_hw *dev,
+ u8 addr, u32 data)
+{
+ rtl8187_write_phy(dev, addr, data);
+}
+
+static inline void rtl8225_write_phy_cck(struct ieee80211_hw *dev,
+ u8 addr, u32 data)
+{
+ rtl8187_write_phy(dev, addr, data | 0x10000);
+}
+
+#endif /* RTL8187_RTL8225_H */
diff --git a/drivers/net/wireless/rtl818x.h b/drivers/net/wireless/rtl818x.h
new file mode 100644
index 000000000000..283de30628e1
--- /dev/null
+++ b/drivers/net/wireless/rtl818x.h
@@ -0,0 +1,226 @@
+/*
+ * Definitions for RTL818x hardware
+ *
+ * Copyright 2007 Michael Wu <flamingice@sourmilk.net>
+ * Copyright 2007 Andrea Merello <andreamrl@tiscali.it>
+ *
+ * Based on the r8187 driver, which is:
+ * Copyright 2005 Andrea Merello <andreamrl@tiscali.it>, et al.
+ *
+ * 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.
+ */
+
+#ifndef RTL818X_H
+#define RTL818X_H
+
+struct rtl818x_csr {
+ u8 MAC[6];
+ u8 reserved_0[2];
+ __le32 MAR[2];
+ u8 RX_FIFO_COUNT;
+ u8 reserved_1;
+ u8 TX_FIFO_COUNT;
+ u8 BQREQ;
+ u8 reserved_2[4];
+ __le32 TSFT[2];
+ __le32 TLPDA;
+ __le32 TNPDA;
+ __le32 THPDA;
+ __le16 BRSR;
+ u8 BSSID[6];
+ u8 RESP_RATE;
+ u8 EIFS;
+ u8 reserved_3[1];
+ u8 CMD;
+#define RTL818X_CMD_TX_ENABLE (1 << 2)
+#define RTL818X_CMD_RX_ENABLE (1 << 3)
+#define RTL818X_CMD_RESET (1 << 4)
+ u8 reserved_4[4];
+ __le16 INT_MASK;
+ __le16 INT_STATUS;
+#define RTL818X_INT_RX_OK (1 << 0)
+#define RTL818X_INT_RX_ERR (1 << 1)
+#define RTL818X_INT_TXL_OK (1 << 2)
+#define RTL818X_INT_TXL_ERR (1 << 3)
+#define RTL818X_INT_RX_DU (1 << 4)
+#define RTL818X_INT_RX_FO (1 << 5)
+#define RTL818X_INT_TXN_OK (1 << 6)
+#define RTL818X_INT_TXN_ERR (1 << 7)
+#define RTL818X_INT_TXH_OK (1 << 8)
+#define RTL818X_INT_TXH_ERR (1 << 9)
+#define RTL818X_INT_TXB_OK (1 << 10)
+#define RTL818X_INT_TXB_ERR (1 << 11)
+#define RTL818X_INT_ATIM (1 << 12)
+#define RTL818X_INT_BEACON (1 << 13)
+#define RTL818X_INT_TIME_OUT (1 << 14)
+#define RTL818X_INT_TX_FO (1 << 15)
+ __le32 TX_CONF;
+#define RTL818X_TX_CONF_LOOPBACK_MAC (1 << 17)
+#define RTL818X_TX_CONF_NO_ICV (1 << 19)
+#define RTL818X_TX_CONF_DISCW (1 << 20)
+#define RTL818X_TX_CONF_R8180_ABCD (2 << 25)
+#define RTL818X_TX_CONF_R8180_F (3 << 25)
+#define RTL818X_TX_CONF_R8185_ABC (4 << 25)
+#define RTL818X_TX_CONF_R8185_D (5 << 25)
+#define RTL818X_TX_CONF_HWVER_MASK (7 << 25)
+#define RTL818X_TX_CONF_CW_MIN (1 << 31)
+ __le32 RX_CONF;
+#define RTL818X_RX_CONF_MONITOR (1 << 0)
+#define RTL818X_RX_CONF_NICMAC (1 << 1)
+#define RTL818X_RX_CONF_MULTICAST (1 << 2)
+#define RTL818X_RX_CONF_BROADCAST (1 << 3)
+#define RTL818X_RX_CONF_DATA (1 << 18)
+#define RTL818X_RX_CONF_CTRL (1 << 19)
+#define RTL818X_RX_CONF_MGMT (1 << 20)
+#define RTL818X_RX_CONF_BSSID (1 << 23)
+#define RTL818X_RX_CONF_RX_AUTORESETPHY (1 << 28)
+#define RTL818X_RX_CONF_ONLYERLPKT (1 << 31)
+ __le32 INT_TIMEOUT;
+ __le32 TBDA;
+ u8 EEPROM_CMD;
+#define RTL818X_EEPROM_CMD_READ (1 << 0)
+#define RTL818X_EEPROM_CMD_WRITE (1 << 1)
+#define RTL818X_EEPROM_CMD_CK (1 << 2)
+#define RTL818X_EEPROM_CMD_CS (1 << 3)
+#define RTL818X_EEPROM_CMD_NORMAL (0 << 6)
+#define RTL818X_EEPROM_CMD_LOAD (1 << 6)
+#define RTL818X_EEPROM_CMD_PROGRAM (2 << 6)
+#define RTL818X_EEPROM_CMD_CONFIG (3 << 6)
+ u8 CONFIG0;
+ u8 CONFIG1;
+ u8 CONFIG2;
+ __le32 ANAPARAM;
+ u8 MSR;
+#define RTL818X_MSR_NO_LINK (0 << 2)
+#define RTL818X_MSR_ADHOC (1 << 2)
+#define RTL818X_MSR_INFRA (2 << 2)
+ u8 CONFIG3;
+#define RTL818X_CONFIG3_ANAPARAM_WRITE (1 << 6)
+ u8 CONFIG4;
+#define RTL818X_CONFIG4_POWEROFF (1 << 6)
+#define RTL818X_CONFIG4_VCOOFF (1 << 7)
+ u8 TESTR;
+ u8 reserved_9[2];
+ __le16 PGSELECT;
+ __le32 ANAPARAM2;
+ u8 reserved_10[12];
+ __le16 BEACON_INTERVAL;
+ __le16 ATIM_WND;
+ __le16 BEACON_INTERVAL_TIME;
+ __le16 ATIMTR_INTERVAL;
+ u8 reserved_11[4];
+ u8 PHY[4];
+ __le16 RFPinsOutput;
+ __le16 RFPinsEnable;
+ __le16 RFPinsSelect;
+ __le16 RFPinsInput;
+ __le32 RF_PARA;
+ __le32 RF_TIMING;
+ u8 GP_ENABLE;
+ u8 GPIO;
+ u8 reserved_12[10];
+ u8 TX_AGC_CTL;
+#define RTL818X_TX_AGC_CTL_PERPACKET_GAIN_SHIFT (1 << 0)
+#define RTL818X_TX_AGC_CTL_PERPACKET_ANTSEL_SHIFT (1 << 1)
+#define RTL818X_TX_AGC_CTL_FEEDBACK_ANT (1 << 2)
+ u8 TX_GAIN_CCK;
+ u8 TX_GAIN_OFDM;
+ u8 TX_ANTENNA;
+ u8 reserved_13[16];
+ u8 WPA_CONF;
+ u8 reserved_14[3];
+ u8 SIFS;
+ u8 DIFS;
+ u8 SLOT;
+ u8 reserved_15[5];
+ u8 CW_CONF;
+#define RTL818X_CW_CONF_PERPACKET_CW_SHIFT (1 << 0)
+#define RTL818X_CW_CONF_PERPACKET_RETRY_SHIFT (1 << 1)
+ u8 CW_VAL;
+ u8 RATE_FALLBACK;
+ u8 reserved_16[25];
+ u8 CONFIG5;
+ u8 TX_DMA_POLLING;
+ u8 reserved_17[2];
+ __le16 CWR;
+ u8 RETRY_CTR;
+ u8 reserved_18[5];
+ __le32 RDSAR;
+ u8 reserved_19[18];
+ u16 TALLY_CNT;
+ u8 TALLY_SEL;
+} __attribute__((packed));
+
+static const struct ieee80211_rate rtl818x_rates[] = {
+ { .rate = 10,
+ .val = 0,
+ .flags = IEEE80211_RATE_CCK },
+ { .rate = 20,
+ .val = 1,
+ .flags = IEEE80211_RATE_CCK },
+ { .rate = 55,
+ .val = 2,
+ .flags = IEEE80211_RATE_CCK },
+ { .rate = 110,
+ .val = 3,
+ .flags = IEEE80211_RATE_CCK },
+ { .rate = 60,
+ .val = 4,
+ .flags = IEEE80211_RATE_OFDM },
+ { .rate = 90,
+ .val = 5,
+ .flags = IEEE80211_RATE_OFDM },
+ { .rate = 120,
+ .val = 6,
+ .flags = IEEE80211_RATE_OFDM },
+ { .rate = 180,
+ .val = 7,
+ .flags = IEEE80211_RATE_OFDM },
+ { .rate = 240,
+ .val = 8,
+ .flags = IEEE80211_RATE_OFDM },
+ { .rate = 360,
+ .val = 9,
+ .flags = IEEE80211_RATE_OFDM },
+ { .rate = 480,
+ .val = 10,
+ .flags = IEEE80211_RATE_OFDM },
+ { .rate = 540,
+ .val = 11,
+ .flags = IEEE80211_RATE_OFDM },
+};
+
+static const struct ieee80211_channel rtl818x_channels[] = {
+ { .chan = 1,
+ .freq = 2412},
+ { .chan = 2,
+ .freq = 2417},
+ { .chan = 3,
+ .freq = 2422},
+ { .chan = 4,
+ .freq = 2427},
+ { .chan = 5,
+ .freq = 2432},
+ { .chan = 6,
+ .freq = 2437},
+ { .chan = 7,
+ .freq = 2442},
+ { .chan = 8,
+ .freq = 2447},
+ { .chan = 9,
+ .freq = 2452},
+ { .chan = 10,
+ .freq = 2457},
+ { .chan = 11,
+ .freq = 2462},
+ { .chan = 12,
+ .freq = 2467},
+ { .chan = 13,
+ .freq = 2472},
+ { .chan = 14,
+ .freq = 2484}
+};
+
+#endif /* RTL818X_H */
diff --git a/drivers/net/wireless/zd1211rw/Makefile b/drivers/net/wireless/zd1211rw/Makefile
index 6603ad5be63d..4d505903352c 100644
--- a/drivers/net/wireless/zd1211rw/Makefile
+++ b/drivers/net/wireless/zd1211rw/Makefile
@@ -3,7 +3,7 @@ obj-$(CONFIG_ZD1211RW) += zd1211rw.o
zd1211rw-objs := zd_chip.o zd_ieee80211.o \
zd_mac.o zd_netdev.o \
zd_rf_al2230.o zd_rf_rf2959.o \
- zd_rf_al7230b.o \
+ zd_rf_al7230b.o zd_rf_uw2453.o \
zd_rf.o zd_usb.o zd_util.o
ifeq ($(CONFIG_ZD1211RW_DEBUG),y)
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c
index 95b4a2a26707..5b624bfc01a6 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.c
+++ b/drivers/net/wireless/zd1211rw/zd_chip.c
@@ -1253,6 +1253,9 @@ static int update_channel_integration_and_calibration(struct zd_chip *chip,
{
int r;
+ if (!zd_rf_should_update_pwr_int(&chip->rf))
+ return 0;
+
r = update_pwr_int(chip, channel);
if (r)
return r;
@@ -1283,7 +1286,7 @@ static int patch_cck_gain(struct zd_chip *chip)
int r;
u32 value;
- if (!chip->patch_cck_gain)
+ if (!chip->patch_cck_gain || !zd_rf_should_patch_cck_gain(&chip->rf))
return 0;
ZD_ASSERT(mutex_is_locked(&chip->mutex));
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.h b/drivers/net/wireless/zd1211rw/zd_chip.h
index ce0a5f6da0d2..79d0288c193a 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.h
+++ b/drivers/net/wireless/zd1211rw/zd_chip.h
@@ -608,6 +608,9 @@ enum {
#define CR_ZD1211B_TXOP CTL_REG(0x0b20)
#define CR_ZD1211B_RETRY_MAX CTL_REG(0x0b28)
+/* Used to detect PLL lock */
+#define UW2453_INTR_REG ((zd_addr_t)0x85c1)
+
#define CWIN_SIZE 0x007f043f
diff --git a/drivers/net/wireless/zd1211rw/zd_rf.c b/drivers/net/wireless/zd1211rw/zd_rf.c
index 549c23bcd6cc..7407409b60b1 100644
--- a/drivers/net/wireless/zd1211rw/zd_rf.c
+++ b/drivers/net/wireless/zd1211rw/zd_rf.c
@@ -52,34 +52,38 @@ const char *zd_rf_name(u8 type)
void zd_rf_init(struct zd_rf *rf)
{
memset(rf, 0, sizeof(*rf));
+
+ /* default to update channel integration, as almost all RF's do want
+ * this */
+ rf->update_channel_int = 1;
}
void zd_rf_clear(struct zd_rf *rf)
{
+ if (rf->clear)
+ rf->clear(rf);
ZD_MEMCLEAR(rf, sizeof(*rf));
}
int zd_rf_init_hw(struct zd_rf *rf, u8 type)
{
- int r, t;
+ int r = 0;
+ int t;
struct zd_chip *chip = zd_rf_to_chip(rf);
ZD_ASSERT(mutex_is_locked(&chip->mutex));
switch (type) {
case RF2959_RF:
r = zd_rf_init_rf2959(rf);
- if (r)
- return r;
break;
case AL2230_RF:
r = zd_rf_init_al2230(rf);
- if (r)
- return r;
break;
case AL7230B_RF:
r = zd_rf_init_al7230b(rf);
- if (r)
- return r;
+ break;
+ case UW2453_RF:
+ r = zd_rf_init_uw2453(rf);
break;
default:
dev_err(zd_chip_dev(chip),
@@ -88,6 +92,9 @@ int zd_rf_init_hw(struct zd_rf *rf, u8 type)
return -ENODEV;
}
+ if (r)
+ return r;
+
rf->type = type;
r = zd_chip_lock_phy_regs(chip);
diff --git a/drivers/net/wireless/zd1211rw/zd_rf.h b/drivers/net/wireless/zd1211rw/zd_rf.h
index aa9cc105ce60..c6dfd8227f6e 100644
--- a/drivers/net/wireless/zd1211rw/zd_rf.h
+++ b/drivers/net/wireless/zd1211rw/zd_rf.h
@@ -48,12 +48,26 @@ struct zd_rf {
u8 channel;
+ /* whether channel integration and calibration should be updated
+ * defaults to 1 (yes) */
+ u8 update_channel_int:1;
+
+ /* whether CR47 should be patched from the EEPROM, if the appropriate
+ * flag is set in the POD. The vendor driver suggests that this should
+ * be done for all RF's, but a bug in their code prevents but their
+ * HW_OverWritePhyRegFromE2P() routine from ever taking effect. */
+ u8 patch_cck_gain:1;
+
+ /* private RF driver data */
+ void *priv;
+
/* RF-specific functions */
int (*init_hw)(struct zd_rf *rf);
int (*set_channel)(struct zd_rf *rf, u8 channel);
int (*switch_radio_on)(struct zd_rf *rf);
int (*switch_radio_off)(struct zd_rf *rf);
int (*patch_6m_band_edge)(struct zd_rf *rf, u8 channel);
+ void (*clear)(struct zd_rf *rf);
};
const char *zd_rf_name(u8 type);
@@ -71,10 +85,24 @@ int zd_switch_radio_off(struct zd_rf *rf);
int zd_rf_patch_6m_band_edge(struct zd_rf *rf, u8 channel);
int zd_rf_generic_patch_6m(struct zd_rf *rf, u8 channel);
+static inline int zd_rf_should_update_pwr_int(struct zd_rf *rf)
+{
+ return rf->update_channel_int;
+}
+
+static inline int zd_rf_should_patch_cck_gain(struct zd_rf *rf)
+{
+ return rf->patch_cck_gain;
+}
+
+int zd_rf_patch_6m_band_edge(struct zd_rf *rf, u8 channel);
+int zd_rf_generic_patch_6m(struct zd_rf *rf, u8 channel);
+
/* Functions for individual RF chips */
int zd_rf_init_rf2959(struct zd_rf *rf);
int zd_rf_init_al2230(struct zd_rf *rf);
int zd_rf_init_al7230b(struct zd_rf *rf);
+int zd_rf_init_uw2453(struct zd_rf *rf);
#endif /* _ZD_RF_H */
diff --git a/drivers/net/wireless/zd1211rw/zd_rf_al2230.c b/drivers/net/wireless/zd1211rw/zd_rf_al2230.c
index 511392acfedf..e7a4ecf7b6e2 100644
--- a/drivers/net/wireless/zd1211rw/zd_rf_al2230.c
+++ b/drivers/net/wireless/zd1211rw/zd_rf_al2230.c
@@ -432,5 +432,6 @@ int zd_rf_init_al2230(struct zd_rf *rf)
rf->switch_radio_on = zd1211_al2230_switch_radio_on;
}
rf->patch_6m_band_edge = zd_rf_generic_patch_6m;
+ rf->patch_cck_gain = 1;
return 0;
}
diff --git a/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c b/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c
index 5e5e9ddc6a74..f4e8b6ada854 100644
--- a/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c
+++ b/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c
@@ -483,6 +483,7 @@ int zd_rf_init_al7230b(struct zd_rf *rf)
rf->switch_radio_on = zd1211_al7230b_switch_radio_on;
rf->set_channel = zd1211_al7230b_set_channel;
rf->patch_6m_band_edge = zd_rf_generic_patch_6m;
+ rf->patch_cck_gain = 1;
}
rf->switch_radio_off = al7230b_switch_radio_off;
diff --git a/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c b/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c
new file mode 100644
index 000000000000..414e40d571ab
--- /dev/null
+++ b/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c
@@ -0,0 +1,534 @@
+/* zd_rf_uw2453.c: Functions for the UW2453 RF controller
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/kernel.h>
+
+#include "zd_rf.h"
+#include "zd_usb.h"
+#include "zd_chip.h"
+
+/* This RF programming code is based upon the code found in v2.16.0.0 of the
+ * ZyDAS vendor driver. Unlike other RF's, Ubec publish full technical specs
+ * for this RF on their website, so we're able to understand more than
+ * usual as to what is going on. Thumbs up for Ubec for doing that. */
+
+/* The 3-wire serial interface provides access to 8 write-only registers.
+ * The data format is a 4 bit register address followed by a 20 bit value. */
+#define UW2453_REGWRITE(reg, val) ((((reg) & 0xf) << 20) | ((val) & 0xfffff))
+
+/* For channel tuning, we have to configure registers 1 (synthesizer), 2 (synth
+ * fractional divide ratio) and 3 (VCO config).
+ *
+ * We configure the RF to produce an interrupt when the PLL is locked onto
+ * the configured frequency. During initialization, we run through a variety
+ * of different VCO configurations on channel 1 until we detect a PLL lock.
+ * When this happens, we remember which VCO configuration produced the lock
+ * and use it later. Actually, we use the configuration *after* the one that
+ * produced the lock, which seems odd, but it works.
+ *
+ * If we do not see a PLL lock on any standard VCO config, we fall back on an
+ * autocal configuration, which has a fixed (as opposed to per-channel) VCO
+ * config and different synth values from the standard set (divide ratio
+ * is still shared with the standard set). */
+
+/* The per-channel synth values for all standard VCO configurations. These get
+ * written to register 1. */
+static const u8 uw2453_std_synth[] = {
+ RF_CHANNEL( 1) = 0x47,
+ RF_CHANNEL( 2) = 0x47,
+ RF_CHANNEL( 3) = 0x67,
+ RF_CHANNEL( 4) = 0x67,
+ RF_CHANNEL( 5) = 0x67,
+ RF_CHANNEL( 6) = 0x67,
+ RF_CHANNEL( 7) = 0x57,
+ RF_CHANNEL( 8) = 0x57,
+ RF_CHANNEL( 9) = 0x57,
+ RF_CHANNEL(10) = 0x57,
+ RF_CHANNEL(11) = 0x77,
+ RF_CHANNEL(12) = 0x77,
+ RF_CHANNEL(13) = 0x77,
+ RF_CHANNEL(14) = 0x4f,
+};
+
+/* This table stores the synthesizer fractional divide ratio for *all* VCO
+ * configurations (both standard and autocal). These get written to register 2.
+ */
+static const u16 uw2453_synth_divide[] = {
+ RF_CHANNEL( 1) = 0x999,
+ RF_CHANNEL( 2) = 0x99b,
+ RF_CHANNEL( 3) = 0x998,
+ RF_CHANNEL( 4) = 0x99a,
+ RF_CHANNEL( 5) = 0x999,
+ RF_CHANNEL( 6) = 0x99b,
+ RF_CHANNEL( 7) = 0x998,
+ RF_CHANNEL( 8) = 0x99a,
+ RF_CHANNEL( 9) = 0x999,
+ RF_CHANNEL(10) = 0x99b,
+ RF_CHANNEL(11) = 0x998,
+ RF_CHANNEL(12) = 0x99a,
+ RF_CHANNEL(13) = 0x999,
+ RF_CHANNEL(14) = 0xccc,
+};
+
+/* Here is the data for all the standard VCO configurations. We shrink our
+ * table a little by observing that both channels in a consecutive pair share
+ * the same value. We also observe that the high 4 bits ([0:3] in the specs)
+ * are all 'Reserved' and are always set to 0x4 - we chop them off in the data
+ * below. */
+#define CHAN_TO_PAIRIDX(a) ((a - 1) / 2)
+#define RF_CHANPAIR(a,b) [CHAN_TO_PAIRIDX(a)]
+static const u16 uw2453_std_vco_cfg[][7] = {
+ { /* table 1 */
+ RF_CHANPAIR( 1, 2) = 0x664d,
+ RF_CHANPAIR( 3, 4) = 0x604d,
+ RF_CHANPAIR( 5, 6) = 0x6675,
+ RF_CHANPAIR( 7, 8) = 0x6475,
+ RF_CHANPAIR( 9, 10) = 0x6655,
+ RF_CHANPAIR(11, 12) = 0x6455,
+ RF_CHANPAIR(13, 14) = 0x6665,
+ },
+ { /* table 2 */
+ RF_CHANPAIR( 1, 2) = 0x666d,
+ RF_CHANPAIR( 3, 4) = 0x606d,
+ RF_CHANPAIR( 5, 6) = 0x664d,
+ RF_CHANPAIR( 7, 8) = 0x644d,
+ RF_CHANPAIR( 9, 10) = 0x6675,
+ RF_CHANPAIR(11, 12) = 0x6475,
+ RF_CHANPAIR(13, 14) = 0x6655,
+ },
+ { /* table 3 */
+ RF_CHANPAIR( 1, 2) = 0x665d,
+ RF_CHANPAIR( 3, 4) = 0x605d,
+ RF_CHANPAIR( 5, 6) = 0x666d,
+ RF_CHANPAIR( 7, 8) = 0x646d,
+ RF_CHANPAIR( 9, 10) = 0x664d,
+ RF_CHANPAIR(11, 12) = 0x644d,
+ RF_CHANPAIR(13, 14) = 0x6675,
+ },
+ { /* table 4 */
+ RF_CHANPAIR( 1, 2) = 0x667d,
+ RF_CHANPAIR( 3, 4) = 0x607d,
+ RF_CHANPAIR( 5, 6) = 0x665d,
+ RF_CHANPAIR( 7, 8) = 0x645d,
+ RF_CHANPAIR( 9, 10) = 0x666d,
+ RF_CHANPAIR(11, 12) = 0x646d,
+ RF_CHANPAIR(13, 14) = 0x664d,
+ },
+ { /* table 5 */
+ RF_CHANPAIR( 1, 2) = 0x6643,
+ RF_CHANPAIR( 3, 4) = 0x6043,
+ RF_CHANPAIR( 5, 6) = 0x667d,
+ RF_CHANPAIR( 7, 8) = 0x647d,
+ RF_CHANPAIR( 9, 10) = 0x665d,
+ RF_CHANPAIR(11, 12) = 0x645d,
+ RF_CHANPAIR(13, 14) = 0x666d,
+ },
+ { /* table 6 */
+ RF_CHANPAIR( 1, 2) = 0x6663,
+ RF_CHANPAIR( 3, 4) = 0x6063,
+ RF_CHANPAIR( 5, 6) = 0x6643,
+ RF_CHANPAIR( 7, 8) = 0x6443,
+ RF_CHANPAIR( 9, 10) = 0x667d,
+ RF_CHANPAIR(11, 12) = 0x647d,
+ RF_CHANPAIR(13, 14) = 0x665d,
+ },
+ { /* table 7 */
+ RF_CHANPAIR( 1, 2) = 0x6653,
+ RF_CHANPAIR( 3, 4) = 0x6053,
+ RF_CHANPAIR( 5, 6) = 0x6663,
+ RF_CHANPAIR( 7, 8) = 0x6463,
+ RF_CHANPAIR( 9, 10) = 0x6643,
+ RF_CHANPAIR(11, 12) = 0x6443,
+ RF_CHANPAIR(13, 14) = 0x667d,
+ },
+ { /* table 8 */
+ RF_CHANPAIR( 1, 2) = 0x6673,
+ RF_CHANPAIR( 3, 4) = 0x6073,
+ RF_CHANPAIR( 5, 6) = 0x6653,
+ RF_CHANPAIR( 7, 8) = 0x6453,
+ RF_CHANPAIR( 9, 10) = 0x6663,
+ RF_CHANPAIR(11, 12) = 0x6463,
+ RF_CHANPAIR(13, 14) = 0x6643,
+ },
+ { /* table 9 */
+ RF_CHANPAIR( 1, 2) = 0x664b,
+ RF_CHANPAIR( 3, 4) = 0x604b,
+ RF_CHANPAIR( 5, 6) = 0x6673,
+ RF_CHANPAIR( 7, 8) = 0x6473,
+ RF_CHANPAIR( 9, 10) = 0x6653,
+ RF_CHANPAIR(11, 12) = 0x6453,
+ RF_CHANPAIR(13, 14) = 0x6663,
+ },
+ { /* table 10 */
+ RF_CHANPAIR( 1, 2) = 0x666b,
+ RF_CHANPAIR( 3, 4) = 0x606b,
+ RF_CHANPAIR( 5, 6) = 0x664b,
+ RF_CHANPAIR( 7, 8) = 0x644b,
+ RF_CHANPAIR( 9, 10) = 0x6673,
+ RF_CHANPAIR(11, 12) = 0x6473,
+ RF_CHANPAIR(13, 14) = 0x6653,
+ },
+ { /* table 11 */
+ RF_CHANPAIR( 1, 2) = 0x665b,
+ RF_CHANPAIR( 3, 4) = 0x605b,
+ RF_CHANPAIR( 5, 6) = 0x666b,
+ RF_CHANPAIR( 7, 8) = 0x646b,
+ RF_CHANPAIR( 9, 10) = 0x664b,
+ RF_CHANPAIR(11, 12) = 0x644b,
+ RF_CHANPAIR(13, 14) = 0x6673,
+ },
+
+};
+
+/* The per-channel synth values for autocal. These get written to register 1. */
+static const u16 uw2453_autocal_synth[] = {
+ RF_CHANNEL( 1) = 0x6847,
+ RF_CHANNEL( 2) = 0x6847,
+ RF_CHANNEL( 3) = 0x6867,
+ RF_CHANNEL( 4) = 0x6867,
+ RF_CHANNEL( 5) = 0x6867,
+ RF_CHANNEL( 6) = 0x6867,
+ RF_CHANNEL( 7) = 0x6857,
+ RF_CHANNEL( 8) = 0x6857,
+ RF_CHANNEL( 9) = 0x6857,
+ RF_CHANNEL(10) = 0x6857,
+ RF_CHANNEL(11) = 0x6877,
+ RF_CHANNEL(12) = 0x6877,
+ RF_CHANNEL(13) = 0x6877,
+ RF_CHANNEL(14) = 0x684f,
+};
+
+/* The VCO configuration for autocal (all channels) */
+static const u16 UW2453_AUTOCAL_VCO_CFG = 0x6662;
+
+/* TX gain settings. The array index corresponds to the TX power integration
+ * values found in the EEPROM. The values get written to register 7. */
+static u32 uw2453_txgain[] = {
+ [0x00] = 0x0e313,
+ [0x01] = 0x0fb13,
+ [0x02] = 0x0e093,
+ [0x03] = 0x0f893,
+ [0x04] = 0x0ea93,
+ [0x05] = 0x1f093,
+ [0x06] = 0x1f493,
+ [0x07] = 0x1f693,
+ [0x08] = 0x1f393,
+ [0x09] = 0x1f35b,
+ [0x0a] = 0x1e6db,
+ [0x0b] = 0x1ff3f,
+ [0x0c] = 0x1ffff,
+ [0x0d] = 0x361d7,
+ [0x0e] = 0x37fbf,
+ [0x0f] = 0x3ff8b,
+ [0x10] = 0x3ff33,
+ [0x11] = 0x3fb3f,
+ [0x12] = 0x3ffff,
+};
+
+/* RF-specific structure */
+struct uw2453_priv {
+ /* index into synth/VCO config tables where PLL lock was found
+ * -1 means autocal */
+ int config;
+};
+
+#define UW2453_PRIV(rf) ((struct uw2453_priv *) (rf)->priv)
+
+static int uw2453_synth_set_channel(struct zd_chip *chip, int channel,
+ bool autocal)
+{
+ int r;
+ int idx = channel - 1;
+ u32 val;
+
+ if (autocal)
+ val = UW2453_REGWRITE(1, uw2453_autocal_synth[idx]);
+ else
+ val = UW2453_REGWRITE(1, uw2453_std_synth[idx]);
+
+ r = zd_rfwrite_locked(chip, val, RF_RV_BITS);
+ if (r)
+ return r;
+
+ return zd_rfwrite_locked(chip,
+ UW2453_REGWRITE(2, uw2453_synth_divide[idx]), RF_RV_BITS);
+}
+
+static int uw2453_write_vco_cfg(struct zd_chip *chip, u16 value)
+{
+ /* vendor driver always sets these upper bits even though the specs say
+ * they are reserved */
+ u32 val = 0x40000 | value;
+ return zd_rfwrite_locked(chip, UW2453_REGWRITE(3, val), RF_RV_BITS);
+}
+
+static int uw2453_init_mode(struct zd_chip *chip)
+{
+ static const u32 rv[] = {
+ UW2453_REGWRITE(0, 0x25f98), /* enter IDLE mode */
+ UW2453_REGWRITE(0, 0x25f9a), /* enter CAL_VCO mode */
+ UW2453_REGWRITE(0, 0x25f94), /* enter RX/TX mode */
+ UW2453_REGWRITE(0, 0x27fd4), /* power down RSSI circuit */
+ };
+
+ return zd_rfwritev_locked(chip, rv, ARRAY_SIZE(rv), RF_RV_BITS);
+}
+
+static int uw2453_set_tx_gain_level(struct zd_chip *chip, int channel)
+{
+ u8 int_value = chip->pwr_int_values[channel - 1];
+
+ if (int_value >= ARRAY_SIZE(uw2453_txgain)) {
+ dev_dbg_f(zd_chip_dev(chip), "can't configure TX gain for "
+ "int value %x on channel %d\n", int_value, channel);
+ return 0;
+ }
+
+ return zd_rfwrite_locked(chip,
+ UW2453_REGWRITE(7, uw2453_txgain[int_value]), RF_RV_BITS);
+}
+
+static int uw2453_init_hw(struct zd_rf *rf)
+{
+ int i, r;
+ int found_config = -1;
+ u16 intr_status;
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+
+ static const struct zd_ioreq16 ioreqs[] = {
+ { CR10, 0x89 }, { CR15, 0x20 },
+ { CR17, 0x28 }, /* 6112 no change */
+ { CR23, 0x38 }, { CR24, 0x20 }, { CR26, 0x93 },
+ { CR27, 0x15 }, { CR28, 0x3e }, { CR29, 0x00 },
+ { CR33, 0x28 }, { CR34, 0x30 },
+ { CR35, 0x43 }, /* 6112 3e->43 */
+ { CR41, 0x24 }, { CR44, 0x32 },
+ { CR46, 0x92 }, /* 6112 96->92 */
+ { CR47, 0x1e },
+ { CR48, 0x04 }, /* 5602 Roger */
+ { CR49, 0xfa }, { CR79, 0x58 }, { CR80, 0x30 },
+ { CR81, 0x30 }, { CR87, 0x0a }, { CR89, 0x04 },
+ { CR91, 0x00 }, { CR92, 0x0a }, { CR98, 0x8d },
+ { CR99, 0x28 }, { CR100, 0x02 },
+ { CR101, 0x09 }, /* 6112 13->1f 6220 1f->13 6407 13->9 */
+ { CR102, 0x27 },
+ { CR106, 0x1c }, /* 5d07 5112 1f->1c 6220 1c->1f 6221 1f->1c */
+ { CR107, 0x1c }, /* 6220 1c->1a 5221 1a->1c */
+ { CR109, 0x13 },
+ { CR110, 0x1f }, /* 6112 13->1f 6221 1f->13 6407 13->0x09 */
+ { CR111, 0x13 }, { CR112, 0x1f }, { CR113, 0x27 },
+ { CR114, 0x23 }, /* 6221 27->23 */
+ { CR115, 0x24 }, /* 6112 24->1c 6220 1c->24 */
+ { CR116, 0x24 }, /* 6220 1c->24 */
+ { CR117, 0xfa }, /* 6112 fa->f8 6220 f8->f4 6220 f4->fa */
+ { CR118, 0xf0 }, /* 5d07 6112 f0->f2 6220 f2->f0 */
+ { CR119, 0x1a }, /* 6112 1a->10 6220 10->14 6220 14->1a */
+ { CR120, 0x4f },
+ { CR121, 0x1f }, /* 6220 4f->1f */
+ { CR122, 0xf0 }, { CR123, 0x57 }, { CR125, 0xad },
+ { CR126, 0x6c }, { CR127, 0x03 },
+ { CR128, 0x14 }, /* 6302 12->11 */
+ { CR129, 0x12 }, /* 6301 10->0f */
+ { CR130, 0x10 }, { CR137, 0x50 }, { CR138, 0xa8 },
+ { CR144, 0xac }, { CR146, 0x20 }, { CR252, 0xff },
+ { CR253, 0xff },
+ };
+
+ static const u32 rv[] = {
+ UW2453_REGWRITE(4, 0x2b), /* configure reciever gain */
+ UW2453_REGWRITE(5, 0x19e4f), /* configure transmitter gain */
+ UW2453_REGWRITE(6, 0xf81ad), /* enable RX/TX filter tuning */
+ UW2453_REGWRITE(7, 0x3fffe), /* disable TX gain in test mode */
+
+ /* enter CAL_FIL mode, TX gain set by registers, RX gain set by pins,
+ * RSSI circuit powered down, reduced RSSI range */
+ UW2453_REGWRITE(0, 0x25f9c), /* 5d01 cal_fil */
+
+ /* synthesizer configuration for channel 1 */
+ UW2453_REGWRITE(1, 0x47),
+ UW2453_REGWRITE(2, 0x999),
+
+ /* disable manual VCO band selection */
+ UW2453_REGWRITE(3, 0x7602),
+
+ /* enable manual VCO band selection, configure current level */
+ UW2453_REGWRITE(3, 0x46063),
+ };
+
+ r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+ if (r)
+ return r;
+
+ r = zd_rfwritev_locked(chip, rv, ARRAY_SIZE(rv), RF_RV_BITS);
+ if (r)
+ return r;
+
+ r = uw2453_init_mode(chip);
+ if (r)
+ return r;
+
+ /* Try all standard VCO configuration settings on channel 1 */
+ for (i = 0; i < ARRAY_SIZE(uw2453_std_vco_cfg) - 1; i++) {
+ /* Configure synthesizer for channel 1 */
+ r = uw2453_synth_set_channel(chip, 1, false);
+ if (r)
+ return r;
+
+ /* Write VCO config */
+ r = uw2453_write_vco_cfg(chip, uw2453_std_vco_cfg[i][0]);
+ if (r)
+ return r;
+
+ /* ack interrupt event */
+ r = zd_iowrite16_locked(chip, 0x0f, UW2453_INTR_REG);
+ if (r)
+ return r;
+
+ /* check interrupt status */
+ r = zd_ioread16_locked(chip, &intr_status, UW2453_INTR_REG);
+ if (r)
+ return r;
+
+ if (!intr_status & 0xf) {
+ dev_dbg_f(zd_chip_dev(chip),
+ "PLL locked on configuration %d\n", i);
+ found_config = i;
+ break;
+ }
+ }
+
+ if (found_config == -1) {
+ /* autocal */
+ dev_dbg_f(zd_chip_dev(chip),
+ "PLL did not lock, using autocal\n");
+
+ r = uw2453_synth_set_channel(chip, 1, true);
+ if (r)
+ return r;
+
+ r = uw2453_write_vco_cfg(chip, UW2453_AUTOCAL_VCO_CFG);
+ if (r)
+ return r;
+ }
+
+ /* To match the vendor driver behaviour, we use the configuration after
+ * the one that produced a lock. */
+ UW2453_PRIV(rf)->config = found_config + 1;
+
+ return zd_iowrite16_locked(chip, 0x06, CR203);
+}
+
+static int uw2453_set_channel(struct zd_rf *rf, u8 channel)
+{
+ int r;
+ u16 vco_cfg;
+ int config = UW2453_PRIV(rf)->config;
+ bool autocal = (config == -1);
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+
+ static const struct zd_ioreq16 ioreqs[] = {
+ { CR80, 0x30 }, { CR81, 0x30 }, { CR79, 0x58 },
+ { CR12, 0xf0 }, { CR77, 0x1b }, { CR78, 0x58 },
+ };
+
+ r = uw2453_synth_set_channel(chip, channel, autocal);
+ if (r)
+ return r;
+
+ if (autocal)
+ vco_cfg = UW2453_AUTOCAL_VCO_CFG;
+ else
+ vco_cfg = uw2453_std_vco_cfg[config][CHAN_TO_PAIRIDX(channel)];
+
+ r = uw2453_write_vco_cfg(chip, vco_cfg);
+ if (r)
+ return r;
+
+ r = uw2453_init_mode(chip);
+ if (r)
+ return r;
+
+ r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+ if (r)
+ return r;
+
+ r = uw2453_set_tx_gain_level(chip, channel);
+ if (r)
+ return r;
+
+ return zd_iowrite16_locked(chip, 0x06, CR203);
+}
+
+static int uw2453_switch_radio_on(struct zd_rf *rf)
+{
+ int r;
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+ struct zd_ioreq16 ioreqs[] = {
+ { CR11, 0x00 }, { CR251, 0x3f },
+ };
+
+ /* enter RXTX mode */
+ r = zd_rfwrite_locked(chip, UW2453_REGWRITE(0, 0x25f94), RF_RV_BITS);
+ if (r)
+ return r;
+
+ if (chip->is_zd1211b)
+ ioreqs[1].value = 0x7f;
+
+ return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+}
+
+static int uw2453_switch_radio_off(struct zd_rf *rf)
+{
+ int r;
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+ static const struct zd_ioreq16 ioreqs[] = {
+ { CR11, 0x04 }, { CR251, 0x2f },
+ };
+
+ /* enter IDLE mode */
+ /* FIXME: shouldn't we go to SLEEP? sent email to zydas */
+ r = zd_rfwrite_locked(chip, UW2453_REGWRITE(0, 0x25f90), RF_RV_BITS);
+ if (r)
+ return r;
+
+ return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+}
+
+static void uw2453_clear(struct zd_rf *rf)
+{
+ kfree(rf->priv);
+}
+
+int zd_rf_init_uw2453(struct zd_rf *rf)
+{
+ rf->init_hw = uw2453_init_hw;
+ rf->set_channel = uw2453_set_channel;
+ rf->switch_radio_on = uw2453_switch_radio_on;
+ rf->switch_radio_off = uw2453_switch_radio_off;
+ rf->patch_6m_band_edge = zd_rf_generic_patch_6m;
+ rf->clear = uw2453_clear;
+ /* we have our own TX integration code */
+ rf->update_channel_int = 0;
+
+ rf->priv = kmalloc(sizeof(struct uw2453_priv), GFP_KERNEL);
+ if (rf->priv == NULL)
+ return -ENOMEM;
+
+ return 0;
+}
+
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index 8459549d0cee..740a2194fdde 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -54,6 +54,7 @@ static struct usb_device_id usb_ids[] = {
{ USB_DEVICE(0x0586, 0x3401), .driver_info = DEVICE_ZD1211 },
{ USB_DEVICE(0x14ea, 0xab13), .driver_info = DEVICE_ZD1211 },
{ USB_DEVICE(0x13b1, 0x001e), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x0586, 0x3407), .driver_info = DEVICE_ZD1211 },
/* ZD1211B */
{ USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x157e, 0x300d), .driver_info = DEVICE_ZD1211B },
diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c
index 6b76babc7fbf..a0ea43598515 100644
--- a/drivers/serial/serial_cs.c
+++ b/drivers/serial/serial_cs.c
@@ -842,12 +842,16 @@ static struct pcmcia_device_id serial_ids[] = {
PCMCIA_PFC_DEVICE_PROD_ID12(1, "Linksys", "EtherFast 10&100 + 56K PC Card (PCMLM56)", 0x0733cc81, 0xb3765033),
PCMCIA_PFC_DEVICE_PROD_ID12(1, "LINKSYS", "PCMLM336", 0xf7cb0b07, 0x7a821b58),
PCMCIA_PFC_DEVICE_PROD_ID12(1, "MEGAHERTZ", "XJEM1144/CCEM1144", 0xf510db04, 0x52d21e1e),
+ PCMCIA_PFC_DEVICE_PROD_ID12(1, "MICRO RESEARCH", "COMBO-L/M-336", 0xb2ced065, 0x3ced0555),
+ PCMCIA_PFC_DEVICE_PROD_ID12(1, "NEC", "PK-UG-J001" ,0x18df0ba0 ,0x831b1064),
PCMCIA_PFC_DEVICE_PROD_ID12(1, "Ositech", "Trumpcard:Jack of Diamonds Modem+Ethernet", 0xc2f80cd, 0x656947b9),
PCMCIA_PFC_DEVICE_PROD_ID12(1, "Ositech", "Trumpcard:Jack of Hearts Modem+Ethernet", 0xc2f80cd, 0xdc9ba5ed),
PCMCIA_PFC_DEVICE_PROD_ID12(1, "PCMCIAs", "ComboCard", 0xdcfe12d3, 0xcd8906cc),
PCMCIA_PFC_DEVICE_PROD_ID12(1, "PCMCIAs", "LanModem", 0xdcfe12d3, 0xc67c648f),
PCMCIA_PFC_DEVICE_PROD_ID12(1, "TDK", "GlobalNetworker 3410/3412", 0x1eae9475, 0xd9a93bed),
PCMCIA_PFC_DEVICE_PROD_ID12(1, "Xircom", "CreditCard Ethernet+Modem II", 0x2e3ee845, 0xeca401bf),
+ PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0032, 0x0a05),
+ PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0032, 0x1101),
PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x0104, 0x0070),
PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x0101, 0x0562),
PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x0104, 0x0070),
diff --git a/include/linux/eeprom_93cx6.h b/include/linux/eeprom_93cx6.h
new file mode 100644
index 000000000000..d774b7778c91
--- /dev/null
+++ b/include/linux/eeprom_93cx6.h
@@ -0,0 +1,72 @@
+/*
+ Copyright (C) 2004 - 2006 rt2x00 SourceForge Project
+ <http://rt2x00.serialmonkey.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the
+ Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ Module: eeprom_93cx6
+ Abstract: EEPROM reader datastructures for 93cx6 chipsets.
+ Supported chipsets: 93c46 & 93c66.
+ */
+
+/*
+ * EEPROM operation defines.
+ */
+#define PCI_EEPROM_WIDTH_93C46 6
+#define PCI_EEPROM_WIDTH_93C66 8
+#define PCI_EEPROM_WIDTH_OPCODE 3
+#define PCI_EEPROM_WRITE_OPCODE 0x05
+#define PCI_EEPROM_READ_OPCODE 0x06
+#define PCI_EEPROM_EWDS_OPCODE 0x10
+#define PCI_EEPROM_EWEN_OPCODE 0x13
+
+/**
+ * struct eeprom_93cx6 - control structure for setting the commands
+ * for reading the eeprom data.
+ * @data: private pointer for the driver.
+ * @register_read(struct eeprom_93cx6 *eeprom): handler to
+ * read the eeprom register, this function should set all reg_* fields.
+ * @register_write(struct eeprom_93cx6 *eeprom): handler to
+ * write to the eeprom register by using all reg_* fields.
+ * @width: eeprom width, should be one of the PCI_EEPROM_WIDTH_* defines
+ * @reg_data_in: register field to indicate data input
+ * @reg_data_out: register field to indicate data output
+ * @reg_data_clock: register field to set the data clock
+ * @reg_chip_select: register field to set the chip select
+ *
+ * This structure is used for the communication between the driver
+ * and the eeprom_93cx6 handlers for reading the eeprom.
+ */
+struct eeprom_93cx6 {
+ void *data;
+
+ void (*register_read)(struct eeprom_93cx6 *eeprom);
+ void (*register_write)(struct eeprom_93cx6 *eeprom);
+
+ int width;
+
+ char reg_data_in;
+ char reg_data_out;
+ char reg_data_clock;
+ char reg_chip_select;
+};
+
+extern void eeprom_93cx6_read(struct eeprom_93cx6 *eeprom,
+ const u8 word, u16 *data);
+extern void eeprom_93cx6_multiread(struct eeprom_93cx6 *eeprom,
+ const u8 word, __le16 *data, const u16 words);
diff --git a/include/pcmcia/ciscode.h b/include/pcmcia/ciscode.h
index eae7e2e84497..ad6e278ba7f2 100644
--- a/include/pcmcia/ciscode.h
+++ b/include/pcmcia/ciscode.h
@@ -126,4 +126,6 @@
#define MANFID_POSSIO 0x030c
#define PRODID_POSSIO_GCC 0x0003
+#define MANFID_NEC 0x0010
+
#endif /* _LINUX_CISCODE_H */
diff --git a/net/ieee80211/softmac/ieee80211softmac_module.c b/net/ieee80211/softmac/ieee80211softmac_module.c
index c308756c2f9d..6398e6e67493 100644
--- a/net/ieee80211/softmac/ieee80211softmac_module.c
+++ b/net/ieee80211/softmac/ieee80211softmac_module.c
@@ -456,18 +456,13 @@ void
ieee80211softmac_add_network_locked(struct ieee80211softmac_device *mac,
struct ieee80211softmac_network *add_net)
{
- struct list_head *list_ptr;
- struct ieee80211softmac_network *softmac_net = NULL;
+ struct ieee80211softmac_network *softmac_net;
- list_for_each(list_ptr, &mac->network_list) {
- softmac_net = list_entry(list_ptr, struct ieee80211softmac_network, list);
+ list_for_each_entry(softmac_net, &mac->network_list, list) {
if(!memcmp(softmac_net->bssid, add_net->bssid, ETH_ALEN))
- break;
- else
- softmac_net = NULL;
+ return;
}
- if(softmac_net == NULL)
- list_add(&(add_net->list), &mac->network_list);
+ list_add(&(add_net->list), &mac->network_list);
}
/* Add a network to the list, with locking */
@@ -506,16 +501,13 @@ struct ieee80211softmac_network *
ieee80211softmac_get_network_by_bssid_locked(struct ieee80211softmac_device *mac,
u8 *bssid)
{
- struct list_head *list_ptr;
- struct ieee80211softmac_network *softmac_net = NULL;
- list_for_each(list_ptr, &mac->network_list) {
- softmac_net = list_entry(list_ptr, struct ieee80211softmac_network, list);
+ struct ieee80211softmac_network *softmac_net;
+
+ list_for_each_entry(softmac_net, &mac->network_list, list) {
if(!memcmp(softmac_net->bssid, bssid, ETH_ALEN))
- break;
- else
- softmac_net = NULL;
+ return softmac_net;
}
- return softmac_net;
+ return NULL;
}
/* Get a network from the list by BSSID with locking */
@@ -537,11 +529,9 @@ struct ieee80211softmac_network *
ieee80211softmac_get_network_by_essid_locked(struct ieee80211softmac_device *mac,
struct ieee80211softmac_essid *essid)
{
- struct list_head *list_ptr;
- struct ieee80211softmac_network *softmac_net = NULL;
+ struct ieee80211softmac_network *softmac_net;
- list_for_each(list_ptr, &mac->network_list) {
- softmac_net = list_entry(list_ptr, struct ieee80211softmac_network, list);
+ list_for_each_entry(softmac_net, &mac->network_list, list) {
if (softmac_net->essid.len == essid->len &&
!memcmp(softmac_net->essid.data, essid->data, essid->len))
return softmac_net;