* [PATCH 3/3] ipip: add module alias for tunl0 tunnel device
From: Stephen Hemminger @ 2010-11-29 19:47 UTC (permalink / raw)
To: David Miller; +Cc: netdev
In-Reply-To: <20101129194746.724222156@vyatta.com>
[-- Attachment #1: ipip-alias.patch --]
[-- Type: text/plain, Size: 536 bytes --]
If ipip is built as a module the 'ip tunnel add' command would fail because
the ipip module was not being autoloaded. Adding an alias for
the tunl0 device name cause dev_load() to autoload it when needed.
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
--- a/net/ipv4/ipip.c 2010-11-29 11:40:25.026277890 -0800
+++ b/net/ipv4/ipip.c 2010-11-29 11:41:05.790681069 -0800
@@ -913,3 +913,4 @@ static void __exit ipip_fini(void)
module_init(ipip_init);
module_exit(ipip_fini);
MODULE_LICENSE("GPL");
+MODULE_ALIAS("tunl0");
^ permalink raw reply
* [PATCH 2/3] gre: add module alias for gre0 tunnel device
From: Stephen Hemminger @ 2010-11-29 19:47 UTC (permalink / raw)
To: David Miller; +Cc: netdev
In-Reply-To: <20101129194746.724222156@vyatta.com>
[-- Attachment #1: gre-alias.patch --]
[-- Type: text/plain, Size: 549 bytes --]
If gre is built as a module the 'ip tunnel add' command would fail because
the ip_gre module was not being autoloaded. Adding an alias for
the gre0 device name cause dev_load() to autoload it when needed.
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
--- a/net/ipv4/ip_gre.c 2010-11-29 11:35:36.388589982 -0800
+++ b/net/ipv4/ip_gre.c 2010-11-29 11:35:46.675624021 -0800
@@ -1764,3 +1764,4 @@ module_exit(ipgre_fini);
MODULE_LICENSE("GPL");
MODULE_ALIAS_RTNL_LINK("gre");
MODULE_ALIAS_RTNL_LINK("gretap");
+MODULE_ALIAS("gre0");
^ permalink raw reply
* [PATCH 1/3] gre: minor cleanups
From: Stephen Hemminger @ 2010-11-29 19:47 UTC (permalink / raw)
To: David Miller; +Cc: netdev
In-Reply-To: <20101129194746.724222156@vyatta.com>
[-- Attachment #1: gre-fix-trivial.patch --]
[-- Type: text/plain, Size: 602 bytes --]
Use strcpy() rather the sprintf() for the case where name is getting
generated. Fix indentation.
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
--- a/net/ipv4/ip_gre.c 2010-11-28 11:28:48.684091117 -0800
+++ b/net/ipv4/ip_gre.c 2010-11-28 11:29:21.839822531 -0800
@@ -405,11 +405,11 @@ static struct ip_tunnel *ipgre_tunnel_lo
if (parms->name[0])
strlcpy(name, parms->name, IFNAMSIZ);
else
- sprintf(name, "gre%%d");
+ strcpy(name, "gre%d");
dev = alloc_netdev(sizeof(*t), name, ipgre_tunnel_setup);
if (!dev)
- return NULL;
+ return NULL;
dev_net_set(dev, net);
^ permalink raw reply
* [PATCH 0/3] Tunneling minor patches
From: Stephen Hemminger @ 2010-11-29 19:47 UTC (permalink / raw)
To: David Miller; +Cc: netdev
^ permalink raw reply
* Re: [PATCH 00/11] forcedeth: Convert to use netdev_<level> and neatening
From: David Miller @ 2010-11-29 19:51 UTC (permalink / raw)
To: joe; +Cc: netdev, bhutchings, szymon, mirqus, linux-kernel
In-Reply-To: <cover.1291051316.git.joe@perches.com>
From: Joe Perches <joe@perches.com>
Date: Mon, 29 Nov 2010 09:41:51 -0800
> Some mild restructuring and some generally neatening.
>
> The conversions of dprintk to netdev_dbg in patches 2 and 4 are
> deleted in patch 10 as these seem to have been used only
> during initial development and are not normally compiled-in.
>
> Patch 10 may be ignored if desired.
>
> Object size is reduced ~2Kb overall.
>
> $ size drivers/net/forcedeth.o.*
> text data bss dec hex filename
> 71739 336 17176 89251 15ca3 drivers/net/forcedeth.o.new
> 73416 240 17696 91352 164d8 drivers/net/forcedeth.o.old
These look fine, applied, thanks.
^ permalink raw reply
* Re: [net-next-2.6] XFRM: remove unused member in xfrm_encap_tmpl.
From: David Shwatrz @ 2010-11-29 20:09 UTC (permalink / raw)
To: Timo Teräs; +Cc: David S. Miller, netdev
In-Reply-To: <4CF3FE85.6040406@iki.fi>
Timo,
Thanks for your answer.
> Alternatively the other RFCs say that the checksum can be just
> recalculated. That's what the linux stack does: it throws the old
> checksum away (ignored on local receive and recalculated on send
> forward paths).
Sorry, something here seems to me still wrong; maybe I miss something.
We are talking about transport mode. Let's take TCP for example.
the packet is received by another peer. It is on port 4500 because of
NAT-T. Since it is ESP encrypted , it is it is decrypted. It reaches
the TCP layer. In TCP (as opposed to UDP), the checksum is mandatory.
But the checksum in that TCP header of the received
packet will not be correct, since the IP header of that packet is
**NOT** the original address ; the IP address was changed by the NAT.
The NAT cannot change the TCP checksum since it is encrypted. So
wouldn't we have a checksum error in the case of TCP ? It seems to me
that the purpose of NAT-OA was to pass the
original address, so that there will be no error in such a case.
But again, maybe I miss something, since I did not heard that
transport mode has any problems with NAT-T. Or maybe this was not
tested?
Rgs,
DS
2010/11/29 Timo Teräs <timo.teras@iki.fi>:
> On 11/29/2010 09:15 PM, David Shwatrz wrote:
>> But isn't something wrong here ?
>>
>> According to RFC 3948:
>> ...
>> 3.1.2. Transport Mode Decapsulation NAT Procedure
>>
>> When a transport mode has been used to transmit packets, contained
>> TCP or UDP headers will have incorrect checksums due to the change of
>> parts of the IP header during transit. This procedure defines how to
>> fix these checksums
>> ...
>> incrementally recompute the
>> TCP/UDP checksum:
>>
>> * Subtract the IP source address in the received packet from the
>> checksum.
>> * Add the real IP source address received via IKE to the
>> checksum (obtained from the NAT-OA)
>> ...
>>
>> So where do we pass the NAT-OA, received from IKE messages, to this
>> checksum recalculation process, which should be done in the kernel
>> (layer 4 TCP/UDP I suppose) ?
>>
>> Should'nt this process be done in the kernel ?
>>
>> Isn't there something missing here ?
>
> That's what the field was intended for. Also it's passed around by e.g.
> 'ip xfrm' command. The header change would break compilation of iproute2
> too.
>
> Alternatively the other RFCs say that the checksum can be just
> recalculated. That's what the linux stack does: it throws the old
> checksum away (ignored on local receive and recalculated on send /
> forward paths). The ESP/AH packets are usually also configured to
> contain a cryptographic hash, so the packet modifications are detected
> even before trying to check the TCP/UDP checksum (making the check
> redundant).
>
> There's also probably some legacy reasons why the nat-oa field is useful
> in kernel; and why the tcp/udp is not updated according the above
> mentioned scheme. I guess doing that might speed up forwarding from one
> tunnel to another where hardware checksum acceleration is not available;
> maybe no one just had the time to implement it.
>
> - Timo
>
^ permalink raw reply
* [PATCH net-next-2.6] can: add slcan driver for serial/USB-serial CAN adapters
From: Oliver Hartkopp @ 2010-11-29 20:30 UTC (permalink / raw)
To: David Miller; +Cc: SocketCAN Core Mailing List, Linux Netdev List, Alan Cox
This patch adds support for serial/USB-serial CAN adapters implementing the
LAWICEL ASCII protocol for CAN frame transport over serial lines.
The driver implements the SLCAN line discipline and is heavily based on the
slip.c driver. Therefore the code style remains similar to slip.c to be able
to apply changes of the SLIP driver to the SLCAN driver easily.
For more details see the slcan Kconfig entry.
Signed-off-by: Oliver Hartkopp <socketcan-fJ+pQTUTwRTk1uMJSBkQmQ@public.gmane.org>
---
diff -u -r -N a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig
--- a/drivers/net/can/Kconfig 2010-11-29 20:36:31.000000000 +0100
+++ b/drivers/net/can/Kconfig 2010-11-29 20:48:47.000000000 +0100
@@ -12,6 +12,27 @@
This driver can also be built as a module. If so, the module
will be called vcan.
+config CAN_SLCAN
+ tristate "Serial / USB serial CAN Adaptors (slcan)"
+ depends on CAN
+ default N
+ ---help---
+ CAN driver for several 'low cost' CAN interfaces that are attached
+ via serial lines or via USB-to-serial adapters using the LAWICEL
+ ASCII protocol. The driver implements the tty linediscipline N_SLCAN.
+
+ As only the sending and receiving of CAN frames is implemented, this
+ driver should work with the (serial/USB) CAN hardware from:
+ www.canusb.com / www.can232.com / www.mictronic.com / www.canhack.de
+
+ Userspace tools to attach the SLCAN line discipline (slcan_attach,
+ slcand) can be found in the can-utils at the SocketCAN SVN, see
+ http://developer.berlios.de/projects/socketcan for details.
+
+ The slcan driver supports up to 10 CAN netdevices by default which
+ can be changed by the 'maxdev=xx' module option. This driver can
+ also be built as a module. If so, the module will be called slcan.
+
config CAN_DEV
tristate "Platform CAN drivers with Netlink support"
depends on CAN
diff -u -r -N a/drivers/net/can/slcan.c b/drivers/net/can/slcan.c
--- a/drivers/net/can/slcan.c 1970-01-01 01:00:00.000000000 +0100
+++ b/drivers/net/can/slcan.c 2010-11-29 20:59:59.000000000 +0100
@@ -0,0 +1,755 @@
+/*
+ * slcan.c - serial line CAN interface driver (using tty line discipline)
+ *
+ * This file is derived from linux/drivers/net/slip.c
+ *
+ * slip.c Authors : Laurence Culhane <loz-ft9vOCmwNo6HCRyBVyKX4rVCufUGDwFn@public.gmane.org>
+ * Fred N. van Kempen <waltje-exq35+CbV4/bARYX+r8/SUB+6BGkLq7r@public.gmane.org>
+ * slcan.c Author : Oliver Hartkopp <socketcan-fJ+pQTUTwRTk1uMJSBkQmQ@public.gmane.org>
+ *
+ * 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. You can also get it
+ * at http://www.gnu.org/licenses/gpl.html
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * Send feedback to <socketcan-users-0fE9KPoRgkgATYTw5x5z8w@public.gmane.org>
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+
+#include <asm/system.h>
+#include <linux/uaccess.h>
+#include <linux/bitops.h>
+#include <linux/string.h>
+#include <linux/tty.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/rtnetlink.h>
+#include <linux/if_arp.h>
+#include <linux/if_ether.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/can.h>
+
+static __initdata const char banner[] =
+ KERN_INFO "slcan: serial line CAN interface driver\n";
+
+MODULE_ALIAS_LDISC(N_SLCAN);
+MODULE_DESCRIPTION("serial line CAN interface");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Oliver Hartkopp <socketcan-fJ+pQTUTwRTk1uMJSBkQmQ@public.gmane.org>");
+
+#define SLCAN_MAGIC 0x53CA
+
+static int maxdev = 10; /* MAX number of SLCAN channels;
+ This can be overridden with
+ insmod slcan.ko maxdev=nnn */
+module_param(maxdev, int, 0);
+MODULE_PARM_DESC(maxdev, "Maximum number of slcan interfaces");
+
+/* maximum rx buffer len: extended CAN frame with timestamp */
+#define SLC_MTU (sizeof("T1111222281122334455667788EA5F\r")+1)
+
+struct slcan {
+ int magic;
+
+ /* Various fields. */
+ struct tty_struct *tty; /* ptr to TTY structure */
+ struct net_device *dev; /* easy for intr handling */
+ spinlock_t lock;
+
+ /* These are pointers to the malloc()ed frame buffers. */
+ unsigned char rbuff[SLC_MTU]; /* receiver buffer */
+ int rcount; /* received chars counter */
+ unsigned char xbuff[SLC_MTU]; /* transmitter buffer */
+ unsigned char *xhead; /* pointer to next XMIT byte */
+ int xleft; /* bytes left in XMIT queue */
+
+ unsigned long flags; /* Flag values/ mode etc */
+#define SLF_INUSE 0 /* Channel in use */
+#define SLF_ERROR 1 /* Parity, etc. error */
+
+ unsigned char leased;
+ dev_t line;
+ pid_t pid;
+};
+
+static struct net_device **slcan_devs;
+
+ /************************************************************************
+ * SLCAN ENCAPSULATION FORMAT *
+ ************************************************************************/
+
+/*
+ * A CAN frame has a can_id (11 bit standard frame format OR 29 bit extended
+ * frame format) a data length code (can_dlc) which can be from 0 to 8
+ * and up to <can_dlc> data bytes as payload.
+ * Additionally a CAN frame may become a remote transmission frame if the
+ * RTR-bit is set. This causes another ECU to send a CAN frame with the
+ * given can_id.
+ *
+ * The SLCAN ASCII representation of these different frame types is:
+ * <type> <id> <dlc> <data>*
+ *
+ * Extended frames (29 bit) are defined by capital characters in the type.
+ * RTR frames are defined as 'r' types - normal frames have 't' type:
+ * t => 11 bit data frame
+ * r => 11 bit RTR frame
+ * T => 29 bit data frame
+ * R => 29 bit RTR frame
+ *
+ * The <id> is 3 (standard) or 8 (extended) bytes in ASCII Hex (base64).
+ * The <dlc> is a one byte ASCII number ('0' - '8')
+ * The <data> section has at much ASCII Hex bytes as defined by the <dlc>
+ *
+ * Examples:
+ *
+ * t1230 : can_id 0x123, can_dlc 0, no data
+ * t4563112233 : can_id 0x456, can_dlc 3, data 0x11 0x22 0x33
+ * T12ABCDEF2AA55 : extended can_id 0x12ABCDEF, can_dlc 2, data 0xAA 0x55
+ * r1230 : can_id 0x123, can_dlc 0, no data, remote transmission request
+ *
+ */
+
+ /************************************************************************
+ * STANDARD SLCAN DECAPSULATION *
+ ************************************************************************/
+
+static int asc2nibble(char c)
+{
+
+ if ((c >= '0') && (c <= '9'))
+ return c - '0';
+
+ if ((c >= 'A') && (c <= 'F'))
+ return c - 'A' + 10;
+
+ if ((c >= 'a') && (c <= 'f'))
+ return c - 'a' + 10;
+
+ return 16; /* error */
+}
+
+/* Send one completely decapsulated can_frame to the network layer */
+static void slc_bump(struct slcan *sl)
+{
+ struct sk_buff *skb;
+ struct can_frame cf;
+ int i, dlc_pos, tmp;
+ unsigned long ultmp;
+ char cmd = sl->rbuff[0];
+
+ if ((cmd != 't') && (cmd != 'T') && (cmd != 'r') && (cmd != 'R'))
+ return;
+
+ if (cmd & 0x20) /* tiny chars 'r' 't' => standard frame format */
+ dlc_pos = 4; /* dlc position tiiid */
+ else
+ dlc_pos = 9; /* dlc position Tiiiiiiiid */
+
+ if (!((sl->rbuff[dlc_pos] >= '0') && (sl->rbuff[dlc_pos] < '9')))
+ return;
+
+ cf.can_dlc = sl->rbuff[dlc_pos] - '0'; /* get can_dlc from ASCII val */
+
+ sl->rbuff[dlc_pos] = 0; /* terminate can_id string */
+
+ if (strict_strtoul(sl->rbuff+1, 16, &ultmp))
+ return;
+
+ cf.can_id = ultmp;
+
+ if (!(cmd & 0x20)) /* NO tiny chars => extended frame format */
+ cf.can_id |= CAN_EFF_FLAG;
+
+ if ((cmd | 0x20) == 'r') /* RTR frame */
+ cf.can_id |= CAN_RTR_FLAG;
+
+ *(u64 *) (&cf.data) = 0; /* clear payload */
+
+ for (i = 0, dlc_pos++; i < cf.can_dlc; i++) {
+
+ tmp = asc2nibble(sl->rbuff[dlc_pos++]);
+ if (tmp > 0x0F)
+ return;
+ cf.data[i] = (tmp << 4);
+ tmp = asc2nibble(sl->rbuff[dlc_pos++]);
+ if (tmp > 0x0F)
+ return;
+ cf.data[i] |= tmp;
+ }
+
+
+ skb = dev_alloc_skb(sizeof(struct can_frame));
+ if (!skb)
+ return;
+
+ skb->dev = sl->dev;
+ skb->protocol = htons(ETH_P_CAN);
+ skb->pkt_type = PACKET_BROADCAST;
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ memcpy(skb_put(skb, sizeof(struct can_frame)),
+ &cf, sizeof(struct can_frame));
+ netif_rx(skb);
+
+ sl->dev->stats.rx_packets++;
+ sl->dev->stats.rx_bytes += cf.can_dlc;
+}
+
+/* parse tty input stream */
+static void slcan_unesc(struct slcan *sl, unsigned char s)
+{
+
+ if ((s == '\r') || (s == '\a')) { /* CR or BEL ends the pdu */
+ if (!test_and_clear_bit(SLF_ERROR, &sl->flags) &&
+ (sl->rcount > 4)) {
+ slc_bump(sl);
+ }
+ sl->rcount = 0;
+ } else {
+ if (!test_bit(SLF_ERROR, &sl->flags)) {
+ if (sl->rcount < SLC_MTU) {
+ sl->rbuff[sl->rcount++] = s;
+ return;
+ } else {
+ sl->dev->stats.rx_over_errors++;
+ set_bit(SLF_ERROR, &sl->flags);
+ }
+ }
+ }
+}
+
+ /************************************************************************
+ * STANDARD SLCAN ENCAPSULATION *
+ ************************************************************************/
+
+/* Encapsulate one can_frame and stuff into a TTY queue. */
+static void slc_encaps(struct slcan *sl, struct can_frame *cf)
+{
+ int actual, idx, i;
+ char cmd;
+
+ if (cf->can_id & CAN_RTR_FLAG)
+ cmd = 'R'; /* becomes 'r' in standard frame format */
+ else
+ cmd = 'T'; /* becomes 't' in standard frame format */
+
+ if (cf->can_id & CAN_EFF_FLAG)
+ sprintf(sl->xbuff, "%c%08X%d", cmd,
+ cf->can_id & CAN_EFF_MASK, cf->can_dlc);
+ else
+ sprintf(sl->xbuff, "%c%03X%d", cmd | 0x20,
+ cf->can_id & CAN_SFF_MASK, cf->can_dlc);
+
+ idx = strlen(sl->xbuff);
+
+ for (i = 0; i < cf->can_dlc; i++)
+ sprintf(&sl->xbuff[idx + 2*i], "%02X", cf->data[i]);
+
+ strcat(sl->xbuff, "\r"); /* add terminating character */
+
+ /* Order of next two lines is *very* important.
+ * When we are sending a little amount of data,
+ * the transfer may be completed inside the ops->write()
+ * routine, because it's running with interrupts enabled.
+ * In this case we *never* got WRITE_WAKEUP event,
+ * if we did not request it before write operation.
+ * 14 Oct 1994 Dmitry Gorodchanin.
+ */
+ set_bit(TTY_DO_WRITE_WAKEUP, &sl->tty->flags);
+ actual = sl->tty->ops->write(sl->tty, sl->xbuff, strlen(sl->xbuff));
+ sl->xleft = strlen(sl->xbuff) - actual;
+ sl->xhead = sl->xbuff + actual;
+ sl->dev->stats.tx_bytes += cf->can_dlc;
+}
+
+/*
+ * Called by the driver when there's room for more data. If we have
+ * more packets to send, we send them here.
+ */
+static void slcan_write_wakeup(struct tty_struct *tty)
+{
+ int actual;
+ struct slcan *sl = (struct slcan *) tty->disc_data;
+
+ /* First make sure we're connected. */
+ if (!sl || sl->magic != SLCAN_MAGIC || !netif_running(sl->dev))
+ return;
+
+ if (sl->xleft <= 0) {
+ /* Now serial buffer is almost free & we can start
+ * transmission of another packet */
+ sl->dev->stats.tx_packets++;
+ clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
+ netif_wake_queue(sl->dev);
+ return;
+ }
+
+ actual = tty->ops->write(tty, sl->xhead, sl->xleft);
+ sl->xleft -= actual;
+ sl->xhead += actual;
+}
+
+/* Send a can_frame to a TTY queue. */
+static netdev_tx_t slc_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct slcan *sl = netdev_priv(dev);
+
+ if (skb->len != sizeof(struct can_frame))
+ goto out;
+
+ spin_lock(&sl->lock);
+ if (!netif_running(dev)) {
+ spin_unlock(&sl->lock);
+ printk(KERN_WARNING "%s: xmit: iface is down\n", dev->name);
+ goto out;
+ }
+ if (sl->tty == NULL) {
+ spin_unlock(&sl->lock);
+ goto out;
+ }
+
+ netif_stop_queue(sl->dev);
+ slc_encaps(sl, (struct can_frame *) skb->data); /* encaps & send */
+ spin_unlock(&sl->lock);
+
+out:
+ kfree_skb(skb);
+ return NETDEV_TX_OK;
+}
+
+
+/******************************************
+ * Routines looking at netdevice side.
+ ******************************************/
+
+/* Netdevice UP -> DOWN routine */
+static int slc_close(struct net_device *dev)
+{
+ struct slcan *sl = netdev_priv(dev);
+
+ spin_lock_bh(&sl->lock);
+ if (sl->tty) {
+ /* TTY discipline is running. */
+ clear_bit(TTY_DO_WRITE_WAKEUP, &sl->tty->flags);
+ }
+ netif_stop_queue(dev);
+ sl->rcount = 0;
+ sl->xleft = 0;
+ spin_unlock_bh(&sl->lock);
+
+ return 0;
+}
+
+/* Netdevice DOWN -> UP routine */
+static int slc_open(struct net_device *dev)
+{
+ struct slcan *sl = netdev_priv(dev);
+
+ if (sl->tty == NULL)
+ return -ENODEV;
+
+ sl->flags &= (1 << SLF_INUSE);
+ netif_start_queue(dev);
+ return 0;
+}
+
+/* Hook the destructor so we can free slcan devs at the right point in time */
+static void slc_free_netdev(struct net_device *dev)
+{
+ int i = dev->base_addr;
+ free_netdev(dev);
+ slcan_devs[i] = NULL;
+}
+
+static const struct net_device_ops slc_netdev_ops = {
+ .ndo_open = slc_open,
+ .ndo_stop = slc_close,
+ .ndo_start_xmit = slc_xmit,
+};
+
+static void slc_setup(struct net_device *dev)
+{
+ dev->netdev_ops = &slc_netdev_ops;
+ dev->destructor = slc_free_netdev;
+
+ dev->hard_header_len = 0;
+ dev->addr_len = 0;
+ dev->tx_queue_len = 10;
+
+ dev->mtu = sizeof(struct can_frame);
+ dev->type = ARPHRD_CAN;
+
+ /* New-style flags. */
+ dev->flags = IFF_NOARP;
+ dev->features = NETIF_F_NO_CSUM;
+}
+
+/******************************************
+ Routines looking at TTY side.
+ ******************************************/
+
+/*
+ * Handle the 'receiver data ready' interrupt.
+ * This function is called by the 'tty_io' module in the kernel when
+ * a block of SLCAN data has been received, which can now be decapsulated
+ * and sent on to some IP layer for further processing. This will not
+ * be re-entered while running but other ldisc functions may be called
+ * in parallel
+ */
+
+static void slcan_receive_buf(struct tty_struct *tty,
+ const unsigned char *cp, char *fp, int count)
+{
+ struct slcan *sl = (struct slcan *) tty->disc_data;
+
+ if (!sl || sl->magic != SLCAN_MAGIC || !netif_running(sl->dev))
+ return;
+
+ /* Read the characters out of the buffer */
+ while (count--) {
+ if (fp && *fp++) {
+ if (!test_and_set_bit(SLF_ERROR, &sl->flags))
+ sl->dev->stats.rx_errors++;
+ cp++;
+ continue;
+ }
+ slcan_unesc(sl, *cp++);
+ }
+}
+
+/************************************
+ * slcan_open helper routines.
+ ************************************/
+
+/* Collect hanged up channels */
+static void slc_sync(void)
+{
+ int i;
+ struct net_device *dev;
+ struct slcan *sl;
+
+ for (i = 0; i < maxdev; i++) {
+ dev = slcan_devs[i];
+ if (dev == NULL)
+ break;
+
+ sl = netdev_priv(dev);
+ if (sl->tty || sl->leased)
+ continue;
+ if (dev->flags & IFF_UP)
+ dev_close(dev);
+ }
+}
+
+/* Find a free SLCAN channel, and link in this `tty' line. */
+static struct slcan *slc_alloc(dev_t line)
+{
+ int i;
+ struct net_device *dev = NULL;
+ struct slcan *sl;
+
+ if (slcan_devs == NULL)
+ return NULL; /* Master array missing ! */
+
+ for (i = 0; i < maxdev; i++) {
+ dev = slcan_devs[i];
+ if (dev == NULL)
+ break;
+
+ }
+
+ /* Sorry, too many, all slots in use */
+ if (i >= maxdev)
+ return NULL;
+
+ if (dev) {
+ sl = netdev_priv(dev);
+ if (test_bit(SLF_INUSE, &sl->flags)) {
+ unregister_netdevice(dev);
+ dev = NULL;
+ slcan_devs[i] = NULL;
+ }
+ }
+
+ if (!dev) {
+ char name[IFNAMSIZ];
+ sprintf(name, "slcan%d", i);
+
+ dev = alloc_netdev(sizeof(*sl), name, slc_setup);
+ if (!dev)
+ return NULL;
+ dev->base_addr = i;
+ }
+
+ sl = netdev_priv(dev);
+
+ /* Initialize channel control data */
+ sl->magic = SLCAN_MAGIC;
+ sl->dev = dev;
+ spin_lock_init(&sl->lock);
+ slcan_devs[i] = dev;
+
+ return sl;
+}
+
+/*
+ * Open the high-level part of the SLCAN channel.
+ * This function is called by the TTY module when the
+ * SLCAN line discipline is called for. Because we are
+ * sure the tty line exists, we only have to link it to
+ * a free SLCAN channel...
+ *
+ * Called in process context serialized from other ldisc calls.
+ */
+
+static int slcan_open(struct tty_struct *tty)
+{
+ struct slcan *sl;
+ int err;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ if (tty->ops->write == NULL)
+ return -EOPNOTSUPP;
+
+ /* RTnetlink lock is misused here to serialize concurrent
+ opens of slcan channels. There are better ways, but it is
+ the simplest one.
+ */
+ rtnl_lock();
+
+ /* Collect hanged up channels. */
+ slc_sync();
+
+ sl = tty->disc_data;
+
+ err = -EEXIST;
+ /* First make sure we're not already connected. */
+ if (sl && sl->magic == SLCAN_MAGIC)
+ goto err_exit;
+
+ /* OK. Find a free SLCAN channel to use. */
+ err = -ENFILE;
+ sl = slc_alloc(tty_devnum(tty));
+ if (sl == NULL)
+ goto err_exit;
+
+ sl->tty = tty;
+ tty->disc_data = sl;
+ sl->line = tty_devnum(tty);
+ sl->pid = current->pid;
+
+ if (!test_bit(SLF_INUSE, &sl->flags)) {
+ /* Perform the low-level SLCAN initialization. */
+ sl->rcount = 0;
+ sl->xleft = 0;
+
+ set_bit(SLF_INUSE, &sl->flags);
+
+ err = register_netdevice(sl->dev);
+ if (err)
+ goto err_free_chan;
+ }
+
+ /* Done. We have linked the TTY line to a channel. */
+ rtnl_unlock();
+ tty->receive_room = 65536; /* We don't flow control */
+ return sl->dev->base_addr;
+
+err_free_chan:
+ sl->tty = NULL;
+ tty->disc_data = NULL;
+ clear_bit(SLF_INUSE, &sl->flags);
+
+err_exit:
+ rtnl_unlock();
+
+ /* Count references from TTY module */
+ return err;
+}
+
+/*
+ * Close down a SLCAN channel.
+ * This means flushing out any pending queues, and then returning. This
+ * call is serialized against other ldisc functions.
+ *
+ * We also use this method for a hangup event.
+ */
+
+static void slcan_close(struct tty_struct *tty)
+{
+ struct slcan *sl = (struct slcan *) tty->disc_data;
+
+ /* First make sure we're connected. */
+ if (!sl || sl->magic != SLCAN_MAGIC || sl->tty != tty)
+ return;
+
+ tty->disc_data = NULL;
+ sl->tty = NULL;
+ if (!sl->leased)
+ sl->line = 0;
+
+ /* Flush network side */
+ unregister_netdev(sl->dev);
+ /* This will complete via sl_free_netdev */
+}
+
+static int slcan_hangup(struct tty_struct *tty)
+{
+ slcan_close(tty);
+ return 0;
+}
+
+/* Perform I/O control on an active SLCAN channel. */
+static int slcan_ioctl(struct tty_struct *tty, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct slcan *sl = (struct slcan *) tty->disc_data;
+ unsigned int tmp;
+
+ /* First make sure we're connected. */
+ if (!sl || sl->magic != SLCAN_MAGIC)
+ return -EINVAL;
+
+ switch (cmd) {
+ case SIOCGIFNAME:
+ tmp = strlen(sl->dev->name) + 1;
+ if (copy_to_user((void __user *)arg, sl->dev->name, tmp))
+ return -EFAULT;
+ return 0;
+
+ case SIOCSIFHWADDR:
+ return -EINVAL;
+
+ default:
+ return tty_mode_ioctl(tty, file, cmd, arg);
+ }
+}
+
+static struct tty_ldisc_ops slc_ldisc = {
+ .owner = THIS_MODULE,
+ .magic = TTY_LDISC_MAGIC,
+ .name = "slcan",
+ .open = slcan_open,
+ .close = slcan_close,
+ .hangup = slcan_hangup,
+ .ioctl = slcan_ioctl,
+ .receive_buf = slcan_receive_buf,
+ .write_wakeup = slcan_write_wakeup,
+};
+
+static int __init slcan_init(void)
+{
+ int status;
+
+ if (maxdev < 4)
+ maxdev = 4; /* Sanity */
+
+ printk(banner);
+ printk(KERN_INFO "slcan: %d dynamic interface channels.\n", maxdev);
+
+ slcan_devs = kzalloc(sizeof(struct net_device *)*maxdev, GFP_KERNEL);
+ if (!slcan_devs) {
+ printk(KERN_ERR "slcan: can't allocate slcan device array!\n");
+ return -ENOMEM;
+ }
+
+ /* Fill in our line protocol discipline, and register it */
+ status = tty_register_ldisc(N_SLCAN, &slc_ldisc);
+ if (status) {
+ printk(KERN_ERR "slcan: can't register line discipline\n");
+ kfree(slcan_devs);
+ }
+ return status;
+}
+
+static void __exit slcan_exit(void)
+{
+ int i;
+ struct net_device *dev;
+ struct slcan *sl;
+ unsigned long timeout = jiffies + HZ;
+ int busy = 0;
+
+ if (slcan_devs == NULL)
+ return;
+
+ /* First of all: check for active disciplines and hangup them.
+ */
+ do {
+ if (busy)
+ msleep_interruptible(100);
+
+ busy = 0;
+ for (i = 0; i < maxdev; i++) {
+ dev = slcan_devs[i];
+ if (!dev)
+ continue;
+ sl = netdev_priv(dev);
+ spin_lock_bh(&sl->lock);
+ if (sl->tty) {
+ busy++;
+ tty_hangup(sl->tty);
+ }
+ spin_unlock_bh(&sl->lock);
+ }
+ } while (busy && time_before(jiffies, timeout));
+
+ /* FIXME: hangup is async so we should wait when doing this second
+ phase */
+
+ for (i = 0; i < maxdev; i++) {
+ dev = slcan_devs[i];
+ if (!dev)
+ continue;
+ slcan_devs[i] = NULL;
+
+ sl = netdev_priv(dev);
+ if (sl->tty) {
+ printk(KERN_ERR "%s: tty discipline still running\n",
+ dev->name);
+ /* Intentionally leak the control block. */
+ dev->destructor = NULL;
+ }
+
+ unregister_netdev(dev);
+ }
+
+ kfree(slcan_devs);
+ slcan_devs = NULL;
+
+ i = tty_unregister_ldisc(N_SLCAN);
+ if (i)
+ printk(KERN_ERR "slcan: can't unregister ldisc (err %d)\n", i);
+}
+
+module_init(slcan_init);
+module_exit(slcan_exit);
^ permalink raw reply
* Re: [net-next-2.6] XFRM: remove unused member in xfrm_encap_tmpl.
From: Timo Teräs @ 2010-11-29 20:35 UTC (permalink / raw)
To: David Shwatrz; +Cc: David S. Miller, netdev
In-Reply-To: <AANLkTimfUFuJKMwp6X65z_NRE4pPKy-6_fEu19Gaqycm@mail.gmail.com>
On 11/29/2010 10:09 PM, David Shwatrz wrote:
> Timo,
> Thanks for your answer.
>
>> Alternatively the other RFCs say that the checksum can be just
>> recalculated. That's what the linux stack does: it throws the old
>> checksum away (ignored on local receive and recalculated on send
>> forward paths).
>
> Sorry, something here seems to me still wrong; maybe I miss something.
> We are talking about transport mode. Let's take TCP for example.
> the packet is received by another peer. It is on port 4500 because of
> NAT-T. Since it is ESP encrypted , it is it is decrypted. It reaches
> the TCP layer. In TCP (as opposed to UDP), the checksum is mandatory.
> But the checksum in that TCP header of the received
> packet will not be correct, since the IP header of that packet is
> **NOT** the original address ; the IP address was changed by the NAT.
> The NAT cannot change the TCP checksum since it is encrypted. So
> wouldn't we have a checksum error in the case of TCP ? It seems to me
> that the purpose of NAT-OA was to pass the
> original address, so that there will be no error in such a case.
> But again, maybe I miss something, since I did not heard that
> transport mode has any problems with NAT-T. Or maybe this was not
> tested?
Yes, it's the primary use case for NAT-OA, to allow "fast" update of the
checksum.
The Linux way works too. It's tested.
Like I said, the IPsec stack says to TCP/UDP stack part "I've already
check the checksum, do not look at it". If the packet is forwarded the
kernel (or NIC hardware) *recalculates* the proper checksum; as if it
was generating the packet in first place.
Using NAT-OA to update checksum is purely an optimisation; mostly useful
only when forwarding form one IPsec tunnel to another one which does not
happen often in transport mode (perhaps only in some very special NAT
setups).
^ permalink raw reply
* [PATCH 0/3] IPv6 inetpeer support
From: David Miller @ 2010-11-29 21:43 UTC (permalink / raw)
To: netdev
Here is the beginning of some refactoring I've been working on.
It's a respin of my older inet-peer ipv6 support patch plus the
beginnings of what's necessary to support TCP time-wait recycling
in ipv6 too.
I also intend to investigate more deeply putting metrics into
the inet-peer cache, but nothing about that is in this series
as that is still a not so clear-and-dry issue.
Supporting the same set of TCP features in both ipv4 and ipv6
is, on the other hand, less controversial so I think we should
do the ipv6 inet-peer thing no matter what.
^ permalink raw reply
* [PATCH 1/3] inetpeer: Support ipv6 addresses.
From: David Miller @ 2010-11-29 21:44 UTC (permalink / raw)
To: netdev
Signed-off-by: David S. Miller <davem@davemloft.net>
---
include/net/inetpeer.h | 21 ++++++++++++++-
net/ipv4/inetpeer.c | 66 ++++++++++++++++++++++++++++++++++++++++-------
net/ipv4/ip_fragment.c | 2 +-
net/ipv4/route.c | 2 +-
net/ipv4/tcp_ipv4.c | 6 ++--
5 files changed, 80 insertions(+), 17 deletions(-)
diff --git a/include/net/inetpeer.h b/include/net/inetpeer.h
index fe239bf..834f045 100644
--- a/include/net/inetpeer.h
+++ b/include/net/inetpeer.h
@@ -13,10 +13,18 @@
#include <linux/spinlock.h>
#include <asm/atomic.h>
+typedef struct {
+ union {
+ __be32 a4;
+ __be32 a6[4];
+ };
+ __u16 family;
+} inet_peer_address_t;
+
struct inet_peer {
/* group together avl_left,avl_right,v4daddr to speedup lookups */
struct inet_peer __rcu *avl_left, *avl_right;
- __be32 v4daddr; /* peer's address */
+ inet_peer_address_t daddr;
__u32 avl_height;
struct list_head unused;
__u32 dtime; /* the time of last use of not
@@ -42,7 +50,16 @@ struct inet_peer {
void inet_initpeers(void) __init;
/* can be called with or without local BH being disabled */
-struct inet_peer *inet_getpeer(__be32 daddr, int create);
+struct inet_peer *inet_getpeer(inet_peer_address_t *daddr, int create);
+
+static inline struct inet_peer *inet_getpeer_v4(__be32 v4daddr, int create)
+{
+ inet_peer_address_t daddr;
+
+ daddr.a4 = v4daddr;
+ daddr.family = AF_INET;
+ return inet_getpeer(&daddr, create);
+}
/* can be called from BH context or outside */
extern void inet_putpeer(struct inet_peer *p);
diff --git a/net/ipv4/inetpeer.c b/net/ipv4/inetpeer.c
index 9e94d7c..39f18c5 100644
--- a/net/ipv4/inetpeer.c
+++ b/net/ipv4/inetpeer.c
@@ -19,6 +19,7 @@
#include <linux/net.h>
#include <net/ip.h>
#include <net/inetpeer.h>
+#include <net/ipv6.h>
/*
* Theory of operations.
@@ -152,11 +153,53 @@ static void unlink_from_unused(struct inet_peer *p)
}
}
+static inline bool inet_peer_addr_equal(inet_peer_address_t *a, inet_peer_address_t *b)
+{
+ if (a->family == b->family) {
+ switch (a->family) {
+ case AF_INET:
+ if (a->a4 == b->a4)
+ return true;
+ break;
+ case AF_INET6:
+ if (!ipv6_addr_cmp((struct in6_addr *)a,
+ (struct in6_addr *)b))
+ return true;
+ break;
+ default:
+ break;
+ }
+ }
+ return false;
+}
+
+static inline u32 inet_peer_key(inet_peer_address_t *a)
+{
+ u32 key;
+
+ switch (a->family) {
+ case AF_INET:
+ key = (__force __u32) a->a4;
+ break;
+ case AF_INET6:
+ key = ((__force __u32)a->a6[0] ^
+ (__force __u32)a->a6[1] ^
+ (__force __u32)a->a6[2] ^
+ (__force __u32)a->a6[3]);
+ break;
+ default:
+ key = 0;
+ break;
+ }
+ return key;
+}
+
/*
* Called with local BH disabled and the pool lock held.
*/
#define lookup(_daddr, _stack) \
({ \
+ u32 key = inet_peer_key(_daddr); \
struct inet_peer *u; \
struct inet_peer __rcu **v; \
\
@@ -165,9 +208,9 @@ static void unlink_from_unused(struct inet_peer *p)
for (u = rcu_dereference_protected(peers.root, \
lockdep_is_held(&peers.lock)); \
u != peer_avl_empty; ) { \
- if (_daddr == u->v4daddr) \
+ if (inet_peer_addr_equal(_daddr, &u->daddr)) \
break; \
- if ((__force __u32)_daddr < (__force __u32)u->v4daddr) \
+ if (key < inet_peer_key(&u->daddr)) \
v = &u->avl_left; \
else \
v = &u->avl_right; \
@@ -185,13 +228,14 @@ static void unlink_from_unused(struct inet_peer *p)
* But every pointer we follow is guaranteed to be valid thanks to RCU.
* We exit from this function if number of links exceeds PEER_MAXDEPTH
*/
-static struct inet_peer *lookup_rcu_bh(__be32 daddr)
+static struct inet_peer *lookup_rcu_bh(inet_peer_address_t *daddr)
{
struct inet_peer *u = rcu_dereference_bh(peers.root);
+ u32 key = inet_peer_key(daddr);
int count = 0;
while (u != peer_avl_empty) {
- if (daddr == u->v4daddr) {
+ if (inet_peer_addr_equal(daddr, &u->daddr)) {
/* Before taking a reference, check if this entry was
* deleted, unlink_from_pool() sets refcnt=-1 to make
* distinction between an unused entry (refcnt=0) and
@@ -201,7 +245,7 @@ static struct inet_peer *lookup_rcu_bh(__be32 daddr)
u = NULL;
return u;
}
- if ((__force __u32)daddr < (__force __u32)u->v4daddr)
+ if (key < inet_peer_key(&u->daddr))
u = rcu_dereference_bh(u->avl_left);
else
u = rcu_dereference_bh(u->avl_right);
@@ -353,7 +397,7 @@ static void unlink_from_pool(struct inet_peer *p)
if (atomic_cmpxchg(&p->refcnt, 1, -1) == 1) {
struct inet_peer __rcu **stack[PEER_MAXDEPTH];
struct inet_peer __rcu ***stackptr, ***delp;
- if (lookup(p->v4daddr, stack) != p)
+ if (lookup(&p->daddr, stack) != p)
BUG();
delp = stackptr - 1; /* *delp[0] == p */
if (p->avl_left == peer_avl_empty_rcu) {
@@ -366,7 +410,7 @@ static void unlink_from_pool(struct inet_peer *p)
BUG_ON(rcu_dereference_protected(*stackptr[-1],
lockdep_is_held(&peers.lock)) != t);
**--stackptr = t->avl_left;
- /* t is removed, t->v4daddr > x->v4daddr for any
+ /* t is removed, t->daddr > x->daddr for any
* x in p->avl_left subtree.
* Put t in the old place of p. */
RCU_INIT_POINTER(*delp[0], t);
@@ -433,7 +477,7 @@ static int cleanup_once(unsigned long ttl)
}
/* Called with or without local BH being disabled. */
-struct inet_peer *inet_getpeer(__be32 daddr, int create)
+struct inet_peer *inet_getpeer(inet_peer_address_t *daddr, int create)
{
struct inet_peer *p;
struct inet_peer __rcu **stack[PEER_MAXDEPTH], ***stackptr;
@@ -467,10 +511,12 @@ struct inet_peer *inet_getpeer(__be32 daddr, int create)
}
p = create ? kmem_cache_alloc(peer_cachep, GFP_ATOMIC) : NULL;
if (p) {
- p->v4daddr = daddr;
+ p->daddr = *daddr;
atomic_set(&p->refcnt, 1);
atomic_set(&p->rid, 0);
- atomic_set(&p->ip_id_count, secure_ip_id(daddr));
+ atomic_set(&p->ip_id_count,
+ (daddr->family == AF_INET) ?
+ secure_ip_id(daddr->a4) : 0);
p->tcp_ts_stamp = 0;
INIT_LIST_HEAD(&p->unused);
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index 1684408..e6215bd 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -141,7 +141,7 @@ static void ip4_frag_init(struct inet_frag_queue *q, void *a)
qp->daddr = arg->iph->daddr;
qp->user = arg->user;
qp->peer = sysctl_ipfrag_max_dist ?
- inet_getpeer(arg->iph->saddr, 1) : NULL;
+ inet_getpeer_v4(arg->iph->saddr, 1) : NULL;
}
static __inline__ void ip4_frag_free(struct inet_frag_queue *q)
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index ec2333f..3843c2d 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -1289,7 +1289,7 @@ void rt_bind_peer(struct rtable *rt, int create)
{
struct inet_peer *peer;
- peer = inet_getpeer(rt->rt_dst, create);
+ peer = inet_getpeer_v4(rt->rt_dst, create);
if (peer && cmpxchg(&rt->peer, NULL, peer) != NULL)
inet_putpeer(peer);
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 69ccbc1..00285fc 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -1347,7 +1347,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
tcp_death_row.sysctl_tw_recycle &&
(dst = inet_csk_route_req(sk, req)) != NULL &&
(peer = rt_get_peer((struct rtable *)dst)) != NULL &&
- peer->v4daddr == saddr) {
+ peer->daddr.a4 == saddr) {
inet_peer_refcheck(peer);
if ((u32)get_seconds() - peer->tcp_ts_stamp < TCP_PAWS_MSL &&
(s32)(peer->tcp_ts - req->ts_recent) >
@@ -1778,7 +1778,7 @@ int tcp_v4_remember_stamp(struct sock *sk)
int release_it = 0;
if (!rt || rt->rt_dst != inet->inet_daddr) {
- peer = inet_getpeer(inet->inet_daddr, 1);
+ peer = inet_getpeer_v4(inet->inet_daddr, 1);
release_it = 1;
} else {
if (!rt->peer)
@@ -1804,7 +1804,7 @@ EXPORT_SYMBOL(tcp_v4_remember_stamp);
int tcp_v4_tw_remember_stamp(struct inet_timewait_sock *tw)
{
- struct inet_peer *peer = inet_getpeer(tw->tw_daddr, 1);
+ struct inet_peer *peer = inet_getpeer_v4(tw->tw_daddr, 1);
if (peer) {
const struct tcp_timewait_sock *tcptw = tcp_twsk((struct sock *)tw);
--
1.7.3.2
^ permalink raw reply related
* [PATCH 2/3] ipv6: Add infrastructure to bind inet_peer objects to routes.
From: David Miller @ 2010-11-29 21:44 UTC (permalink / raw)
To: netdev
They are only allowed on cached ipv6 routes.
Signed-off-by: David S. Miller <davem@davemloft.net>
---
include/net/inetpeer.h | 10 ++++++++++
include/net/ip6_fib.h | 2 ++
include/net/ip6_route.h | 3 +++
net/ipv4/inetpeer.c | 2 ++
net/ipv6/route.c | 18 ++++++++++++++++++
5 files changed, 35 insertions(+), 0 deletions(-)
diff --git a/include/net/inetpeer.h b/include/net/inetpeer.h
index 834f045..fb8aeb1 100644
--- a/include/net/inetpeer.h
+++ b/include/net/inetpeer.h
@@ -11,6 +11,7 @@
#include <linux/init.h>
#include <linux/jiffies.h>
#include <linux/spinlock.h>
+#include <net/ipv6.h>
#include <asm/atomic.h>
typedef struct {
@@ -61,6 +62,15 @@ static inline struct inet_peer *inet_getpeer_v4(__be32 v4daddr, int create)
return inet_getpeer(&daddr, create);
}
+static inline struct inet_peer *inet_getpeer_v6(struct in6_addr *v6daddr, int create)
+{
+ inet_peer_address_t daddr;
+
+ ipv6_addr_copy((struct in6_addr *)daddr.a6, v6daddr);
+ daddr.family = AF_INET6;
+ return inet_getpeer(&daddr, create);
+}
+
/* can be called from BH context or outside */
extern void inet_putpeer(struct inet_peer *p);
diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h
index 062a823..708ff7c 100644
--- a/include/net/ip6_fib.h
+++ b/include/net/ip6_fib.h
@@ -21,6 +21,7 @@
#include <net/dst.h>
#include <net/flow.h>
#include <net/netlink.h>
+#include <net/inetpeer.h>
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
#define FIB6_TABLE_HASHSZ 256
@@ -109,6 +110,7 @@ struct rt6_info {
u32 rt6i_metric;
struct inet6_dev *rt6i_idev;
+ struct inet_peer *rt6i_peer;
#ifdef CONFIG_XFRM
u32 rt6i_flow_cache_genid;
diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h
index 278312c..23fed28 100644
--- a/include/net/ip6_route.h
+++ b/include/net/ip6_route.h
@@ -56,6 +56,9 @@ static inline unsigned int rt6_flags2srcprefs(int flags)
return (flags >> 3) & 7;
}
+extern void rt6_bind_peer(struct rt6_info *rt,
+ int create);
+
extern void ip6_route_input(struct sk_buff *skb);
extern struct dst_entry * ip6_route_output(struct net *net,
diff --git a/net/ipv4/inetpeer.c b/net/ipv4/inetpeer.c
index 39f18c5..a442e99 100644
--- a/net/ipv4/inetpeer.c
+++ b/net/ipv4/inetpeer.c
@@ -533,6 +533,7 @@ struct inet_peer *inet_getpeer(inet_peer_address_t *daddr, int create)
return p;
}
+EXPORT_SYMBOL_GPL(inet_getpeer);
/* Called with local BH disabled. */
static void peer_check_expire(unsigned long dummy)
@@ -576,3 +577,4 @@ void inet_putpeer(struct inet_peer *p)
local_bh_enable();
}
+EXPORT_SYMBOL_GPL(inet_putpeer);
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index a0c4ad1..026caef 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -188,11 +188,29 @@ static void ip6_dst_destroy(struct dst_entry *dst)
{
struct rt6_info *rt = (struct rt6_info *)dst;
struct inet6_dev *idev = rt->rt6i_idev;
+ struct inet_peer *peer = rt->rt6i_peer;
if (idev != NULL) {
rt->rt6i_idev = NULL;
in6_dev_put(idev);
}
+ if (peer) {
+ BUG_ON(!(rt->rt6i_flags & RTF_CACHE));
+ rt->rt6i_peer = NULL;
+ inet_putpeer(peer);
+ }
+}
+
+void rt6_bind_peer(struct rt6_info *rt, int create)
+{
+ struct inet_peer *peer;
+
+ if (WARN_ON(!(rt->rt6i_flags & RTF_CACHE)))
+ return;
+
+ peer = inet_getpeer_v6(&rt->rt6i_dst.addr, create);
+ if (peer && cmpxchg(&rt->rt6i_peer, NULL, peer) != NULL)
+ inet_putpeer(peer);
}
static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
--
1.7.3.2
^ permalink raw reply related
* [PATCH 3/3] inet: Turn ->remember_stamp into ->get_peer in connection AF ops.
From: David Miller @ 2010-11-29 21:44 UTC (permalink / raw)
To: netdev
Then we can make a completely generic tcp_remember_stamp()
that uses ->get_peer() as a helper, minimizing the AF specific
code and making the eventual code duplication when we implement
the ipv6 side of TW recycling.
Signed-off-by: David S. Miller <davem@davemloft.net>
---
include/net/inet_connection_sock.h | 2 +-
include/net/tcp.h | 2 +-
net/ipv4/tcp_ipv4.c | 35 ++++++++---------------------------
net/ipv4/tcp_minisocks.c | 31 ++++++++++++++++++++++++++++++-
net/ipv6/tcp_ipv6.c | 8 ++++----
5 files changed, 44 insertions(+), 34 deletions(-)
diff --git a/include/net/inet_connection_sock.h b/include/net/inet_connection_sock.h
index e4f494b..6c93a56 100644
--- a/include/net/inet_connection_sock.h
+++ b/include/net/inet_connection_sock.h
@@ -43,7 +43,7 @@ struct inet_connection_sock_af_ops {
struct sock *(*syn_recv_sock)(struct sock *sk, struct sk_buff *skb,
struct request_sock *req,
struct dst_entry *dst);
- int (*remember_stamp)(struct sock *sk);
+ struct inet_peer *(*get_peer)(struct sock *sk, bool *release_it);
u16 net_header_len;
u16 sockaddr_len;
int (*setsockopt)(struct sock *sk, int level, int optname,
diff --git a/include/net/tcp.h b/include/net/tcp.h
index e36c874..3e23964 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -312,7 +312,7 @@ extern void tcp_shutdown (struct sock *sk, int how);
extern int tcp_v4_rcv(struct sk_buff *skb);
-extern int tcp_v4_remember_stamp(struct sock *sk);
+extern struct inet_peer *tcp_v4_get_peer(struct sock *sk, bool *release_it);
extern int tcp_v4_tw_remember_stamp(struct inet_timewait_sock *tw);
extern int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
size_t size);
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 00285fc..0ddf819 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -1763,44 +1763,25 @@ do_time_wait:
goto discard_it;
}
-/* VJ's idea. Save last timestamp seen from this destination
- * and hold it at least for normal timewait interval to use for duplicate
- * segment detection in subsequent connections, before they enter synchronized
- * state.
- */
-
-int tcp_v4_remember_stamp(struct sock *sk)
+struct inet_peer *tcp_v4_get_peer(struct sock *sk, bool *release_it)
{
+ struct rtable *rt = (struct rtable *) __sk_dst_get(sk);
struct inet_sock *inet = inet_sk(sk);
- struct tcp_sock *tp = tcp_sk(sk);
- struct rtable *rt = (struct rtable *)__sk_dst_get(sk);
- struct inet_peer *peer = NULL;
- int release_it = 0;
+ struct inet_peer *peer;
if (!rt || rt->rt_dst != inet->inet_daddr) {
peer = inet_getpeer_v4(inet->inet_daddr, 1);
- release_it = 1;
+ *release_it = true;
} else {
if (!rt->peer)
rt_bind_peer(rt, 1);
peer = rt->peer;
+ *release_it = false;
}
- if (peer) {
- if ((s32)(peer->tcp_ts - tp->rx_opt.ts_recent) <= 0 ||
- ((u32)get_seconds() - peer->tcp_ts_stamp > TCP_PAWS_MSL &&
- peer->tcp_ts_stamp <= (u32)tp->rx_opt.ts_recent_stamp)) {
- peer->tcp_ts_stamp = (u32)tp->rx_opt.ts_recent_stamp;
- peer->tcp_ts = tp->rx_opt.ts_recent;
- }
- if (release_it)
- inet_putpeer(peer);
- return 1;
- }
-
- return 0;
+ return peer;
}
-EXPORT_SYMBOL(tcp_v4_remember_stamp);
+EXPORT_SYMBOL(tcp_v4_get_peer);
int tcp_v4_tw_remember_stamp(struct inet_timewait_sock *tw)
{
@@ -1828,7 +1809,7 @@ const struct inet_connection_sock_af_ops ipv4_specific = {
.rebuild_header = inet_sk_rebuild_header,
.conn_request = tcp_v4_conn_request,
.syn_recv_sock = tcp_v4_syn_recv_sock,
- .remember_stamp = tcp_v4_remember_stamp,
+ .get_peer = tcp_v4_get_peer,
.net_header_len = sizeof(struct iphdr),
.setsockopt = ip_setsockopt,
.getsockopt = ip_getsockopt,
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
index 43cf901..059082c 100644
--- a/net/ipv4/tcp_minisocks.c
+++ b/net/ipv4/tcp_minisocks.c
@@ -49,6 +49,35 @@ struct inet_timewait_death_row tcp_death_row = {
};
EXPORT_SYMBOL_GPL(tcp_death_row);
+/* VJ's idea. Save last timestamp seen from this destination
+ * and hold it at least for normal timewait interval to use for duplicate
+ * segment detection in subsequent connections, before they enter synchronized
+ * state.
+ */
+
+static int tcp_remember_stamp(struct sock *sk)
+{
+ const struct inet_connection_sock *icsk = inet_csk(sk);
+ struct tcp_sock *tp = tcp_sk(sk);
+ struct inet_peer *peer;
+ bool release_it;
+
+ peer = icsk->icsk_af_ops->get_peer(sk, &release_it);
+ if (peer) {
+ if ((s32)(peer->tcp_ts - tp->rx_opt.ts_recent) <= 0 ||
+ ((u32)get_seconds() - peer->tcp_ts_stamp > TCP_PAWS_MSL &&
+ peer->tcp_ts_stamp <= (u32)tp->rx_opt.ts_recent_stamp)) {
+ peer->tcp_ts_stamp = (u32)tp->rx_opt.ts_recent_stamp;
+ peer->tcp_ts = tp->rx_opt.ts_recent;
+ }
+ if (release_it)
+ inet_putpeer(peer);
+ return 1;
+ }
+
+ return 0;
+}
+
static __inline__ int tcp_in_window(u32 seq, u32 end_seq, u32 s_win, u32 e_win)
{
if (seq == s_win)
@@ -274,7 +303,7 @@ void tcp_time_wait(struct sock *sk, int state, int timeo)
int recycle_ok = 0;
if (tcp_death_row.sysctl_tw_recycle && tp->rx_opt.ts_recent_stamp)
- recycle_ok = icsk->icsk_af_ops->remember_stamp(sk);
+ recycle_ok = tcp_remember_stamp(sk);
if (tcp_death_row.tw_count < tcp_death_row.sysctl_max_tw_buckets)
tw = inet_twsk_alloc(sk, state);
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 7e41e2c..e394d00 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -1818,10 +1818,10 @@ do_time_wait:
goto discard_it;
}
-static int tcp_v6_remember_stamp(struct sock *sk)
+struct inet_peer *tcp_v6_get_peer(struct sock *sk, bool *release_it)
{
/* Alas, not yet... */
- return 0;
+ return NULL;
}
static const struct inet_connection_sock_af_ops ipv6_specific = {
@@ -1830,7 +1830,7 @@ static const struct inet_connection_sock_af_ops ipv6_specific = {
.rebuild_header = inet6_sk_rebuild_header,
.conn_request = tcp_v6_conn_request,
.syn_recv_sock = tcp_v6_syn_recv_sock,
- .remember_stamp = tcp_v6_remember_stamp,
+ .get_peer = tcp_v6_get_peer,
.net_header_len = sizeof(struct ipv6hdr),
.setsockopt = ipv6_setsockopt,
.getsockopt = ipv6_getsockopt,
@@ -1862,7 +1862,7 @@ static const struct inet_connection_sock_af_ops ipv6_mapped = {
.rebuild_header = inet_sk_rebuild_header,
.conn_request = tcp_v6_conn_request,
.syn_recv_sock = tcp_v6_syn_recv_sock,
- .remember_stamp = tcp_v4_remember_stamp,
+ .get_peer = tcp_v4_get_peer,
.net_header_len = sizeof(struct iphdr),
.setsockopt = ipv6_setsockopt,
.getsockopt = ipv6_getsockopt,
--
1.7.3.2
^ permalink raw reply related
* Re: [PATCH] ssb: Add sysfs attributes to ssb devices
From: Michael Büsch @ 2010-11-29 22:19 UTC (permalink / raw)
To: Hauke Mehrtens; +Cc: davem, netdev, Bernhard Loos
In-Reply-To: <1290943372-27749-1-git-send-email-hauke@hauke-m.de>
On Sun, 2010-11-28 at 12:22 +0100, Hauke Mehrtens wrote:
> Make it possible to read out the attributes, till now only show on
> dmesg, through sysfs.
>
> This patch was some time in OpenWrt.
>
> Signed-off-by: Bernhard Loos <bernhardloos@googlemail.com>
> Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
Acked-by: Michael Buesch <mb@bu3sch.de>
> ---
> drivers/ssb/main.c | 30 ++++++++++++++++++++++++++++++
> 1 files changed, 30 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c
> index c68b3dc..3918d2c 100644
> --- a/drivers/ssb/main.c
> +++ b/drivers/ssb/main.c
> @@ -383,6 +383,35 @@ static int ssb_device_uevent(struct device *dev, struct kobj_uevent_env *env)
> ssb_dev->id.revision);
> }
>
> +#define ssb_config_attr(attrib, field, format_string) \
> +static ssize_t \
> +attrib##_show(struct device *dev, struct device_attribute *attr, char *buf) \
> +{ \
> + return sprintf(buf, format_string, dev_to_ssb_dev(dev)->field); \
> +}
> +
> +ssb_config_attr(core_num, core_index, "%u\n")
> +ssb_config_attr(coreid, id.coreid, "0x%04x\n")
> +ssb_config_attr(vendor, id.vendor, "0x%04x\n")
> +ssb_config_attr(revision, id.revision, "%u\n")
> +ssb_config_attr(irq, irq, "%u\n")
> +static ssize_t
> +name_show(struct device *dev, struct device_attribute *attr, char *buf)
> +{
> + return sprintf(buf, "%s\n",
> + ssb_core_name(dev_to_ssb_dev(dev)->id.coreid));
> +}
> +
> +static struct device_attribute ssb_device_attrs[] = {
> + __ATTR_RO(name),
> + __ATTR_RO(core_num),
> + __ATTR_RO(coreid),
> + __ATTR_RO(vendor),
> + __ATTR_RO(revision),
> + __ATTR_RO(irq),
> + __ATTR_NULL,
> +};
> +
> static struct bus_type ssb_bustype = {
> .name = "ssb",
> .match = ssb_bus_match,
> @@ -392,6 +421,7 @@ static struct bus_type ssb_bustype = {
> .suspend = ssb_device_suspend,
> .resume = ssb_device_resume,
> .uevent = ssb_device_uevent,
> + .dev_attrs = ssb_device_attrs,
> };
>
> static void ssb_buses_lock(void)
--
Greetings Michael.
^ permalink raw reply
* Re: [PATCH 1/3] inetpeer: Support ipv6 addresses.
From: Stephen Hemminger @ 2010-11-29 22:33 UTC (permalink / raw)
To: David Miller; +Cc: netdev
In-Reply-To: <20101129.134403.179947389.davem@davemloft.net>
On Mon, 29 Nov 2010 13:44:03 -0800 (PST)
David Miller <davem@davemloft.net> wrote:
> +static inline bool inet_peer_addr_equal(inet_peer_address_t *a, inet_peer_address_t *b)
Let the compiler decide about inline.
Should be const inet_peer_address_t *
--
^ permalink raw reply
* Re: [PATCH v2 0/4] kthread: NUMA aware kthread_create_on_cpu()
From: Rusty Russell @ 2010-11-29 23:31 UTC (permalink / raw)
To: Eric Dumazet
Cc: David Miller, Andrew Morton, andi, linux-kernel, linux-arch,
netdev, tj, tony.luck, fenghua.yu
In-Reply-To: <1291053583.3435.1269.camel@edumazet-laptop>
On Tue, 30 Nov 2010 04:29:43 am Eric Dumazet wrote:
> Le lundi 29 novembre 2010 à 09:39 -0800, David Miller a écrit :
> > From: Eric Dumazet <eric.dumazet@gmail.com>
> > Date: Mon, 29 Nov 2010 16:13:23 +0100
> >
> > > Note : compiled and tested on x86_32 and x86_64 only, but these patches
> > > take care of other arches as well.
> > >
> > > Cc: linux-arch@vger.kernel.org
> > >
> > > Thanks for your feedback Andi !
> >
> > I'm fine with these changes:
> >
> > Acked-by: David S. Miller <davem@davemloft.net>
> >
> > Since the majority is non-networking it is pretty clear
> > that someone other than me should integrate these patches.
> > :-)
>
> Sure !
>
> I was thinking Andrew was the guy to carry this patch series, once
> things settle down of course...
I'm happy with that.
Acked-by: Rusty Russell <rusty@rustcorp.com.au>
Cheers,
Rusty.
^ permalink raw reply
* Re: [PATCH] net/r8169: Correct the ram code for RTL8111D(L)
From: Francois Romieu @ 2010-11-29 23:33 UTC (permalink / raw)
To: hayeswang
Cc: 'Ben Hutchings', netdev, linux-kernel,
'David Miller', 564628
In-Reply-To: <CE0F8B12F31D4E82860F4CE06907E98B@realtek.com.tw>
[-- Attachment #1: Type: text/plain, Size: 1108 bytes --]
hayeswang <hayeswang@realtek.com> :
> Excuse me, I have some questions about the firmware patch.
>
> 1. I should convert the data into the binary files (.bin). Is it right?
You may do it.
Fwiw I have cooked something for it in the attached patch #9 this WE. Feel
free to take bits from it. I will not do more changes while you work on it.
> 2. Where should I update the firmware files? Is the path the
> linux-2.6/firmware?
! This directory is only here to contain firmware images extracted from old
! device drivers which predate the common use of request_firmware().
It is fine for the existing code.
> However, according to linux-2.6/firmeware/README.AddingFirmware, I
> should update they to another repository:
>
> git://git.kernel.org/pub/scm/linux/kernel/git/dwmw2/linux-firmware.git
/me scratches head.
Assuming Realtek does not intend to stand this code / data as GPLable, yes.
It will help people staying clear from non-free code, it will help packaging
something useful and it will remove some cruft from the code.
So everybody will end happy. Especially after an aspirin.
--
Ueimor
[-- Attachment #2: 0001-Correct-the-binary-code-Low-pass-filter-DLY_CAP-fine.patch --]
[-- Type: text/plain, Size: 6873 bytes --]
>From da437a4f6a2483589b9da6d3b96f6655699a6923 Mon Sep 17 00:00:00 2001
From: Francois Romieu <romieu@fr.zoreil.com>
Date: Sat, 27 Nov 2010 00:13:32 +0100
Subject: [PATCH 1/9] Correct the binary code (Low pass filter & DLY_CAP fine tune from uC).
The incorrect ram code would make the nic working abnormally.
Signed-off-by: Hayes Wang <hayeswang@realtek.com>
Acked-by: Francois Romieu <romieu@fr.zoreil.com>
---
drivers/net/r8169.c | 141 +++++++++++++++++++++++++++++++++++++++++----------
1 files changed, 113 insertions(+), 28 deletions(-)
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
index 7d33ef4..114b9ce 100644
--- a/drivers/net/r8169.c
+++ b/drivers/net/r8169.c
@@ -1718,6 +1718,7 @@ static void rtl8168c_4_hw_phy_config(void __iomem *ioaddr)
static void rtl8168d_1_hw_phy_config(void __iomem *ioaddr)
{
static const struct phy_reg phy_reg_init_0[] = {
+ /* Channel Estimation */
{ 0x1f, 0x0001 },
{ 0x06, 0x4064 },
{ 0x07, 0x2863 },
@@ -1734,19 +1735,33 @@ static void rtl8168d_1_hw_phy_config(void __iomem *ioaddr)
{ 0x12, 0xf49f },
{ 0x13, 0x070b },
{ 0x1a, 0x05ad },
- { 0x14, 0x94c0 }
- };
- static const struct phy_reg phy_reg_init_1[] = {
+ { 0x14, 0x94c0 },
+
+ /*
+ * Tx Error Issue
+ * enhance line driver power
+ */
{ 0x1f, 0x0002 },
{ 0x06, 0x5561 },
{ 0x1f, 0x0005 },
{ 0x05, 0x8332 },
- { 0x06, 0x5561 }
+ { 0x06, 0x5561 },
+
+ /*
+ * Can not link to 1Gbps with bad cable
+ * Decrease SNR threshold form 21.07dB to 19.04dB
+ */
+ { 0x1f, 0x0001 },
+ { 0x17, 0x0cc0 },
+
+ { 0x1f, 0x0000 },
+ { 0x0d, 0xf880 }
};
static const struct phy_reg phy_reg_init_2[] = {
+ /* Low pass filter & DLY_CAP fine tune from uC */
{ 0x1f, 0x0005 },
- { 0x05, 0xffc2 },
- { 0x1f, 0x0005 },
+ { 0x05, 0xfff6 },
+ { 0x06, 0x0080 },
{ 0x05, 0x8000 },
{ 0x06, 0xf8f9 },
{ 0x06, 0xfaef },
@@ -2084,29 +2099,51 @@ static void rtl8168d_1_hw_phy_config(void __iomem *ioaddr)
{ 0x06, 0xff01 },
{ 0x06, 0x4edd },
{ 0x06, 0xff01 },
- { 0x05, 0x83d4 },
- { 0x06, 0x8000 },
+ { 0x06, 0xf8fa },
+ { 0x06, 0xfbef },
+ { 0x06, 0x79bf },
+ { 0x06, 0xf822 },
+ { 0x06, 0xd819 },
+ { 0x06, 0xd958 },
+ { 0x06, 0x849f },
+ { 0x06, 0x09bf },
+ { 0x06, 0x82be },
+ { 0x06, 0xd682 },
+ { 0x06, 0xc602 },
+ { 0x06, 0x014f },
+ { 0x06, 0xef97 },
+ { 0x06, 0xfffe },
+ { 0x06, 0xfc05 },
+ { 0x06, 0x17ff },
+ { 0x06, 0xfe01 },
+ { 0x06, 0x1700 },
+ { 0x06, 0x0102 },
{ 0x05, 0x83d8 },
{ 0x06, 0x8051 },
- { 0x02, 0x6010 },
+ { 0x05, 0x83d6 },
+ { 0x06, 0x82a0 },
+ { 0x05, 0x83d4 },
+ { 0x06, 0x8000 },
+ { 0x02, 0x2010 },
{ 0x03, 0xdc00 },
+ { 0x1f, 0x0000 },
+ { 0x0b, 0x0600 },
+ { 0x1f, 0x0005 },
{ 0x05, 0xfff6 },
{ 0x06, 0x00fc },
- { 0x1f, 0x0000 },
-
- { 0x1f, 0x0000 },
- { 0x0d, 0xf880 },
{ 0x1f, 0x0000 }
};
rtl_phy_write(ioaddr, phy_reg_init_0, ARRAY_SIZE(phy_reg_init_0));
+ /*
+ * Rx Error Issue
+ * Fine Tune Switching regulator parameter
+ */
mdio_write(ioaddr, 0x1f, 0x0002);
mdio_plus_minus(ioaddr, 0x0b, 0x0010, 0x00ef);
mdio_plus_minus(ioaddr, 0x0c, 0xa200, 0x5d00);
- rtl_phy_write(ioaddr, phy_reg_init_1, ARRAY_SIZE(phy_reg_init_1));
-
if (rtl8168d_efuse_read(ioaddr, 0x01) == 0xb1) {
static const struct phy_reg phy_reg_init[] = {
{ 0x1f, 0x0002 },
@@ -2147,20 +2184,28 @@ static void rtl8168d_1_hw_phy_config(void __iomem *ioaddr)
rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
}
+ /* RSET couple improve */
mdio_write(ioaddr, 0x1f, 0x0002);
mdio_patch(ioaddr, 0x0d, 0x0300);
mdio_patch(ioaddr, 0x0f, 0x0010);
+ /* Fine tune PLL performance */
mdio_write(ioaddr, 0x1f, 0x0002);
mdio_plus_minus(ioaddr, 0x02, 0x0100, 0x0600);
mdio_plus_minus(ioaddr, 0x03, 0x0000, 0xe000);
- rtl_phy_write(ioaddr, phy_reg_init_2, ARRAY_SIZE(phy_reg_init_2));
+ mdio_write(ioaddr, 0x1f, 0x0005);
+ mdio_write(ioaddr, 0x05, 0x001b);
+ if (mdio_read(ioaddr, 0x06) == 0xbf00)
+ rtl_phy_write(ioaddr, phy_reg_init_2, ARRAY_SIZE(phy_reg_init_2));
+
+ mdio_write(ioaddr, 0x1f, 0x0000);
}
static void rtl8168d_2_hw_phy_config(void __iomem *ioaddr)
{
static const struct phy_reg phy_reg_init_0[] = {
+ /* Channel Estimation */
{ 0x1f, 0x0001 },
{ 0x06, 0x4064 },
{ 0x07, 0x2863 },
@@ -2179,16 +2224,31 @@ static void rtl8168d_2_hw_phy_config(void __iomem *ioaddr)
{ 0x1a, 0x05ad },
{ 0x14, 0x94c0 },
+ /*
+ * Tx Error Issue
+ * enhance line driver power
+ */
{ 0x1f, 0x0002 },
{ 0x06, 0x5561 },
{ 0x1f, 0x0005 },
{ 0x05, 0x8332 },
- { 0x06, 0x5561 }
+ { 0x06, 0x5561 },
+
+ /*
+ * Can not link to 1Gbps with bad cable
+ * Decrease SNR threshold form 21.07dB to 19.04dB
+ */
+ { 0x1f, 0x0001 },
+ { 0x17, 0x0cc0 },
+
+ { 0x1f, 0x0000 },
+ { 0x0d, 0xf880 }
};
static const struct phy_reg phy_reg_init_1[] = {
+ /* Low pass filter & DLY_CAP fine tune from uC */
{ 0x1f, 0x0005 },
- { 0x05, 0xffc2 },
- { 0x1f, 0x0005 },
+ { 0x05, 0xfff6 },
+ { 0x06, 0x0080 },
{ 0x05, 0x8000 },
{ 0x06, 0xf8f9 },
{ 0x06, 0xfaee },
@@ -2485,16 +2545,37 @@ static void rtl8168d_2_hw_phy_config(void __iomem *ioaddr)
{ 0x06, 0xdfff },
{ 0x06, 0x014e },
{ 0x06, 0xddff },
- { 0x06, 0x0100 },
+ { 0x06, 0x01f8 },
+ { 0x06, 0xfafb },
+ { 0x06, 0xef79 },
+ { 0x06, 0xbff8 },
+ { 0x06, 0x22d8 },
+ { 0x06, 0x19d9 },
+ { 0x06, 0x5884 },
+ { 0x06, 0x9f09 },
+ { 0x06, 0xbf82 },
+ { 0x06, 0x6dd6 },
+ { 0x06, 0x8275 },
+ { 0x06, 0x0201 },
+ { 0x06, 0x4fef },
+ { 0x06, 0x97ff },
+ { 0x06, 0xfefc },
+ { 0x06, 0x0517 },
+ { 0x06, 0xfffe },
+ { 0x06, 0x0117 },
+ { 0x06, 0x0001 },
+ { 0x06, 0x0200 },
{ 0x05, 0x83d8 },
{ 0x06, 0x8000 },
+ { 0x05, 0x83d6 },
+ { 0x06, 0x824f },
+ { 0x02, 0x2010 },
{ 0x03, 0xdc00 },
+ { 0x1f, 0x0000 },
+ { 0x0b, 0x0600 },
+ { 0x1f, 0x0005 },
{ 0x05, 0xfff6 },
{ 0x06, 0x00fc },
- { 0x1f, 0x0000 },
-
- { 0x1f, 0x0000 },
- { 0x0d, 0xf880 },
{ 0x1f, 0x0000 }
};
@@ -2540,17 +2621,21 @@ static void rtl8168d_2_hw_phy_config(void __iomem *ioaddr)
rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
}
+ /* Fine tune PLL performance */
mdio_write(ioaddr, 0x1f, 0x0002);
mdio_plus_minus(ioaddr, 0x02, 0x0100, 0x0600);
mdio_plus_minus(ioaddr, 0x03, 0x0000, 0xe000);
- mdio_write(ioaddr, 0x1f, 0x0001);
- mdio_write(ioaddr, 0x17, 0x0cc0);
-
+ /* Switching regulator Slew rate */
mdio_write(ioaddr, 0x1f, 0x0002);
mdio_patch(ioaddr, 0x0f, 0x0017);
- rtl_phy_write(ioaddr, phy_reg_init_1, ARRAY_SIZE(phy_reg_init_1));
+ mdio_write(ioaddr, 0x1f, 0x0005);
+ mdio_write(ioaddr, 0x05, 0x001b);
+ if (mdio_read(ioaddr, 0x06) == 0xb300)
+ rtl_phy_write(ioaddr, phy_reg_init_1, ARRAY_SIZE(phy_reg_init_1));
+
+ mdio_write(ioaddr, 0x1f, 0x0000);
}
static void rtl8168d_3_hw_phy_config(void __iomem *ioaddr)
--
1.7.3.2
[-- Attachment #3: 0002-r8169-identify-different-registers.patch --]
[-- Type: text/plain, Size: 3244 bytes --]
>From 673eb7bf34422ed0078af92d09dc66584cc29fa5 Mon Sep 17 00:00:00 2001
From: Francois Romieu <romieu@fr.zoreil.com>
Date: Thu, 23 Sep 2010 23:34:09 +0200
Subject: [PATCH 2/9] r8169: identify different registers.
Documentation.
The location are the same, the values are the same but it is
just accidental. Note that the 810x could cope with a smaller
value as it does not support jumbo frames.
Signed-off-by: Francois Romieu <romieu@fr.zoreil.com>
Cc: Hayes <hayeswang@realtek.com>
---
drivers/net/r8169.c | 22 ++++++++++++++--------
1 files changed, 14 insertions(+), 8 deletions(-)
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
index 114b9ce..6e80df6 100644
--- a/drivers/net/r8169.c
+++ b/drivers/net/r8169.c
@@ -63,7 +63,6 @@ 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 SafeMtu 0x1c20 /* ... actually life sucks beyond ~7k */
#define InterFrameGap 0x03 /* 3 means InterFrameGap = the shortest one */
@@ -227,7 +226,14 @@ enum rtl_registers {
IntrMitigate = 0xe2,
RxDescAddrLow = 0xe4,
RxDescAddrHigh = 0xe8,
- EarlyTxThres = 0xec,
+ EarlyTxThres = 0xec, /* 8169. Unit of 32 bytes. */
+
+#define NoEarlyTx 0x3f /* Max value : no early transmit. */
+
+ MaxTxPacketSize = 0xec, /* 8101/8168. Unit of 128 bytes. */
+
+#define TxPacketMax (8064 >> 7)
+
FuncEvent = 0xf0,
FuncEventMask = 0xf4,
FuncPresetState = 0xf8,
@@ -3522,7 +3528,7 @@ static void rtl_hw_start_8169(struct net_device *dev)
(tp->mac_version == RTL_GIGA_MAC_VER_04))
RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
- RTL_W8(EarlyTxThres, EarlyTxThld);
+ RTL_W8(EarlyTxThres, NoEarlyTx);
rtl_set_rx_max_size(ioaddr, rx_buf_sz);
@@ -3657,7 +3663,7 @@ static void rtl_hw_start_8168bef(void __iomem *ioaddr, struct pci_dev *pdev)
{
rtl_hw_start_8168bb(ioaddr, pdev);
- RTL_W8(EarlyTxThres, EarlyTxThld);
+ RTL_W8(MaxTxPacketSize, 0x3f);
RTL_W8(Config4, RTL_R8(Config4) & ~(1 << 0));
}
@@ -3712,7 +3718,7 @@ static void rtl_hw_start_8168cp_3(void __iomem *ioaddr, struct pci_dev *pdev)
/* Magic. */
RTL_W8(DBG_REG, 0x20);
- RTL_W8(EarlyTxThres, EarlyTxThld);
+ RTL_W8(MaxTxPacketSize, TxPacketMax);
rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
@@ -3768,7 +3774,7 @@ static void rtl_hw_start_8168d(void __iomem *ioaddr, struct pci_dev *pdev)
rtl_disable_clock_request(pdev);
- RTL_W8(EarlyTxThres, EarlyTxThld);
+ RTL_W8(MaxTxPacketSize, TxPacketMax);
rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
@@ -3783,7 +3789,7 @@ static void rtl_hw_start_8168(struct net_device *dev)
RTL_W8(Cfg9346, Cfg9346_Unlock);
- RTL_W8(EarlyTxThres, EarlyTxThld);
+ RTL_W8(MaxTxPacketSize, TxPacketMax);
rtl_set_rx_max_size(ioaddr, rx_buf_sz);
@@ -3963,7 +3969,7 @@ static void rtl_hw_start_8101(struct net_device *dev)
RTL_W8(Cfg9346, Cfg9346_Unlock);
- RTL_W8(EarlyTxThres, EarlyTxThld);
+ RTL_W8(MaxTxPacketSize, TxPacketMax);
rtl_set_rx_max_size(ioaddr, rx_buf_sz);
--
1.7.3.2
[-- Attachment #4: 0003-r8169-use-device-dependent-methods-to-access-the-MII.patch --]
[-- Type: text/plain, Size: 24064 bytes --]
>From b84eaf51494f6e46609f2fb0c8961bf99c6ea9ec Mon Sep 17 00:00:00 2001
From: Francois Romieu <romieu@fr.zoreil.com>
Date: Fri, 1 Oct 2010 00:28:16 +0200
Subject: [PATCH 3/9] r8169: use device dependent methods to access the MII registers.
Current mdio_{read/write} can not reach enough information to
work correctly with newer chipsets.
Signed-off-by: Francois Romieu <romieu@fr.zoreil.com>
Cc: Hayes <hayeswang@realtek.com>
---
drivers/net/r8169.c | 309 ++++++++++++++++++++++++++-------------------------
1 files changed, 160 insertions(+), 149 deletions(-)
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
index 6e80df6..790d34a 100644
--- a/drivers/net/r8169.c
+++ b/drivers/net/r8169.c
@@ -498,9 +498,9 @@ struct rtl8169_private {
#endif
int (*set_speed)(struct net_device *, u8 autoneg, u16 speed, u8 duplex);
int (*get_settings)(struct net_device *, struct ethtool_cmd *);
- void (*phy_reset_enable)(void __iomem *);
+ void (*phy_reset_enable)(struct rtl8169_private *tp);
void (*hw_start)(struct net_device *);
- unsigned int (*phy_reset_pending)(void __iomem *);
+ unsigned int (*phy_reset_pending)(struct rtl8169_private *tp);
unsigned int (*link_ok)(void __iomem *);
int (*do_ioctl)(struct rtl8169_private *tp, struct mii_ioctl_data *data, int cmd);
int pcie_cap;
@@ -541,7 +541,7 @@ static int rtl8169_poll(struct napi_struct *napi, int budget);
static const unsigned int rtl8169_rx_config =
(RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift);
-static void mdio_write(void __iomem *ioaddr, int reg_addr, int value)
+static void r8169_mdio_write(void __iomem *ioaddr, int reg_addr, int value)
{
int i;
@@ -563,7 +563,7 @@ static void mdio_write(void __iomem *ioaddr, int reg_addr, int value)
udelay(20);
}
-static int mdio_read(void __iomem *ioaddr, int reg_addr)
+static int r8169_mdio_read(void __iomem *ioaddr, int reg_addr)
{
int i, value = -1;
@@ -589,34 +589,42 @@ static int mdio_read(void __iomem *ioaddr, int reg_addr)
return value;
}
-static void mdio_patch(void __iomem *ioaddr, int reg_addr, int value)
+static void rtl_writephy(struct rtl8169_private *tp, int location, u32 val)
{
- mdio_write(ioaddr, reg_addr, mdio_read(ioaddr, reg_addr) | value);
+ r8169_mdio_write(tp->mmio_addr, location, val);
}
-static void mdio_plus_minus(void __iomem *ioaddr, int reg_addr, int p, int m)
+static int rtl_readphy(struct rtl8169_private *tp, int location)
+{
+ return r8169_mdio_read(tp->mmio_addr, location);
+}
+
+static void rtl_patchphy(struct rtl8169_private *tp, int reg_addr, int value)
+{
+ rtl_writephy(tp, reg_addr, rtl_readphy(tp, reg_addr) | value);
+}
+
+static void rtl_w1w0_phy(struct rtl8169_private *tp, int reg_addr, int p, int m)
{
int val;
- val = mdio_read(ioaddr, reg_addr);
- mdio_write(ioaddr, reg_addr, (val | p) & ~m);
+ val = rtl_readphy(tp, reg_addr);
+ rtl_writephy(tp, reg_addr, (val | p) & ~m);
}
static void rtl_mdio_write(struct net_device *dev, int phy_id, int location,
int val)
{
struct rtl8169_private *tp = netdev_priv(dev);
- void __iomem *ioaddr = tp->mmio_addr;
- mdio_write(ioaddr, location, val);
+ rtl_writephy(tp, location, val);
}
static int rtl_mdio_read(struct net_device *dev, int phy_id, int location)
{
struct rtl8169_private *tp = netdev_priv(dev);
- void __iomem *ioaddr = tp->mmio_addr;
- return mdio_read(ioaddr, location);
+ return rtl_readphy(tp, location);
}
static void rtl_ephy_write(void __iomem *ioaddr, int reg_addr, int value)
@@ -717,14 +725,16 @@ static void rtl8169_asic_down(void __iomem *ioaddr)
RTL_R16(CPlusCmd);
}
-static unsigned int rtl8169_tbi_reset_pending(void __iomem *ioaddr)
+static unsigned int rtl8169_tbi_reset_pending(struct rtl8169_private *tp)
{
+ void __iomem *ioaddr = tp->mmio_addr;
+
return RTL_R32(TBICSR) & TBIReset;
}
-static unsigned int rtl8169_xmii_reset_pending(void __iomem *ioaddr)
+static unsigned int rtl8169_xmii_reset_pending(struct rtl8169_private *tp)
{
- return mdio_read(ioaddr, MII_BMCR) & BMCR_RESET;
+ return rtl_readphy(tp, MII_BMCR) & BMCR_RESET;
}
static unsigned int rtl8169_tbi_link_ok(void __iomem *ioaddr)
@@ -737,17 +747,19 @@ static unsigned int rtl8169_xmii_link_ok(void __iomem *ioaddr)
return RTL_R8(PHYstatus) & LinkStatus;
}
-static void rtl8169_tbi_reset_enable(void __iomem *ioaddr)
+static void rtl8169_tbi_reset_enable(struct rtl8169_private *tp)
{
+ void __iomem *ioaddr = tp->mmio_addr;
+
RTL_W32(TBICSR, RTL_R32(TBICSR) | TBIReset);
}
-static void rtl8169_xmii_reset_enable(void __iomem *ioaddr)
+static void rtl8169_xmii_reset_enable(struct rtl8169_private *tp)
{
unsigned int val;
- val = mdio_read(ioaddr, MII_BMCR) | BMCR_RESET;
- mdio_write(ioaddr, MII_BMCR, val & 0xffff);
+ val = rtl_readphy(tp, MII_BMCR) | BMCR_RESET;
+ rtl_writephy(tp, MII_BMCR, val & 0xffff);
}
static void rtl8169_check_link_status(struct net_device *dev,
@@ -901,18 +913,17 @@ static int rtl8169_set_speed_xmii(struct net_device *dev,
u8 autoneg, u16 speed, u8 duplex)
{
struct rtl8169_private *tp = netdev_priv(dev);
- void __iomem *ioaddr = tp->mmio_addr;
int giga_ctrl, bmcr;
if (autoneg == AUTONEG_ENABLE) {
int auto_nego;
- auto_nego = mdio_read(ioaddr, MII_ADVERTISE);
+ auto_nego = rtl_readphy(tp, MII_ADVERTISE);
auto_nego |= (ADVERTISE_10HALF | ADVERTISE_10FULL |
ADVERTISE_100HALF | ADVERTISE_100FULL);
auto_nego |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
- giga_ctrl = mdio_read(ioaddr, MII_CTRL1000);
+ giga_ctrl = rtl_readphy(tp, MII_CTRL1000);
giga_ctrl &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
/* The 8100e/8101e/8102e do Fast Ethernet only. */
@@ -940,12 +951,12 @@ static int rtl8169_set_speed_xmii(struct net_device *dev,
* Vendor specific (0x1f) and reserved (0x0e) MII
* registers.
*/
- mdio_write(ioaddr, 0x1f, 0x0000);
- mdio_write(ioaddr, 0x0e, 0x0000);
+ rtl_writephy(tp, 0x1f, 0x0000);
+ rtl_writephy(tp, 0x0e, 0x0000);
}
- mdio_write(ioaddr, MII_ADVERTISE, auto_nego);
- mdio_write(ioaddr, MII_CTRL1000, giga_ctrl);
+ rtl_writephy(tp, MII_ADVERTISE, auto_nego);
+ rtl_writephy(tp, MII_CTRL1000, giga_ctrl);
} else {
giga_ctrl = 0;
@@ -959,21 +970,21 @@ static int rtl8169_set_speed_xmii(struct net_device *dev,
if (duplex == DUPLEX_FULL)
bmcr |= BMCR_FULLDPLX;
- mdio_write(ioaddr, 0x1f, 0x0000);
+ rtl_writephy(tp, 0x1f, 0x0000);
}
tp->phy_1000_ctrl_reg = giga_ctrl;
- mdio_write(ioaddr, MII_BMCR, bmcr);
+ rtl_writephy(tp, MII_BMCR, bmcr);
if ((tp->mac_version == RTL_GIGA_MAC_VER_02) ||
(tp->mac_version == RTL_GIGA_MAC_VER_03)) {
if ((speed == SPEED_100) && (autoneg != AUTONEG_ENABLE)) {
- mdio_write(ioaddr, 0x17, 0x2138);
- mdio_write(ioaddr, 0x0e, 0x0260);
+ rtl_writephy(tp, 0x17, 0x2138);
+ rtl_writephy(tp, 0x0e, 0x0260);
} else {
- mdio_write(ioaddr, 0x17, 0x2108);
- mdio_write(ioaddr, 0x0e, 0x0000);
+ rtl_writephy(tp, 0x17, 0x2108);
+ rtl_writephy(tp, 0x0e, 0x0000);
}
}
@@ -1381,15 +1392,16 @@ struct phy_reg {
u16 val;
};
-static void rtl_phy_write(void __iomem *ioaddr, const struct phy_reg *regs, int len)
+static void rtl_writephy_batch(struct rtl8169_private *tp,
+ const struct phy_reg *regs, int len)
{
while (len-- > 0) {
- mdio_write(ioaddr, regs->reg, regs->val);
+ rtl_writephy(tp, regs->reg, regs->val);
regs++;
}
}
-static void rtl8169s_hw_phy_config(void __iomem *ioaddr)
+static void rtl8169s_hw_phy_config(struct rtl8169_private *tp)
{
static const struct phy_reg phy_reg_init[] = {
{ 0x1f, 0x0001 },
@@ -1453,10 +1465,10 @@ static void rtl8169s_hw_phy_config(void __iomem *ioaddr)
{ 0x00, 0x9200 }
};
- rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+ rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
}
-static void rtl8169sb_hw_phy_config(void __iomem *ioaddr)
+static void rtl8169sb_hw_phy_config(struct rtl8169_private *tp)
{
static const struct phy_reg phy_reg_init[] = {
{ 0x1f, 0x0002 },
@@ -1464,11 +1476,10 @@ static void rtl8169sb_hw_phy_config(void __iomem *ioaddr)
{ 0x1f, 0x0000 }
};
- rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+ rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
}
-static void rtl8169scd_hw_phy_config_quirk(struct rtl8169_private *tp,
- void __iomem *ioaddr)
+static void rtl8169scd_hw_phy_config_quirk(struct rtl8169_private *tp)
{
struct pci_dev *pdev = tp->pci_dev;
u16 vendor_id, device_id;
@@ -1479,13 +1490,12 @@ static void rtl8169scd_hw_phy_config_quirk(struct rtl8169_private *tp,
if ((vendor_id != PCI_VENDOR_ID_GIGABYTE) || (device_id != 0xe000))
return;
- mdio_write(ioaddr, 0x1f, 0x0001);
- mdio_write(ioaddr, 0x10, 0xf01b);
- mdio_write(ioaddr, 0x1f, 0x0000);
+ rtl_writephy(tp, 0x1f, 0x0001);
+ rtl_writephy(tp, 0x10, 0xf01b);
+ rtl_writephy(tp, 0x1f, 0x0000);
}
-static void rtl8169scd_hw_phy_config(struct rtl8169_private *tp,
- void __iomem *ioaddr)
+static void rtl8169scd_hw_phy_config(struct rtl8169_private *tp)
{
static const struct phy_reg phy_reg_init[] = {
{ 0x1f, 0x0001 },
@@ -1527,12 +1537,12 @@ static void rtl8169scd_hw_phy_config(struct rtl8169_private *tp,
{ 0x1f, 0x0000 }
};
- rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+ rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
- rtl8169scd_hw_phy_config_quirk(tp, ioaddr);
+ rtl8169scd_hw_phy_config_quirk(tp);
}
-static void rtl8169sce_hw_phy_config(void __iomem *ioaddr)
+static void rtl8169sce_hw_phy_config(struct rtl8169_private *tp)
{
static const struct phy_reg phy_reg_init[] = {
{ 0x1f, 0x0001 },
@@ -1582,23 +1592,23 @@ static void rtl8169sce_hw_phy_config(void __iomem *ioaddr)
{ 0x1f, 0x0000 }
};
- rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+ rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
}
-static void rtl8168bb_hw_phy_config(void __iomem *ioaddr)
+static void rtl8168bb_hw_phy_config(struct rtl8169_private *tp)
{
static const struct phy_reg phy_reg_init[] = {
{ 0x10, 0xf41b },
{ 0x1f, 0x0000 }
};
- mdio_write(ioaddr, 0x1f, 0x0001);
- mdio_patch(ioaddr, 0x16, 1 << 0);
+ rtl_writephy(tp, 0x1f, 0x0001);
+ rtl_patchphy(tp, 0x16, 1 << 0);
- rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+ rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
}
-static void rtl8168bef_hw_phy_config(void __iomem *ioaddr)
+static void rtl8168bef_hw_phy_config(struct rtl8169_private *tp)
{
static const struct phy_reg phy_reg_init[] = {
{ 0x1f, 0x0001 },
@@ -1606,10 +1616,10 @@ static void rtl8168bef_hw_phy_config(void __iomem *ioaddr)
{ 0x1f, 0x0000 }
};
- rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+ rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
}
-static void rtl8168cp_1_hw_phy_config(void __iomem *ioaddr)
+static void rtl8168cp_1_hw_phy_config(struct rtl8169_private *tp)
{
static const struct phy_reg phy_reg_init[] = {
{ 0x1f, 0x0000 },
@@ -1619,10 +1629,10 @@ static void rtl8168cp_1_hw_phy_config(void __iomem *ioaddr)
{ 0x1f, 0x0000 }
};
- rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+ rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
}
-static void rtl8168cp_2_hw_phy_config(void __iomem *ioaddr)
+static void rtl8168cp_2_hw_phy_config(struct rtl8169_private *tp)
{
static const struct phy_reg phy_reg_init[] = {
{ 0x1f, 0x0001 },
@@ -1630,14 +1640,14 @@ static void rtl8168cp_2_hw_phy_config(void __iomem *ioaddr)
{ 0x1f, 0x0000 }
};
- mdio_write(ioaddr, 0x1f, 0x0000);
- mdio_patch(ioaddr, 0x14, 1 << 5);
- mdio_patch(ioaddr, 0x0d, 1 << 5);
+ rtl_writephy(tp, 0x1f, 0x0000);
+ rtl_patchphy(tp, 0x14, 1 << 5);
+ rtl_patchphy(tp, 0x0d, 1 << 5);
- rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+ rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
}
-static void rtl8168c_1_hw_phy_config(void __iomem *ioaddr)
+static void rtl8168c_1_hw_phy_config(struct rtl8169_private *tp)
{
static const struct phy_reg phy_reg_init[] = {
{ 0x1f, 0x0001 },
@@ -1659,14 +1669,14 @@ static void rtl8168c_1_hw_phy_config(void __iomem *ioaddr)
{ 0x09, 0x0000 }
};
- rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+ rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
- mdio_patch(ioaddr, 0x14, 1 << 5);
- mdio_patch(ioaddr, 0x0d, 1 << 5);
- mdio_write(ioaddr, 0x1f, 0x0000);
+ rtl_patchphy(tp, 0x14, 1 << 5);
+ rtl_patchphy(tp, 0x0d, 1 << 5);
+ rtl_writephy(tp, 0x1f, 0x0000);
}
-static void rtl8168c_2_hw_phy_config(void __iomem *ioaddr)
+static void rtl8168c_2_hw_phy_config(struct rtl8169_private *tp)
{
static const struct phy_reg phy_reg_init[] = {
{ 0x1f, 0x0001 },
@@ -1686,15 +1696,15 @@ static void rtl8168c_2_hw_phy_config(void __iomem *ioaddr)
{ 0x1f, 0x0000 }
};
- rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+ rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
- mdio_patch(ioaddr, 0x16, 1 << 0);
- mdio_patch(ioaddr, 0x14, 1 << 5);
- mdio_patch(ioaddr, 0x0d, 1 << 5);
- mdio_write(ioaddr, 0x1f, 0x0000);
+ rtl_patchphy(tp, 0x16, 1 << 0);
+ rtl_patchphy(tp, 0x14, 1 << 5);
+ rtl_patchphy(tp, 0x0d, 1 << 5);
+ rtl_writephy(tp, 0x1f, 0x0000);
}
-static void rtl8168c_3_hw_phy_config(void __iomem *ioaddr)
+static void rtl8168c_3_hw_phy_config(struct rtl8169_private *tp)
{
static const struct phy_reg phy_reg_init[] = {
{ 0x1f, 0x0001 },
@@ -1708,21 +1718,22 @@ static void rtl8168c_3_hw_phy_config(void __iomem *ioaddr)
{ 0x1f, 0x0000 }
};
- rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+ rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
- mdio_patch(ioaddr, 0x16, 1 << 0);
- mdio_patch(ioaddr, 0x14, 1 << 5);
- mdio_patch(ioaddr, 0x0d, 1 << 5);
- mdio_write(ioaddr, 0x1f, 0x0000);
+ rtl_patchphy(tp, 0x16, 1 << 0);
+ rtl_patchphy(tp, 0x14, 1 << 5);
+ rtl_patchphy(tp, 0x0d, 1 << 5);
+ rtl_writephy(tp, 0x1f, 0x0000);
}
-static void rtl8168c_4_hw_phy_config(void __iomem *ioaddr)
+static void rtl8168c_4_hw_phy_config(struct rtl8169_private *tp)
{
- rtl8168c_3_hw_phy_config(ioaddr);
+ rtl8168c_3_hw_phy_config(tp);
}
-static void rtl8168d_1_hw_phy_config(void __iomem *ioaddr)
+static void rtl8168d_1_hw_phy_config(struct rtl8169_private *tp)
{
+ void __iomem *ioaddr = tp->mmio_addr;
static const struct phy_reg phy_reg_init_0[] = {
/* Channel Estimation */
{ 0x1f, 0x0001 },
@@ -2140,15 +2151,15 @@ static void rtl8168d_1_hw_phy_config(void __iomem *ioaddr)
{ 0x1f, 0x0000 }
};
- rtl_phy_write(ioaddr, phy_reg_init_0, ARRAY_SIZE(phy_reg_init_0));
+ rtl_writephy_batch(tp, phy_reg_init_0, ARRAY_SIZE(phy_reg_init_0));
/*
* Rx Error Issue
* Fine Tune Switching regulator parameter
*/
- mdio_write(ioaddr, 0x1f, 0x0002);
- mdio_plus_minus(ioaddr, 0x0b, 0x0010, 0x00ef);
- mdio_plus_minus(ioaddr, 0x0c, 0xa200, 0x5d00);
+ rtl_writephy(tp, 0x1f, 0x0002);
+ rtl_w1w0_phy(tp, 0x0b, 0x0010, 0x00ef);
+ rtl_w1w0_phy(tp, 0x0c, 0xa200, 0x5d00);
if (rtl8168d_efuse_read(ioaddr, 0x01) == 0xb1) {
static const struct phy_reg phy_reg_init[] = {
@@ -2161,9 +2172,9 @@ static void rtl8168d_1_hw_phy_config(void __iomem *ioaddr)
};
int val;
- rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+ rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
- val = mdio_read(ioaddr, 0x0d);
+ val = rtl_readphy(tp, 0x0d);
if ((val & 0x00ff) != 0x006c) {
static const u32 set[] = {
@@ -2172,11 +2183,11 @@ static void rtl8168d_1_hw_phy_config(void __iomem *ioaddr)
};
int i;
- mdio_write(ioaddr, 0x1f, 0x0002);
+ rtl_writephy(tp, 0x1f, 0x0002);
val &= 0xff00;
for (i = 0; i < ARRAY_SIZE(set); i++)
- mdio_write(ioaddr, 0x0d, val | set[i]);
+ rtl_writephy(tp, 0x0d, val | set[i]);
}
} else {
static const struct phy_reg phy_reg_init[] = {
@@ -2187,28 +2198,28 @@ static void rtl8168d_1_hw_phy_config(void __iomem *ioaddr)
{ 0x06, 0x6662 }
};
- rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+ rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
}
/* RSET couple improve */
- mdio_write(ioaddr, 0x1f, 0x0002);
- mdio_patch(ioaddr, 0x0d, 0x0300);
- mdio_patch(ioaddr, 0x0f, 0x0010);
+ rtl_writephy(tp, 0x1f, 0x0002);
+ rtl_patchphy(tp, 0x0d, 0x0300);
+ rtl_patchphy(tp, 0x0f, 0x0010);
/* Fine tune PLL performance */
- mdio_write(ioaddr, 0x1f, 0x0002);
- mdio_plus_minus(ioaddr, 0x02, 0x0100, 0x0600);
- mdio_plus_minus(ioaddr, 0x03, 0x0000, 0xe000);
+ rtl_writephy(tp, 0x1f, 0x0002);
+ rtl_w1w0_phy(tp, 0x02, 0x0100, 0x0600);
+ rtl_w1w0_phy(tp, 0x03, 0x0000, 0xe000);
- mdio_write(ioaddr, 0x1f, 0x0005);
- mdio_write(ioaddr, 0x05, 0x001b);
- if (mdio_read(ioaddr, 0x06) == 0xbf00)
- rtl_phy_write(ioaddr, phy_reg_init_2, ARRAY_SIZE(phy_reg_init_2));
+ rtl_writephy(tp, 0x1f, 0x0005);
+ rtl_writephy(tp, 0x05, 0x001b);
+ if (rtl_readphy(tp, 0x06) == 0xbf00)
+ rtl_writephy_batch(tp, phy_reg_init_2, ARRAY_SIZE(phy_reg_init_2));
- mdio_write(ioaddr, 0x1f, 0x0000);
+ rtl_writephy(tp, 0x1f, 0x0000);
}
-static void rtl8168d_2_hw_phy_config(void __iomem *ioaddr)
+static void rtl8168d_2_hw_phy_config(struct rtl8169_private *tp)
{
static const struct phy_reg phy_reg_init_0[] = {
/* Channel Estimation */
@@ -2584,8 +2595,9 @@ static void rtl8168d_2_hw_phy_config(void __iomem *ioaddr)
{ 0x06, 0x00fc },
{ 0x1f, 0x0000 }
};
+ void __iomem *ioaddr = tp->mmio_addr;
- rtl_phy_write(ioaddr, phy_reg_init_0, ARRAY_SIZE(phy_reg_init_0));
+ rtl_writephy_batch(tp, phy_reg_init_0, ARRAY_SIZE(phy_reg_init_0));
if (rtl8168d_efuse_read(ioaddr, 0x01) == 0xb1) {
static const struct phy_reg phy_reg_init[] = {
@@ -2599,9 +2611,9 @@ static void rtl8168d_2_hw_phy_config(void __iomem *ioaddr)
};
int val;
- rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+ rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
- val = mdio_read(ioaddr, 0x0d);
+ val = rtl_readphy(tp, 0x0d);
if ((val & 0x00ff) != 0x006c) {
u32 set[] = {
0x0065, 0x0066, 0x0067, 0x0068,
@@ -2609,11 +2621,11 @@ static void rtl8168d_2_hw_phy_config(void __iomem *ioaddr)
};
int i;
- mdio_write(ioaddr, 0x1f, 0x0002);
+ rtl_writephy(tp, 0x1f, 0x0002);
val &= 0xff00;
for (i = 0; i < ARRAY_SIZE(set); i++)
- mdio_write(ioaddr, 0x0d, val | set[i]);
+ rtl_writephy(tp, 0x0d, val | set[i]);
}
} else {
static const struct phy_reg phy_reg_init[] = {
@@ -2624,27 +2636,27 @@ static void rtl8168d_2_hw_phy_config(void __iomem *ioaddr)
{ 0x06, 0x2642 }
};
- rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+ rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
}
/* Fine tune PLL performance */
- mdio_write(ioaddr, 0x1f, 0x0002);
- mdio_plus_minus(ioaddr, 0x02, 0x0100, 0x0600);
- mdio_plus_minus(ioaddr, 0x03, 0x0000, 0xe000);
+ rtl_writephy(tp, 0x1f, 0x0002);
+ rtl_w1w0_phy(tp, 0x02, 0x0100, 0x0600);
+ rtl_w1w0_phy(tp, 0x03, 0x0000, 0xe000);
/* Switching regulator Slew rate */
- mdio_write(ioaddr, 0x1f, 0x0002);
- mdio_patch(ioaddr, 0x0f, 0x0017);
+ rtl_writephy(tp, 0x1f, 0x0002);
+ rtl_patchphy(tp, 0x0f, 0x0017);
- mdio_write(ioaddr, 0x1f, 0x0005);
- mdio_write(ioaddr, 0x05, 0x001b);
- if (mdio_read(ioaddr, 0x06) == 0xb300)
- rtl_phy_write(ioaddr, phy_reg_init_1, ARRAY_SIZE(phy_reg_init_1));
+ rtl_writephy(tp, 0x1f, 0x0005);
+ rtl_writephy(tp, 0x05, 0x001b);
+ if (rtl_readphy(tp, 0x06) == 0xb300)
+ rtl_writephy_batch(tp, phy_reg_init_1, ARRAY_SIZE(phy_reg_init_1));
- mdio_write(ioaddr, 0x1f, 0x0000);
+ rtl_writephy(tp, 0x1f, 0x0000);
}
-static void rtl8168d_3_hw_phy_config(void __iomem *ioaddr)
+static void rtl8168d_3_hw_phy_config(struct rtl8169_private *tp)
{
static const struct phy_reg phy_reg_init[] = {
{ 0x1f, 0x0002 },
@@ -2702,10 +2714,10 @@ static void rtl8168d_3_hw_phy_config(void __iomem *ioaddr)
{ 0x1f, 0x0000 }
};
- rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+ rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
}
-static void rtl8102e_hw_phy_config(void __iomem *ioaddr)
+static void rtl8102e_hw_phy_config(struct rtl8169_private *tp)
{
static const struct phy_reg phy_reg_init[] = {
{ 0x1f, 0x0003 },
@@ -2714,18 +2726,17 @@ static void rtl8102e_hw_phy_config(void __iomem *ioaddr)
{ 0x1f, 0x0000 }
};
- mdio_write(ioaddr, 0x1f, 0x0000);
- mdio_patch(ioaddr, 0x11, 1 << 12);
- mdio_patch(ioaddr, 0x19, 1 << 13);
- mdio_patch(ioaddr, 0x10, 1 << 15);
+ rtl_writephy(tp, 0x1f, 0x0000);
+ rtl_patchphy(tp, 0x11, 1 << 12);
+ rtl_patchphy(tp, 0x19, 1 << 13);
+ rtl_patchphy(tp, 0x10, 1 << 15);
- rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+ rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
}
static void rtl_hw_phy_config(struct net_device *dev)
{
struct rtl8169_private *tp = netdev_priv(dev);
- void __iomem *ioaddr = tp->mmio_addr;
rtl8169_print_mac_version(tp);
@@ -2734,58 +2745,58 @@ static void rtl_hw_phy_config(struct net_device *dev)
break;
case RTL_GIGA_MAC_VER_02:
case RTL_GIGA_MAC_VER_03:
- rtl8169s_hw_phy_config(ioaddr);
+ rtl8169s_hw_phy_config(tp);
break;
case RTL_GIGA_MAC_VER_04:
- rtl8169sb_hw_phy_config(ioaddr);
+ rtl8169sb_hw_phy_config(tp);
break;
case RTL_GIGA_MAC_VER_05:
- rtl8169scd_hw_phy_config(tp, ioaddr);
+ rtl8169scd_hw_phy_config(tp);
break;
case RTL_GIGA_MAC_VER_06:
- rtl8169sce_hw_phy_config(ioaddr);
+ rtl8169sce_hw_phy_config(tp);
break;
case RTL_GIGA_MAC_VER_07:
case RTL_GIGA_MAC_VER_08:
case RTL_GIGA_MAC_VER_09:
- rtl8102e_hw_phy_config(ioaddr);
+ rtl8102e_hw_phy_config(tp);
break;
case RTL_GIGA_MAC_VER_11:
- rtl8168bb_hw_phy_config(ioaddr);
+ rtl8168bb_hw_phy_config(tp);
break;
case RTL_GIGA_MAC_VER_12:
- rtl8168bef_hw_phy_config(ioaddr);
+ rtl8168bef_hw_phy_config(tp);
break;
case RTL_GIGA_MAC_VER_17:
- rtl8168bef_hw_phy_config(ioaddr);
+ rtl8168bef_hw_phy_config(tp);
break;
case RTL_GIGA_MAC_VER_18:
- rtl8168cp_1_hw_phy_config(ioaddr);
+ rtl8168cp_1_hw_phy_config(tp);
break;
case RTL_GIGA_MAC_VER_19:
- rtl8168c_1_hw_phy_config(ioaddr);
+ rtl8168c_1_hw_phy_config(tp);
break;
case RTL_GIGA_MAC_VER_20:
- rtl8168c_2_hw_phy_config(ioaddr);
+ rtl8168c_2_hw_phy_config(tp);
break;
case RTL_GIGA_MAC_VER_21:
- rtl8168c_3_hw_phy_config(ioaddr);
+ rtl8168c_3_hw_phy_config(tp);
break;
case RTL_GIGA_MAC_VER_22:
- rtl8168c_4_hw_phy_config(ioaddr);
+ rtl8168c_4_hw_phy_config(tp);
break;
case RTL_GIGA_MAC_VER_23:
case RTL_GIGA_MAC_VER_24:
- rtl8168cp_2_hw_phy_config(ioaddr);
+ rtl8168cp_2_hw_phy_config(tp);
break;
case RTL_GIGA_MAC_VER_25:
- rtl8168d_1_hw_phy_config(ioaddr);
+ rtl8168d_1_hw_phy_config(tp);
break;
case RTL_GIGA_MAC_VER_26:
- rtl8168d_2_hw_phy_config(ioaddr);
+ rtl8168d_2_hw_phy_config(tp);
break;
case RTL_GIGA_MAC_VER_27:
- rtl8168d_3_hw_phy_config(ioaddr);
+ rtl8168d_3_hw_phy_config(tp);
break;
default:
@@ -2914,7 +2925,7 @@ static void rtl8169_init_phy(struct net_device *dev, struct rtl8169_private *tp)
dprintk("Set MAC Reg C+CR Offset 0x82h = 0x01h\n");
RTL_W8(0x82, 0x01);
dprintk("Set PHY Reg 0x0bh = 0x00h\n");
- mdio_write(ioaddr, 0x0b, 0x0000); //w 0x0b 15 0 0
+ rtl_writephy(tp, 0x0b, 0x0000); //w 0x0b 15 0 0
}
rtl8169_phy_reset(dev, tp);
@@ -2984,11 +2995,11 @@ static int rtl_xmii_ioctl(struct rtl8169_private *tp, struct mii_ioctl_data *dat
return 0;
case SIOCGMIIREG:
- data->val_out = mdio_read(tp->mmio_addr, data->reg_num & 0x1f);
+ data->val_out = rtl_readphy(tp, data->reg_num & 0x1f);
return 0;
case SIOCSMIIREG:
- mdio_write(tp->mmio_addr, data->reg_num & 0x1f, data->val_in);
+ rtl_writephy(tp, data->reg_num & 0x1f, data->val_in);
return 0;
}
return -EOPNOTSUPP;
--
1.7.3.2
[-- Attachment #5: 0004-r8169-8168DP-specific-MII-registers-access-methods.patch --]
[-- Type: text/plain, Size: 3970 bytes --]
>From 2fec3ab72680867e74e89c8df86637e4114474ec Mon Sep 17 00:00:00 2001
From: Francois Romieu <romieu@fr.zoreil.com>
Date: Thu, 4 Nov 2010 23:07:46 +0100
Subject: [PATCH 4/9] r8169: 8168DP specific MII registers access methods.
Adapted from version 8.019.00 of Realtek's r8168 driver.
Signed-off-by: Francois Romieu <romieu@fr.zoreil.com>
Cc: Hayes <hayeswang@realtek.com>
---
drivers/net/r8169.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 81 insertions(+), 2 deletions(-)
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
index 790d34a..78e3999 100644
--- a/drivers/net/r8169.c
+++ b/drivers/net/r8169.c
@@ -273,6 +273,20 @@ enum rtl8168_8101_registers {
#define EFUSEAR_DATA_MASK 0xff
};
+enum rtl8168_registers {
+ EPHY_RXER_NUM = 0x7c,
+ OCPDR = 0xb0, /* OCP GPHY access */
+#define OCPDR_WRITE_CMD 0x80000000
+#define OCPDR_READ_CMD 0x00000000
+#define OCPDR_REG_MASK 0xff
+#define OCPDR_GPHY_REG_SHIFT 12
+#define OCPDR_DATA_MASK 0xffff
+ OCPAR = 0xb4,
+#define OCPAR_FLAG 0x80000000
+#define OCPAR_GPHY_WRITE_CMD 0x8000f060
+#define OCPAR_GPHY_READ_CMD 0x0000f060
+};
+
enum rtl_register_content {
/* InterruptStatusBits */
SYSErr = 0x8000,
@@ -496,6 +510,12 @@ struct rtl8169_private {
#ifdef CONFIG_R8169_VLAN
struct vlan_group *vlgrp;
#endif
+
+ struct mdio_ops {
+ void (*write)(void __iomem *, int, int);
+ int (*read)(void __iomem *, int);
+ } mdio_ops;
+
int (*set_speed)(struct net_device *, u8 autoneg, u16 speed, u8 duplex);
int (*get_settings)(struct net_device *, struct ethtool_cmd *);
void (*phy_reset_enable)(struct rtl8169_private *tp);
@@ -589,14 +609,55 @@ static int r8169_mdio_read(void __iomem *ioaddr, int reg_addr)
return value;
}
+static void r8168dp_1_mdio_access(void __iomem *ioaddr, int reg_addr, u32 data)
+{
+ int i;
+
+ RTL_W32(OCPDR, data |
+ ((reg_addr & OCPDR_REG_MASK) << OCPDR_GPHY_REG_SHIFT));
+ RTL_W32(OCPAR, OCPAR_GPHY_WRITE_CMD);
+ RTL_W32(EPHY_RXER_NUM, 0);
+
+ for (i = 0; i < 100; i++) {
+ mdelay(1);
+ if (!(RTL_R32(OCPAR) & OCPAR_FLAG))
+ break;
+ }
+}
+
+static void r8168dp_1_mdio_write(void __iomem *ioaddr, int reg_addr, int value)
+{
+ r8168dp_1_mdio_access(ioaddr, reg_addr, OCPDR_WRITE_CMD |
+ (value & OCPDR_DATA_MASK));
+}
+
+static int r8168dp_1_mdio_read(void __iomem *ioaddr, int reg_addr)
+{
+ int i;
+
+ r8168dp_1_mdio_access(ioaddr, reg_addr, OCPDR_READ_CMD);
+
+ mdelay(1);
+ RTL_W32(OCPAR, OCPAR_GPHY_READ_CMD);
+ RTL_W32(EPHY_RXER_NUM, 0);
+
+ for (i = 0; i < 100; i++) {
+ mdelay(1);
+ if (RTL_R32(OCPAR) & OCPAR_FLAG)
+ break;
+ }
+
+ return RTL_R32(OCPDR) & OCPDR_DATA_MASK;
+}
+
static void rtl_writephy(struct rtl8169_private *tp, int location, u32 val)
{
- r8169_mdio_write(tp->mmio_addr, location, val);
+ tp->mdio_ops.write(tp->mmio_addr, location, val);
}
static int rtl_readphy(struct rtl8169_private *tp, int location)
{
- return r8169_mdio_read(tp->mmio_addr, location);
+ return tp->mdio_ops.read(tp->mmio_addr, location);
}
static void rtl_patchphy(struct rtl8169_private *tp, int reg_addr, int value)
@@ -3099,6 +3160,22 @@ static const struct net_device_ops rtl8169_netdev_ops = {
};
+static void __devinit rtl_init_mdio_ops(struct rtl8169_private *tp)
+{
+ struct mdio_ops *ops = &tp->mdio_ops;
+
+ switch (tp->mac_version) {
+ case RTL_GIGA_MAC_VER_27:
+ ops->write = r8168dp_1_mdio_write;
+ ops->read = r8168dp_1_mdio_read;
+ break;
+ default:
+ ops->write = r8169_mdio_write;
+ ops->read = r8169_mdio_read;
+ break;
+ }
+}
+
static int __devinit
rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
@@ -3217,6 +3294,8 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
/* Identify chip attached to board */
rtl8169_get_mac_version(tp, ioaddr);
+ rtl_init_mdio_ops(tp);
+
/* Use appropriate default if unknown */
if (tp->mac_version == RTL_GIGA_MAC_NONE) {
netif_notice(tp, probe, dev,
--
1.7.3.2
[-- Attachment #6: 0005-r8169-phy-power-ops.patch --]
[-- Type: text/plain, Size: 6191 bytes --]
>From 29f7bb17c47e79e9e55fe86358d2bfab59ae3f5f Mon Sep 17 00:00:00 2001
From: Francois Romieu <romieu@fr.zoreil.com>
Date: Mon, 15 Nov 2010 23:32:55 +0100
Subject: [PATCH 5/9] r8169: phy power ops
Bits from :
- version 8.019.00 of Realtek's 8168 driver
- version 1.019.00 of Realtek's 8101 driver
Plain old 8169 (PCI) devices do not seem to need anything akin to it.
Signed-off-by: Francois Romieu <romieu@fr.zoreil.com>
---
drivers/net/r8169.c | 167 ++++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 166 insertions(+), 1 deletions(-)
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
index 78e3999..11519c8 100644
--- a/drivers/net/r8169.c
+++ b/drivers/net/r8169.c
@@ -254,7 +254,7 @@ enum rtl8168_8101_registers {
#define CSIAR_BYTE_ENABLE 0x0f
#define CSIAR_BYTE_ENABLE_SHIFT 12
#define CSIAR_ADDR_MASK 0x0fff
-
+ PMCH = 0x6f,
EPHYAR = 0x80,
#define EPHYAR_FLAG 0x80000000
#define EPHYAR_WRITE_CMD 0x80000000
@@ -516,6 +516,11 @@ struct rtl8169_private {
int (*read)(void __iomem *, int);
} mdio_ops;
+ struct pll_power_ops {
+ void (*down)(struct rtl8169_private *);
+ void (*up)(struct rtl8169_private *);
+ } pll_power_ops;
+
int (*set_speed)(struct net_device *, u8 autoneg, u16 speed, u8 duplex);
int (*get_settings)(struct net_device *, struct ethtool_cmd *);
void (*phy_reset_enable)(struct rtl8169_private *tp);
@@ -3176,6 +3181,152 @@ static void __devinit rtl_init_mdio_ops(struct rtl8169_private *tp)
}
}
+static void r810x_phy_power_down(struct rtl8169_private *tp)
+{
+ rtl_writephy(tp, 0x1f, 0x0000);
+ rtl_writephy(tp, MII_BMCR, BMCR_PDOWN);
+}
+
+static void r810x_phy_power_up(struct rtl8169_private *tp)
+{
+ rtl_writephy(tp, 0x1f, 0x0000);
+ rtl_writephy(tp, MII_BMCR, BMCR_ANENABLE);
+}
+
+static void r810x_pll_power_down(struct rtl8169_private *tp)
+{
+ if (__rtl8169_get_wol(tp) & WAKE_ANY) {
+ rtl_writephy(tp, 0x1f, 0x0000);
+ rtl_writephy(tp, MII_BMCR, 0x0000);
+ return;
+ }
+
+ r810x_phy_power_down(tp);
+}
+
+static void r810x_pll_power_up(struct rtl8169_private *tp)
+{
+ r810x_phy_power_up(tp);
+}
+
+static void r8168_phy_power_up(struct rtl8169_private *tp)
+{
+ rtl_writephy(tp, 0x1f, 0x0000);
+ rtl_writephy(tp, 0x0e, 0x0000);
+ rtl_writephy(tp, MII_BMCR, BMCR_ANENABLE);
+}
+
+static void r8168_phy_power_down(struct rtl8169_private *tp)
+{
+ rtl_writephy(tp, 0x1f, 0x0000);
+ rtl_writephy(tp, 0x0e, 0x0200);
+ rtl_writephy(tp, MII_BMCR, BMCR_PDOWN);
+}
+
+static void r8168_pll_power_down(struct rtl8169_private *tp)
+{
+ void __iomem *ioaddr = tp->mmio_addr;
+
+ if (tp->mac_version == RTL_GIGA_MAC_VER_27)
+ return;
+
+ if (((tp->mac_version == RTL_GIGA_MAC_VER_23) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_24)) &&
+ (RTL_R16(CPlusCmd) & ASF)) {
+ return;
+ }
+
+ if (__rtl8169_get_wol(tp) & WAKE_ANY) {
+ rtl_writephy(tp, 0x1f, 0x0000);
+ rtl_writephy(tp, MII_BMCR, 0x0000);
+
+ RTL_W32(RxConfig, RTL_R32(RxConfig) |
+ AcceptBroadcast | AcceptMulticast | AcceptMyPhys);
+ return;
+ }
+
+ r8168_phy_power_down(tp);
+
+ switch (tp->mac_version) {
+ case RTL_GIGA_MAC_VER_25:
+ case RTL_GIGA_MAC_VER_26:
+ RTL_W8(PMCH, RTL_R8(PMCH) & ~0x80);
+ break;
+ }
+}
+
+static void r8168_pll_power_up(struct rtl8169_private *tp)
+{
+ void __iomem *ioaddr = tp->mmio_addr;
+
+ if (tp->mac_version == RTL_GIGA_MAC_VER_27)
+ return;
+
+ switch (tp->mac_version) {
+ case RTL_GIGA_MAC_VER_25:
+ case RTL_GIGA_MAC_VER_26:
+ RTL_W8(PMCH, RTL_R8(PMCH) | 0x80);
+ break;
+ }
+
+ r8168_phy_power_up(tp);
+}
+
+static void rtl_pll_power_op(struct rtl8169_private *tp,
+ void (*op)(struct rtl8169_private *))
+{
+ if (op)
+ op(tp);
+}
+
+static void rtl_pll_power_down(struct rtl8169_private *tp)
+{
+ rtl_pll_power_op(tp, tp->pll_power_ops.down);
+}
+
+static void rtl_pll_power_up(struct rtl8169_private *tp)
+{
+ rtl_pll_power_op(tp, tp->pll_power_ops.up);
+}
+
+static void __devinit rtl_init_pll_power_ops(struct rtl8169_private *tp)
+{
+ struct pll_power_ops *ops = &tp->pll_power_ops;
+
+ switch (tp->mac_version) {
+ case RTL_GIGA_MAC_VER_07:
+ case RTL_GIGA_MAC_VER_08:
+ case RTL_GIGA_MAC_VER_09:
+ case RTL_GIGA_MAC_VER_10:
+ case RTL_GIGA_MAC_VER_16:
+ ops->down = r810x_pll_power_down;
+ ops->up = r810x_pll_power_up;
+ break;
+
+ case RTL_GIGA_MAC_VER_11:
+ case RTL_GIGA_MAC_VER_12:
+ case RTL_GIGA_MAC_VER_17:
+ case RTL_GIGA_MAC_VER_18:
+ case RTL_GIGA_MAC_VER_19:
+ case RTL_GIGA_MAC_VER_20:
+ case RTL_GIGA_MAC_VER_21:
+ case RTL_GIGA_MAC_VER_22:
+ case RTL_GIGA_MAC_VER_23:
+ case RTL_GIGA_MAC_VER_24:
+ case RTL_GIGA_MAC_VER_25:
+ case RTL_GIGA_MAC_VER_26:
+ case RTL_GIGA_MAC_VER_27:
+ ops->down = r8168_pll_power_down;
+ ops->up = r8168_pll_power_up;
+ break;
+
+ default:
+ ops->down = NULL;
+ ops->up = NULL;
+ break;
+ }
+}
+
static int __devinit
rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
@@ -3295,6 +3446,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
rtl8169_get_mac_version(tp, ioaddr);
rtl_init_mdio_ops(tp);
+ rtl_init_pll_power_ops(tp);
/* Use appropriate default if unknown */
if (tp->mac_version == RTL_GIGA_MAC_NONE) {
@@ -3474,6 +3626,8 @@ static int rtl8169_open(struct net_device *dev)
napi_enable(&tp->napi);
+ rtl_pll_power_up(tp);
+
rtl_hw_start(dev);
rtl8169_request_timer(dev);
@@ -4882,6 +5036,8 @@ static void rtl8169_down(struct net_device *dev)
rtl8169_tx_clear(tp);
rtl8169_rx_clear(tp);
+
+ rtl_pll_power_down(tp);
}
static int rtl8169_close(struct net_device *dev)
@@ -4986,9 +5142,13 @@ static struct net_device_stats *rtl8169_get_stats(struct net_device *dev)
static void rtl8169_net_suspend(struct net_device *dev)
{
+ struct rtl8169_private *tp = netdev_priv(dev);
+
if (!netif_running(dev))
return;
+ rtl_pll_power_down(tp);
+
netif_device_detach(dev);
netif_stop_queue(dev);
}
@@ -5007,7 +5167,12 @@ static int rtl8169_suspend(struct device *device)
static void __rtl8169_resume(struct net_device *dev)
{
+ struct rtl8169_private *tp = netdev_priv(dev);
+
netif_device_attach(dev);
+
+ rtl_pll_power_up(tp);
+
rtl8169_schedule_work(dev, rtl8169_reset_task);
}
--
1.7.3.2
[-- Attachment #7: 0006-r8169-rtl_csi_access_enable-rename.patch --]
[-- Type: text/plain, Size: 3627 bytes --]
>From 545d1caeb4f23e0c1df58971a045e81f2359e612 Mon Sep 17 00:00:00 2001
From: Francois Romieu <romieu@fr.zoreil.com>
Date: Mon, 15 Nov 2010 23:41:02 +0100
Subject: [PATCH 6/9] r8169: rtl_csi_access_enable rename.
Newer 8168 needs a slightly different rtl_csi_access_enable.
This patch separates some noise from the real thing.
No functional change.
Signed-off-by: Francois Romieu <romieu@fr.zoreil.com>
---
drivers/net/r8169.c | 27 ++++++++++++++++-----------
1 files changed, 16 insertions(+), 11 deletions(-)
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
index 11519c8..6ae08d9 100644
--- a/drivers/net/r8169.c
+++ b/drivers/net/r8169.c
@@ -3842,12 +3842,17 @@ static void rtl_tx_performance_tweak(struct pci_dev *pdev, u16 force)
}
}
-static void rtl_csi_access_enable(void __iomem *ioaddr)
+static void rtl_csi_access_enable(void __iomem *ioaddr, u32 bits)
{
u32 csi;
csi = rtl_csi_read(ioaddr, 0x070c) & 0x00ffffff;
- rtl_csi_write(ioaddr, 0x070c, csi | 0x27000000);
+ rtl_csi_write(ioaddr, 0x070c, csi | bits);
+}
+
+static void rtl_csi_access_enable_2(void __iomem *ioaddr)
+{
+ rtl_csi_access_enable(ioaddr, 0x27000000);
}
struct ephy_info {
@@ -3935,7 +3940,7 @@ static void rtl_hw_start_8168cp_1(void __iomem *ioaddr, struct pci_dev *pdev)
{ 0x07, 0, 0x2000 }
};
- rtl_csi_access_enable(ioaddr);
+ rtl_csi_access_enable_2(ioaddr);
rtl_ephy_init(ioaddr, e_info_8168cp, ARRAY_SIZE(e_info_8168cp));
@@ -3944,7 +3949,7 @@ static void rtl_hw_start_8168cp_1(void __iomem *ioaddr, struct pci_dev *pdev)
static void rtl_hw_start_8168cp_2(void __iomem *ioaddr, struct pci_dev *pdev)
{
- rtl_csi_access_enable(ioaddr);
+ rtl_csi_access_enable_2(ioaddr);
RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
@@ -3955,7 +3960,7 @@ static void rtl_hw_start_8168cp_2(void __iomem *ioaddr, struct pci_dev *pdev)
static void rtl_hw_start_8168cp_3(void __iomem *ioaddr, struct pci_dev *pdev)
{
- rtl_csi_access_enable(ioaddr);
+ rtl_csi_access_enable_2(ioaddr);
RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
@@ -3977,7 +3982,7 @@ static void rtl_hw_start_8168c_1(void __iomem *ioaddr, struct pci_dev *pdev)
{ 0x06, 0x0080, 0x0000 }
};
- rtl_csi_access_enable(ioaddr);
+ rtl_csi_access_enable_2(ioaddr);
RTL_W8(DBG_REG, 0x06 | FIX_NAK_1 | FIX_NAK_2);
@@ -3993,7 +3998,7 @@ static void rtl_hw_start_8168c_2(void __iomem *ioaddr, struct pci_dev *pdev)
{ 0x03, 0x0400, 0x0220 }
};
- rtl_csi_access_enable(ioaddr);
+ rtl_csi_access_enable_2(ioaddr);
rtl_ephy_init(ioaddr, e_info_8168c_2, ARRAY_SIZE(e_info_8168c_2));
@@ -4007,14 +4012,14 @@ static void rtl_hw_start_8168c_3(void __iomem *ioaddr, struct pci_dev *pdev)
static void rtl_hw_start_8168c_4(void __iomem *ioaddr, struct pci_dev *pdev)
{
- rtl_csi_access_enable(ioaddr);
+ rtl_csi_access_enable_2(ioaddr);
__rtl_hw_start_8168cp(ioaddr, pdev);
}
static void rtl_hw_start_8168d(void __iomem *ioaddr, struct pci_dev *pdev)
{
- rtl_csi_access_enable(ioaddr);
+ rtl_csi_access_enable_2(ioaddr);
rtl_disable_clock_request(pdev);
@@ -4143,7 +4148,7 @@ static void rtl_hw_start_8102e_1(void __iomem *ioaddr, struct pci_dev *pdev)
};
u8 cfg1;
- rtl_csi_access_enable(ioaddr);
+ rtl_csi_access_enable_2(ioaddr);
RTL_W8(DBG_REG, FIX_NAK_1);
@@ -4164,7 +4169,7 @@ static void rtl_hw_start_8102e_1(void __iomem *ioaddr, struct pci_dev *pdev)
static void rtl_hw_start_8102e_2(void __iomem *ioaddr, struct pci_dev *pdev)
{
- rtl_csi_access_enable(ioaddr);
+ rtl_csi_access_enable_2(ioaddr);
rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
--
1.7.3.2
[-- Attachment #8: 0007-r8169-magic.patch --]
[-- Type: text/plain, Size: 3549 bytes --]
>From 9bc18cb4015df72e26f7a8df17b418fb593bc135 Mon Sep 17 00:00:00 2001
From: Francois Romieu <romieu@fr.zoreil.com>
Date: Mon, 15 Nov 2010 23:53:26 +0100
Subject: [PATCH 7/9] r8169: magic.
Adapted from version 8.019.00 of Realtek's r8168 driver.
Signed-off-by: Francois Romieu <romieu@fr.zoreil.com>
---
drivers/net/r8169.c | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 93 insertions(+), 0 deletions(-)
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
index 6ae08d9..949586c 100644
--- a/drivers/net/r8169.c
+++ b/drivers/net/r8169.c
@@ -274,6 +274,18 @@ enum rtl8168_8101_registers {
};
enum rtl8168_registers {
+ ERIDR = 0x70,
+ ERIAR = 0x74,
+#define ERIAR_FLAG 0x80000000
+#define ERIAR_WRITE_CMD 0x80000000
+#define ERIAR_READ_CMD 0x00000000
+#define ERIAR_ADDR_BYTE_ALIGN 4
+#define ERIAR_EXGMAC 0
+#define ERIAR_MSIX 1
+#define ERIAR_ASF 2
+#define ERIAR_TYPE_SHIFT 16
+#define ERIAR_BYTEEN 0x0f
+#define ERIAR_BYTEEN_SHIFT 12
EPHY_RXER_NUM = 0x7c,
OCPDR = 0xb0, /* OCP GPHY access */
#define OCPDR_WRITE_CMD 0x80000000
@@ -566,6 +578,81 @@ static int rtl8169_poll(struct napi_struct *napi, int budget);
static const unsigned int rtl8169_rx_config =
(RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift);
+static u32 ocp_read(struct rtl8169_private *tp, u8 mask, u16 reg)
+{
+ void __iomem *ioaddr = tp->mmio_addr;
+ int i;
+
+ RTL_W32(OCPAR, ((u32)mask & 0x0f) << 12 | (reg & 0x0fff));
+ for (i = 0; i < 20; i++) {
+ udelay(100);
+ if (RTL_R32(OCPAR) & OCPAR_FLAG)
+ break;
+ }
+ return RTL_R32(OCPDR);
+}
+
+static void ocp_write(struct rtl8169_private *tp, u8 mask, u16 reg, u32 data)
+{
+ void __iomem *ioaddr = tp->mmio_addr;
+ int i;
+
+ RTL_W32(OCPDR, data);
+ RTL_W32(OCPAR, OCPAR_FLAG | ((u32)mask & 0x0f) << 12 | (reg & 0x0fff));
+ for (i = 0; i < 20; i++) {
+ udelay(100);
+ if ((RTL_R32(OCPAR) & OCPAR_FLAG) == 0)
+ break;
+ }
+}
+
+static void rtl8168_oob_notify(void __iomem *ioaddr, u8 cmd)
+{
+ int i;
+
+ RTL_W8(ERIDR, cmd);
+ RTL_W32(ERIAR, 0x800010e8);
+ msleep(2);
+ for (i = 0; i < 5; i++) {
+ udelay(100);
+ if (!(RTL_R32(ERIDR) & ERIAR_FLAG))
+ break;
+ }
+
+ ocp_write(ioaddr, 0x1, 0x30, 0x00000001);
+}
+
+#define OOB_CMD_RESET 0x00
+#define OOB_CMD_DRIVER_START 0x05
+#define OOB_CMD_DRIVER_STOP 0x06
+
+static void rtl8168_driver_start(struct rtl8169_private *tp)
+{
+ int i;
+
+ rtl8168_oob_notify(tp, OOB_CMD_DRIVER_START);
+
+ for (i = 0; i < 10; i++) {
+ msleep(10);
+ if (ocp_read(tp, 0x0f, 0x0010) & 0x00000800)
+ break;
+ }
+}
+
+static void rtl8168_driver_stop(struct rtl8169_private *tp)
+{
+ int i;
+
+ rtl8168_oob_notify(tp, OOB_CMD_DRIVER_STOP);
+
+ for (i = 0; i < 10; i++) {
+ msleep(10);
+ if ((ocp_read(tp, 0x0f, 0x0010) & 0x00000800) == 0)
+ break;
+ }
+}
+
+
static void r8169_mdio_write(void __iomem *ioaddr, int reg_addr, int value)
{
int i;
@@ -3538,6 +3625,9 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
dev->base_addr, dev->dev_addr,
(u32)(RTL_R32(TxConfig) & 0x9cf0f8ff), dev->irq);
+ if (tp->mac_version == RTL_GIGA_MAC_VER_27)
+ rtl8168_driver_start(tp);
+
rtl8169_init_phy(dev, tp);
/*
@@ -3573,6 +3663,9 @@ 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);
+ if (tp->mac_version == RTL_GIGA_MAC_VER_27)
+ rtl8168_driver_stop(tp);
+
flush_scheduled_work();
unregister_netdev(dev);
--
1.7.3.2
[-- Attachment #9: 0008-r8169-more-8168dp-support.patch --]
[-- Type: text/plain, Size: 9185 bytes --]
>From e3aaef05f2acea88f23ec9498c142eaae7e36689 Mon Sep 17 00:00:00 2001
From: Francois Romieu <romieu@fr.zoreil.com>
Date: Mon, 15 Nov 2010 23:56:27 +0100
Subject: [PATCH 8/9] r8169: more 8168dp support.
Adapted from version 8.019.00 of Realtek's r8168 driver
Signed-off-by: Francois Romieu <romieu@fr.zoreil.com>
---
drivers/net/r8169.c | 145 +++++++++++++++++++++++++++++++++++++++++++++++---
1 files changed, 136 insertions(+), 9 deletions(-)
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
index 949586c..fe93379 100644
--- a/drivers/net/r8169.c
+++ b/drivers/net/r8169.c
@@ -117,7 +117,8 @@ enum mac_version {
RTL_GIGA_MAC_VER_24 = 0x18, // 8168CP
RTL_GIGA_MAC_VER_25 = 0x19, // 8168D
RTL_GIGA_MAC_VER_26 = 0x1a, // 8168D
- RTL_GIGA_MAC_VER_27 = 0x1b // 8168DP
+ RTL_GIGA_MAC_VER_27 = 0x1b, // 8168DP
+ RTL_GIGA_MAC_VER_28 = 0x1c, // 8168DP
};
#define _R(NAME,MAC,MASK) \
@@ -154,7 +155,8 @@ static const struct {
_R("RTL8168cp/8111cp", RTL_GIGA_MAC_VER_24, 0xff7e1880), // PCI-E
_R("RTL8168d/8111d", RTL_GIGA_MAC_VER_25, 0xff7e1880), // PCI-E
_R("RTL8168d/8111d", RTL_GIGA_MAC_VER_26, 0xff7e1880), // PCI-E
- _R("RTL8168dp/8111dp", RTL_GIGA_MAC_VER_27, 0xff7e1880) // PCI-E
+ _R("RTL8168dp/8111dp", RTL_GIGA_MAC_VER_27, 0xff7e1880), // PCI-E
+ _R("RTL8168dp/8111dp", RTL_GIGA_MAC_VER_28, 0xff7e1880) // PCI-E
};
#undef _R
@@ -297,6 +299,7 @@ enum rtl8168_registers {
#define OCPAR_FLAG 0x80000000
#define OCPAR_GPHY_WRITE_CMD 0x8000f060
#define OCPAR_GPHY_READ_CMD 0x0000f060
+ RDSAR1 = 0xd0 /* 8168c only. Undocumented on 8168dp */
};
enum rtl_register_content {
@@ -742,6 +745,40 @@ static int r8168dp_1_mdio_read(void __iomem *ioaddr, int reg_addr)
return RTL_R32(OCPDR) & OCPDR_DATA_MASK;
}
+#define R8168DP_1_MDIO_ACCESS_BIT 0x00020000
+
+static void r8168dp_2_mdio_start(void __iomem *ioaddr)
+{
+ RTL_W32(0xd0, RTL_R32(0xd0) & ~R8168DP_1_MDIO_ACCESS_BIT);
+}
+
+static void r8168dp_2_mdio_stop(void __iomem *ioaddr)
+{
+ RTL_W32(0xd0, RTL_R32(0xd0) | R8168DP_1_MDIO_ACCESS_BIT);
+}
+
+static void r8168dp_2_mdio_write(void __iomem *ioaddr, int reg_addr, int value)
+{
+ r8168dp_2_mdio_start(ioaddr);
+
+ r8169_mdio_write(ioaddr, reg_addr, value);
+
+ r8168dp_2_mdio_stop(ioaddr);
+}
+
+static int r8168dp_2_mdio_read(void __iomem *ioaddr, int reg_addr)
+{
+ int value;
+
+ r8168dp_2_mdio_start(ioaddr);
+
+ value = r8169_mdio_read(ioaddr, reg_addr);
+
+ r8168dp_2_mdio_stop(ioaddr);
+
+ return value;
+}
+
static void rtl_writephy(struct rtl8169_private *tp, int location, u32 val)
{
tp->mdio_ops.write(tp->mmio_addr, location, val);
@@ -1479,9 +1516,12 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp,
/* 8168D family. */
{ 0x7cf00000, 0x28300000, RTL_GIGA_MAC_VER_26 },
{ 0x7cf00000, 0x28100000, RTL_GIGA_MAC_VER_25 },
- { 0x7c800000, 0x28800000, RTL_GIGA_MAC_VER_27 },
{ 0x7c800000, 0x28000000, RTL_GIGA_MAC_VER_26 },
+ /* 8168DP family. */
+ { 0x7cf00000, 0x28800000, RTL_GIGA_MAC_VER_27 },
+ { 0x7cf00000, 0x28a00000, RTL_GIGA_MAC_VER_28 },
+
/* 8168C family. */
{ 0x7cf00000, 0x3cb00000, RTL_GIGA_MAC_VER_24 },
{ 0x7cf00000, 0x3c900000, RTL_GIGA_MAC_VER_23 },
@@ -2870,6 +2910,22 @@ static void rtl8168d_3_hw_phy_config(struct rtl8169_private *tp)
rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
}
+static void rtl8168d_4_hw_phy_config(struct rtl8169_private *tp)
+{
+ static const struct phy_reg phy_reg_init[] = {
+ { 0x1f, 0x0001 },
+ { 0x17, 0x0cc0 },
+
+ { 0x1f, 0x0007 },
+ { 0x1e, 0x002d },
+ { 0x18, 0x0040 },
+ { 0x1f, 0x0000 }
+ };
+
+ rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+ rtl_patchphy(tp, 0x0d, 1 << 5);
+}
+
static void rtl8102e_hw_phy_config(struct rtl8169_private *tp)
{
static const struct phy_reg phy_reg_init[] = {
@@ -2951,6 +3007,9 @@ static void rtl_hw_phy_config(struct net_device *dev)
case RTL_GIGA_MAC_VER_27:
rtl8168d_3_hw_phy_config(tp);
break;
+ case RTL_GIGA_MAC_VER_28:
+ rtl8168d_4_hw_phy_config(tp);
+ break;
default:
break;
@@ -3261,6 +3320,10 @@ static void __devinit rtl_init_mdio_ops(struct rtl8169_private *tp)
ops->write = r8168dp_1_mdio_write;
ops->read = r8168dp_1_mdio_read;
break;
+ case RTL_GIGA_MAC_VER_28:
+ ops->write = r8168dp_2_mdio_write;
+ ops->read = r8168dp_2_mdio_read;
+ break;
default:
ops->write = r8169_mdio_write;
ops->read = r8169_mdio_read;
@@ -3403,6 +3466,7 @@ static void __devinit rtl_init_pll_power_ops(struct rtl8169_private *tp)
case RTL_GIGA_MAC_VER_25:
case RTL_GIGA_MAC_VER_26:
case RTL_GIGA_MAC_VER_27:
+ case RTL_GIGA_MAC_VER_28:
ops->down = r8168_pll_power_down;
ops->up = r8168_pll_power_up;
break;
@@ -3625,8 +3689,10 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
dev->base_addr, dev->dev_addr,
(u32)(RTL_R32(TxConfig) & 0x9cf0f8ff), dev->irq);
- if (tp->mac_version == RTL_GIGA_MAC_VER_27)
+ if ((tp->mac_version == RTL_GIGA_MAC_VER_27) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_28)) {
rtl8168_driver_start(tp);
+ }
rtl8169_init_phy(dev, tp);
@@ -3663,8 +3729,10 @@ 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);
- if (tp->mac_version == RTL_GIGA_MAC_VER_27)
+ if ((tp->mac_version == RTL_GIGA_MAC_VER_27) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_28)) {
rtl8168_driver_stop(tp);
+ }
flush_scheduled_work();
@@ -3747,11 +3815,19 @@ err_pm_runtime_put:
goto out;
}
-static void rtl8169_hw_reset(void __iomem *ioaddr)
+static void rtl8169_hw_reset(struct rtl8169_private *tp)
{
+ void __iomem *ioaddr = tp->mmio_addr;
+
/* Disable interrupts */
rtl8169_irq_mask_and_ack(ioaddr);
+ if (tp->mac_version == RTL_GIGA_MAC_VER_28) {
+ while (RTL_R8(TxPoll) & NPQ)
+ udelay(20);
+
+ }
+
/* Reset the chipset */
RTL_W8(ChipCmd, CmdReset);
@@ -3943,6 +4019,11 @@ static void rtl_csi_access_enable(void __iomem *ioaddr, u32 bits)
rtl_csi_write(ioaddr, 0x070c, csi | bits);
}
+static void rtl_csi_access_enable_1(void __iomem *ioaddr)
+{
+ rtl_csi_access_enable(ioaddr, 0x17000000);
+}
+
static void rtl_csi_access_enable_2(void __iomem *ioaddr)
{
rtl_csi_access_enable(ioaddr, 0x27000000);
@@ -3980,6 +4061,21 @@ static void rtl_disable_clock_request(struct pci_dev *pdev)
}
}
+static void rtl_enable_clock_request(struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct rtl8169_private *tp = netdev_priv(dev);
+ int cap = tp->pcie_cap;
+
+ if (cap) {
+ u16 ctl;
+
+ pci_read_config_word(pdev, cap + PCI_EXP_LNKCTL, &ctl);
+ ctl |= PCI_EXP_LNKCTL_CLKREQ_EN;
+ pci_write_config_word(pdev, cap + PCI_EXP_LNKCTL, ctl);
+ }
+}
+
#define R8168_CPCMD_QUIRK_MASK (\
EnableBist | \
Mac_dbgo_oe | \
@@ -4123,6 +4219,32 @@ static void rtl_hw_start_8168d(void __iomem *ioaddr, struct pci_dev *pdev)
RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
}
+static void rtl_hw_start_8168d_4(void __iomem *ioaddr, struct pci_dev *pdev)
+{
+ static const struct ephy_info e_info_8168d_4[] = {
+ { 0x0b, ~0, 0x48 },
+ { 0x19, 0x20, 0x50 },
+ { 0x0c, ~0, 0x20 }
+ };
+ int i;
+
+ rtl_csi_access_enable_1(ioaddr);
+
+ rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
+
+ RTL_W8(MaxTxPacketSize, TxPacketMax);
+
+ for (i = 0; i < ARRAY_SIZE(e_info_8168d_4); i++) {
+ const struct ephy_info *e = e_info_8168d_4 + i;
+ u16 w;
+
+ w = rtl_ephy_read(ioaddr, e->offset);
+ rtl_ephy_write(ioaddr, 0x03, (w & e->mask) | e->bits);
+ }
+
+ rtl_enable_clock_request(pdev);
+}
+
static void rtl_hw_start_8168(struct net_device *dev)
{
struct rtl8169_private *tp = netdev_priv(dev);
@@ -4200,6 +4322,10 @@ static void rtl_hw_start_8168(struct net_device *dev)
rtl_hw_start_8168d(ioaddr, pdev);
break;
+ case RTL_GIGA_MAC_VER_28:
+ rtl_hw_start_8168d_4(ioaddr, pdev);
+ break;
+
default:
printk(KERN_ERR PFX "%s: unknown chipset (mac_version = %d).\n",
dev->name, tp->mac_version);
@@ -4612,7 +4738,7 @@ static void rtl8169_tx_timeout(struct net_device *dev)
{
struct rtl8169_private *tp = netdev_priv(dev);
- rtl8169_hw_reset(tp->mmio_addr);
+ rtl8169_hw_reset(tp);
/* Let's wait a bit while any (async) irq lands on */
rtl8169_schedule_work(dev, rtl8169_reset_task);
@@ -4770,7 +4896,6 @@ static void rtl8169_pcierr_interrupt(struct net_device *dev)
{
struct rtl8169_private *tp = netdev_priv(dev);
struct pci_dev *pdev = tp->pci_dev;
- void __iomem *ioaddr = tp->mmio_addr;
u16 pci_status, pci_cmd;
pci_read_config_word(pdev, PCI_COMMAND, &pci_cmd);
@@ -4801,13 +4926,15 @@ static void rtl8169_pcierr_interrupt(struct net_device *dev)
/* The infamous DAC f*ckup only happens at boot time */
if ((tp->cp_cmd & PCIDAC) && !tp->dirty_rx && !tp->cur_rx) {
+ void __iomem *ioaddr = tp->mmio_addr;
+
netif_info(tp, intr, dev, "disabling PCI DAC\n");
tp->cp_cmd &= ~PCIDAC;
RTL_W16(CPlusCmd, tp->cp_cmd);
dev->features &= ~NETIF_F_HIGHDMA;
}
- rtl8169_hw_reset(ioaddr);
+ rtl8169_hw_reset(tp);
rtl8169_schedule_work(dev, rtl8169_reinit_task);
}
--
1.7.3.2
[-- Attachment #10: 0009-r8169-firmware-isolation-wip.patch --]
[-- Type: text/plain, Size: 56906 bytes --]
>From 112e171c1532b2a340f1c9cfc634f0e050efb4b9 Mon Sep 17 00:00:00 2001
From: Francois Romieu <romieu@fr.zoreil.com>
Date: Mon, 29 Nov 2010 23:49:14 +0100
Subject: [PATCH 9/9] r8169: firmware isolation (wip)
Bits from Ben Hutchings. Some bits from me.
Signed-off-by: Francois Romieu <romieu@fr.zoreil.com>
---
drivers/net/r8169.c | 1198 +++++---------------------------------------
firmware/r8169/8168c_1.h | 19 +
firmware/r8169/8168c_2.h | 17 +
firmware/r8169/8168c_3.h | 11 +
firmware/r8169/8168d_1_0.h | 40 ++
firmware/r8169/8168d_1_1.h | 376 ++++++++++++++
firmware/r8169/8168d_2_0.h | 40 ++
firmware/r8169/8168d_2_1.h | 334 ++++++++++++
firmware/r8169/8168d_3.h | 55 ++
firmware/r8169/8169s.h | 61 +++
firmware/r8169/8169scd.h | 39 ++
firmware/r8169/8169sce.h | 47 ++
firmware/r8169/main.c | 79 +++
13 files changed, 1239 insertions(+), 1077 deletions(-)
create mode 100644 firmware/r8169/8168c_1.h
create mode 100644 firmware/r8169/8168c_2.h
create mode 100644 firmware/r8169/8168c_3.h
create mode 100644 firmware/r8169/8168d_1_0.h
create mode 100644 firmware/r8169/8168d_1_1.h
create mode 100644 firmware/r8169/8168d_2_0.h
create mode 100644 firmware/r8169/8168d_2_1.h
create mode 100644 firmware/r8169/8168d_3.h
create mode 100644 firmware/r8169/8169s.h
create mode 100644 firmware/r8169/8169scd.h
create mode 100644 firmware/r8169/8169sce.h
create mode 100644 firmware/r8169/main.c
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
index fe93379..f1c5d01 100644
--- a/drivers/net/r8169.c
+++ b/drivers/net/r8169.c
@@ -24,6 +24,7 @@
#include <linux/init.h>
#include <linux/dma-mapping.h>
#include <linux/pm_runtime.h>
+#include <linux/firmware.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -1594,71 +1595,36 @@ static void rtl_writephy_batch(struct rtl8169_private *tp,
}
}
-static void rtl8169s_hw_phy_config(struct rtl8169_private *tp)
+static int rtl_writephy_fw(struct rtl8169_private *tp, const char * name)
{
- static const struct phy_reg phy_reg_init[] = {
- { 0x1f, 0x0001 },
- { 0x06, 0x006e },
- { 0x08, 0x0708 },
- { 0x15, 0x4000 },
- { 0x18, 0x65c7 },
+ const struct firmware *fw;
+ const __le16 *data;
+ int rc, i;
- { 0x1f, 0x0001 },
- { 0x03, 0x00a1 },
- { 0x02, 0x0008 },
- { 0x01, 0x0120 },
- { 0x00, 0x1000 },
- { 0x04, 0x0800 },
- { 0x04, 0x0000 },
-
- { 0x03, 0xff41 },
- { 0x02, 0xdf60 },
- { 0x01, 0x0140 },
- { 0x00, 0x0077 },
- { 0x04, 0x7800 },
- { 0x04, 0x7000 },
-
- { 0x03, 0x802f },
- { 0x02, 0x4f02 },
- { 0x01, 0x0409 },
- { 0x00, 0xf0f9 },
- { 0x04, 0x9800 },
- { 0x04, 0x9000 },
-
- { 0x03, 0xdf01 },
- { 0x02, 0xdf20 },
- { 0x01, 0xff95 },
- { 0x00, 0xba00 },
- { 0x04, 0xa800 },
- { 0x04, 0xa000 },
-
- { 0x03, 0xff41 },
- { 0x02, 0xdf20 },
- { 0x01, 0x0140 },
- { 0x00, 0x00bb },
- { 0x04, 0xb800 },
- { 0x04, 0xb000 },
-
- { 0x03, 0xdf41 },
- { 0x02, 0xdc60 },
- { 0x01, 0x6340 },
- { 0x00, 0x007d },
- { 0x04, 0xd800 },
- { 0x04, 0xd000 },
-
- { 0x03, 0xdf01 },
- { 0x02, 0xdf20 },
- { 0x01, 0x100a },
- { 0x00, 0xa0ff },
- { 0x04, 0xf800 },
- { 0x04, 0xf000 },
+ rc = request_firmware(&fw, name, &tp->pci_dev->dev);
+ if (rc < 0) {
+ netif_err(tp, drv, tp->dev, "phy firmware patch failure (%s\n)",
+ name);
+ goto out;
+ }
- { 0x1f, 0x0000 },
- { 0x0b, 0x0000 },
- { 0x00, 0x9200 }
- };
+ data = (const __le16 *)fw->data;
+ for (i = 0; i < (fw->size / sizeof(struct phy_reg)); i++) {
+ u16 reg = le16_to_cpu(*data++);
+ u16 val = le16_to_cpu(*data++);
- rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+ rtl_writephy(tp, reg, val);
+ }
+
+ release_firmware(fw);
+out:
+ return rc;
+}
+
+MODULE_FIRMWARE("rtl8169s_phy.fw");
+static int rtl8169s_hw_phy_config(struct rtl8169_private *tp)
+{
+ return rtl_writephy_fw(tp, "rtl8169s_phy.fw");
}
static void rtl8169sb_hw_phy_config(struct rtl8169_private *tp)
@@ -1688,104 +1654,24 @@ static void rtl8169scd_hw_phy_config_quirk(struct rtl8169_private *tp)
rtl_writephy(tp, 0x1f, 0x0000);
}
-static void rtl8169scd_hw_phy_config(struct rtl8169_private *tp)
+MODULE_FIRMWARE("rtl8169scd_phy.fw");
+static int rtl8169scd_hw_phy_config(struct rtl8169_private *tp)
{
- static const struct phy_reg phy_reg_init[] = {
- { 0x1f, 0x0001 },
- { 0x04, 0x0000 },
- { 0x03, 0x00a1 },
- { 0x02, 0x0008 },
- { 0x01, 0x0120 },
- { 0x00, 0x1000 },
- { 0x04, 0x0800 },
- { 0x04, 0x9000 },
- { 0x03, 0x802f },
- { 0x02, 0x4f02 },
- { 0x01, 0x0409 },
- { 0x00, 0xf099 },
- { 0x04, 0x9800 },
- { 0x04, 0xa000 },
- { 0x03, 0xdf01 },
- { 0x02, 0xdf20 },
- { 0x01, 0xff95 },
- { 0x00, 0xba00 },
- { 0x04, 0xa800 },
- { 0x04, 0xf000 },
- { 0x03, 0xdf01 },
- { 0x02, 0xdf20 },
- { 0x01, 0x101a },
- { 0x00, 0xa0ff },
- { 0x04, 0xf800 },
- { 0x04, 0x0000 },
- { 0x1f, 0x0000 },
-
- { 0x1f, 0x0001 },
- { 0x10, 0xf41b },
- { 0x14, 0xfb54 },
- { 0x18, 0xf5c7 },
- { 0x1f, 0x0000 },
-
- { 0x1f, 0x0001 },
- { 0x17, 0x0cc0 },
- { 0x1f, 0x0000 }
- };
+ int rc;
- rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+ rc = rtl_writephy_fw(tp, "rtl8169scd_phy.fw");
+ if (rc < 0)
+ goto out;
rtl8169scd_hw_phy_config_quirk(tp);
+out:
+ return rc;
}
-static void rtl8169sce_hw_phy_config(struct rtl8169_private *tp)
+MODULE_FIRMWARE("rtl8169sce_phy.fw");
+static int rtl8169sce_hw_phy_config(struct rtl8169_private *tp)
{
- static const struct phy_reg phy_reg_init[] = {
- { 0x1f, 0x0001 },
- { 0x04, 0x0000 },
- { 0x03, 0x00a1 },
- { 0x02, 0x0008 },
- { 0x01, 0x0120 },
- { 0x00, 0x1000 },
- { 0x04, 0x0800 },
- { 0x04, 0x9000 },
- { 0x03, 0x802f },
- { 0x02, 0x4f02 },
- { 0x01, 0x0409 },
- { 0x00, 0xf099 },
- { 0x04, 0x9800 },
- { 0x04, 0xa000 },
- { 0x03, 0xdf01 },
- { 0x02, 0xdf20 },
- { 0x01, 0xff95 },
- { 0x00, 0xba00 },
- { 0x04, 0xa800 },
- { 0x04, 0xf000 },
- { 0x03, 0xdf01 },
- { 0x02, 0xdf20 },
- { 0x01, 0x101a },
- { 0x00, 0xa0ff },
- { 0x04, 0xf800 },
- { 0x04, 0x0000 },
- { 0x1f, 0x0000 },
-
- { 0x1f, 0x0001 },
- { 0x0b, 0x8480 },
- { 0x1f, 0x0000 },
-
- { 0x1f, 0x0001 },
- { 0x18, 0x67c7 },
- { 0x04, 0x2000 },
- { 0x03, 0x002f },
- { 0x02, 0x4360 },
- { 0x01, 0x0109 },
- { 0x00, 0x3022 },
- { 0x04, 0x2800 },
- { 0x1f, 0x0000 },
-
- { 0x1f, 0x0001 },
- { 0x17, 0x0cc0 },
- { 0x1f, 0x0000 }
- };
-
- rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+ return rtl_writephy_fw(tp, "rtl8169sce_phy.fw");
}
static void rtl8168bb_hw_phy_config(struct rtl8169_private *tp)
@@ -1840,511 +1726,71 @@ static void rtl8168cp_2_hw_phy_config(struct rtl8169_private *tp)
rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
}
-static void rtl8168c_1_hw_phy_config(struct rtl8169_private *tp)
+MODULE_FIRMWARE("rtl8168c_1_phy.fw");
+static int rtl8168c_1_hw_phy_config(struct rtl8169_private *tp)
{
- static const struct phy_reg phy_reg_init[] = {
- { 0x1f, 0x0001 },
- { 0x12, 0x2300 },
- { 0x1f, 0x0002 },
- { 0x00, 0x88d4 },
- { 0x01, 0x82b1 },
- { 0x03, 0x7002 },
- { 0x08, 0x9e30 },
- { 0x09, 0x01f0 },
- { 0x0a, 0x5500 },
- { 0x0c, 0x00c8 },
- { 0x1f, 0x0003 },
- { 0x12, 0xc096 },
- { 0x16, 0x000a },
- { 0x1f, 0x0000 },
- { 0x1f, 0x0000 },
- { 0x09, 0x2000 },
- { 0x09, 0x0000 }
- };
+ int rc;
- rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+ rc = rtl_writephy_fw(tp, "rtl8168c_1_phy.fw");
+ if (rc < 0)
+ goto out;
rtl_patchphy(tp, 0x14, 1 << 5);
rtl_patchphy(tp, 0x0d, 1 << 5);
rtl_writephy(tp, 0x1f, 0x0000);
+out:
+ return rc;
}
-static void rtl8168c_2_hw_phy_config(struct rtl8169_private *tp)
+MODULE_FIRMWARE("rtl8168c_2_phy.fw");
+static int rtl8168c_2_hw_phy_config(struct rtl8169_private *tp)
{
- static const struct phy_reg phy_reg_init[] = {
- { 0x1f, 0x0001 },
- { 0x12, 0x2300 },
- { 0x03, 0x802f },
- { 0x02, 0x4f02 },
- { 0x01, 0x0409 },
- { 0x00, 0xf099 },
- { 0x04, 0x9800 },
- { 0x04, 0x9000 },
- { 0x1d, 0x3d98 },
- { 0x1f, 0x0002 },
- { 0x0c, 0x7eb8 },
- { 0x06, 0x0761 },
- { 0x1f, 0x0003 },
- { 0x16, 0x0f0a },
- { 0x1f, 0x0000 }
- };
+ int rc;
- rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+ rc = rtl_writephy_fw(tp, "rtl8168c_2_phy.fw");
+ if (rc < 0)
+ goto out;
rtl_patchphy(tp, 0x16, 1 << 0);
rtl_patchphy(tp, 0x14, 1 << 5);
rtl_patchphy(tp, 0x0d, 1 << 5);
rtl_writephy(tp, 0x1f, 0x0000);
+out:
+ return rc;
}
-static void rtl8168c_3_hw_phy_config(struct rtl8169_private *tp)
+MODULE_FIRMWARE("rtl8168c_3_phy.fw");
+static int rtl8168c_3_hw_phy_config(struct rtl8169_private *tp)
{
- static const struct phy_reg phy_reg_init[] = {
- { 0x1f, 0x0001 },
- { 0x12, 0x2300 },
- { 0x1d, 0x3d98 },
- { 0x1f, 0x0002 },
- { 0x0c, 0x7eb8 },
- { 0x06, 0x5461 },
- { 0x1f, 0x0003 },
- { 0x16, 0x0f0a },
- { 0x1f, 0x0000 }
- };
+ int rc;
- rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+ rc = rtl_writephy_fw(tp, "rtl8168c_3_phy.fw");
+ if (rc < 0)
+ goto out;
rtl_patchphy(tp, 0x16, 1 << 0);
rtl_patchphy(tp, 0x14, 1 << 5);
rtl_patchphy(tp, 0x0d, 1 << 5);
rtl_writephy(tp, 0x1f, 0x0000);
+out:
+ return rc;
}
-static void rtl8168c_4_hw_phy_config(struct rtl8169_private *tp)
+static int rtl8168c_4_hw_phy_config(struct rtl8169_private *tp)
{
- rtl8168c_3_hw_phy_config(tp);
+ return rtl8168c_3_hw_phy_config(tp);
}
-static void rtl8168d_1_hw_phy_config(struct rtl8169_private *tp)
+MODULE_FIRMWARE("rtl8168d_1_0_phy.fw");
+MODULE_FIRMWARE("rtl8168d_1_1_phy.fw");
+static int rtl8168d_1_hw_phy_config(struct rtl8169_private *tp)
{
void __iomem *ioaddr = tp->mmio_addr;
- static const struct phy_reg phy_reg_init_0[] = {
- /* Channel Estimation */
- { 0x1f, 0x0001 },
- { 0x06, 0x4064 },
- { 0x07, 0x2863 },
- { 0x08, 0x059c },
- { 0x09, 0x26b4 },
- { 0x0a, 0x6a19 },
- { 0x0b, 0xdcc8 },
- { 0x10, 0xf06d },
- { 0x14, 0x7f68 },
- { 0x18, 0x7fd9 },
- { 0x1c, 0xf0ff },
- { 0x1d, 0x3d9c },
- { 0x1f, 0x0003 },
- { 0x12, 0xf49f },
- { 0x13, 0x070b },
- { 0x1a, 0x05ad },
- { 0x14, 0x94c0 },
-
- /*
- * Tx Error Issue
- * enhance line driver power
- */
- { 0x1f, 0x0002 },
- { 0x06, 0x5561 },
- { 0x1f, 0x0005 },
- { 0x05, 0x8332 },
- { 0x06, 0x5561 },
-
- /*
- * Can not link to 1Gbps with bad cable
- * Decrease SNR threshold form 21.07dB to 19.04dB
- */
- { 0x1f, 0x0001 },
- { 0x17, 0x0cc0 },
-
- { 0x1f, 0x0000 },
- { 0x0d, 0xf880 }
- };
- static const struct phy_reg phy_reg_init_2[] = {
- /* Low pass filter & DLY_CAP fine tune from uC */
- { 0x1f, 0x0005 },
- { 0x05, 0xfff6 },
- { 0x06, 0x0080 },
- { 0x05, 0x8000 },
- { 0x06, 0xf8f9 },
- { 0x06, 0xfaef },
- { 0x06, 0x59ee },
- { 0x06, 0xf8ea },
- { 0x06, 0x00ee },
- { 0x06, 0xf8eb },
- { 0x06, 0x00e0 },
- { 0x06, 0xf87c },
- { 0x06, 0xe1f8 },
- { 0x06, 0x7d59 },
- { 0x06, 0x0fef },
- { 0x06, 0x0139 },
- { 0x06, 0x029e },
- { 0x06, 0x06ef },
- { 0x06, 0x1039 },
- { 0x06, 0x089f },
- { 0x06, 0x2aee },
- { 0x06, 0xf8ea },
- { 0x06, 0x00ee },
- { 0x06, 0xf8eb },
- { 0x06, 0x01e0 },
- { 0x06, 0xf87c },
- { 0x06, 0xe1f8 },
- { 0x06, 0x7d58 },
- { 0x06, 0x409e },
- { 0x06, 0x0f39 },
- { 0x06, 0x46aa },
- { 0x06, 0x0bbf },
- { 0x06, 0x8290 },
- { 0x06, 0xd682 },
- { 0x06, 0x9802 },
- { 0x06, 0x014f },
- { 0x06, 0xae09 },
- { 0x06, 0xbf82 },
- { 0x06, 0x98d6 },
- { 0x06, 0x82a0 },
- { 0x06, 0x0201 },
- { 0x06, 0x4fef },
- { 0x06, 0x95fe },
- { 0x06, 0xfdfc },
- { 0x06, 0x05f8 },
- { 0x06, 0xf9fa },
- { 0x06, 0xeef8 },
- { 0x06, 0xea00 },
- { 0x06, 0xeef8 },
- { 0x06, 0xeb00 },
- { 0x06, 0xe2f8 },
- { 0x06, 0x7ce3 },
- { 0x06, 0xf87d },
- { 0x06, 0xa511 },
- { 0x06, 0x1112 },
- { 0x06, 0xd240 },
- { 0x06, 0xd644 },
- { 0x06, 0x4402 },
- { 0x06, 0x8217 },
- { 0x06, 0xd2a0 },
- { 0x06, 0xd6aa },
- { 0x06, 0xaa02 },
- { 0x06, 0x8217 },
- { 0x06, 0xae0f },
- { 0x06, 0xa544 },
- { 0x06, 0x4402 },
- { 0x06, 0xae4d },
- { 0x06, 0xa5aa },
- { 0x06, 0xaa02 },
- { 0x06, 0xae47 },
- { 0x06, 0xaf82 },
- { 0x06, 0x13ee },
- { 0x06, 0x834e },
- { 0x06, 0x00ee },
- { 0x06, 0x834d },
- { 0x06, 0x0fee },
- { 0x06, 0x834c },
- { 0x06, 0x0fee },
- { 0x06, 0x834f },
- { 0x06, 0x00ee },
- { 0x06, 0x8351 },
- { 0x06, 0x00ee },
- { 0x06, 0x834a },
- { 0x06, 0xffee },
- { 0x06, 0x834b },
- { 0x06, 0xffe0 },
- { 0x06, 0x8330 },
- { 0x06, 0xe183 },
- { 0x06, 0x3158 },
- { 0x06, 0xfee4 },
- { 0x06, 0xf88a },
- { 0x06, 0xe5f8 },
- { 0x06, 0x8be0 },
- { 0x06, 0x8332 },
- { 0x06, 0xe183 },
- { 0x06, 0x3359 },
- { 0x06, 0x0fe2 },
- { 0x06, 0x834d },
- { 0x06, 0x0c24 },
- { 0x06, 0x5af0 },
- { 0x06, 0x1e12 },
- { 0x06, 0xe4f8 },
- { 0x06, 0x8ce5 },
- { 0x06, 0xf88d },
- { 0x06, 0xaf82 },
- { 0x06, 0x13e0 },
- { 0x06, 0x834f },
- { 0x06, 0x10e4 },
- { 0x06, 0x834f },
- { 0x06, 0xe083 },
- { 0x06, 0x4e78 },
- { 0x06, 0x009f },
- { 0x06, 0x0ae0 },
- { 0x06, 0x834f },
- { 0x06, 0xa010 },
- { 0x06, 0xa5ee },
- { 0x06, 0x834e },
- { 0x06, 0x01e0 },
- { 0x06, 0x834e },
- { 0x06, 0x7805 },
- { 0x06, 0x9e9a },
- { 0x06, 0xe083 },
- { 0x06, 0x4e78 },
- { 0x06, 0x049e },
- { 0x06, 0x10e0 },
- { 0x06, 0x834e },
- { 0x06, 0x7803 },
- { 0x06, 0x9e0f },
- { 0x06, 0xe083 },
- { 0x06, 0x4e78 },
- { 0x06, 0x019e },
- { 0x06, 0x05ae },
- { 0x06, 0x0caf },
- { 0x06, 0x81f8 },
- { 0x06, 0xaf81 },
- { 0x06, 0xa3af },
- { 0x06, 0x81dc },
- { 0x06, 0xaf82 },
- { 0x06, 0x13ee },
- { 0x06, 0x8348 },
- { 0x06, 0x00ee },
- { 0x06, 0x8349 },
- { 0x06, 0x00e0 },
- { 0x06, 0x8351 },
- { 0x06, 0x10e4 },
- { 0x06, 0x8351 },
- { 0x06, 0x5801 },
- { 0x06, 0x9fea },
- { 0x06, 0xd000 },
- { 0x06, 0xd180 },
- { 0x06, 0x1f66 },
- { 0x06, 0xe2f8 },
- { 0x06, 0xeae3 },
- { 0x06, 0xf8eb },
- { 0x06, 0x5af8 },
- { 0x06, 0x1e20 },
- { 0x06, 0xe6f8 },
- { 0x06, 0xeae5 },
- { 0x06, 0xf8eb },
- { 0x06, 0xd302 },
- { 0x06, 0xb3fe },
- { 0x06, 0xe2f8 },
- { 0x06, 0x7cef },
- { 0x06, 0x325b },
- { 0x06, 0x80e3 },
- { 0x06, 0xf87d },
- { 0x06, 0x9e03 },
- { 0x06, 0x7dff },
- { 0x06, 0xff0d },
- { 0x06, 0x581c },
- { 0x06, 0x551a },
- { 0x06, 0x6511 },
- { 0x06, 0xa190 },
- { 0x06, 0xd3e2 },
- { 0x06, 0x8348 },
- { 0x06, 0xe383 },
- { 0x06, 0x491b },
- { 0x06, 0x56ab },
- { 0x06, 0x08ef },
- { 0x06, 0x56e6 },
- { 0x06, 0x8348 },
- { 0x06, 0xe783 },
- { 0x06, 0x4910 },
- { 0x06, 0xd180 },
- { 0x06, 0x1f66 },
- { 0x06, 0xa004 },
- { 0x06, 0xb9e2 },
- { 0x06, 0x8348 },
- { 0x06, 0xe383 },
- { 0x06, 0x49ef },
- { 0x06, 0x65e2 },
- { 0x06, 0x834a },
- { 0x06, 0xe383 },
- { 0x06, 0x4b1b },
- { 0x06, 0x56aa },
- { 0x06, 0x0eef },
- { 0x06, 0x56e6 },
- { 0x06, 0x834a },
- { 0x06, 0xe783 },
- { 0x06, 0x4be2 },
- { 0x06, 0x834d },
- { 0x06, 0xe683 },
- { 0x06, 0x4ce0 },
- { 0x06, 0x834d },
- { 0x06, 0xa000 },
- { 0x06, 0x0caf },
- { 0x06, 0x81dc },
- { 0x06, 0xe083 },
- { 0x06, 0x4d10 },
- { 0x06, 0xe483 },
- { 0x06, 0x4dae },
- { 0x06, 0x0480 },
- { 0x06, 0xe483 },
- { 0x06, 0x4de0 },
- { 0x06, 0x834e },
- { 0x06, 0x7803 },
- { 0x06, 0x9e0b },
- { 0x06, 0xe083 },
- { 0x06, 0x4e78 },
- { 0x06, 0x049e },
- { 0x06, 0x04ee },
- { 0x06, 0x834e },
- { 0x06, 0x02e0 },
- { 0x06, 0x8332 },
- { 0x06, 0xe183 },
- { 0x06, 0x3359 },
- { 0x06, 0x0fe2 },
- { 0x06, 0x834d },
- { 0x06, 0x0c24 },
- { 0x06, 0x5af0 },
- { 0x06, 0x1e12 },
- { 0x06, 0xe4f8 },
- { 0x06, 0x8ce5 },
- { 0x06, 0xf88d },
- { 0x06, 0xe083 },
- { 0x06, 0x30e1 },
- { 0x06, 0x8331 },
- { 0x06, 0x6801 },
- { 0x06, 0xe4f8 },
- { 0x06, 0x8ae5 },
- { 0x06, 0xf88b },
- { 0x06, 0xae37 },
- { 0x06, 0xee83 },
- { 0x06, 0x4e03 },
- { 0x06, 0xe083 },
- { 0x06, 0x4ce1 },
- { 0x06, 0x834d },
- { 0x06, 0x1b01 },
- { 0x06, 0x9e04 },
- { 0x06, 0xaaa1 },
- { 0x06, 0xaea8 },
- { 0x06, 0xee83 },
- { 0x06, 0x4e04 },
- { 0x06, 0xee83 },
- { 0x06, 0x4f00 },
- { 0x06, 0xaeab },
- { 0x06, 0xe083 },
- { 0x06, 0x4f78 },
- { 0x06, 0x039f },
- { 0x06, 0x14ee },
- { 0x06, 0x834e },
- { 0x06, 0x05d2 },
- { 0x06, 0x40d6 },
- { 0x06, 0x5554 },
- { 0x06, 0x0282 },
- { 0x06, 0x17d2 },
- { 0x06, 0xa0d6 },
- { 0x06, 0xba00 },
- { 0x06, 0x0282 },
- { 0x06, 0x17fe },
- { 0x06, 0xfdfc },
- { 0x06, 0x05f8 },
- { 0x06, 0xe0f8 },
- { 0x06, 0x60e1 },
- { 0x06, 0xf861 },
- { 0x06, 0x6802 },
- { 0x06, 0xe4f8 },
- { 0x06, 0x60e5 },
- { 0x06, 0xf861 },
- { 0x06, 0xe0f8 },
- { 0x06, 0x48e1 },
- { 0x06, 0xf849 },
- { 0x06, 0x580f },
- { 0x06, 0x1e02 },
- { 0x06, 0xe4f8 },
- { 0x06, 0x48e5 },
- { 0x06, 0xf849 },
- { 0x06, 0xd000 },
- { 0x06, 0x0282 },
- { 0x06, 0x5bbf },
- { 0x06, 0x8350 },
- { 0x06, 0xef46 },
- { 0x06, 0xdc19 },
- { 0x06, 0xddd0 },
- { 0x06, 0x0102 },
- { 0x06, 0x825b },
- { 0x06, 0x0282 },
- { 0x06, 0x77e0 },
- { 0x06, 0xf860 },
- { 0x06, 0xe1f8 },
- { 0x06, 0x6158 },
- { 0x06, 0xfde4 },
- { 0x06, 0xf860 },
- { 0x06, 0xe5f8 },
- { 0x06, 0x61fc },
- { 0x06, 0x04f9 },
- { 0x06, 0xfafb },
- { 0x06, 0xc6bf },
- { 0x06, 0xf840 },
- { 0x06, 0xbe83 },
- { 0x06, 0x50a0 },
- { 0x06, 0x0101 },
- { 0x06, 0x071b },
- { 0x06, 0x89cf },
- { 0x06, 0xd208 },
- { 0x06, 0xebdb },
- { 0x06, 0x19b2 },
- { 0x06, 0xfbff },
- { 0x06, 0xfefd },
- { 0x06, 0x04f8 },
- { 0x06, 0xe0f8 },
- { 0x06, 0x48e1 },
- { 0x06, 0xf849 },
- { 0x06, 0x6808 },
- { 0x06, 0xe4f8 },
- { 0x06, 0x48e5 },
- { 0x06, 0xf849 },
- { 0x06, 0x58f7 },
- { 0x06, 0xe4f8 },
- { 0x06, 0x48e5 },
- { 0x06, 0xf849 },
- { 0x06, 0xfc04 },
- { 0x06, 0x4d20 },
- { 0x06, 0x0002 },
- { 0x06, 0x4e22 },
- { 0x06, 0x0002 },
- { 0x06, 0x4ddf },
- { 0x06, 0xff01 },
- { 0x06, 0x4edd },
- { 0x06, 0xff01 },
- { 0x06, 0xf8fa },
- { 0x06, 0xfbef },
- { 0x06, 0x79bf },
- { 0x06, 0xf822 },
- { 0x06, 0xd819 },
- { 0x06, 0xd958 },
- { 0x06, 0x849f },
- { 0x06, 0x09bf },
- { 0x06, 0x82be },
- { 0x06, 0xd682 },
- { 0x06, 0xc602 },
- { 0x06, 0x014f },
- { 0x06, 0xef97 },
- { 0x06, 0xfffe },
- { 0x06, 0xfc05 },
- { 0x06, 0x17ff },
- { 0x06, 0xfe01 },
- { 0x06, 0x1700 },
- { 0x06, 0x0102 },
- { 0x05, 0x83d8 },
- { 0x06, 0x8051 },
- { 0x05, 0x83d6 },
- { 0x06, 0x82a0 },
- { 0x05, 0x83d4 },
- { 0x06, 0x8000 },
- { 0x02, 0x2010 },
- { 0x03, 0xdc00 },
- { 0x1f, 0x0000 },
- { 0x0b, 0x0600 },
- { 0x1f, 0x0005 },
- { 0x05, 0xfff6 },
- { 0x06, 0x00fc },
- { 0x1f, 0x0000 }
- };
+ int rc;
- rtl_writephy_batch(tp, phy_reg_init_0, ARRAY_SIZE(phy_reg_init_0));
+ rc = rtl_writephy_fw(tp, "rtl8168d_1_0_phy.fw");
+ if (rc < 0)
+ goto out;
/*
* Rx Error Issue
@@ -2406,391 +1852,27 @@ static void rtl8168d_1_hw_phy_config(struct rtl8169_private *tp)
rtl_writephy(tp, 0x1f, 0x0005);
rtl_writephy(tp, 0x05, 0x001b);
- if (rtl_readphy(tp, 0x06) == 0xbf00)
- rtl_writephy_batch(tp, phy_reg_init_2, ARRAY_SIZE(phy_reg_init_2));
+ if (rtl_readphy(tp, 0x06) == 0xbf00) {
+ rc = rtl_writephy_fw(tp, "rtl8168d_1_1_phy.fw");
+ if (rc < 0)
+ goto out;
+ }
rtl_writephy(tp, 0x1f, 0x0000);
+out:
+ return rc;
}
-static void rtl8168d_2_hw_phy_config(struct rtl8169_private *tp)
+MODULE_FIRMWARE("rtl8168d_2_0-phy.fw");
+MODULE_FIRMWARE("rtl8168d_2_1-phy.fw");
+static int rtl8168d_2_hw_phy_config(struct rtl8169_private *tp)
{
- static const struct phy_reg phy_reg_init_0[] = {
- /* Channel Estimation */
- { 0x1f, 0x0001 },
- { 0x06, 0x4064 },
- { 0x07, 0x2863 },
- { 0x08, 0x059c },
- { 0x09, 0x26b4 },
- { 0x0a, 0x6a19 },
- { 0x0b, 0xdcc8 },
- { 0x10, 0xf06d },
- { 0x14, 0x7f68 },
- { 0x18, 0x7fd9 },
- { 0x1c, 0xf0ff },
- { 0x1d, 0x3d9c },
- { 0x1f, 0x0003 },
- { 0x12, 0xf49f },
- { 0x13, 0x070b },
- { 0x1a, 0x05ad },
- { 0x14, 0x94c0 },
-
- /*
- * Tx Error Issue
- * enhance line driver power
- */
- { 0x1f, 0x0002 },
- { 0x06, 0x5561 },
- { 0x1f, 0x0005 },
- { 0x05, 0x8332 },
- { 0x06, 0x5561 },
-
- /*
- * Can not link to 1Gbps with bad cable
- * Decrease SNR threshold form 21.07dB to 19.04dB
- */
- { 0x1f, 0x0001 },
- { 0x17, 0x0cc0 },
-
- { 0x1f, 0x0000 },
- { 0x0d, 0xf880 }
- };
- static const struct phy_reg phy_reg_init_1[] = {
- /* Low pass filter & DLY_CAP fine tune from uC */
- { 0x1f, 0x0005 },
- { 0x05, 0xfff6 },
- { 0x06, 0x0080 },
- { 0x05, 0x8000 },
- { 0x06, 0xf8f9 },
- { 0x06, 0xfaee },
- { 0x06, 0xf8ea },
- { 0x06, 0x00ee },
- { 0x06, 0xf8eb },
- { 0x06, 0x00e2 },
- { 0x06, 0xf87c },
- { 0x06, 0xe3f8 },
- { 0x06, 0x7da5 },
- { 0x06, 0x1111 },
- { 0x06, 0x12d2 },
- { 0x06, 0x40d6 },
- { 0x06, 0x4444 },
- { 0x06, 0x0281 },
- { 0x06, 0xc6d2 },
- { 0x06, 0xa0d6 },
- { 0x06, 0xaaaa },
- { 0x06, 0x0281 },
- { 0x06, 0xc6ae },
- { 0x06, 0x0fa5 },
- { 0x06, 0x4444 },
- { 0x06, 0x02ae },
- { 0x06, 0x4da5 },
- { 0x06, 0xaaaa },
- { 0x06, 0x02ae },
- { 0x06, 0x47af },
- { 0x06, 0x81c2 },
- { 0x06, 0xee83 },
- { 0x06, 0x4e00 },
- { 0x06, 0xee83 },
- { 0x06, 0x4d0f },
- { 0x06, 0xee83 },
- { 0x06, 0x4c0f },
- { 0x06, 0xee83 },
- { 0x06, 0x4f00 },
- { 0x06, 0xee83 },
- { 0x06, 0x5100 },
- { 0x06, 0xee83 },
- { 0x06, 0x4aff },
- { 0x06, 0xee83 },
- { 0x06, 0x4bff },
- { 0x06, 0xe083 },
- { 0x06, 0x30e1 },
- { 0x06, 0x8331 },
- { 0x06, 0x58fe },
- { 0x06, 0xe4f8 },
- { 0x06, 0x8ae5 },
- { 0x06, 0xf88b },
- { 0x06, 0xe083 },
- { 0x06, 0x32e1 },
- { 0x06, 0x8333 },
- { 0x06, 0x590f },
- { 0x06, 0xe283 },
- { 0x06, 0x4d0c },
- { 0x06, 0x245a },
- { 0x06, 0xf01e },
- { 0x06, 0x12e4 },
- { 0x06, 0xf88c },
- { 0x06, 0xe5f8 },
- { 0x06, 0x8daf },
- { 0x06, 0x81c2 },
- { 0x06, 0xe083 },
- { 0x06, 0x4f10 },
- { 0x06, 0xe483 },
- { 0x06, 0x4fe0 },
- { 0x06, 0x834e },
- { 0x06, 0x7800 },
- { 0x06, 0x9f0a },
- { 0x06, 0xe083 },
- { 0x06, 0x4fa0 },
- { 0x06, 0x10a5 },
- { 0x06, 0xee83 },
- { 0x06, 0x4e01 },
- { 0x06, 0xe083 },
- { 0x06, 0x4e78 },
- { 0x06, 0x059e },
- { 0x06, 0x9ae0 },
- { 0x06, 0x834e },
- { 0x06, 0x7804 },
- { 0x06, 0x9e10 },
- { 0x06, 0xe083 },
- { 0x06, 0x4e78 },
- { 0x06, 0x039e },
- { 0x06, 0x0fe0 },
- { 0x06, 0x834e },
- { 0x06, 0x7801 },
- { 0x06, 0x9e05 },
- { 0x06, 0xae0c },
- { 0x06, 0xaf81 },
- { 0x06, 0xa7af },
- { 0x06, 0x8152 },
- { 0x06, 0xaf81 },
- { 0x06, 0x8baf },
- { 0x06, 0x81c2 },
- { 0x06, 0xee83 },
- { 0x06, 0x4800 },
- { 0x06, 0xee83 },
- { 0x06, 0x4900 },
- { 0x06, 0xe083 },
- { 0x06, 0x5110 },
- { 0x06, 0xe483 },
- { 0x06, 0x5158 },
- { 0x06, 0x019f },
- { 0x06, 0xead0 },
- { 0x06, 0x00d1 },
- { 0x06, 0x801f },
- { 0x06, 0x66e2 },
- { 0x06, 0xf8ea },
- { 0x06, 0xe3f8 },
- { 0x06, 0xeb5a },
- { 0x06, 0xf81e },
- { 0x06, 0x20e6 },
- { 0x06, 0xf8ea },
- { 0x06, 0xe5f8 },
- { 0x06, 0xebd3 },
- { 0x06, 0x02b3 },
- { 0x06, 0xfee2 },
- { 0x06, 0xf87c },
- { 0x06, 0xef32 },
- { 0x06, 0x5b80 },
- { 0x06, 0xe3f8 },
- { 0x06, 0x7d9e },
- { 0x06, 0x037d },
- { 0x06, 0xffff },
- { 0x06, 0x0d58 },
- { 0x06, 0x1c55 },
- { 0x06, 0x1a65 },
- { 0x06, 0x11a1 },
- { 0x06, 0x90d3 },
- { 0x06, 0xe283 },
- { 0x06, 0x48e3 },
- { 0x06, 0x8349 },
- { 0x06, 0x1b56 },
- { 0x06, 0xab08 },
- { 0x06, 0xef56 },
- { 0x06, 0xe683 },
- { 0x06, 0x48e7 },
- { 0x06, 0x8349 },
- { 0x06, 0x10d1 },
- { 0x06, 0x801f },
- { 0x06, 0x66a0 },
- { 0x06, 0x04b9 },
- { 0x06, 0xe283 },
- { 0x06, 0x48e3 },
- { 0x06, 0x8349 },
- { 0x06, 0xef65 },
- { 0x06, 0xe283 },
- { 0x06, 0x4ae3 },
- { 0x06, 0x834b },
- { 0x06, 0x1b56 },
- { 0x06, 0xaa0e },
- { 0x06, 0xef56 },
- { 0x06, 0xe683 },
- { 0x06, 0x4ae7 },
- { 0x06, 0x834b },
- { 0x06, 0xe283 },
- { 0x06, 0x4de6 },
- { 0x06, 0x834c },
- { 0x06, 0xe083 },
- { 0x06, 0x4da0 },
- { 0x06, 0x000c },
- { 0x06, 0xaf81 },
- { 0x06, 0x8be0 },
- { 0x06, 0x834d },
- { 0x06, 0x10e4 },
- { 0x06, 0x834d },
- { 0x06, 0xae04 },
- { 0x06, 0x80e4 },
- { 0x06, 0x834d },
- { 0x06, 0xe083 },
- { 0x06, 0x4e78 },
- { 0x06, 0x039e },
- { 0x06, 0x0be0 },
- { 0x06, 0x834e },
- { 0x06, 0x7804 },
- { 0x06, 0x9e04 },
- { 0x06, 0xee83 },
- { 0x06, 0x4e02 },
- { 0x06, 0xe083 },
- { 0x06, 0x32e1 },
- { 0x06, 0x8333 },
- { 0x06, 0x590f },
- { 0x06, 0xe283 },
- { 0x06, 0x4d0c },
- { 0x06, 0x245a },
- { 0x06, 0xf01e },
- { 0x06, 0x12e4 },
- { 0x06, 0xf88c },
- { 0x06, 0xe5f8 },
- { 0x06, 0x8de0 },
- { 0x06, 0x8330 },
- { 0x06, 0xe183 },
- { 0x06, 0x3168 },
- { 0x06, 0x01e4 },
- { 0x06, 0xf88a },
- { 0x06, 0xe5f8 },
- { 0x06, 0x8bae },
- { 0x06, 0x37ee },
- { 0x06, 0x834e },
- { 0x06, 0x03e0 },
- { 0x06, 0x834c },
- { 0x06, 0xe183 },
- { 0x06, 0x4d1b },
- { 0x06, 0x019e },
- { 0x06, 0x04aa },
- { 0x06, 0xa1ae },
- { 0x06, 0xa8ee },
- { 0x06, 0x834e },
- { 0x06, 0x04ee },
- { 0x06, 0x834f },
- { 0x06, 0x00ae },
- { 0x06, 0xabe0 },
- { 0x06, 0x834f },
- { 0x06, 0x7803 },
- { 0x06, 0x9f14 },
- { 0x06, 0xee83 },
- { 0x06, 0x4e05 },
- { 0x06, 0xd240 },
- { 0x06, 0xd655 },
- { 0x06, 0x5402 },
- { 0x06, 0x81c6 },
- { 0x06, 0xd2a0 },
- { 0x06, 0xd6ba },
- { 0x06, 0x0002 },
- { 0x06, 0x81c6 },
- { 0x06, 0xfefd },
- { 0x06, 0xfc05 },
- { 0x06, 0xf8e0 },
- { 0x06, 0xf860 },
- { 0x06, 0xe1f8 },
- { 0x06, 0x6168 },
- { 0x06, 0x02e4 },
- { 0x06, 0xf860 },
- { 0x06, 0xe5f8 },
- { 0x06, 0x61e0 },
- { 0x06, 0xf848 },
- { 0x06, 0xe1f8 },
- { 0x06, 0x4958 },
- { 0x06, 0x0f1e },
- { 0x06, 0x02e4 },
- { 0x06, 0xf848 },
- { 0x06, 0xe5f8 },
- { 0x06, 0x49d0 },
- { 0x06, 0x0002 },
- { 0x06, 0x820a },
- { 0x06, 0xbf83 },
- { 0x06, 0x50ef },
- { 0x06, 0x46dc },
- { 0x06, 0x19dd },
- { 0x06, 0xd001 },
- { 0x06, 0x0282 },
- { 0x06, 0x0a02 },
- { 0x06, 0x8226 },
- { 0x06, 0xe0f8 },
- { 0x06, 0x60e1 },
- { 0x06, 0xf861 },
- { 0x06, 0x58fd },
- { 0x06, 0xe4f8 },
- { 0x06, 0x60e5 },
- { 0x06, 0xf861 },
- { 0x06, 0xfc04 },
- { 0x06, 0xf9fa },
- { 0x06, 0xfbc6 },
- { 0x06, 0xbff8 },
- { 0x06, 0x40be },
- { 0x06, 0x8350 },
- { 0x06, 0xa001 },
- { 0x06, 0x0107 },
- { 0x06, 0x1b89 },
- { 0x06, 0xcfd2 },
- { 0x06, 0x08eb },
- { 0x06, 0xdb19 },
- { 0x06, 0xb2fb },
- { 0x06, 0xfffe },
- { 0x06, 0xfd04 },
- { 0x06, 0xf8e0 },
- { 0x06, 0xf848 },
- { 0x06, 0xe1f8 },
- { 0x06, 0x4968 },
- { 0x06, 0x08e4 },
- { 0x06, 0xf848 },
- { 0x06, 0xe5f8 },
- { 0x06, 0x4958 },
- { 0x06, 0xf7e4 },
- { 0x06, 0xf848 },
- { 0x06, 0xe5f8 },
- { 0x06, 0x49fc },
- { 0x06, 0x044d },
- { 0x06, 0x2000 },
- { 0x06, 0x024e },
- { 0x06, 0x2200 },
- { 0x06, 0x024d },
- { 0x06, 0xdfff },
- { 0x06, 0x014e },
- { 0x06, 0xddff },
- { 0x06, 0x01f8 },
- { 0x06, 0xfafb },
- { 0x06, 0xef79 },
- { 0x06, 0xbff8 },
- { 0x06, 0x22d8 },
- { 0x06, 0x19d9 },
- { 0x06, 0x5884 },
- { 0x06, 0x9f09 },
- { 0x06, 0xbf82 },
- { 0x06, 0x6dd6 },
- { 0x06, 0x8275 },
- { 0x06, 0x0201 },
- { 0x06, 0x4fef },
- { 0x06, 0x97ff },
- { 0x06, 0xfefc },
- { 0x06, 0x0517 },
- { 0x06, 0xfffe },
- { 0x06, 0x0117 },
- { 0x06, 0x0001 },
- { 0x06, 0x0200 },
- { 0x05, 0x83d8 },
- { 0x06, 0x8000 },
- { 0x05, 0x83d6 },
- { 0x06, 0x824f },
- { 0x02, 0x2010 },
- { 0x03, 0xdc00 },
- { 0x1f, 0x0000 },
- { 0x0b, 0x0600 },
- { 0x1f, 0x0005 },
- { 0x05, 0xfff6 },
- { 0x06, 0x00fc },
- { 0x1f, 0x0000 }
- };
void __iomem *ioaddr = tp->mmio_addr;
+ int rc;
- rtl_writephy_batch(tp, phy_reg_init_0, ARRAY_SIZE(phy_reg_init_0));
+ rc = rtl_writephy_fw(tp, "rtl8168d_2_0-phy.fw");
+ if (rc < 0)
+ goto out;
if (rtl8168d_efuse_read(ioaddr, 0x01) == 0xb1) {
static const struct phy_reg phy_reg_init[] = {
@@ -2843,71 +1925,21 @@ static void rtl8168d_2_hw_phy_config(struct rtl8169_private *tp)
rtl_writephy(tp, 0x1f, 0x0005);
rtl_writephy(tp, 0x05, 0x001b);
- if (rtl_readphy(tp, 0x06) == 0xb300)
- rtl_writephy_batch(tp, phy_reg_init_1, ARRAY_SIZE(phy_reg_init_1));
+ if (rtl_readphy(tp, 0x06) == 0xb300) {
+ rc = rtl_writephy_fw(tp, "rtl8168d_2_1_phy.fw");
+ if (rc < 0)
+ goto out;
+ }
rtl_writephy(tp, 0x1f, 0x0000);
+out:
+ return rc;
}
-static void rtl8168d_3_hw_phy_config(struct rtl8169_private *tp)
+MODULE_FIRMWARE("rtl8168d_3_phy.fw");
+static int rtl8168d_3_hw_phy_config(struct rtl8169_private *tp)
{
- static const struct phy_reg phy_reg_init[] = {
- { 0x1f, 0x0002 },
- { 0x10, 0x0008 },
- { 0x0d, 0x006c },
-
- { 0x1f, 0x0000 },
- { 0x0d, 0xf880 },
-
- { 0x1f, 0x0001 },
- { 0x17, 0x0cc0 },
-
- { 0x1f, 0x0001 },
- { 0x0b, 0xa4d8 },
- { 0x09, 0x281c },
- { 0x07, 0x2883 },
- { 0x0a, 0x6b35 },
- { 0x1d, 0x3da4 },
- { 0x1c, 0xeffd },
- { 0x14, 0x7f52 },
- { 0x18, 0x7fc6 },
- { 0x08, 0x0601 },
- { 0x06, 0x4063 },
- { 0x10, 0xf074 },
- { 0x1f, 0x0003 },
- { 0x13, 0x0789 },
- { 0x12, 0xf4bd },
- { 0x1a, 0x04fd },
- { 0x14, 0x84b0 },
- { 0x1f, 0x0000 },
- { 0x00, 0x9200 },
-
- { 0x1f, 0x0005 },
- { 0x01, 0x0340 },
- { 0x1f, 0x0001 },
- { 0x04, 0x4000 },
- { 0x03, 0x1d21 },
- { 0x02, 0x0c32 },
- { 0x01, 0x0200 },
- { 0x00, 0x5554 },
- { 0x04, 0x4800 },
- { 0x04, 0x4000 },
- { 0x04, 0xf000 },
- { 0x03, 0xdf01 },
- { 0x02, 0xdf20 },
- { 0x01, 0x101a },
- { 0x00, 0xa0ff },
- { 0x04, 0xf800 },
- { 0x04, 0xf000 },
- { 0x1f, 0x0000 },
-
- { 0x1f, 0x0007 },
- { 0x1e, 0x0023 },
- { 0x16, 0x0000 },
- { 0x1f, 0x0000 }
- };
-
- rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+ return rtl_writephy_fw(tp, "rtl8168d_3_phy.fw");
}
static void rtl8168d_4_hw_phy_config(struct rtl8169_private *tp)
@@ -2943,9 +1975,10 @@ static void rtl8102e_hw_phy_config(struct rtl8169_private *tp)
rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
}
-static void rtl_hw_phy_config(struct net_device *dev)
+static int rtl_hw_phy_config(struct net_device *dev)
{
struct rtl8169_private *tp = netdev_priv(dev);
+ int rc = 0;
rtl8169_print_mac_version(tp);
@@ -2954,16 +1987,16 @@ static void rtl_hw_phy_config(struct net_device *dev)
break;
case RTL_GIGA_MAC_VER_02:
case RTL_GIGA_MAC_VER_03:
- rtl8169s_hw_phy_config(tp);
+ rc = rtl8169s_hw_phy_config(tp);
break;
case RTL_GIGA_MAC_VER_04:
rtl8169sb_hw_phy_config(tp);
break;
case RTL_GIGA_MAC_VER_05:
- rtl8169scd_hw_phy_config(tp);
+ rc = rtl8169scd_hw_phy_config(tp);
break;
case RTL_GIGA_MAC_VER_06:
- rtl8169sce_hw_phy_config(tp);
+ rc = rtl8169sce_hw_phy_config(tp);
break;
case RTL_GIGA_MAC_VER_07:
case RTL_GIGA_MAC_VER_08:
@@ -2983,29 +2016,29 @@ static void rtl_hw_phy_config(struct net_device *dev)
rtl8168cp_1_hw_phy_config(tp);
break;
case RTL_GIGA_MAC_VER_19:
- rtl8168c_1_hw_phy_config(tp);
+ rc = rtl8168c_1_hw_phy_config(tp);
break;
case RTL_GIGA_MAC_VER_20:
- rtl8168c_2_hw_phy_config(tp);
+ rc = rtl8168c_2_hw_phy_config(tp);
break;
case RTL_GIGA_MAC_VER_21:
- rtl8168c_3_hw_phy_config(tp);
+ rc = rtl8168c_3_hw_phy_config(tp);
break;
case RTL_GIGA_MAC_VER_22:
- rtl8168c_4_hw_phy_config(tp);
+ rc = rtl8168c_4_hw_phy_config(tp);
break;
case RTL_GIGA_MAC_VER_23:
case RTL_GIGA_MAC_VER_24:
rtl8168cp_2_hw_phy_config(tp);
break;
case RTL_GIGA_MAC_VER_25:
- rtl8168d_1_hw_phy_config(tp);
+ rc = rtl8168d_1_hw_phy_config(tp);
break;
case RTL_GIGA_MAC_VER_26:
- rtl8168d_2_hw_phy_config(tp);
+ rc = rtl8168d_2_hw_phy_config(tp);
break;
case RTL_GIGA_MAC_VER_27:
- rtl8168d_3_hw_phy_config(tp);
+ rc = rtl8168d_3_hw_phy_config(tp);
break;
case RTL_GIGA_MAC_VER_28:
rtl8168d_4_hw_phy_config(tp);
@@ -3014,6 +2047,8 @@ static void rtl_hw_phy_config(struct net_device *dev)
default:
break;
}
+
+ return rc;
}
static void rtl8169_phy_timer(unsigned long __opaque)
@@ -3117,11 +2152,14 @@ static void rtl8169_phy_reset(struct net_device *dev,
netif_err(tp, link, dev, "PHY reset failed\n");
}
-static void rtl8169_init_phy(struct net_device *dev, struct rtl8169_private *tp)
+static int rtl8169_init_phy(struct net_device *dev, struct rtl8169_private *tp)
{
void __iomem *ioaddr = tp->mmio_addr;
+ int rc;
- rtl_hw_phy_config(dev);
+ rc = rtl_hw_phy_config(dev);
+ if (rc < 0)
+ goto out;
if (tp->mac_version <= RTL_GIGA_MAC_VER_06) {
dprintk("Set MAC Reg C+CR Offset 0x82h = 0x01h\n");
@@ -3150,6 +2188,8 @@ static void rtl8169_init_phy(struct net_device *dev, struct rtl8169_private *tp)
if (RTL_R8(PHYstatus) & TBI_Enable)
netif_info(tp, link, dev, "TBI auto-negotiating\n");
+out:
+ return rc;
}
static void rtl_rar_set(struct rtl8169_private *tp, u8 *addr)
@@ -3694,7 +2734,9 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
rtl8168_driver_start(tp);
}
- rtl8169_init_phy(dev, tp);
+ rc = rtl8169_init_phy(dev, tp);
+ if (rc < 0)
+ goto err_out_unregister_5;
/*
* Pretend we are using VLANs; This bypasses a nasty bug where
@@ -3711,6 +2753,8 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
out:
return rc;
+err_out_unregister_5:
+ unregister_netdev(dev);
err_out_msi_4:
rtl_disable_msi(pdev, tp);
iounmap(ioaddr);
diff --git a/firmware/r8169/8168c_1.h b/firmware/r8169/8168c_1.h
new file mode 100644
index 0000000..d944a85
--- /dev/null
+++ b/firmware/r8169/8168c_1.h
@@ -0,0 +1,19 @@
+static const struct phy_reg phy_reg_init_8168c_1[] = {
+ { 0x1f, 0x0001 },
+ { 0x12, 0x2300 },
+ { 0x1f, 0x0002 },
+ { 0x00, 0x88d4 },
+ { 0x01, 0x82b1 },
+ { 0x03, 0x7002 },
+ { 0x08, 0x9e30 },
+ { 0x09, 0x01f0 },
+ { 0x0a, 0x5500 },
+ { 0x0c, 0x00c8 },
+ { 0x1f, 0x0003 },
+ { 0x12, 0xc096 },
+ { 0x16, 0x000a },
+ { 0x1f, 0x0000 },
+ { 0x1f, 0x0000 },
+ { 0x09, 0x2000 },
+ { 0x09, 0x0000 }
+};
diff --git a/firmware/r8169/8168c_2.h b/firmware/r8169/8168c_2.h
new file mode 100644
index 0000000..36e487e
--- /dev/null
+++ b/firmware/r8169/8168c_2.h
@@ -0,0 +1,17 @@
+static const struct phy_reg phy_reg_init_8168c_2[] = {
+ { 0x1f, 0x0001 },
+ { 0x12, 0x2300 },
+ { 0x03, 0x802f },
+ { 0x02, 0x4f02 },
+ { 0x01, 0x0409 },
+ { 0x00, 0xf099 },
+ { 0x04, 0x9800 },
+ { 0x04, 0x9000 },
+ { 0x1d, 0x3d98 },
+ { 0x1f, 0x0002 },
+ { 0x0c, 0x7eb8 },
+ { 0x06, 0x0761 },
+ { 0x1f, 0x0003 },
+ { 0x16, 0x0f0a },
+ { 0x1f, 0x0000 }
+};
diff --git a/firmware/r8169/8168c_3.h b/firmware/r8169/8168c_3.h
new file mode 100644
index 0000000..83f13f7
--- /dev/null
+++ b/firmware/r8169/8168c_3.h
@@ -0,0 +1,11 @@
+static const struct phy_reg phy_reg_init_8168c_3[] = {
+ { 0x1f, 0x0001 },
+ { 0x12, 0x2300 },
+ { 0x1d, 0x3d98 },
+ { 0x1f, 0x0002 },
+ { 0x0c, 0x7eb8 },
+ { 0x06, 0x5461 },
+ { 0x1f, 0x0003 },
+ { 0x16, 0x0f0a },
+ { 0x1f, 0x0000 }
+};
diff --git a/firmware/r8169/8168d_1_0.h b/firmware/r8169/8168d_1_0.h
new file mode 100644
index 0000000..2177a92
--- /dev/null
+++ b/firmware/r8169/8168d_1_0.h
@@ -0,0 +1,40 @@
+static const struct phy_reg phy_reg_init_8168d_1_0[] = {
+ /* Channel Estimation */
+ { 0x1f, 0x0001 },
+ { 0x06, 0x4064 },
+ { 0x07, 0x2863 },
+ { 0x08, 0x059c },
+ { 0x09, 0x26b4 },
+ { 0x0a, 0x6a19 },
+ { 0x0b, 0xdcc8 },
+ { 0x10, 0xf06d },
+ { 0x14, 0x7f68 },
+ { 0x18, 0x7fd9 },
+ { 0x1c, 0xf0ff },
+ { 0x1d, 0x3d9c },
+ { 0x1f, 0x0003 },
+ { 0x12, 0xf49f },
+ { 0x13, 0x070b },
+ { 0x1a, 0x05ad },
+ { 0x14, 0x94c0 },
+
+ /*
+ * Tx Error Issue
+ * enhance line driver power
+ */
+ { 0x1f, 0x0002 },
+ { 0x06, 0x5561 },
+ { 0x1f, 0x0005 },
+ { 0x05, 0x8332 },
+ { 0x06, 0x5561 },
+
+ /*
+ * Can not link to 1Gbps with bad cable
+ * Decrease SNR threshold form 21.07dB to 19.04dB
+ */
+ { 0x1f, 0x0001 },
+ { 0x17, 0x0cc0 },
+
+ { 0x1f, 0x0000 },
+ { 0x0d, 0xf880 }
+};
diff --git a/firmware/r8169/8168d_1_1.h b/firmware/r8169/8168d_1_1.h
new file mode 100644
index 0000000..cc20cb2
--- /dev/null
+++ b/firmware/r8169/8168d_1_1.h
@@ -0,0 +1,376 @@
+static const struct phy_reg phy_reg_init_8168d_1_1[] = {
+ /* Low pass filter & DLY_CAP fine tune from uC */
+ { 0x1f, 0x0005 },
+ { 0x05, 0xfff6 },
+ { 0x06, 0x0080 },
+ { 0x05, 0x8000 },
+ { 0x06, 0xf8f9 },
+ { 0x06, 0xfaef },
+ { 0x06, 0x59ee },
+ { 0x06, 0xf8ea },
+ { 0x06, 0x00ee },
+ { 0x06, 0xf8eb },
+ { 0x06, 0x00e0 },
+ { 0x06, 0xf87c },
+ { 0x06, 0xe1f8 },
+ { 0x06, 0x7d59 },
+ { 0x06, 0x0fef },
+ { 0x06, 0x0139 },
+ { 0x06, 0x029e },
+ { 0x06, 0x06ef },
+ { 0x06, 0x1039 },
+ { 0x06, 0x089f },
+ { 0x06, 0x2aee },
+ { 0x06, 0xf8ea },
+ { 0x06, 0x00ee },
+ { 0x06, 0xf8eb },
+ { 0x06, 0x01e0 },
+ { 0x06, 0xf87c },
+ { 0x06, 0xe1f8 },
+ { 0x06, 0x7d58 },
+ { 0x06, 0x409e },
+ { 0x06, 0x0f39 },
+ { 0x06, 0x46aa },
+ { 0x06, 0x0bbf },
+ { 0x06, 0x8290 },
+ { 0x06, 0xd682 },
+ { 0x06, 0x9802 },
+ { 0x06, 0x014f },
+ { 0x06, 0xae09 },
+ { 0x06, 0xbf82 },
+ { 0x06, 0x98d6 },
+ { 0x06, 0x82a0 },
+ { 0x06, 0x0201 },
+ { 0x06, 0x4fef },
+ { 0x06, 0x95fe },
+ { 0x06, 0xfdfc },
+ { 0x06, 0x05f8 },
+ { 0x06, 0xf9fa },
+ { 0x06, 0xeef8 },
+ { 0x06, 0xea00 },
+ { 0x06, 0xeef8 },
+ { 0x06, 0xeb00 },
+ { 0x06, 0xe2f8 },
+ { 0x06, 0x7ce3 },
+ { 0x06, 0xf87d },
+ { 0x06, 0xa511 },
+ { 0x06, 0x1112 },
+ { 0x06, 0xd240 },
+ { 0x06, 0xd644 },
+ { 0x06, 0x4402 },
+ { 0x06, 0x8217 },
+ { 0x06, 0xd2a0 },
+ { 0x06, 0xd6aa },
+ { 0x06, 0xaa02 },
+ { 0x06, 0x8217 },
+ { 0x06, 0xae0f },
+ { 0x06, 0xa544 },
+ { 0x06, 0x4402 },
+ { 0x06, 0xae4d },
+ { 0x06, 0xa5aa },
+ { 0x06, 0xaa02 },
+ { 0x06, 0xae47 },
+ { 0x06, 0xaf82 },
+ { 0x06, 0x13ee },
+ { 0x06, 0x834e },
+ { 0x06, 0x00ee },
+ { 0x06, 0x834d },
+ { 0x06, 0x0fee },
+ { 0x06, 0x834c },
+ { 0x06, 0x0fee },
+ { 0x06, 0x834f },
+ { 0x06, 0x00ee },
+ { 0x06, 0x8351 },
+ { 0x06, 0x00ee },
+ { 0x06, 0x834a },
+ { 0x06, 0xffee },
+ { 0x06, 0x834b },
+ { 0x06, 0xffe0 },
+ { 0x06, 0x8330 },
+ { 0x06, 0xe183 },
+ { 0x06, 0x3158 },
+ { 0x06, 0xfee4 },
+ { 0x06, 0xf88a },
+ { 0x06, 0xe5f8 },
+ { 0x06, 0x8be0 },
+ { 0x06, 0x8332 },
+ { 0x06, 0xe183 },
+ { 0x06, 0x3359 },
+ { 0x06, 0x0fe2 },
+ { 0x06, 0x834d },
+ { 0x06, 0x0c24 },
+ { 0x06, 0x5af0 },
+ { 0x06, 0x1e12 },
+ { 0x06, 0xe4f8 },
+ { 0x06, 0x8ce5 },
+ { 0x06, 0xf88d },
+ { 0x06, 0xaf82 },
+ { 0x06, 0x13e0 },
+ { 0x06, 0x834f },
+ { 0x06, 0x10e4 },
+ { 0x06, 0x834f },
+ { 0x06, 0xe083 },
+ { 0x06, 0x4e78 },
+ { 0x06, 0x009f },
+ { 0x06, 0x0ae0 },
+ { 0x06, 0x834f },
+ { 0x06, 0xa010 },
+ { 0x06, 0xa5ee },
+ { 0x06, 0x834e },
+ { 0x06, 0x01e0 },
+ { 0x06, 0x834e },
+ { 0x06, 0x7805 },
+ { 0x06, 0x9e9a },
+ { 0x06, 0xe083 },
+ { 0x06, 0x4e78 },
+ { 0x06, 0x049e },
+ { 0x06, 0x10e0 },
+ { 0x06, 0x834e },
+ { 0x06, 0x7803 },
+ { 0x06, 0x9e0f },
+ { 0x06, 0xe083 },
+ { 0x06, 0x4e78 },
+ { 0x06, 0x019e },
+ { 0x06, 0x05ae },
+ { 0x06, 0x0caf },
+ { 0x06, 0x81f8 },
+ { 0x06, 0xaf81 },
+ { 0x06, 0xa3af },
+ { 0x06, 0x81dc },
+ { 0x06, 0xaf82 },
+ { 0x06, 0x13ee },
+ { 0x06, 0x8348 },
+ { 0x06, 0x00ee },
+ { 0x06, 0x8349 },
+ { 0x06, 0x00e0 },
+ { 0x06, 0x8351 },
+ { 0x06, 0x10e4 },
+ { 0x06, 0x8351 },
+ { 0x06, 0x5801 },
+ { 0x06, 0x9fea },
+ { 0x06, 0xd000 },
+ { 0x06, 0xd180 },
+ { 0x06, 0x1f66 },
+ { 0x06, 0xe2f8 },
+ { 0x06, 0xeae3 },
+ { 0x06, 0xf8eb },
+ { 0x06, 0x5af8 },
+ { 0x06, 0x1e20 },
+ { 0x06, 0xe6f8 },
+ { 0x06, 0xeae5 },
+ { 0x06, 0xf8eb },
+ { 0x06, 0xd302 },
+ { 0x06, 0xb3fe },
+ { 0x06, 0xe2f8 },
+ { 0x06, 0x7cef },
+ { 0x06, 0x325b },
+ { 0x06, 0x80e3 },
+ { 0x06, 0xf87d },
+ { 0x06, 0x9e03 },
+ { 0x06, 0x7dff },
+ { 0x06, 0xff0d },
+ { 0x06, 0x581c },
+ { 0x06, 0x551a },
+ { 0x06, 0x6511 },
+ { 0x06, 0xa190 },
+ { 0x06, 0xd3e2 },
+ { 0x06, 0x8348 },
+ { 0x06, 0xe383 },
+ { 0x06, 0x491b },
+ { 0x06, 0x56ab },
+ { 0x06, 0x08ef },
+ { 0x06, 0x56e6 },
+ { 0x06, 0x8348 },
+ { 0x06, 0xe783 },
+ { 0x06, 0x4910 },
+ { 0x06, 0xd180 },
+ { 0x06, 0x1f66 },
+ { 0x06, 0xa004 },
+ { 0x06, 0xb9e2 },
+ { 0x06, 0x8348 },
+ { 0x06, 0xe383 },
+ { 0x06, 0x49ef },
+ { 0x06, 0x65e2 },
+ { 0x06, 0x834a },
+ { 0x06, 0xe383 },
+ { 0x06, 0x4b1b },
+ { 0x06, 0x56aa },
+ { 0x06, 0x0eef },
+ { 0x06, 0x56e6 },
+ { 0x06, 0x834a },
+ { 0x06, 0xe783 },
+ { 0x06, 0x4be2 },
+ { 0x06, 0x834d },
+ { 0x06, 0xe683 },
+ { 0x06, 0x4ce0 },
+ { 0x06, 0x834d },
+ { 0x06, 0xa000 },
+ { 0x06, 0x0caf },
+ { 0x06, 0x81dc },
+ { 0x06, 0xe083 },
+ { 0x06, 0x4d10 },
+ { 0x06, 0xe483 },
+ { 0x06, 0x4dae },
+ { 0x06, 0x0480 },
+ { 0x06, 0xe483 },
+ { 0x06, 0x4de0 },
+ { 0x06, 0x834e },
+ { 0x06, 0x7803 },
+ { 0x06, 0x9e0b },
+ { 0x06, 0xe083 },
+ { 0x06, 0x4e78 },
+ { 0x06, 0x049e },
+ { 0x06, 0x04ee },
+ { 0x06, 0x834e },
+ { 0x06, 0x02e0 },
+ { 0x06, 0x8332 },
+ { 0x06, 0xe183 },
+ { 0x06, 0x3359 },
+ { 0x06, 0x0fe2 },
+ { 0x06, 0x834d },
+ { 0x06, 0x0c24 },
+ { 0x06, 0x5af0 },
+ { 0x06, 0x1e12 },
+ { 0x06, 0xe4f8 },
+ { 0x06, 0x8ce5 },
+ { 0x06, 0xf88d },
+ { 0x06, 0xe083 },
+ { 0x06, 0x30e1 },
+ { 0x06, 0x8331 },
+ { 0x06, 0x6801 },
+ { 0x06, 0xe4f8 },
+ { 0x06, 0x8ae5 },
+ { 0x06, 0xf88b },
+ { 0x06, 0xae37 },
+ { 0x06, 0xee83 },
+ { 0x06, 0x4e03 },
+ { 0x06, 0xe083 },
+ { 0x06, 0x4ce1 },
+ { 0x06, 0x834d },
+ { 0x06, 0x1b01 },
+ { 0x06, 0x9e04 },
+ { 0x06, 0xaaa1 },
+ { 0x06, 0xaea8 },
+ { 0x06, 0xee83 },
+ { 0x06, 0x4e04 },
+ { 0x06, 0xee83 },
+ { 0x06, 0x4f00 },
+ { 0x06, 0xaeab },
+ { 0x06, 0xe083 },
+ { 0x06, 0x4f78 },
+ { 0x06, 0x039f },
+ { 0x06, 0x14ee },
+ { 0x06, 0x834e },
+ { 0x06, 0x05d2 },
+ { 0x06, 0x40d6 },
+ { 0x06, 0x5554 },
+ { 0x06, 0x0282 },
+ { 0x06, 0x17d2 },
+ { 0x06, 0xa0d6 },
+ { 0x06, 0xba00 },
+ { 0x06, 0x0282 },
+ { 0x06, 0x17fe },
+ { 0x06, 0xfdfc },
+ { 0x06, 0x05f8 },
+ { 0x06, 0xe0f8 },
+ { 0x06, 0x60e1 },
+ { 0x06, 0xf861 },
+ { 0x06, 0x6802 },
+ { 0x06, 0xe4f8 },
+ { 0x06, 0x60e5 },
+ { 0x06, 0xf861 },
+ { 0x06, 0xe0f8 },
+ { 0x06, 0x48e1 },
+ { 0x06, 0xf849 },
+ { 0x06, 0x580f },
+ { 0x06, 0x1e02 },
+ { 0x06, 0xe4f8 },
+ { 0x06, 0x48e5 },
+ { 0x06, 0xf849 },
+ { 0x06, 0xd000 },
+ { 0x06, 0x0282 },
+ { 0x06, 0x5bbf },
+ { 0x06, 0x8350 },
+ { 0x06, 0xef46 },
+ { 0x06, 0xdc19 },
+ { 0x06, 0xddd0 },
+ { 0x06, 0x0102 },
+ { 0x06, 0x825b },
+ { 0x06, 0x0282 },
+ { 0x06, 0x77e0 },
+ { 0x06, 0xf860 },
+ { 0x06, 0xe1f8 },
+ { 0x06, 0x6158 },
+ { 0x06, 0xfde4 },
+ { 0x06, 0xf860 },
+ { 0x06, 0xe5f8 },
+ { 0x06, 0x61fc },
+ { 0x06, 0x04f9 },
+ { 0x06, 0xfafb },
+ { 0x06, 0xc6bf },
+ { 0x06, 0xf840 },
+ { 0x06, 0xbe83 },
+ { 0x06, 0x50a0 },
+ { 0x06, 0x0101 },
+ { 0x06, 0x071b },
+ { 0x06, 0x89cf },
+ { 0x06, 0xd208 },
+ { 0x06, 0xebdb },
+ { 0x06, 0x19b2 },
+ { 0x06, 0xfbff },
+ { 0x06, 0xfefd },
+ { 0x06, 0x04f8 },
+ { 0x06, 0xe0f8 },
+ { 0x06, 0x48e1 },
+ { 0x06, 0xf849 },
+ { 0x06, 0x6808 },
+ { 0x06, 0xe4f8 },
+ { 0x06, 0x48e5 },
+ { 0x06, 0xf849 },
+ { 0x06, 0x58f7 },
+ { 0x06, 0xe4f8 },
+ { 0x06, 0x48e5 },
+ { 0x06, 0xf849 },
+ { 0x06, 0xfc04 },
+ { 0x06, 0x4d20 },
+ { 0x06, 0x0002 },
+ { 0x06, 0x4e22 },
+ { 0x06, 0x0002 },
+ { 0x06, 0x4ddf },
+ { 0x06, 0xff01 },
+ { 0x06, 0x4edd },
+ { 0x06, 0xff01 },
+ { 0x06, 0xf8fa },
+ { 0x06, 0xfbef },
+ { 0x06, 0x79bf },
+ { 0x06, 0xf822 },
+ { 0x06, 0xd819 },
+ { 0x06, 0xd958 },
+ { 0x06, 0x849f },
+ { 0x06, 0x09bf },
+ { 0x06, 0x82be },
+ { 0x06, 0xd682 },
+ { 0x06, 0xc602 },
+ { 0x06, 0x014f },
+ { 0x06, 0xef97 },
+ { 0x06, 0xfffe },
+ { 0x06, 0xfc05 },
+ { 0x06, 0x17ff },
+ { 0x06, 0xfe01 },
+ { 0x06, 0x1700 },
+ { 0x06, 0x0102 },
+ { 0x05, 0x83d8 },
+ { 0x06, 0x8051 },
+ { 0x05, 0x83d6 },
+ { 0x06, 0x82a0 },
+ { 0x05, 0x83d4 },
+ { 0x06, 0x8000 },
+ { 0x02, 0x2010 },
+ { 0x03, 0xdc00 },
+ { 0x1f, 0x0000 },
+ { 0x0b, 0x0600 },
+ { 0x1f, 0x0005 },
+ { 0x05, 0xfff6 },
+ { 0x06, 0x00fc },
+ { 0x1f, 0x0000 }
+};
diff --git a/firmware/r8169/8168d_2_0.h b/firmware/r8169/8168d_2_0.h
new file mode 100644
index 0000000..c7988c1
--- /dev/null
+++ b/firmware/r8169/8168d_2_0.h
@@ -0,0 +1,40 @@
+static const struct phy_reg phy_reg_init_8168d_2_0[] = {
+ /* Channel Estimation */
+ { 0x1f, 0x0001 },
+ { 0x06, 0x4064 },
+ { 0x07, 0x2863 },
+ { 0x08, 0x059c },
+ { 0x09, 0x26b4 },
+ { 0x0a, 0x6a19 },
+ { 0x0b, 0xdcc8 },
+ { 0x10, 0xf06d },
+ { 0x14, 0x7f68 },
+ { 0x18, 0x7fd9 },
+ { 0x1c, 0xf0ff },
+ { 0x1d, 0x3d9c },
+ { 0x1f, 0x0003 },
+ { 0x12, 0xf49f },
+ { 0x13, 0x070b },
+ { 0x1a, 0x05ad },
+ { 0x14, 0x94c0 },
+
+ /*
+ * Tx Error Issue
+ * enhance line driver power
+ */
+ { 0x1f, 0x0002 },
+ { 0x06, 0x5561 },
+ { 0x1f, 0x0005 },
+ { 0x05, 0x8332 },
+ { 0x06, 0x5561 },
+
+ /*
+ * Can not link to 1Gbps with bad cable
+ * Decrease SNR threshold form 21.07dB to 19.04dB
+ */
+ { 0x1f, 0x0001 },
+ { 0x17, 0x0cc0 },
+
+ { 0x1f, 0x0000 },
+ { 0x0d, 0xf880 }
+};
diff --git a/firmware/r8169/8168d_2_1.h b/firmware/r8169/8168d_2_1.h
new file mode 100644
index 0000000..8b0855a
--- /dev/null
+++ b/firmware/r8169/8168d_2_1.h
@@ -0,0 +1,334 @@
+static const struct phy_reg phy_reg_init_8168d_2_1[] = {
+ /* Low pass filter & DLY_CAP fine tune from uC */
+ { 0x1f, 0x0005 },
+ { 0x05, 0xfff6 },
+ { 0x06, 0x0080 },
+ { 0x05, 0x8000 },
+ { 0x06, 0xf8f9 },
+ { 0x06, 0xfaee },
+ { 0x06, 0xf8ea },
+ { 0x06, 0x00ee },
+ { 0x06, 0xf8eb },
+ { 0x06, 0x00e2 },
+ { 0x06, 0xf87c },
+ { 0x06, 0xe3f8 },
+ { 0x06, 0x7da5 },
+ { 0x06, 0x1111 },
+ { 0x06, 0x12d2 },
+ { 0x06, 0x40d6 },
+ { 0x06, 0x4444 },
+ { 0x06, 0x0281 },
+ { 0x06, 0xc6d2 },
+ { 0x06, 0xa0d6 },
+ { 0x06, 0xaaaa },
+ { 0x06, 0x0281 },
+ { 0x06, 0xc6ae },
+ { 0x06, 0x0fa5 },
+ { 0x06, 0x4444 },
+ { 0x06, 0x02ae },
+ { 0x06, 0x4da5 },
+ { 0x06, 0xaaaa },
+ { 0x06, 0x02ae },
+ { 0x06, 0x47af },
+ { 0x06, 0x81c2 },
+ { 0x06, 0xee83 },
+ { 0x06, 0x4e00 },
+ { 0x06, 0xee83 },
+ { 0x06, 0x4d0f },
+ { 0x06, 0xee83 },
+ { 0x06, 0x4c0f },
+ { 0x06, 0xee83 },
+ { 0x06, 0x4f00 },
+ { 0x06, 0xee83 },
+ { 0x06, 0x5100 },
+ { 0x06, 0xee83 },
+ { 0x06, 0x4aff },
+ { 0x06, 0xee83 },
+ { 0x06, 0x4bff },
+ { 0x06, 0xe083 },
+ { 0x06, 0x30e1 },
+ { 0x06, 0x8331 },
+ { 0x06, 0x58fe },
+ { 0x06, 0xe4f8 },
+ { 0x06, 0x8ae5 },
+ { 0x06, 0xf88b },
+ { 0x06, 0xe083 },
+ { 0x06, 0x32e1 },
+ { 0x06, 0x8333 },
+ { 0x06, 0x590f },
+ { 0x06, 0xe283 },
+ { 0x06, 0x4d0c },
+ { 0x06, 0x245a },
+ { 0x06, 0xf01e },
+ { 0x06, 0x12e4 },
+ { 0x06, 0xf88c },
+ { 0x06, 0xe5f8 },
+ { 0x06, 0x8daf },
+ { 0x06, 0x81c2 },
+ { 0x06, 0xe083 },
+ { 0x06, 0x4f10 },
+ { 0x06, 0xe483 },
+ { 0x06, 0x4fe0 },
+ { 0x06, 0x834e },
+ { 0x06, 0x7800 },
+ { 0x06, 0x9f0a },
+ { 0x06, 0xe083 },
+ { 0x06, 0x4fa0 },
+ { 0x06, 0x10a5 },
+ { 0x06, 0xee83 },
+ { 0x06, 0x4e01 },
+ { 0x06, 0xe083 },
+ { 0x06, 0x4e78 },
+ { 0x06, 0x059e },
+ { 0x06, 0x9ae0 },
+ { 0x06, 0x834e },
+ { 0x06, 0x7804 },
+ { 0x06, 0x9e10 },
+ { 0x06, 0xe083 },
+ { 0x06, 0x4e78 },
+ { 0x06, 0x039e },
+ { 0x06, 0x0fe0 },
+ { 0x06, 0x834e },
+ { 0x06, 0x7801 },
+ { 0x06, 0x9e05 },
+ { 0x06, 0xae0c },
+ { 0x06, 0xaf81 },
+ { 0x06, 0xa7af },
+ { 0x06, 0x8152 },
+ { 0x06, 0xaf81 },
+ { 0x06, 0x8baf },
+ { 0x06, 0x81c2 },
+ { 0x06, 0xee83 },
+ { 0x06, 0x4800 },
+ { 0x06, 0xee83 },
+ { 0x06, 0x4900 },
+ { 0x06, 0xe083 },
+ { 0x06, 0x5110 },
+ { 0x06, 0xe483 },
+ { 0x06, 0x5158 },
+ { 0x06, 0x019f },
+ { 0x06, 0xead0 },
+ { 0x06, 0x00d1 },
+ { 0x06, 0x801f },
+ { 0x06, 0x66e2 },
+ { 0x06, 0xf8ea },
+ { 0x06, 0xe3f8 },
+ { 0x06, 0xeb5a },
+ { 0x06, 0xf81e },
+ { 0x06, 0x20e6 },
+ { 0x06, 0xf8ea },
+ { 0x06, 0xe5f8 },
+ { 0x06, 0xebd3 },
+ { 0x06, 0x02b3 },
+ { 0x06, 0xfee2 },
+ { 0x06, 0xf87c },
+ { 0x06, 0xef32 },
+ { 0x06, 0x5b80 },
+ { 0x06, 0xe3f8 },
+ { 0x06, 0x7d9e },
+ { 0x06, 0x037d },
+ { 0x06, 0xffff },
+ { 0x06, 0x0d58 },
+ { 0x06, 0x1c55 },
+ { 0x06, 0x1a65 },
+ { 0x06, 0x11a1 },
+ { 0x06, 0x90d3 },
+ { 0x06, 0xe283 },
+ { 0x06, 0x48e3 },
+ { 0x06, 0x8349 },
+ { 0x06, 0x1b56 },
+ { 0x06, 0xab08 },
+ { 0x06, 0xef56 },
+ { 0x06, 0xe683 },
+ { 0x06, 0x48e7 },
+ { 0x06, 0x8349 },
+ { 0x06, 0x10d1 },
+ { 0x06, 0x801f },
+ { 0x06, 0x66a0 },
+ { 0x06, 0x04b9 },
+ { 0x06, 0xe283 },
+ { 0x06, 0x48e3 },
+ { 0x06, 0x8349 },
+ { 0x06, 0xef65 },
+ { 0x06, 0xe283 },
+ { 0x06, 0x4ae3 },
+ { 0x06, 0x834b },
+ { 0x06, 0x1b56 },
+ { 0x06, 0xaa0e },
+ { 0x06, 0xef56 },
+ { 0x06, 0xe683 },
+ { 0x06, 0x4ae7 },
+ { 0x06, 0x834b },
+ { 0x06, 0xe283 },
+ { 0x06, 0x4de6 },
+ { 0x06, 0x834c },
+ { 0x06, 0xe083 },
+ { 0x06, 0x4da0 },
+ { 0x06, 0x000c },
+ { 0x06, 0xaf81 },
+ { 0x06, 0x8be0 },
+ { 0x06, 0x834d },
+ { 0x06, 0x10e4 },
+ { 0x06, 0x834d },
+ { 0x06, 0xae04 },
+ { 0x06, 0x80e4 },
+ { 0x06, 0x834d },
+ { 0x06, 0xe083 },
+ { 0x06, 0x4e78 },
+ { 0x06, 0x039e },
+ { 0x06, 0x0be0 },
+ { 0x06, 0x834e },
+ { 0x06, 0x7804 },
+ { 0x06, 0x9e04 },
+ { 0x06, 0xee83 },
+ { 0x06, 0x4e02 },
+ { 0x06, 0xe083 },
+ { 0x06, 0x32e1 },
+ { 0x06, 0x8333 },
+ { 0x06, 0x590f },
+ { 0x06, 0xe283 },
+ { 0x06, 0x4d0c },
+ { 0x06, 0x245a },
+ { 0x06, 0xf01e },
+ { 0x06, 0x12e4 },
+ { 0x06, 0xf88c },
+ { 0x06, 0xe5f8 },
+ { 0x06, 0x8de0 },
+ { 0x06, 0x8330 },
+ { 0x06, 0xe183 },
+ { 0x06, 0x3168 },
+ { 0x06, 0x01e4 },
+ { 0x06, 0xf88a },
+ { 0x06, 0xe5f8 },
+ { 0x06, 0x8bae },
+ { 0x06, 0x37ee },
+ { 0x06, 0x834e },
+ { 0x06, 0x03e0 },
+ { 0x06, 0x834c },
+ { 0x06, 0xe183 },
+ { 0x06, 0x4d1b },
+ { 0x06, 0x019e },
+ { 0x06, 0x04aa },
+ { 0x06, 0xa1ae },
+ { 0x06, 0xa8ee },
+ { 0x06, 0x834e },
+ { 0x06, 0x04ee },
+ { 0x06, 0x834f },
+ { 0x06, 0x00ae },
+ { 0x06, 0xabe0 },
+ { 0x06, 0x834f },
+ { 0x06, 0x7803 },
+ { 0x06, 0x9f14 },
+ { 0x06, 0xee83 },
+ { 0x06, 0x4e05 },
+ { 0x06, 0xd240 },
+ { 0x06, 0xd655 },
+ { 0x06, 0x5402 },
+ { 0x06, 0x81c6 },
+ { 0x06, 0xd2a0 },
+ { 0x06, 0xd6ba },
+ { 0x06, 0x0002 },
+ { 0x06, 0x81c6 },
+ { 0x06, 0xfefd },
+ { 0x06, 0xfc05 },
+ { 0x06, 0xf8e0 },
+ { 0x06, 0xf860 },
+ { 0x06, 0xe1f8 },
+ { 0x06, 0x6168 },
+ { 0x06, 0x02e4 },
+ { 0x06, 0xf860 },
+ { 0x06, 0xe5f8 },
+ { 0x06, 0x61e0 },
+ { 0x06, 0xf848 },
+ { 0x06, 0xe1f8 },
+ { 0x06, 0x4958 },
+ { 0x06, 0x0f1e },
+ { 0x06, 0x02e4 },
+ { 0x06, 0xf848 },
+ { 0x06, 0xe5f8 },
+ { 0x06, 0x49d0 },
+ { 0x06, 0x0002 },
+ { 0x06, 0x820a },
+ { 0x06, 0xbf83 },
+ { 0x06, 0x50ef },
+ { 0x06, 0x46dc },
+ { 0x06, 0x19dd },
+ { 0x06, 0xd001 },
+ { 0x06, 0x0282 },
+ { 0x06, 0x0a02 },
+ { 0x06, 0x8226 },
+ { 0x06, 0xe0f8 },
+ { 0x06, 0x60e1 },
+ { 0x06, 0xf861 },
+ { 0x06, 0x58fd },
+ { 0x06, 0xe4f8 },
+ { 0x06, 0x60e5 },
+ { 0x06, 0xf861 },
+ { 0x06, 0xfc04 },
+ { 0x06, 0xf9fa },
+ { 0x06, 0xfbc6 },
+ { 0x06, 0xbff8 },
+ { 0x06, 0x40be },
+ { 0x06, 0x8350 },
+ { 0x06, 0xa001 },
+ { 0x06, 0x0107 },
+ { 0x06, 0x1b89 },
+ { 0x06, 0xcfd2 },
+ { 0x06, 0x08eb },
+ { 0x06, 0xdb19 },
+ { 0x06, 0xb2fb },
+ { 0x06, 0xfffe },
+ { 0x06, 0xfd04 },
+ { 0x06, 0xf8e0 },
+ { 0x06, 0xf848 },
+ { 0x06, 0xe1f8 },
+ { 0x06, 0x4968 },
+ { 0x06, 0x08e4 },
+ { 0x06, 0xf848 },
+ { 0x06, 0xe5f8 },
+ { 0x06, 0x4958 },
+ { 0x06, 0xf7e4 },
+ { 0x06, 0xf848 },
+ { 0x06, 0xe5f8 },
+ { 0x06, 0x49fc },
+ { 0x06, 0x044d },
+ { 0x06, 0x2000 },
+ { 0x06, 0x024e },
+ { 0x06, 0x2200 },
+ { 0x06, 0x024d },
+ { 0x06, 0xdfff },
+ { 0x06, 0x014e },
+ { 0x06, 0xddff },
+ { 0x06, 0x01f8 },
+ { 0x06, 0xfafb },
+ { 0x06, 0xef79 },
+ { 0x06, 0xbff8 },
+ { 0x06, 0x22d8 },
+ { 0x06, 0x19d9 },
+ { 0x06, 0x5884 },
+ { 0x06, 0x9f09 },
+ { 0x06, 0xbf82 },
+ { 0x06, 0x6dd6 },
+ { 0x06, 0x8275 },
+ { 0x06, 0x0201 },
+ { 0x06, 0x4fef },
+ { 0x06, 0x97ff },
+ { 0x06, 0xfefc },
+ { 0x06, 0x0517 },
+ { 0x06, 0xfffe },
+ { 0x06, 0x0117 },
+ { 0x06, 0x0001 },
+ { 0x06, 0x0200 },
+ { 0x05, 0x83d8 },
+ { 0x06, 0x8000 },
+ { 0x05, 0x83d6 },
+ { 0x06, 0x824f },
+ { 0x02, 0x2010 },
+ { 0x03, 0xdc00 },
+ { 0x1f, 0x0000 },
+ { 0x0b, 0x0600 },
+ { 0x1f, 0x0005 },
+ { 0x05, 0xfff6 },
+ { 0x06, 0x00fc },
+ { 0x1f, 0x0000 }
+};
diff --git a/firmware/r8169/8168d_3.h b/firmware/r8169/8168d_3.h
new file mode 100644
index 0000000..b121976
--- /dev/null
+++ b/firmware/r8169/8168d_3.h
@@ -0,0 +1,55 @@
+static const struct phy_reg phy_reg_init_8168d_3[] = {
+ { 0x1f, 0x0002 },
+ { 0x10, 0x0008 },
+ { 0x0d, 0x006c },
+
+ { 0x1f, 0x0000 },
+ { 0x0d, 0xf880 },
+
+ { 0x1f, 0x0001 },
+ { 0x17, 0x0cc0 },
+
+ { 0x1f, 0x0001 },
+ { 0x0b, 0xa4d8 },
+ { 0x09, 0x281c },
+ { 0x07, 0x2883 },
+ { 0x0a, 0x6b35 },
+ { 0x1d, 0x3da4 },
+ { 0x1c, 0xeffd },
+ { 0x14, 0x7f52 },
+ { 0x18, 0x7fc6 },
+ { 0x08, 0x0601 },
+ { 0x06, 0x4063 },
+ { 0x10, 0xf074 },
+ { 0x1f, 0x0003 },
+ { 0x13, 0x0789 },
+ { 0x12, 0xf4bd },
+ { 0x1a, 0x04fd },
+ { 0x14, 0x84b0 },
+ { 0x1f, 0x0000 },
+ { 0x00, 0x9200 },
+
+ { 0x1f, 0x0005 },
+ { 0x01, 0x0340 },
+ { 0x1f, 0x0001 },
+ { 0x04, 0x4000 },
+ { 0x03, 0x1d21 },
+ { 0x02, 0x0c32 },
+ { 0x01, 0x0200 },
+ { 0x00, 0x5554 },
+ { 0x04, 0x4800 },
+ { 0x04, 0x4000 },
+ { 0x04, 0xf000 },
+ { 0x03, 0xdf01 },
+ { 0x02, 0xdf20 },
+ { 0x01, 0x101a },
+ { 0x00, 0xa0ff },
+ { 0x04, 0xf800 },
+ { 0x04, 0xf000 },
+ { 0x1f, 0x0000 },
+
+ { 0x1f, 0x0007 },
+ { 0x1e, 0x0023 },
+ { 0x16, 0x0000 },
+ { 0x1f, 0x0000 }
+};
diff --git a/firmware/r8169/8169s.h b/firmware/r8169/8169s.h
new file mode 100644
index 0000000..52c934b
--- /dev/null
+++ b/firmware/r8169/8169s.h
@@ -0,0 +1,61 @@
+static const struct phy_reg phy_reg_init_8169s[] = {
+ { 0x1f, 0x0001 },
+ { 0x06, 0x006e },
+ { 0x08, 0x0708 },
+ { 0x15, 0x4000 },
+ { 0x18, 0x65c7 },
+
+ { 0x1f, 0x0001 },
+ { 0x03, 0x00a1 },
+ { 0x02, 0x0008 },
+ { 0x01, 0x0120 },
+ { 0x00, 0x1000 },
+ { 0x04, 0x0800 },
+ { 0x04, 0x0000 },
+
+ { 0x03, 0xff41 },
+ { 0x02, 0xdf60 },
+ { 0x01, 0x0140 },
+ { 0x00, 0x0077 },
+ { 0x04, 0x7800 },
+ { 0x04, 0x7000 },
+
+ { 0x03, 0x802f },
+ { 0x02, 0x4f02 },
+ { 0x01, 0x0409 },
+ { 0x00, 0xf0f9 },
+ { 0x04, 0x9800 },
+ { 0x04, 0x9000 },
+
+ { 0x03, 0xdf01 },
+ { 0x02, 0xdf20 },
+ { 0x01, 0xff95 },
+ { 0x00, 0xba00 },
+ { 0x04, 0xa800 },
+ { 0x04, 0xa000 },
+
+ { 0x03, 0xff41 },
+ { 0x02, 0xdf20 },
+ { 0x01, 0x0140 },
+ { 0x00, 0x00bb },
+ { 0x04, 0xb800 },
+ { 0x04, 0xb000 },
+
+ { 0x03, 0xdf41 },
+ { 0x02, 0xdc60 },
+ { 0x01, 0x6340 },
+ { 0x00, 0x007d },
+ { 0x04, 0xd800 },
+ { 0x04, 0xd000 },
+
+ { 0x03, 0xdf01 },
+ { 0x02, 0xdf20 },
+ { 0x01, 0x100a },
+ { 0x00, 0xa0ff },
+ { 0x04, 0xf800 },
+ { 0x04, 0xf000 },
+
+ { 0x1f, 0x0000 },
+ { 0x0b, 0x0000 },
+ { 0x00, 0x9200 }
+};
diff --git a/firmware/r8169/8169scd.h b/firmware/r8169/8169scd.h
new file mode 100644
index 0000000..8d5f007
--- /dev/null
+++ b/firmware/r8169/8169scd.h
@@ -0,0 +1,39 @@
+static const struct phy_reg phy_reg_init_8169scd[] = {
+ { 0x1f, 0x0001 },
+ { 0x04, 0x0000 },
+ { 0x03, 0x00a1 },
+ { 0x02, 0x0008 },
+ { 0x01, 0x0120 },
+ { 0x00, 0x1000 },
+ { 0x04, 0x0800 },
+ { 0x04, 0x9000 },
+ { 0x03, 0x802f },
+ { 0x02, 0x4f02 },
+ { 0x01, 0x0409 },
+ { 0x00, 0xf099 },
+ { 0x04, 0x9800 },
+ { 0x04, 0xa000 },
+ { 0x03, 0xdf01 },
+ { 0x02, 0xdf20 },
+ { 0x01, 0xff95 },
+ { 0x00, 0xba00 },
+ { 0x04, 0xa800 },
+ { 0x04, 0xf000 },
+ { 0x03, 0xdf01 },
+ { 0x02, 0xdf20 },
+ { 0x01, 0x101a },
+ { 0x00, 0xa0ff },
+ { 0x04, 0xf800 },
+ { 0x04, 0x0000 },
+ { 0x1f, 0x0000 },
+
+ { 0x1f, 0x0001 },
+ { 0x10, 0xf41b },
+ { 0x14, 0xfb54 },
+ { 0x18, 0xf5c7 },
+ { 0x1f, 0x0000 },
+
+ { 0x1f, 0x0001 },
+ { 0x17, 0x0cc0 },
+ { 0x1f, 0x0000 }
+};
diff --git a/firmware/r8169/8169sce.h b/firmware/r8169/8169sce.h
new file mode 100644
index 0000000..ee610cf
--- /dev/null
+++ b/firmware/r8169/8169sce.h
@@ -0,0 +1,47 @@
+static const struct phy_reg phy_reg_init_8169sce[] = {
+ { 0x1f, 0x0001 },
+ { 0x04, 0x0000 },
+ { 0x03, 0x00a1 },
+ { 0x02, 0x0008 },
+ { 0x01, 0x0120 },
+ { 0x00, 0x1000 },
+ { 0x04, 0x0800 },
+ { 0x04, 0x9000 },
+ { 0x03, 0x802f },
+ { 0x02, 0x4f02 },
+ { 0x01, 0x0409 },
+ { 0x00, 0xf099 },
+ { 0x04, 0x9800 },
+ { 0x04, 0xa000 },
+ { 0x03, 0xdf01 },
+ { 0x02, 0xdf20 },
+ { 0x01, 0xff95 },
+ { 0x00, 0xba00 },
+ { 0x04, 0xa800 },
+ { 0x04, 0xf000 },
+ { 0x03, 0xdf01 },
+ { 0x02, 0xdf20 },
+ { 0x01, 0x101a },
+ { 0x00, 0xa0ff },
+ { 0x04, 0xf800 },
+ { 0x04, 0x0000 },
+ { 0x1f, 0x0000 },
+
+ { 0x1f, 0x0001 },
+ { 0x0b, 0x8480 },
+ { 0x1f, 0x0000 },
+
+ { 0x1f, 0x0001 },
+ { 0x18, 0x67c7 },
+ { 0x04, 0x2000 },
+ { 0x03, 0x002f },
+ { 0x02, 0x4360 },
+ { 0x01, 0x0109 },
+ { 0x00, 0x3022 },
+ { 0x04, 0x2800 },
+ { 0x1f, 0x0000 },
+
+ { 0x1f, 0x0001 },
+ { 0x17, 0x0cc0 },
+ { 0x1f, 0x0000 }
+};
diff --git a/firmware/r8169/main.c b/firmware/r8169/main.c
new file mode 100644
index 0000000..8f7c206
--- /dev/null
+++ b/firmware/r8169/main.c
@@ -0,0 +1,79 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#define ARRAY_SIZE(A) sizeof(A)/sizeof(A[0])
+
+#define _R(s) \
+ { #s, phy_reg_init_##s, ARRAY_SIZE(phy_reg_init_##s) }
+
+struct phy_reg {
+ unsigned short reg;
+ unsigned short val;
+};
+
+#include "8168c_1.h"
+#include "8168c_2.h"
+#include "8168c_3.h"
+#include "8168d_1_0.h"
+#include "8168d_1_1.h"
+#include "8168d_2_0.h"
+#include "8168d_2_1.h"
+#include "8168d_3.h"
+#include "8169scd.h"
+#include "8169sce.h"
+#include "8169s.h"
+
+struct {
+ char name[16];
+ const struct phy_reg *phy_reg;
+ const size;
+} fws[] = {
+ _R(8168c_1),
+ _R(8168c_2),
+ _R(8168c_3),
+ _R(8168d_1_0),
+ _R(8168d_1_1),
+ _R(8168d_2_0),
+ _R(8168d_2_1),
+ _R(8168d_3),
+ _R(8169scd),
+ _R(8169sce),
+ _R(8169s)
+};
+
+int main(int argc, char *argv[])
+{
+ int rc = 0, i;
+
+ for (i = 0; (i < ARRAY_SIZE(fws)) && !rc; i++) {
+ char name[42];
+ FILE *f;
+ int j;
+
+ snprintf(name, 42, "%s.fw", fws[i].name);
+ f = fopen(name, "w");
+ if (!f) {
+ rc = errno;
+ perror(name);
+ break;
+ }
+
+ for (j = 0; j < fws[i].size; j++) {
+ struct phy_reg pr = fws[i].phy_reg[j];
+ char c[4];
+
+ c[0] = pr.reg;
+ c[1] = pr.reg >> 8;
+ c[2] = pr.val;
+ c[3] = pr.val >> 8;
+ if (fwrite(c, 4, 1, f) != 1) {
+ rc = -1;
+ break;
+ }
+ }
+ fclose(f);
+ }
+
+ return rc;
+}
--
1.7.3.2
^ permalink raw reply related
* Re: [PATCH net-next-2.6] can: add slcan driver for serial/USB-serial CAN adapters
From: Alan Cox @ 2010-11-29 23:37 UTC (permalink / raw)
To: Oliver Hartkopp
Cc: David Miller, Linux Netdev List, SocketCAN Core Mailing List
In-Reply-To: <4CF40D75.8030203@hartkopp.net>
On Mon, 29 Nov 2010 21:30:45 +0100
Oliver Hartkopp <socketcan@hartkopp.net> wrote:
> This patch adds support for serial/USB-serial CAN adapters implementing the
> LAWICEL ASCII protocol for CAN frame transport over serial lines.
>
> The driver implements the SLCAN line discipline and is heavily based on the
> slip.c driver. Therefore the code style remains similar to slip.c to be able
> to apply changes of the SLIP driver to the SLCAN driver easily.
It looks almost identical. Would it not be better to either extract the
common code or put slip and slcann together as one, otherwise changes
will always get missed as they have to be done twice ?
How hard would it be to make the encap/decap pointers that can be
set to cleanly abstract both ?
Alan
^ permalink raw reply
* Ensure Your Account
From: WEBMASTER SERVICE @ 2010-11-29 21:45 UTC (permalink / raw)
Ensure Your Account
We are currently upgrading our data base and e-mail home center is
managed. Enter your email to delete accounts that are not actively
users.we parents to create more space for new accounts have also
studied the system security audit to improve and enhance our current
security situation.
Continue to use our services are needed to update and
re-comfirmed your requested information via e-mail below.
To complete the new account confirmation, reply to this email
immediately and enter the account number below to
Username: ................
User E-mail ..............
Password: ..................
Password: ............
Date of Birth: .................
Otherwise, your account will be disabled immediately to the database
and information service is not interrupted and important messages can
be lost in the reduction of the new coordinates comfirmed to us.
We apologize for any inconvenience this causes this season but is
confident that we are here to serve you better and
providing more technology which revolves around email and internet.
It is also essential to understand that the most important
epréoccupation our customers and the security of their files and
data....
^ permalink raw reply
* Re: [PATCH] net/r8169: Correct the ram code for RTL8111D(L)
From: Stephen Hemminger @ 2010-11-30 0:13 UTC (permalink / raw)
To: Francois Romieu
Cc: hayeswang, 'Ben Hutchings', netdev, linux-kernel,
'David Miller', 564628
In-Reply-To: <20101129233334.GA2888@electric-eye.fr.zoreil.com>
On Tue, 30 Nov 2010 00:33:34 +0100
Francois Romieu <romieu@fr.zoreil.com> wrote:
> hayeswang <hayeswang@realtek.com> :
> > Excuse me, I have some questions about the firmware patch.
> >
> > 1. I should convert the data into the binary files (.bin). Is it right?
>
> You may do it.
>
> Fwiw I have cooked something for it in the attached patch #9 this WE. Feel
> free to take bits from it. I will not do more changes while you work on it.
>
> > 2. Where should I update the firmware files? Is the path the
> > linux-2.6/firmware?
>
> ! This directory is only here to contain firmware images extracted from old
> ! device drivers which predate the common use of request_firmware().
>
> It is fine for the existing code.
>
> > However, according to linux-2.6/firmeware/README.AddingFirmware, I
> > should update they to another repository:
> >
> > git://git.kernel.org/pub/scm/linux/kernel/git/dwmw2/linux-firmware.git
>
> /me scratches head.
>
> Assuming Realtek does not intend to stand this code / data as GPLable, yes.
> It will help people staying clear from non-free code, it will help packaging
> something useful and it will remove some cruft from the code.
>
> So everybody will end happy. Especially after an aspirin.
The plan is to do away with linux-2.6/firmware entirely.
Distributions are shipping the firmware from linux-firmware, not the
kernel files.
^ permalink raw reply
* Re: 2.6.35 -> 2.6.36 panic when vlan and promisc with tg3
From: Ben Greear @ 2010-11-30 0:19 UTC (permalink / raw)
To: Michael Leun; +Cc: linux-kernel, netdev
In-Reply-To: <20101129201716.1d0257c4@xenia.leun.net>
On 11/29/2010 11:17 AM, Michael Leun wrote:
> Hi,
>
> only kernel message I was able to capture on serial were:
>
> UG: unable to handle kernel paging request at 01cc921c
> IP: [<c034bfce>] vlan_hwaccel_do_receive+0x59/0xd0
> *pdpt = 0000000036a2a001 *pde = 0000000000000000
> Oops: 0002 [#1] SMP
> last sysfs
>
> Then machine dead.
>
> In 2.6.35.x this did not happen (but vlans broken - cannot see vlan
> tags with tcpdump),
Try this patch:
http://permalink.gmane.org/gmane.linux.network/176566
It looks like this hasn't made it into stable yet?
Thanks,
Ben
>
> To reproduce:
>
> ip link set eth0 up
> vconfig add eth0 2
> ip link set eth0 promisc on
>
> Machines with these ethernet cards I've seen to be affected:
>
> Ethernet controller: Broadcom Corporation NetXtreme BCM5714 Gigabit
> Ethernet (rev a3)
>
> Ethernet controller: Broadcom Corporation NetXtreme BCM5752M Gigabit
> Ethernet PCI Express (rev 02)
>
> Machine with this card is NOT affected (no vlan hw accel?):
>
> Ethernet controller: Broadcom Corporation NetLink BCM5906M Fast
> Ethernet PCI Express (rev 02)
>
>
--
Ben Greear <greearb@candelatech.com>
Candela Technologies Inc http://www.candelatech.com
^ permalink raw reply
* [PATCH v2] net: avoid the unnecessary kmalloc
From: Changli Gao @ 2010-11-30 0:40 UTC (permalink / raw)
To: David S. Miller; +Cc: netdev, Changli Gao
If the old memory allocated by kmalloc() is larger than the new requested,
pskb_expand_head() doesn't need to allocate a new one, unless the skb->head
is shared.
Signed-off-by: Changli Gao <xiaosuo@gmail.com>
---
v2: apply this trick for the cloned but not shared skb
net/core/skbuff.c | 34 +++++++++++++++++++++++-----------
1 file changed, 23 insertions(+), 11 deletions(-)
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 104f844..8814a9a 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -778,6 +778,28 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
size = SKB_DATA_ALIGN(size);
+ /* Check if we can avoid taking references on fragments if we own
+ * the last reference on skb->head. (see skb_release_data())
+ */
+ if (!skb->cloned)
+ fastpath = true;
+ else {
+ int delta = skb->nohdr ? (1 << SKB_DATAREF_SHIFT) + 1 : 1;
+
+ fastpath = atomic_read(&skb_shinfo(skb)->dataref) == delta;
+ }
+
+ if (fastpath &&
+ size + sizeof(struct skb_shared_info) <= ksize(skb->head)) {
+ memmove(skb->head + size, skb_shinfo(skb),
+ offsetof(struct skb_shared_info,
+ frags[skb_shinfo(skb)->nr_frags]));
+ memmove(skb->head + nhead, skb->head,
+ skb_tail_pointer(skb) - skb->head);
+ off = nhead;
+ goto adjust_others;
+ }
+
data = kmalloc(size + sizeof(struct skb_shared_info), gfp_mask);
if (!data)
goto nodata;
@@ -791,17 +813,6 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
skb_shinfo(skb),
offsetof(struct skb_shared_info, frags[skb_shinfo(skb)->nr_frags]));
- /* Check if we can avoid taking references on fragments if we own
- * the last reference on skb->head. (see skb_release_data())
- */
- if (!skb->cloned)
- fastpath = true;
- else {
- int delta = skb->nohdr ? (1 << SKB_DATAREF_SHIFT) + 1 : 1;
-
- fastpath = atomic_read(&skb_shinfo(skb)->dataref) == delta;
- }
-
if (fastpath) {
kfree(skb->head);
} else {
@@ -816,6 +827,7 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
off = (data + nhead) - skb->head;
skb->head = data;
+adjust_others:
skb->data += off;
#ifdef NET_SKBUFF_DATA_USES_OFFSET
skb->end = size;
^ permalink raw reply related
* Re: [PATCH 1/3] inetpeer: Support ipv6 addresses.
From: Brian Haley @ 2010-11-30 2:11 UTC (permalink / raw)
To: David Miller; +Cc: netdev
In-Reply-To: <20101129.134403.179947389.davem@davemloft.net>
On 11/29/2010 04:44 PM, David Miller wrote:
> +static inline bool inet_peer_addr_equal(inet_peer_address_t *a, inet_peer_address_t *b)
> +{
> + if (a->family == b->family) {
> + switch (a->family) {
> + case AF_INET:
> + if (a->a4 == b->a4)
> + return true;
> + break;
> + case AF_INET6:
> + if (!ipv6_addr_cmp((struct in6_addr *)a,
> + (struct in6_addr *)b))
> + return true;
> + break;
ipv6_addr_equal() ?
-Brian
^ permalink raw reply
* Re: [PATCH 1/3] inetpeer: Support ipv6 addresses.
From: Changli Gao @ 2010-11-30 2:33 UTC (permalink / raw)
To: David Miller; +Cc: netdev
In-Reply-To: <20101129.134403.179947389.davem@davemloft.net>
On Tue, Nov 30, 2010 at 5:44 AM, David Miller <davem@davemloft.net> wrote:
>
> Signed-off-by: David S. Miller <davem@davemloft.net>
> ---
> include/net/inetpeer.h | 21 ++++++++++++++-
> net/ipv4/inetpeer.c | 66 ++++++++++++++++++++++++++++++++++++++++-------
> net/ipv4/ip_fragment.c | 2 +-
> net/ipv4/route.c | 2 +-
> net/ipv4/tcp_ipv4.c | 6 ++--
> 5 files changed, 80 insertions(+), 17 deletions(-)
>
> diff --git a/include/net/inetpeer.h b/include/net/inetpeer.h
> index fe239bf..834f045 100644
> --- a/include/net/inetpeer.h
> +++ b/include/net/inetpeer.h
> @@ -13,10 +13,18 @@
> #include <linux/spinlock.h>
> #include <asm/atomic.h>
>
> +typedef struct {
> + union {
> + __be32 a4;
> + __be32 a6[4];
> + };
> + __u16 family;
> +} inet_peer_address_t;
> +
This makes inet_peer large even though ipv6 isn't enabled.
> struct inet_peer {
> /* group together avl_left,avl_right,v4daddr to speedup lookups */
> struct inet_peer __rcu *avl_left, *avl_right;
> - __be32 v4daddr; /* peer's address */
> + inet_peer_address_t daddr;
I have thought about converting this AVL tree to rbtree. When I saw
the comment above, I gave it up, because rbtree makes this structure
bigger. If ipv6 support is added, I think it is time to turn to
rbtree. :)
> __u32 avl_height;
> struct list_head unused;
> __u32 dtime; /* the time of last use of not
> @@ -42,7 +50,16 @@ struct inet_peer {
> void inet_initpeers(void) __init;
>
> /* can be called with or without local BH being disabled */
> -struct inet_peer *inet_getpeer(__be32 daddr, int create);
> +struct inet_peer *inet_getpeer(inet_peer_address_t *daddr, int create);
> +
> +static inline struct inet_peer *inet_getpeer_v4(__be32 v4daddr, int create)
> +{
> + inet_peer_address_t daddr;
> +
> + daddr.a4 = v4daddr;
> + daddr.family = AF_INET;
> + return inet_getpeer(&daddr, create);
> +}
>
> /* can be called from BH context or outside */
> extern void inet_putpeer(struct inet_peer *p);
> diff --git a/net/ipv4/inetpeer.c b/net/ipv4/inetpeer.c
> index 9e94d7c..39f18c5 100644
> --- a/net/ipv4/inetpeer.c
> +++ b/net/ipv4/inetpeer.c
> @@ -19,6 +19,7 @@
> #include <linux/net.h>
> #include <net/ip.h>
> #include <net/inetpeer.h>
> +#include <net/ipv6.h>
>
> /*
> * Theory of operations.
> @@ -152,11 +153,53 @@ static void unlink_from_unused(struct inet_peer *p)
> }
> }
>
> +static inline bool inet_peer_addr_equal(inet_peer_address_t *a, inet_peer_address_t *b)
> +{
> + if (a->family == b->family) {
> + switch (a->family) {
> + case AF_INET:
> + if (a->a4 == b->a4)
> + return true;
> + break;
> + case AF_INET6:
> + if (!ipv6_addr_cmp((struct in6_addr *)a,
> + (struct in6_addr *)b))
> + return true;
> + break;
> + default:
> + break;
> + }
> + }
> + return false;
> +}
> +
> +static inline u32 inet_peer_key(inet_peer_address_t *a)
> +{
> + u32 key;
> +
> + switch (a->family) {
> + case AF_INET:
> + key = (__force __u32) a->a4;
> + break;
> + case AF_INET6:
> + key = ((__force __u32)a->a6[0] ^
> + (__force __u32)a->a6[1] ^
> + (__force __u32)a->a6[2] ^
> + (__force __u32)a->a6[3]);
> + break;
> + default:
> + key = 0;
> + break;
> + }
> + return key;
> +}
> +
> /*
> * Called with local BH disabled and the pool lock held.
> */
> #define lookup(_daddr, _stack) \
> ({ \
> + u32 key = inet_peer_key(_daddr); \
> struct inet_peer *u; \
> struct inet_peer __rcu **v; \
> \
> @@ -165,9 +208,9 @@ static void unlink_from_unused(struct inet_peer *p)
> for (u = rcu_dereference_protected(peers.root, \
> lockdep_is_held(&peers.lock)); \
> u != peer_avl_empty; ) { \
> - if (_daddr == u->v4daddr) \
> + if (inet_peer_addr_equal(_daddr, &u->daddr)) \
> break; \
> - if ((__force __u32)_daddr < (__force __u32)u->v4daddr) \
> + if (key < inet_peer_key(&u->daddr)) \
> v = &u->avl_left; \
> else \
> v = &u->avl_right; \
> @@ -185,13 +228,14 @@ static void unlink_from_unused(struct inet_peer *p)
> * But every pointer we follow is guaranteed to be valid thanks to RCU.
> * We exit from this function if number of links exceeds PEER_MAXDEPTH
> */
> -static struct inet_peer *lookup_rcu_bh(__be32 daddr)
> +static struct inet_peer *lookup_rcu_bh(inet_peer_address_t *daddr)
> {
> struct inet_peer *u = rcu_dereference_bh(peers.root);
> + u32 key = inet_peer_key(daddr);
> int count = 0;
>
> while (u != peer_avl_empty) {
> - if (daddr == u->v4daddr) {
> + if (inet_peer_addr_equal(daddr, &u->daddr)) {
> /* Before taking a reference, check if this entry was
> * deleted, unlink_from_pool() sets refcnt=-1 to make
> * distinction between an unused entry (refcnt=0) and
> @@ -201,7 +245,7 @@ static struct inet_peer *lookup_rcu_bh(__be32 daddr)
> u = NULL;
> return u;
> }
> - if ((__force __u32)daddr < (__force __u32)u->v4daddr)
> + if (key < inet_peer_key(&u->daddr))
> u = rcu_dereference_bh(u->avl_left);
> else
> u = rcu_dereference_bh(u->avl_right);
> @@ -353,7 +397,7 @@ static void unlink_from_pool(struct inet_peer *p)
> if (atomic_cmpxchg(&p->refcnt, 1, -1) == 1) {
> struct inet_peer __rcu **stack[PEER_MAXDEPTH];
> struct inet_peer __rcu ***stackptr, ***delp;
> - if (lookup(p->v4daddr, stack) != p)
> + if (lookup(&p->daddr, stack) != p)
> BUG();
> delp = stackptr - 1; /* *delp[0] == p */
> if (p->avl_left == peer_avl_empty_rcu) {
> @@ -366,7 +410,7 @@ static void unlink_from_pool(struct inet_peer *p)
> BUG_ON(rcu_dereference_protected(*stackptr[-1],
> lockdep_is_held(&peers.lock)) != t);
> **--stackptr = t->avl_left;
> - /* t is removed, t->v4daddr > x->v4daddr for any
> + /* t is removed, t->daddr > x->daddr for any
> * x in p->avl_left subtree.
> * Put t in the old place of p. */
> RCU_INIT_POINTER(*delp[0], t);
> @@ -433,7 +477,7 @@ static int cleanup_once(unsigned long ttl)
> }
>
> /* Called with or without local BH being disabled. */
> -struct inet_peer *inet_getpeer(__be32 daddr, int create)
> +struct inet_peer *inet_getpeer(inet_peer_address_t *daddr, int create)
> {
> struct inet_peer *p;
> struct inet_peer __rcu **stack[PEER_MAXDEPTH], ***stackptr;
> @@ -467,10 +511,12 @@ struct inet_peer *inet_getpeer(__be32 daddr, int create)
> }
> p = create ? kmem_cache_alloc(peer_cachep, GFP_ATOMIC) : NULL;
> if (p) {
> - p->v4daddr = daddr;
> + p->daddr = *daddr;
> atomic_set(&p->refcnt, 1);
> atomic_set(&p->rid, 0);
> - atomic_set(&p->ip_id_count, secure_ip_id(daddr));
> + atomic_set(&p->ip_id_count,
> + (daddr->family == AF_INET) ?
> + secure_ip_id(daddr->a4) : 0);
> p->tcp_ts_stamp = 0;
> INIT_LIST_HEAD(&p->unused);
>
> diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
> index 1684408..e6215bd 100644
> --- a/net/ipv4/ip_fragment.c
> +++ b/net/ipv4/ip_fragment.c
> @@ -141,7 +141,7 @@ static void ip4_frag_init(struct inet_frag_queue *q, void *a)
> qp->daddr = arg->iph->daddr;
> qp->user = arg->user;
> qp->peer = sysctl_ipfrag_max_dist ?
> - inet_getpeer(arg->iph->saddr, 1) : NULL;
> + inet_getpeer_v4(arg->iph->saddr, 1) : NULL;
> }
>
> static __inline__ void ip4_frag_free(struct inet_frag_queue *q)
> diff --git a/net/ipv4/route.c b/net/ipv4/route.c
> index ec2333f..3843c2d 100644
> --- a/net/ipv4/route.c
> +++ b/net/ipv4/route.c
> @@ -1289,7 +1289,7 @@ void rt_bind_peer(struct rtable *rt, int create)
> {
> struct inet_peer *peer;
>
> - peer = inet_getpeer(rt->rt_dst, create);
> + peer = inet_getpeer_v4(rt->rt_dst, create);
>
> if (peer && cmpxchg(&rt->peer, NULL, peer) != NULL)
> inet_putpeer(peer);
> diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
> index 69ccbc1..00285fc 100644
> --- a/net/ipv4/tcp_ipv4.c
> +++ b/net/ipv4/tcp_ipv4.c
> @@ -1347,7 +1347,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
> tcp_death_row.sysctl_tw_recycle &&
> (dst = inet_csk_route_req(sk, req)) != NULL &&
> (peer = rt_get_peer((struct rtable *)dst)) != NULL &&
> - peer->v4daddr == saddr) {
> + peer->daddr.a4 == saddr) {
> inet_peer_refcheck(peer);
> if ((u32)get_seconds() - peer->tcp_ts_stamp < TCP_PAWS_MSL &&
> (s32)(peer->tcp_ts - req->ts_recent) >
> @@ -1778,7 +1778,7 @@ int tcp_v4_remember_stamp(struct sock *sk)
> int release_it = 0;
>
> if (!rt || rt->rt_dst != inet->inet_daddr) {
> - peer = inet_getpeer(inet->inet_daddr, 1);
> + peer = inet_getpeer_v4(inet->inet_daddr, 1);
> release_it = 1;
> } else {
> if (!rt->peer)
> @@ -1804,7 +1804,7 @@ EXPORT_SYMBOL(tcp_v4_remember_stamp);
>
> int tcp_v4_tw_remember_stamp(struct inet_timewait_sock *tw)
> {
> - struct inet_peer *peer = inet_getpeer(tw->tw_daddr, 1);
> + struct inet_peer *peer = inet_getpeer_v4(tw->tw_daddr, 1);
>
> if (peer) {
> const struct tcp_timewait_sock *tcptw = tcp_twsk((struct sock *)tw);
> --
> 1.7.3.2
>
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
--
Regards,
Changli Gao(xiaosuo@gmail.com)
^ permalink raw reply
* Re: Broken TX checksumming offloads
From: Jesse Gross @ 2010-11-30 2:35 UTC (permalink / raw)
To: Ben Hutchings
Cc: Michał Mirosław, netdev, Toshiharu Okada, e1000-devel
In-Reply-To: <1291058003.20703.16.camel@bwh-desktop>
2010/11/29 Ben Hutchings <bhutchings@solarflare.com>:
> On Mon, 2010-11-29 at 19:17 +0100, Michał Mirosław wrote:
>> Hi!
>>
>> Unless I'm horribly mistaken, generic HW checksumming works as follows:
>> - driver sets netdev->features & NETIF_F_HW_CSUM to indicate support
>> for generic checksumming; if the flag is not set, networking core
>> will checksum skb before calling ndo_start_xmit (let's ignore
>> other checksumming options for now) and not pass skb with
>> skb->ip_summed == CHECKSUM_PARTIAL
>> - ndo_start_xmit() should use skb->csum_start and skb->csum_offset
>> (or skb->csum) to update checksum in software or instruct HW to do so
>>
>> Looking at pch_gbe_xmit_frame() and its callee - pch_gbe_tx_queue() it
>> looks like the driver should set NETIF_F_IP_CSUM instead of NETIF_F_HW_CSUM
>> feature.
>>
>> Similar thing happens in ixgbe driver: it sets NETIF_F_HW_CSUM and checks
>> for skb->ip_summed == CHECKSUM_PARTIAL, but then just warns on protocols
>> other that TCP and SCTP (see: ixgbe_psum()).
>
> AFAIK only {TCP,UDP}/IPv{4,6} use the simple 16-bit checksum algorithm
> that NETIF_F_HW_CSUM implies, so in practice it is equivalent to
> NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM even though it doesn't mean the same
> thing.
There are a few cases that I can think of where the extra generality
of NETIF_F_HW_CSUM is useful:
* The checksum in GRE (maybe other protocols as well) uses the same
algorithm as TCP/UDP. In theory this means that we could use hardware
offloading for GRE on cards that have NETIF_F_HW_CSUM. The one issue
is that NETIF_F_IP_CSUM really means TCP/UDP checksumming but we only
test if the protocol is IP. This means that other IP based protocols
(like GRE) can't use checksum offloading since there is no software
fallback path.
* TCP/UDP packets that are deeply encapsulated. Currently we can
express that checksum offloading is supported in one level of vlan
encapsulation through vlan_features. However, a NIC that exposes
NETIF_F_HW_CSUM should in theory be able to checksum over a packet
that has an arbitrary number of vlan tags in front of it, a GRE
header, or any other type of encapsulation.
^ permalink raw reply
* Re: 2.6.35 -> 2.6.36 panic when vlan and promisc with tg3
From: Jesse Gross @ 2010-11-30 3:10 UTC (permalink / raw)
To: Ben Greear, David Miller; +Cc: Michael Leun, linux-kernel, netdev
In-Reply-To: <4CF442FA.4070701@candelatech.com>
On Mon, Nov 29, 2010 at 4:19 PM, Ben Greear <greearb@candelatech.com> wrote:
> On 11/29/2010 11:17 AM, Michael Leun wrote:
>>
>> Hi,
>>
>> only kernel message I was able to capture on serial were:
>>
>> UG: unable to handle kernel paging request at 01cc921c
>> IP: [<c034bfce>] vlan_hwaccel_do_receive+0x59/0xd0
>> *pdpt = 0000000036a2a001 *pde = 0000000000000000
>> Oops: 0002 [#1] SMP
>> last sysfs
>>
>> Then machine dead.
>>
>> In 2.6.35.x this did not happen (but vlans broken - cannot see vlan
>> tags with tcpdump),
>
> Try this patch:
>
> http://permalink.gmane.org/gmane.linux.network/176566
>
> It looks like this hasn't made it into stable yet?
It didn't make it into 2.6.36.1.
David, I know that you already acked this patch but it sounds like
Greg would prefer to get it from you directly:
https://lkml.org/lkml/2010/11/19/685
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox