* [RFC] bridge: allow passing link-local multicast
From: Stephen Hemminger @ 2011-08-15 22:05 UTC (permalink / raw)
To: Ed Swierk; +Cc: netdev, Nick Carter, David Lamparter, bridge
In-Reply-To: <CAF5U64B_fb2tFMLHmK+zw3n6gmq+bYDyFnXhLE0ayssK5m+THA@mail.gmail.com>
Several users have wanted to forward 802.1x EAP multicast
packets through a bridge. And there has been a couple of
attempts at allowing some form of this in the past.
If a bridge does not have spanning tree turned on, then it should
act like a pure hub and forward all traffic. This makes it fully
transparent, and if there is another bridge using spanning tree
the STP packets will still work for detecting loops in the network.
If bridge has STP enabled, then the default behavior is to
process all link-local multicasts locally. The expectation is
that if 802.1x or other protocol using link-local multicasts
that a service (or proxy) for that protocol will be used.
Optionally, a sysctl value can be set to allow non STP packets
to still be forwarded. I chose sysctl for this because it is
where such modifications exist when doing IP or netfilter.
There are other filtering/configuration options that are needed
and this is a better way to enable them.
Thanks to David Lamparter, and others for bringing this up.
Users who need this facility should provide feedback, is this
a usable solution?
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
---
Patch against net-next
Documentation/networking/ip-sysctl.txt | 4 ++
net/bridge/Makefile | 2 -
net/bridge/br.c | 12 ++++++
net/bridge/br_input.c | 30 ++++++++++++++++-
net/bridge/br_private.h | 5 ++
net/bridge/br_sysctl.c | 57 +++++++++++++++++++++++++++++++++
6 files changed, 107 insertions(+), 3 deletions(-)
--- a/Documentation/networking/ip-sysctl.txt 2011-08-15 10:58:36.451532115 -0700
+++ b/Documentation/networking/ip-sysctl.txt 2011-08-15 11:39:57.719438766 -0700
@@ -1289,6 +1289,10 @@ bridge-nf-filter-pppoe-tagged - BOOLEAN
0 : disable this.
Default: 1
+bridge-forward-link-local - BOOLEAN
+ 1 : pass link-local multicasts through bridge in STP mode
+ 0 : disable this.
+ Default: 0
proc/sys/net/sctp/* Variables:
--- a/net/bridge/Makefile 2011-08-15 10:30:25.203595742 -0700
+++ b/net/bridge/Makefile 2011-08-15 11:22:38.139477877 -0700
@@ -9,7 +9,7 @@ bridge-y := br.o br_device.o br_fdb.o br
br_stp_if.o br_stp_timer.o br_netlink.o
bridge-$(CONFIG_SYSFS) += br_sysfs_if.o br_sysfs_br.o
-
+bridge-$(CONFIG_SYSCTL) += br_sysctl.o
bridge-$(CONFIG_BRIDGE_NETFILTER) += br_netfilter.o
bridge-$(CONFIG_BRIDGE_IGMP_SNOOPING) += br_multicast.o
--- a/net/bridge/br.c 2011-08-15 10:30:48.755594855 -0700
+++ b/net/bridge/br.c 2011-08-15 10:33:07.215589647 -0700
@@ -60,6 +60,12 @@ static int __init br_init(void)
if (err)
goto err_out4;
+#ifdef CONFIG_SYSCTL
+ err = br_sysctl_init();
+ if (err)
+ goto err_out5;
+#endif
+
brioctl_set(br_ioctl_deviceless_stub);
#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
@@ -67,6 +73,9 @@ static int __init br_init(void)
#endif
return 0;
+
+err_out5:
+ br_netlink_fini();
err_out4:
unregister_netdevice_notifier(&br_device_notifier);
err_out3:
@@ -84,6 +93,9 @@ static void __exit br_deinit(void)
{
stp_proto_unregister(&br_stp_proto);
+#ifdef CONFIG_SYSCTL
+ br_sysctl_fini();
+#endif
br_netlink_fini();
unregister_netdevice_notifier(&br_device_notifier);
brioctl_set(NULL);
--- a/net/bridge/br_input.c 2011-08-15 10:40:21.435573311 -0700
+++ b/net/bridge/br_input.c 2011-08-15 11:39:57.719438766 -0700
@@ -16,11 +16,18 @@
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/netfilter_bridge.h>
+#include <linux/llc.h>
+#include <net/llc.h>
+#include <net/llc_pdu.h>
+
#include "br_private.h"
/* Bridge group multicast address 802.1d (pg 51). */
const u8 br_group_address[ETH_ALEN] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 };
+/* Should link-local packets be forwarded (in STP mode) */
+int br_forward_link_local;
+
/* Hook for brouter */
br_should_route_hook_t __rcu *br_should_route_hook __read_mostly;
EXPORT_SYMBOL(br_should_route_hook);
@@ -138,6 +145,17 @@ static inline int is_link_local(const un
return ((a[0] ^ b[0]) | (a[1] ^ b[1]) | ((a[2] ^ b[2]) & m)) == 0;
}
+/* Identify Spanning Tree packets based on header */
+static bool is_stp_bpdu(struct sk_buff *skb)
+{
+ struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
+
+ return skb->protocol == htons(ETH_P_802_2) &&
+ pdu->ctrl_1 == LLC_PDU_TYPE_U &&
+ pdu->dsap == LLC_SAP_BSPAN &&
+ pdu->ssap == LLC_SAP_BSPAN;
+}
+
/*
* Return NULL if skb is handled
* note: already called with rcu_read_lock
@@ -166,8 +184,16 @@ rx_handler_result_t br_handle_frame(stru
if (skb->protocol == htons(ETH_P_PAUSE))
goto drop;
- /* If STP is turned off, then forward */
- if (p->br->stp_enabled == BR_NO_STP && dest[5] == 0)
+ /* If STP is turned off, then in hub mode */
+ if (p->br->stp_enabled == BR_NO_STP)
+ goto forward;
+
+ /*
+ * If STP is on
+ * then Always handle STP packets locally,
+ * other packets can be forwarded if sysctl is enabled.
+ */
+ if (!is_stp_bpdu(skb) && br_forward_link_local)
goto forward;
if (NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN, skb, skb->dev,
--- a/net/bridge/br_private.h 2011-08-15 10:38:35.587577293 -0700
+++ b/net/bridge/br_private.h 2011-08-15 10:57:36.983534352 -0700
@@ -284,6 +284,7 @@ struct br_input_skb_cb {
pr_debug("%s: " format, (br)->dev->name, ##args)
extern struct notifier_block br_device_notifier;
+extern int br_forward_link_local;
extern const u8 br_group_address[ETH_ALEN];
/* called under bridge lock */
@@ -546,6 +547,10 @@ extern int br_sysfs_renameif(struct net_
extern int br_sysfs_addbr(struct net_device *dev);
extern void br_sysfs_delbr(struct net_device *dev);
+/* br_sysctl.c */
+extern int br_sysctl_init(void);
+extern void br_sysctl_fini(void);
+
#else
#define br_sysfs_addif(p) (0)
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ b/net/bridge/br_sysctl.c 2011-08-15 11:41:00.819436393 -0700
@@ -0,0 +1,57 @@
+/*
+ * Sysctl settings for bridge
+ *
+ * Authors:
+ * Stephen Hemminger <shemminger@osdl.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.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/ip.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/if_ether.h>
+#include <linux/if_vlan.h>
+#include <linux/if_pppox.h>
+#include <linux/sysctl.h>
+
+#include "br_private.h"
+
+static struct ctl_table bridge_table[] = {
+ {
+ .procname = "bridge-forward-link-local",
+ .data = &br_forward_link_local,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec
+ },
+};
+
+static struct ctl_path bridge_ctl_path[] = {
+ { .procname = "net", },
+ { .procname = "bridge", },
+ { },
+};
+
+static struct ctl_table_header *br_sysctl;
+
+int __init br_sysctl_init(void)
+{
+ br_sysctl = register_sysctl_paths(bridge_ctl_path, bridge_table);
+ if (br_sysctl == NULL)
+ return -ENOMEM;
+
+ return 0;
+}
+
+void __exit br_sysctl_fini(void)
+{
+ unregister_net_sysctl_table(br_sysctl);
+}
^ permalink raw reply
* Re: [PATCH] virtio-net: Read MAC only after initializing MSI-X
From: Sasha Levin @ 2011-08-15 22:17 UTC (permalink / raw)
To: Rusty Russell
Cc: linux-kernel, Michael S. Tsirkin, virtualization, netdev, kvm
In-Reply-To: <87vctz7c7d.fsf@rustcorp.com.au>
On Mon, 2011-08-15 at 09:55 +0930, Rusty Russell wrote:
> On Sun, 14 Aug 2011 16:57:32 +0300, Sasha Levin <levinsasha928@gmail.com> wrote:
> > On Sun, 2011-08-14 at 12:23 +0930, Rusty Russell wrote:
> > > On Sat, 13 Aug 2011 11:51:01 +0300, Sasha Levin <levinsasha928@gmail.com> wrote:
> > > > The MAC of a virtio-net device is located at the first field of the device
> > > > specific header. This header is located at offset 20 if the device doesn't
> > > > support MSI-X or offset 24 if it does.
> > >
> > > Erk. This means, in general, we have to do virtio_find_single_vq or
> > > config->find_vqs before we examine any config options.
> > >
> > > Look at virtio_blk, which has the same error.
> > >
> > > Solutions in order of best to worst:
> > > (1) Enable MSI-X before calling device probe. This means reserving two
> > > vectors in virtio_pci_probe to ensure we *can* do this, I think. Michael?
> >
> > Do you mean reserving the vectors even before we probed the device for
> > MSI-X support? Wouldn't we need 3 vectors then? (config, input, output).
>
> We want three, but *need* two: see vp_find_vqs(). Also, the generic
> code doesn't know how many virtqueues we have on the device.
We can just pci_enable_msix() and see if we can get 2 vectors, if we can
- we assume the device has msix on, right?
--
Sasha.
^ permalink raw reply
* [PATCH net-next 1/5] ethtool: Reformat struct ethtool_coalesce comments into kernel-doc format
From: Ben Hutchings @ 2011-08-16 0:06 UTC (permalink / raw)
To: David Miller; +Cc: netdev, Eli Cohen
This reorders and duplicates some wording, but should make no
substantive changes.
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
include/linux/ethtool.h | 135 ++++++++++++++++++++++-------------------------
1 files changed, 64 insertions(+), 71 deletions(-)
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index c6e427a..be32dd0 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -117,99 +117,92 @@ struct ethtool_eeprom {
__u8 data[0];
};
-/* for configuring coalescing parameters of chip */
+/**
+ * struct ethtool_coalesce - coalescing parameters of chip
+ * @cmd: ETHTOOL_{G,S}COALESCE
+ * @rx_coalesce_usecs: How many usecs to delay an RX interrupt after
+ * a packet arrives. If 0, only @rx_max_coalesced_frames is used.
+ * @rx_max_coalesced_frames: How many packets to delay an RX interrupt
+ * after a packet arrives. If 0, only @rx_coalesce_usecs is used.
+ * @rx_coalesce_usecs_irq: Same as @rx_coalesce_usecs, except that
+ * this value applies while an IRQ is being serviced by the host.
+ * @rx_max_coalesced_frames_irq: Same as @rx_max_coalesced_frames,
+ * except that this value applies while an IRQ is being serviced
+ * by the host.
+ * @tx_coalesce_usecs: How many usecs to delay a TX interrupt after
+ * a packet is sent. If 0, only @tx_max_coalesced_frames
+ * is used.
+ * @tx_max_coalesced_frames: How many packets to delay a TX interrupt
+ * after a packet is sent. If 0, only @tx_coalesce_usecs is
+ * used.
+ * @tx_coalesce_usecs_irq: Same as @tx_coalesce_usecs, except that
+ * this value applies while an IRQ is being serviced by the host.
+ * @tx_max_coalesced_frames_irq: Same as @tx_max_coalesced_frames,
+ * except that this value applies while an IRQ is being serviced
+ * by the host.
+ * @stats_block_coalesce_usecs: How many usecs to delay in-memory
+ * statistics block updates. Some drivers do not have an
+ * in-memory statistic block, and in such cases this value is
+ * ignored. This value must not be zero.
+ * @use_adaptive_rx_coalesce: Enable adaptive RX coalescing.
+ * @use_adaptive_tx_coalesce: Enable adaptive TX coalescing.
+ * @pkt_rate_low: Threshold for low packet rate (packets per second).
+ * @rx_coalesce_usecs_low: How many usecs to delay an RX interrupt after
+ * a packet arrives, when the packet rate is below @pkt_rate_low.
+ * @rx_max_coalesced_frames_low: How many packets to delay an RX interrupt
+ * after a packet arrives, when the packet rate is below @pkt_rate_low.
+ * @tx_coalesce_usecs_low: How many usecs to delay a TX interrupt after
+ * a packet is sent, when the packet rate is below @pkt_rate_low.
+ * @tx_max_coalesced_frames_low: How many packets to delay a TX interrupt
+ * after a packet is sent, when the packet rate is below @pkt_rate_low.
+ * @pkt_rate_high: Threshold for high packet rate (packets per second).
+ * @rx_coalesce_usecs_high: How many usecs to delay an RX interrupt after
+ * a packet arrives, when the packet rate is above @pkt_rate_high.
+ * @rx_max_coalesced_frames_high: How many packets to delay an RX interrupt
+ * after a packet arrives, when the packet rate is above @pkt_rate_high.
+ * @tx_coalesce_usecs_high: How many usecs to delay a TX interrupt after
+ * a packet is sent, when the packet rate is above @pkt_rate_high.
+ * @tx_max_coalesced_frames_high: How many packets to delay a TX interrupt
+ * after a packet is sent, when the packet rate is above @pkt_rate_high.
+ * @rate_sample_interval: How often to do adaptive coalescing packet rate
+ * sampling, measured in seconds. Must not be zero.
+ *
+ * It is illegal to set both usecs and max frames to zero as this
+ * would cause interrupts to never be generated.
+ *
+ * Adaptive RX/TX coalescing is an algorithm implemented by some
+ * drivers to improve latency under low packet rates and improve
+ * throughput under high packet rates. Some drivers only implement
+ * one of RX or TX adaptive coalescing. Anything not implemented by
+ * the driver causes these values to be silently ignored.
+ *
+ * When the packet rate is below @pkt_rate_high but above
+ * @pkt_rate_low (both measured in packets per second) the
+ * normal {rx,tx}_* coalescing parameters are used.
+ */
struct ethtool_coalesce {
- __u32 cmd; /* ETHTOOL_{G,S}COALESCE */
-
- /* How many usecs to delay an RX interrupt after
- * a packet arrives. If 0, only rx_max_coalesced_frames
- * is used.
- */
+ __u32 cmd;
__u32 rx_coalesce_usecs;
-
- /* How many packets to delay an RX interrupt after
- * a packet arrives. If 0, only rx_coalesce_usecs is
- * used. It is illegal to set both usecs and max frames
- * to zero as this would cause RX interrupts to never be
- * generated.
- */
__u32 rx_max_coalesced_frames;
-
- /* Same as above two parameters, except that these values
- * apply while an IRQ is being serviced by the host. Not
- * all cards support this feature and the values are ignored
- * in that case.
- */
__u32 rx_coalesce_usecs_irq;
__u32 rx_max_coalesced_frames_irq;
-
- /* How many usecs to delay a TX interrupt after
- * a packet is sent. If 0, only tx_max_coalesced_frames
- * is used.
- */
__u32 tx_coalesce_usecs;
-
- /* How many packets to delay a TX interrupt after
- * a packet is sent. If 0, only tx_coalesce_usecs is
- * used. It is illegal to set both usecs and max frames
- * to zero as this would cause TX interrupts to never be
- * generated.
- */
__u32 tx_max_coalesced_frames;
-
- /* Same as above two parameters, except that these values
- * apply while an IRQ is being serviced by the host. Not
- * all cards support this feature and the values are ignored
- * in that case.
- */
__u32 tx_coalesce_usecs_irq;
__u32 tx_max_coalesced_frames_irq;
-
- /* How many usecs to delay in-memory statistics
- * block updates. Some drivers do not have an in-memory
- * statistic block, and in such cases this value is ignored.
- * This value must not be zero.
- */
__u32 stats_block_coalesce_usecs;
-
- /* Adaptive RX/TX coalescing is an algorithm implemented by
- * some drivers to improve latency under low packet rates and
- * improve throughput under high packet rates. Some drivers
- * only implement one of RX or TX adaptive coalescing. Anything
- * not implemented by the driver causes these values to be
- * silently ignored.
- */
__u32 use_adaptive_rx_coalesce;
__u32 use_adaptive_tx_coalesce;
-
- /* When the packet rate (measured in packets per second)
- * is below pkt_rate_low, the {rx,tx}_*_low parameters are
- * used.
- */
__u32 pkt_rate_low;
__u32 rx_coalesce_usecs_low;
__u32 rx_max_coalesced_frames_low;
__u32 tx_coalesce_usecs_low;
__u32 tx_max_coalesced_frames_low;
-
- /* When the packet rate is below pkt_rate_high but above
- * pkt_rate_low (both measured in packets per second) the
- * normal {rx,tx}_* coalescing parameters are used.
- */
-
- /* When the packet rate is (measured in packets per second)
- * is above pkt_rate_high, the {rx,tx}_*_high parameters are
- * used.
- */
__u32 pkt_rate_high;
__u32 rx_coalesce_usecs_high;
__u32 rx_max_coalesced_frames_high;
__u32 tx_coalesce_usecs_high;
__u32 tx_max_coalesced_frames_high;
-
- /* How often to do adaptive coalescing packet rate sampling,
- * measured in seconds. Must not be zero.
- */
__u32 rate_sample_interval;
};
--
1.7.4.4
--
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply related
* [PATCH net-next 2/5] ethtool: Specify what kind of coalescing struct ethtool_coalesce covers
From: Ben Hutchings @ 2011-08-16 0:07 UTC (permalink / raw)
To: David Miller; +Cc: netdev, Eli Cohen
In-Reply-To: <1313453180.2731.57.camel@bwh-desktop>
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
include/linux/ethtool.h | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index be32dd0..71d45a1 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -118,7 +118,7 @@ struct ethtool_eeprom {
};
/**
- * struct ethtool_coalesce - coalescing parameters of chip
+ * struct ethtool_coalesce - coalescing parameters for IRQs and stats updates
* @cmd: ETHTOOL_{G,S}COALESCE
* @rx_coalesce_usecs: How many usecs to delay an RX interrupt after
* a packet arrives. If 0, only @rx_max_coalesced_frames is used.
--
1.7.4.4
--
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply related
* [PATCH net-next 3/5] ethtool: Correct description of 'max_coalesced_frames' fields
From: Ben Hutchings @ 2011-08-16 0:07 UTC (permalink / raw)
To: David Miller; +Cc: netdev, Eli Cohen
In-Reply-To: <1313453180.2731.57.camel@bwh-desktop>
The current descriptions state that these fields specify 'How many
packets to delay ... after a packet ...' which implies that the
hardware should wait for (max_coalesced_frames + 1) completions before
generating an interrupt. It is also stated that setting both this
field and the corresponding 'coalesce_usecs' field to 0 is invalid.
Together, this implies that the hardware must always be configured
to delay a completion IRQ for at least 1 usec or 1 more completion.
I believe that the addition of 1 is not intended, and David Miller
confirms that the original implementation (in tg3) does not do this.
Clarify the descriptions of these fields to avoid this interpretation.
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
include/linux/ethtool.h | 26 +++++++++++++-------------
1 files changed, 13 insertions(+), 13 deletions(-)
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index 71d45a1..18059ca 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -122,8 +122,8 @@ struct ethtool_eeprom {
* @cmd: ETHTOOL_{G,S}COALESCE
* @rx_coalesce_usecs: How many usecs to delay an RX interrupt after
* a packet arrives. If 0, only @rx_max_coalesced_frames is used.
- * @rx_max_coalesced_frames: How many packets to delay an RX interrupt
- * after a packet arrives. If 0, only @rx_coalesce_usecs is used.
+ * @rx_max_coalesced_frames: Maximum number of packets to receive
+ * before an RX interrupt. If 0, only @rx_coalesce_usecs is used.
* @rx_coalesce_usecs_irq: Same as @rx_coalesce_usecs, except that
* this value applies while an IRQ is being serviced by the host.
* @rx_max_coalesced_frames_irq: Same as @rx_max_coalesced_frames,
@@ -132,9 +132,9 @@ struct ethtool_eeprom {
* @tx_coalesce_usecs: How many usecs to delay a TX interrupt after
* a packet is sent. If 0, only @tx_max_coalesced_frames
* is used.
- * @tx_max_coalesced_frames: How many packets to delay a TX interrupt
- * after a packet is sent. If 0, only @tx_coalesce_usecs is
- * used.
+ * @tx_max_coalesced_frames: Maximum number of packets to be sent
+ * before a TX interrupt. If 0, only @tx_coalesce_usecs is
+ * used.
* @tx_coalesce_usecs_irq: Same as @tx_coalesce_usecs, except that
* this value applies while an IRQ is being serviced by the host.
* @tx_max_coalesced_frames_irq: Same as @tx_max_coalesced_frames,
@@ -149,21 +149,21 @@ struct ethtool_eeprom {
* @pkt_rate_low: Threshold for low packet rate (packets per second).
* @rx_coalesce_usecs_low: How many usecs to delay an RX interrupt after
* a packet arrives, when the packet rate is below @pkt_rate_low.
- * @rx_max_coalesced_frames_low: How many packets to delay an RX interrupt
- * after a packet arrives, when the packet rate is below @pkt_rate_low.
+ * @rx_max_coalesced_frames_low: Maximum number of packets to be received
+ * before an RX interrupt, when the packet rate is below @pkt_rate_low.
* @tx_coalesce_usecs_low: How many usecs to delay a TX interrupt after
* a packet is sent, when the packet rate is below @pkt_rate_low.
- * @tx_max_coalesced_frames_low: How many packets to delay a TX interrupt
- * after a packet is sent, when the packet rate is below @pkt_rate_low.
+ * @tx_max_coalesced_frames_low: Maximum nuumber of packets to be sent before
+ * a TX interrupt, when the packet rate is below @pkt_rate_low.
* @pkt_rate_high: Threshold for high packet rate (packets per second).
* @rx_coalesce_usecs_high: How many usecs to delay an RX interrupt after
* a packet arrives, when the packet rate is above @pkt_rate_high.
- * @rx_max_coalesced_frames_high: How many packets to delay an RX interrupt
- * after a packet arrives, when the packet rate is above @pkt_rate_high.
+ * @rx_max_coalesced_frames_high: Maximum number of packets to be received
+ * before an RX interrupt, when the packet rate is above @pkt_rate_high.
* @tx_coalesce_usecs_high: How many usecs to delay a TX interrupt after
* a packet is sent, when the packet rate is above @pkt_rate_high.
- * @tx_max_coalesced_frames_high: How many packets to delay a TX interrupt
- * after a packet is sent, when the packet rate is above @pkt_rate_high.
+ * @tx_max_coalesced_frames_high: Maximum number of packets to be sent before
+ * a TX interrupt, when the packet rate is above @pkt_rate_high.
* @rate_sample_interval: How often to do adaptive coalescing packet rate
* sampling, measured in seconds. Must not be zero.
*
--
1.7.4.4
--
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply related
* [PATCH net-next 4/5] ethtool: Explicitly state the exit condition for interrupt coalescing
From: Ben Hutchings @ 2011-08-16 0:08 UTC (permalink / raw)
To: David Miller; +Cc: netdev, Eli Cohen
In-Reply-To: <1313453180.2731.57.camel@bwh-desktop>
Also explicitly state how to disable interrupt coalescing.
Remove the now-redundant text from field descriptions.
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
include/linux/ethtool.h | 19 +++++++++++--------
1 files changed, 11 insertions(+), 8 deletions(-)
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index 18059ca..42378b3 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -121,20 +121,18 @@ struct ethtool_eeprom {
* struct ethtool_coalesce - coalescing parameters for IRQs and stats updates
* @cmd: ETHTOOL_{G,S}COALESCE
* @rx_coalesce_usecs: How many usecs to delay an RX interrupt after
- * a packet arrives. If 0, only @rx_max_coalesced_frames is used.
+ * a packet arrives.
* @rx_max_coalesced_frames: Maximum number of packets to receive
- * before an RX interrupt. If 0, only @rx_coalesce_usecs is used.
+ * before an RX interrupt.
* @rx_coalesce_usecs_irq: Same as @rx_coalesce_usecs, except that
* this value applies while an IRQ is being serviced by the host.
* @rx_max_coalesced_frames_irq: Same as @rx_max_coalesced_frames,
* except that this value applies while an IRQ is being serviced
* by the host.
* @tx_coalesce_usecs: How many usecs to delay a TX interrupt after
- * a packet is sent. If 0, only @tx_max_coalesced_frames
- * is used.
+ * a packet is sent.
* @tx_max_coalesced_frames: Maximum number of packets to be sent
- * before a TX interrupt. If 0, only @tx_coalesce_usecs is
- * used.
+ * before a TX interrupt.
* @tx_coalesce_usecs_irq: Same as @tx_coalesce_usecs, except that
* this value applies while an IRQ is being serviced by the host.
* @tx_max_coalesced_frames_irq: Same as @tx_max_coalesced_frames,
@@ -167,8 +165,13 @@ struct ethtool_eeprom {
* @rate_sample_interval: How often to do adaptive coalescing packet rate
* sampling, measured in seconds. Must not be zero.
*
- * It is illegal to set both usecs and max frames to zero as this
- * would cause interrupts to never be generated.
+ * Each pair of (usecs, max_frames) fields specifies this exit
+ * condition for interrupt coalescing:
+ * (usecs > 0 && time_since_first_completion >= usecs) ||
+ * (max_frames > 0 && completed_frames >= max_frames)
+ * It is illegal to set both usecs and max_frames to zero as this
+ * would cause interrupts to never be generated. To disable
+ * coalescing, set usecs = 0 and max_frames = 1.
*
* Adaptive RX/TX coalescing is an algorithm implemented by some
* drivers to improve latency under low packet rates and improve
--
1.7.4.4
--
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply related
* [PATCH net-next 5/5] ethtool: Note common alternate exit condition for interrupt coalescing
From: Ben Hutchings @ 2011-08-16 0:09 UTC (permalink / raw)
To: David Miller; +Cc: netdev, Eli Cohen
In-Reply-To: <1313453180.2731.57.camel@bwh-desktop>
Many implementations ignore the value of max_frames and do not
treat usecs == 0 as special. Document this as deprecated.
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
include/linux/ethtool.h | 6 ++++++
1 files changed, 6 insertions(+), 0 deletions(-)
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index 42378b3..3829712 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -173,6 +173,12 @@ struct ethtool_eeprom {
* would cause interrupts to never be generated. To disable
* coalescing, set usecs = 0 and max_frames = 1.
*
+ * Some implementations ignore the value of max_frames and use the
+ * condition:
+ * time_since_first_completion >= usecs
+ * This is deprecated. Drivers for hardware that does not support
+ * counting completions should validate that max_frames == !rx_usecs.
+ *
* Adaptive RX/TX coalescing is an algorithm implemented by some
* drivers to improve latency under low packet rates and improve
* throughput under high packet rates. Some drivers only implement
--
1.7.4.4
--
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply related
* [PATCH net-2.6 V2] bonding:reset backup and inactive flag of slave
From: Weiping Pan @ 2011-08-16 1:57 UTC (permalink / raw)
To: netdev; +Cc: Weiping Pan
In-Reply-To: <j2bgs2$pf5$1@dough.gmane.org>
Eduard Sinelnikov (eduard.sinelnikov@gmail.com) found that if we change
bonding mode from active backup to round robin, some slaves are still keeping
"backup", and won't transmit packets.
As Jay Vosburgh(fubar@us.ibm.com) pointed out that we can work around that by
removing the bond_is_active_slave() check, because the "backup" flag is only
meaningful for active backup mode.
But if we just simply ignore the bond_is_active_slave() check,
the transmission will work fine, but we can't maintain the correct value of
"backup" flag for each slaves, though it is meaningless for other mode than
active backup.
I'd like to reset "backup" and "inactive" flag in bond_open,
thus we can keep the correct value of them.
As for bond_is_active_slave(), I'd like to prepare another patch to handle it.
V2:
Use C style comment.
Move read_lock(&bond->curr_slave_lock).
Replace restore with reset, for active backup mode, it means "restore",
but for other modes, it means "reset".
Signed-off-by: Weiping Pan <panweiping3@gmail.com>
---
drivers/net/bonding/bond_main.c | 18 ++++++++++++++++++
1 files changed, 18 insertions(+), 0 deletions(-)
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 38a83ac..43f2ea5 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -3419,9 +3419,27 @@ static int bond_xmit_hash_policy_l2(struct sk_buff *skb, int count)
static int bond_open(struct net_device *bond_dev)
{
struct bonding *bond = netdev_priv(bond_dev);
+ struct slave *slave;
+ int i;
bond->kill_timers = 0;
+ /* reset slave->backup and slave->inactive */
+ read_lock(&bond->lock);
+ if (bond->slave_cnt > 0) {
+ read_lock(&bond->curr_slave_lock);
+ bond_for_each_slave(bond, slave, i) {
+ if ((bond->params.mode == BOND_MODE_ACTIVEBACKUP)
+ && (slave != bond->curr_active_slave)) {
+ bond_set_slave_inactive_flags(slave);
+ } else {
+ bond_set_slave_active_flags(slave);
+ }
+ }
+ read_unlock(&bond->curr_slave_lock);
+ }
+ read_unlock(&bond->lock);
+
INIT_DELAYED_WORK(&bond->mcast_work, bond_resend_igmp_join_requests_delayed);
if (bond_is_lb(bond)) {
--
1.7.4.4
^ permalink raw reply related
* linux-next: build failure after merge of the net tree
From: Stephen Rothwell @ 2011-08-16 3:26 UTC (permalink / raw)
To: David Miller, netdev; +Cc: linux-next, linux-kernel
Hi all,
After merging the net tree, today's linux-next build (x86_64 allmodconfig)
failed like this:
drivers/net/ethernet/sun/sungem_phy.c:36:24: fatal error: sungem_phy.h: No such file or directory
Caused by commit 2bb698412d8a ("net: Move sungem_phy.h under
include/linux").
I applied this patch for today:
From: Stephen Rothwell <sfr@canb.auug.org.au>
Date: Tue, 16 Aug 2011 13:22:24 +1000
Subject: [PATCH] sungem: sungem_phy.h moved
Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
---
drivers/net/ethernet/sun/sungem_phy.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/drivers/net/ethernet/sun/sungem_phy.c b/drivers/net/ethernet/sun/sungem_phy.c
index d16880d..db99c22 100644
--- a/drivers/net/ethernet/sun/sungem_phy.c
+++ b/drivers/net/ethernet/sun/sungem_phy.c
@@ -33,7 +33,7 @@
#include <asm/prom.h>
#endif
-#include "sungem_phy.h"
+#include <linux/sungem_phy.h>
/* Link modes of the BCM5400 PHY */
static const int phy_BCM5400_link_table[8][3] = {
--
1.7.5.4
--
Cheers,
Stephen Rothwell sfr@canb.auug.org.au
http://www.canb.auug.org.au/~sfr/
^ permalink raw reply related
* Re: linux-next: build failure after merge of the net tree
From: David Miller @ 2011-08-16 4:03 UTC (permalink / raw)
To: sfr; +Cc: netdev, linux-next, linux-kernel
In-Reply-To: <20110816132659.7719837bd136aa520c5814ac@canb.auug.org.au>
From: Stephen Rothwell <sfr@canb.auug.org.au>
Date: Tue, 16 Aug 2011 13:26:59 +1000
> I applied this patch for today:
>
> From: Stephen Rothwell <sfr@canb.auug.org.au>
> Date: Tue, 16 Aug 2011 13:22:24 +1000
> Subject: [PATCH] sungem: sungem_phy.h moved
>
> Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
Sigh, applied, sorry about this.
^ permalink raw reply
* Re: linux-next: build failure after merge of the final tree (net tree related)
From: Stephen Rothwell @ 2011-08-16 5:28 UTC (permalink / raw)
To: David Miller; +Cc: netdev, linux-next, linux-kernel, jeffrey.t.kirsher
In-Reply-To: <20110814.225610.2264854100578866902.davem@davemloft.net>
[-- Attachment #1: Type: text/plain, Size: 467 bytes --]
Hi Dave,
On Sun, 14 Aug 2011 22:56:10 -0700 (PDT) David Miller <davem@davemloft.net> wrote:
>
> This should fix the include problem, but I suspect this thing won't
> link.
Yep, indeed, today I get:
make[5]: *** No rule to make target `drivers/net/ethernet/toshiba/ethernet/sun/sungem_phy.o', needed by `drivers/net/ethernet/toshiba/built-in.o'.
--
Cheers,
Stephen Rothwell sfr@canb.auug.org.au
http://www.canb.auug.org.au/~sfr/
[-- Attachment #2: Type: application/pgp-signature, Size: 490 bytes --]
^ permalink raw reply
* Re: linux-next: build failure after merge of the final tree (net tree related)
From: David Miller @ 2011-08-16 6:11 UTC (permalink / raw)
To: sfr; +Cc: netdev, linux-next, linux-kernel, jeffrey.t.kirsher
In-Reply-To: <20110816152815.911f15937efa2ebf58a2795d@canb.auug.org.au>
From: Stephen Rothwell <sfr@canb.auug.org.au>
Date: Tue, 16 Aug 2011 15:28:15 +1000
> Hi Dave,
>
> On Sun, 14 Aug 2011 22:56:10 -0700 (PDT) David Miller <davem@davemloft.net> wrote:
>>
>> This should fix the include problem, but I suspect this thing won't
>> link.
>
> Yep, indeed, today I get:
>
> make[5]: *** No rule to make target `drivers/net/ethernet/toshiba/ethernet/sun/sungem_phy.o', needed by `drivers/net/ethernet/toshiba/built-in.o'.
Please test this patch:
--------------------
net: Fix sungem_phy sharing.
Since sungem_phy is used by multiple, unrelated, drivers make it
build as a real module under drivers/net.
depmod will pick up the symbol dependency and make sure sungem_phy.ko
gets loaded any time sungem.ko or spider_net.ko is loaded.
Signed-off-by: David S. Miller <davem@davemloft.net>
---
drivers/net/Kconfig | 3 +
drivers/net/Makefile | 2 +
drivers/net/ethernet/sun/Makefile | 1 -
drivers/net/ethernet/sun/sungem.c | 2 +-
drivers/net/ethernet/sun/sungem_phy.c | 1200 -----------------------------
drivers/net/ethernet/toshiba/Makefile | 2 +-
drivers/net/ethernet/toshiba/spider_net.c | 4 +-
drivers/net/sungem_phy.c | 1199 ++++++++++++++++++++++++++++
include/linux/sungem_phy.h | 2 +-
9 files changed, 1209 insertions(+), 1206 deletions(-)
delete mode 100644 drivers/net/ethernet/sun/sungem_phy.c
create mode 100644 drivers/net/sungem_phy.c
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 31d8792..ef6b6be 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -186,6 +186,9 @@ config MII
source "drivers/net/phy/Kconfig"
+config SUNGEM_PHY
+ tristate
+
#
# Ethernet
#
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 9cb47bb..c33009b 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -75,3 +75,5 @@ obj-$(CONFIG_VIRTIO_NET) += virtio_net.o
obj-$(CONFIG_WIMAX) += wimax/
obj-$(CONFIG_CAIF) += caif/
+
+obj-$(CONFIG_SUNGEM_PHY) += sungem_phy.o
diff --git a/drivers/net/ethernet/sun/Makefile b/drivers/net/ethernet/sun/Makefile
index 6e25dad..1e620ff 100644
--- a/drivers/net/ethernet/sun/Makefile
+++ b/drivers/net/ethernet/sun/Makefile
@@ -6,7 +6,6 @@ obj-$(CONFIG_HAPPYMEAL) += sunhme.o
obj-$(CONFIG_SUNQE) += sunqe.o
obj-$(CONFIG_SUNBMAC) += sunbmac.o
obj-$(CONFIG_SUNGEM) += sungem.o
-obj-$(CONFIG_SUNGEM_PHY) += sungem_phy.o
obj-$(CONFIG_CASSINI) += cassini.o
obj-$(CONFIG_SUNVNET) += sunvnet.o
obj-$(CONFIG_NIU) += niu.o
diff --git a/drivers/net/ethernet/sun/sungem.c b/drivers/net/ethernet/sun/sungem.c
index 0f13c5d..fb9885d 100644
--- a/drivers/net/ethernet/sun/sungem.c
+++ b/drivers/net/ethernet/sun/sungem.c
@@ -1721,7 +1721,7 @@ static void gem_init_phy(struct gem *gp)
if (gp->phy_type == phy_mii_mdio0 ||
gp->phy_type == phy_mii_mdio1) {
/* Reset and detect MII PHY */
- mii_phy_probe(&gp->phy_mii, gp->mii_phy_addr);
+ sungem_phy_probe(&gp->phy_mii, gp->mii_phy_addr);
/* Init PHY */
if (gp->phy_mii.def && gp->phy_mii.def->ops->init)
diff --git a/drivers/net/ethernet/sun/sungem_phy.c b/drivers/net/ethernet/sun/sungem_phy.c
deleted file mode 100644
index db99c22..0000000
--- a/drivers/net/ethernet/sun/sungem_phy.c
+++ /dev/null
@@ -1,1200 +0,0 @@
-/*
- * PHY drivers for the sungem ethernet driver.
- *
- * This file could be shared with other drivers.
- *
- * (c) 2002-2007, Benjamin Herrenscmidt (benh@kernel.crashing.org)
- *
- * TODO:
- * - Add support for PHYs that provide an IRQ line
- * - Eventually moved the entire polling state machine in
- * there (out of the eth driver), so that it can easily be
- * skipped on PHYs that implement it in hardware.
- * - On LXT971 & BCM5201, Apple uses some chip specific regs
- * to read the link status. Figure out why and if it makes
- * sense to do the same (magic aneg ?)
- * - Apple has some additional power management code for some
- * Broadcom PHYs that they "hide" from the OpenSource version
- * of darwin, still need to reverse engineer that
- */
-
-
-#include <linux/module.h>
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/mii.h>
-#include <linux/ethtool.h>
-#include <linux/delay.h>
-
-#ifdef CONFIG_PPC_PMAC
-#include <asm/prom.h>
-#endif
-
-#include <linux/sungem_phy.h>
-
-/* Link modes of the BCM5400 PHY */
-static const int phy_BCM5400_link_table[8][3] = {
- { 0, 0, 0 }, /* No link */
- { 0, 0, 0 }, /* 10BT Half Duplex */
- { 1, 0, 0 }, /* 10BT Full Duplex */
- { 0, 1, 0 }, /* 100BT Half Duplex */
- { 0, 1, 0 }, /* 100BT Half Duplex */
- { 1, 1, 0 }, /* 100BT Full Duplex*/
- { 1, 0, 1 }, /* 1000BT */
- { 1, 0, 1 }, /* 1000BT */
-};
-
-static inline int __phy_read(struct mii_phy* phy, int id, int reg)
-{
- return phy->mdio_read(phy->dev, id, reg);
-}
-
-static inline void __phy_write(struct mii_phy* phy, int id, int reg, int val)
-{
- phy->mdio_write(phy->dev, id, reg, val);
-}
-
-static inline int phy_read(struct mii_phy* phy, int reg)
-{
- return phy->mdio_read(phy->dev, phy->mii_id, reg);
-}
-
-static inline void phy_write(struct mii_phy* phy, int reg, int val)
-{
- phy->mdio_write(phy->dev, phy->mii_id, reg, val);
-}
-
-static int reset_one_mii_phy(struct mii_phy* phy, int phy_id)
-{
- u16 val;
- int limit = 10000;
-
- val = __phy_read(phy, phy_id, MII_BMCR);
- val &= ~(BMCR_ISOLATE | BMCR_PDOWN);
- val |= BMCR_RESET;
- __phy_write(phy, phy_id, MII_BMCR, val);
-
- udelay(100);
-
- while (--limit) {
- val = __phy_read(phy, phy_id, MII_BMCR);
- if ((val & BMCR_RESET) == 0)
- break;
- udelay(10);
- }
- if ((val & BMCR_ISOLATE) && limit > 0)
- __phy_write(phy, phy_id, MII_BMCR, val & ~BMCR_ISOLATE);
-
- return limit <= 0;
-}
-
-static int bcm5201_init(struct mii_phy* phy)
-{
- u16 data;
-
- data = phy_read(phy, MII_BCM5201_MULTIPHY);
- data &= ~MII_BCM5201_MULTIPHY_SUPERISOLATE;
- phy_write(phy, MII_BCM5201_MULTIPHY, data);
-
- phy_write(phy, MII_BCM5201_INTERRUPT, 0);
-
- return 0;
-}
-
-static int bcm5201_suspend(struct mii_phy* phy)
-{
- phy_write(phy, MII_BCM5201_INTERRUPT, 0);
- phy_write(phy, MII_BCM5201_MULTIPHY, MII_BCM5201_MULTIPHY_SUPERISOLATE);
-
- return 0;
-}
-
-static int bcm5221_init(struct mii_phy* phy)
-{
- u16 data;
-
- data = phy_read(phy, MII_BCM5221_TEST);
- phy_write(phy, MII_BCM5221_TEST,
- data | MII_BCM5221_TEST_ENABLE_SHADOWS);
-
- data = phy_read(phy, MII_BCM5221_SHDOW_AUX_STAT2);
- phy_write(phy, MII_BCM5221_SHDOW_AUX_STAT2,
- data | MII_BCM5221_SHDOW_AUX_STAT2_APD);
-
- data = phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
- phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
- data | MII_BCM5221_SHDOW_AUX_MODE4_CLKLOPWR);
-
- data = phy_read(phy, MII_BCM5221_TEST);
- phy_write(phy, MII_BCM5221_TEST,
- data & ~MII_BCM5221_TEST_ENABLE_SHADOWS);
-
- return 0;
-}
-
-static int bcm5221_suspend(struct mii_phy* phy)
-{
- u16 data;
-
- data = phy_read(phy, MII_BCM5221_TEST);
- phy_write(phy, MII_BCM5221_TEST,
- data | MII_BCM5221_TEST_ENABLE_SHADOWS);
-
- data = phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
- phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
- data | MII_BCM5221_SHDOW_AUX_MODE4_IDDQMODE);
-
- return 0;
-}
-
-static int bcm5241_init(struct mii_phy* phy)
-{
- u16 data;
-
- data = phy_read(phy, MII_BCM5221_TEST);
- phy_write(phy, MII_BCM5221_TEST,
- data | MII_BCM5221_TEST_ENABLE_SHADOWS);
-
- data = phy_read(phy, MII_BCM5221_SHDOW_AUX_STAT2);
- phy_write(phy, MII_BCM5221_SHDOW_AUX_STAT2,
- data | MII_BCM5221_SHDOW_AUX_STAT2_APD);
-
- data = phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
- phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
- data & ~MII_BCM5241_SHDOW_AUX_MODE4_STANDBYPWR);
-
- data = phy_read(phy, MII_BCM5221_TEST);
- phy_write(phy, MII_BCM5221_TEST,
- data & ~MII_BCM5221_TEST_ENABLE_SHADOWS);
-
- return 0;
-}
-
-static int bcm5241_suspend(struct mii_phy* phy)
-{
- u16 data;
-
- data = phy_read(phy, MII_BCM5221_TEST);
- phy_write(phy, MII_BCM5221_TEST,
- data | MII_BCM5221_TEST_ENABLE_SHADOWS);
-
- data = phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
- phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
- data | MII_BCM5241_SHDOW_AUX_MODE4_STANDBYPWR);
-
- return 0;
-}
-
-static int bcm5400_init(struct mii_phy* phy)
-{
- u16 data;
-
- /* Configure for gigabit full duplex */
- data = phy_read(phy, MII_BCM5400_AUXCONTROL);
- data |= MII_BCM5400_AUXCONTROL_PWR10BASET;
- phy_write(phy, MII_BCM5400_AUXCONTROL, data);
-
- data = phy_read(phy, MII_BCM5400_GB_CONTROL);
- data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
- phy_write(phy, MII_BCM5400_GB_CONTROL, data);
-
- udelay(100);
-
- /* Reset and configure cascaded 10/100 PHY */
- (void)reset_one_mii_phy(phy, 0x1f);
-
- data = __phy_read(phy, 0x1f, MII_BCM5201_MULTIPHY);
- data |= MII_BCM5201_MULTIPHY_SERIALMODE;
- __phy_write(phy, 0x1f, MII_BCM5201_MULTIPHY, data);
-
- data = phy_read(phy, MII_BCM5400_AUXCONTROL);
- data &= ~MII_BCM5400_AUXCONTROL_PWR10BASET;
- phy_write(phy, MII_BCM5400_AUXCONTROL, data);
-
- return 0;
-}
-
-static int bcm5400_suspend(struct mii_phy* phy)
-{
-#if 0 /* Commented out in Darwin... someone has those dawn docs ? */
- phy_write(phy, MII_BMCR, BMCR_PDOWN);
-#endif
- return 0;
-}
-
-static int bcm5401_init(struct mii_phy* phy)
-{
- u16 data;
- int rev;
-
- rev = phy_read(phy, MII_PHYSID2) & 0x000f;
- if (rev == 0 || rev == 3) {
- /* Some revisions of 5401 appear to need this
- * initialisation sequence to disable, according
- * to OF, "tap power management"
- *
- * WARNING ! OF and Darwin don't agree on the
- * register addresses. OF seem to interpret the
- * register numbers below as decimal
- *
- * Note: This should (and does) match tg3_init_5401phy_dsp
- * in the tg3.c driver. -DaveM
- */
- phy_write(phy, 0x18, 0x0c20);
- phy_write(phy, 0x17, 0x0012);
- phy_write(phy, 0x15, 0x1804);
- phy_write(phy, 0x17, 0x0013);
- phy_write(phy, 0x15, 0x1204);
- phy_write(phy, 0x17, 0x8006);
- phy_write(phy, 0x15, 0x0132);
- phy_write(phy, 0x17, 0x8006);
- phy_write(phy, 0x15, 0x0232);
- phy_write(phy, 0x17, 0x201f);
- phy_write(phy, 0x15, 0x0a20);
- }
-
- /* Configure for gigabit full duplex */
- data = phy_read(phy, MII_BCM5400_GB_CONTROL);
- data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
- phy_write(phy, MII_BCM5400_GB_CONTROL, data);
-
- udelay(10);
-
- /* Reset and configure cascaded 10/100 PHY */
- (void)reset_one_mii_phy(phy, 0x1f);
-
- data = __phy_read(phy, 0x1f, MII_BCM5201_MULTIPHY);
- data |= MII_BCM5201_MULTIPHY_SERIALMODE;
- __phy_write(phy, 0x1f, MII_BCM5201_MULTIPHY, data);
-
- return 0;
-}
-
-static int bcm5401_suspend(struct mii_phy* phy)
-{
-#if 0 /* Commented out in Darwin... someone has those dawn docs ? */
- phy_write(phy, MII_BMCR, BMCR_PDOWN);
-#endif
- return 0;
-}
-
-static int bcm5411_init(struct mii_phy* phy)
-{
- u16 data;
-
- /* Here's some more Apple black magic to setup
- * some voltage stuffs.
- */
- phy_write(phy, 0x1c, 0x8c23);
- phy_write(phy, 0x1c, 0x8ca3);
- phy_write(phy, 0x1c, 0x8c23);
-
- /* Here, Apple seems to want to reset it, do
- * it as well
- */
- phy_write(phy, MII_BMCR, BMCR_RESET);
- phy_write(phy, MII_BMCR, 0x1340);
-
- data = phy_read(phy, MII_BCM5400_GB_CONTROL);
- data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
- phy_write(phy, MII_BCM5400_GB_CONTROL, data);
-
- udelay(10);
-
- /* Reset and configure cascaded 10/100 PHY */
- (void)reset_one_mii_phy(phy, 0x1f);
-
- return 0;
-}
-
-static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise)
-{
- u16 ctl, adv;
-
- phy->autoneg = 1;
- phy->speed = SPEED_10;
- phy->duplex = DUPLEX_HALF;
- phy->pause = 0;
- phy->advertising = advertise;
-
- /* Setup standard advertise */
- adv = phy_read(phy, MII_ADVERTISE);
- adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
- if (advertise & ADVERTISED_10baseT_Half)
- adv |= ADVERTISE_10HALF;
- if (advertise & ADVERTISED_10baseT_Full)
- adv |= ADVERTISE_10FULL;
- if (advertise & ADVERTISED_100baseT_Half)
- adv |= ADVERTISE_100HALF;
- if (advertise & ADVERTISED_100baseT_Full)
- adv |= ADVERTISE_100FULL;
- phy_write(phy, MII_ADVERTISE, adv);
-
- /* Start/Restart aneg */
- ctl = phy_read(phy, MII_BMCR);
- ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
- phy_write(phy, MII_BMCR, ctl);
-
- return 0;
-}
-
-static int genmii_setup_forced(struct mii_phy *phy, int speed, int fd)
-{
- u16 ctl;
-
- phy->autoneg = 0;
- phy->speed = speed;
- phy->duplex = fd;
- phy->pause = 0;
-
- ctl = phy_read(phy, MII_BMCR);
- ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_ANENABLE);
-
- /* First reset the PHY */
- phy_write(phy, MII_BMCR, ctl | BMCR_RESET);
-
- /* Select speed & duplex */
- switch(speed) {
- case SPEED_10:
- break;
- case SPEED_100:
- ctl |= BMCR_SPEED100;
- break;
- case SPEED_1000:
- default:
- return -EINVAL;
- }
- if (fd == DUPLEX_FULL)
- ctl |= BMCR_FULLDPLX;
- phy_write(phy, MII_BMCR, ctl);
-
- return 0;
-}
-
-static int genmii_poll_link(struct mii_phy *phy)
-{
- u16 status;
-
- (void)phy_read(phy, MII_BMSR);
- status = phy_read(phy, MII_BMSR);
- if ((status & BMSR_LSTATUS) == 0)
- return 0;
- if (phy->autoneg && !(status & BMSR_ANEGCOMPLETE))
- return 0;
- return 1;
-}
-
-static int genmii_read_link(struct mii_phy *phy)
-{
- u16 lpa;
-
- if (phy->autoneg) {
- lpa = phy_read(phy, MII_LPA);
-
- if (lpa & (LPA_10FULL | LPA_100FULL))
- phy->duplex = DUPLEX_FULL;
- else
- phy->duplex = DUPLEX_HALF;
- if (lpa & (LPA_100FULL | LPA_100HALF))
- phy->speed = SPEED_100;
- else
- phy->speed = SPEED_10;
- phy->pause = 0;
- }
- /* On non-aneg, we assume what we put in BMCR is the speed,
- * though magic-aneg shouldn't prevent this case from occurring
- */
-
- return 0;
-}
-
-static int generic_suspend(struct mii_phy* phy)
-{
- phy_write(phy, MII_BMCR, BMCR_PDOWN);
-
- return 0;
-}
-
-static int bcm5421_init(struct mii_phy* phy)
-{
- u16 data;
- unsigned int id;
-
- id = (phy_read(phy, MII_PHYSID1) << 16 | phy_read(phy, MII_PHYSID2));
-
- /* Revision 0 of 5421 needs some fixups */
- if (id == 0x002060e0) {
- /* This is borrowed from MacOS
- */
- phy_write(phy, 0x18, 0x1007);
- data = phy_read(phy, 0x18);
- phy_write(phy, 0x18, data | 0x0400);
- phy_write(phy, 0x18, 0x0007);
- data = phy_read(phy, 0x18);
- phy_write(phy, 0x18, data | 0x0800);
- phy_write(phy, 0x17, 0x000a);
- data = phy_read(phy, 0x15);
- phy_write(phy, 0x15, data | 0x0200);
- }
-
- /* Pick up some init code from OF for K2 version */
- if ((id & 0xfffffff0) == 0x002062e0) {
- phy_write(phy, 4, 0x01e1);
- phy_write(phy, 9, 0x0300);
- }
-
- /* Check if we can enable automatic low power */
-#ifdef CONFIG_PPC_PMAC
- if (phy->platform_data) {
- struct device_node *np = of_get_parent(phy->platform_data);
- int can_low_power = 1;
- if (np == NULL || of_get_property(np, "no-autolowpower", NULL))
- can_low_power = 0;
- if (can_low_power) {
- /* Enable automatic low-power */
- phy_write(phy, 0x1c, 0x9002);
- phy_write(phy, 0x1c, 0xa821);
- phy_write(phy, 0x1c, 0x941d);
- }
- }
-#endif /* CONFIG_PPC_PMAC */
-
- return 0;
-}
-
-static int bcm54xx_setup_aneg(struct mii_phy *phy, u32 advertise)
-{
- u16 ctl, adv;
-
- phy->autoneg = 1;
- phy->speed = SPEED_10;
- phy->duplex = DUPLEX_HALF;
- phy->pause = 0;
- phy->advertising = advertise;
-
- /* Setup standard advertise */
- adv = phy_read(phy, MII_ADVERTISE);
- adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
- if (advertise & ADVERTISED_10baseT_Half)
- adv |= ADVERTISE_10HALF;
- if (advertise & ADVERTISED_10baseT_Full)
- adv |= ADVERTISE_10FULL;
- if (advertise & ADVERTISED_100baseT_Half)
- adv |= ADVERTISE_100HALF;
- if (advertise & ADVERTISED_100baseT_Full)
- adv |= ADVERTISE_100FULL;
- if (advertise & ADVERTISED_Pause)
- adv |= ADVERTISE_PAUSE_CAP;
- if (advertise & ADVERTISED_Asym_Pause)
- adv |= ADVERTISE_PAUSE_ASYM;
- phy_write(phy, MII_ADVERTISE, adv);
-
- /* Setup 1000BT advertise */
- adv = phy_read(phy, MII_1000BASETCONTROL);
- adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP|MII_1000BASETCONTROL_HALFDUPLEXCAP);
- if (advertise & SUPPORTED_1000baseT_Half)
- adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP;
- if (advertise & SUPPORTED_1000baseT_Full)
- adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP;
- phy_write(phy, MII_1000BASETCONTROL, adv);
-
- /* Start/Restart aneg */
- ctl = phy_read(phy, MII_BMCR);
- ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
- phy_write(phy, MII_BMCR, ctl);
-
- return 0;
-}
-
-static int bcm54xx_setup_forced(struct mii_phy *phy, int speed, int fd)
-{
- u16 ctl;
-
- phy->autoneg = 0;
- phy->speed = speed;
- phy->duplex = fd;
- phy->pause = 0;
-
- ctl = phy_read(phy, MII_BMCR);
- ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_SPD2|BMCR_ANENABLE);
-
- /* First reset the PHY */
- phy_write(phy, MII_BMCR, ctl | BMCR_RESET);
-
- /* Select speed & duplex */
- switch(speed) {
- case SPEED_10:
- break;
- case SPEED_100:
- ctl |= BMCR_SPEED100;
- break;
- case SPEED_1000:
- ctl |= BMCR_SPD2;
- }
- if (fd == DUPLEX_FULL)
- ctl |= BMCR_FULLDPLX;
-
- // XXX Should we set the sungem to GII now on 1000BT ?
-
- phy_write(phy, MII_BMCR, ctl);
-
- return 0;
-}
-
-static int bcm54xx_read_link(struct mii_phy *phy)
-{
- int link_mode;
- u16 val;
-
- if (phy->autoneg) {
- val = phy_read(phy, MII_BCM5400_AUXSTATUS);
- link_mode = ((val & MII_BCM5400_AUXSTATUS_LINKMODE_MASK) >>
- MII_BCM5400_AUXSTATUS_LINKMODE_SHIFT);
- phy->duplex = phy_BCM5400_link_table[link_mode][0] ?
- DUPLEX_FULL : DUPLEX_HALF;
- phy->speed = phy_BCM5400_link_table[link_mode][2] ?
- SPEED_1000 :
- (phy_BCM5400_link_table[link_mode][1] ?
- SPEED_100 : SPEED_10);
- val = phy_read(phy, MII_LPA);
- phy->pause = (phy->duplex == DUPLEX_FULL) &&
- ((val & LPA_PAUSE) != 0);
- }
- /* On non-aneg, we assume what we put in BMCR is the speed,
- * though magic-aneg shouldn't prevent this case from occurring
- */
-
- return 0;
-}
-
-static int marvell88e1111_init(struct mii_phy* phy)
-{
- u16 rev;
-
- /* magic init sequence for rev 0 */
- rev = phy_read(phy, MII_PHYSID2) & 0x000f;
- if (rev == 0) {
- phy_write(phy, 0x1d, 0x000a);
- phy_write(phy, 0x1e, 0x0821);
-
- phy_write(phy, 0x1d, 0x0006);
- phy_write(phy, 0x1e, 0x8600);
-
- phy_write(phy, 0x1d, 0x000b);
- phy_write(phy, 0x1e, 0x0100);
-
- phy_write(phy, 0x1d, 0x0004);
- phy_write(phy, 0x1e, 0x4850);
- }
- return 0;
-}
-
-#define BCM5421_MODE_MASK (1 << 5)
-
-static int bcm5421_poll_link(struct mii_phy* phy)
-{
- u32 phy_reg;
- int mode;
-
- /* find out in what mode we are */
- phy_write(phy, MII_NCONFIG, 0x1000);
- phy_reg = phy_read(phy, MII_NCONFIG);
-
- mode = (phy_reg & BCM5421_MODE_MASK) >> 5;
-
- if ( mode == BCM54XX_COPPER)
- return genmii_poll_link(phy);
-
- /* try to find out wether we have a link */
- phy_write(phy, MII_NCONFIG, 0x2000);
- phy_reg = phy_read(phy, MII_NCONFIG);
-
- if (phy_reg & 0x0020)
- return 0;
- else
- return 1;
-}
-
-static int bcm5421_read_link(struct mii_phy* phy)
-{
- u32 phy_reg;
- int mode;
-
- /* find out in what mode we are */
- phy_write(phy, MII_NCONFIG, 0x1000);
- phy_reg = phy_read(phy, MII_NCONFIG);
-
- mode = (phy_reg & BCM5421_MODE_MASK ) >> 5;
-
- if ( mode == BCM54XX_COPPER)
- return bcm54xx_read_link(phy);
-
- phy->speed = SPEED_1000;
-
- /* find out wether we are running half- or full duplex */
- phy_write(phy, MII_NCONFIG, 0x2000);
- phy_reg = phy_read(phy, MII_NCONFIG);
-
- if ( (phy_reg & 0x0080) >> 7)
- phy->duplex |= DUPLEX_HALF;
- else
- phy->duplex |= DUPLEX_FULL;
-
- return 0;
-}
-
-static int bcm5421_enable_fiber(struct mii_phy* phy, int autoneg)
-{
- /* enable fiber mode */
- phy_write(phy, MII_NCONFIG, 0x9020);
- /* LEDs active in both modes, autosense prio = fiber */
- phy_write(phy, MII_NCONFIG, 0x945f);
-
- if (!autoneg) {
- /* switch off fibre autoneg */
- phy_write(phy, MII_NCONFIG, 0xfc01);
- phy_write(phy, 0x0b, 0x0004);
- }
-
- phy->autoneg = autoneg;
-
- return 0;
-}
-
-#define BCM5461_FIBER_LINK (1 << 2)
-#define BCM5461_MODE_MASK (3 << 1)
-
-static int bcm5461_poll_link(struct mii_phy* phy)
-{
- u32 phy_reg;
- int mode;
-
- /* find out in what mode we are */
- phy_write(phy, MII_NCONFIG, 0x7c00);
- phy_reg = phy_read(phy, MII_NCONFIG);
-
- mode = (phy_reg & BCM5461_MODE_MASK ) >> 1;
-
- if ( mode == BCM54XX_COPPER)
- return genmii_poll_link(phy);
-
- /* find out wether we have a link */
- phy_write(phy, MII_NCONFIG, 0x7000);
- phy_reg = phy_read(phy, MII_NCONFIG);
-
- if (phy_reg & BCM5461_FIBER_LINK)
- return 1;
- else
- return 0;
-}
-
-#define BCM5461_FIBER_DUPLEX (1 << 3)
-
-static int bcm5461_read_link(struct mii_phy* phy)
-{
- u32 phy_reg;
- int mode;
-
- /* find out in what mode we are */
- phy_write(phy, MII_NCONFIG, 0x7c00);
- phy_reg = phy_read(phy, MII_NCONFIG);
-
- mode = (phy_reg & BCM5461_MODE_MASK ) >> 1;
-
- if ( mode == BCM54XX_COPPER) {
- return bcm54xx_read_link(phy);
- }
-
- phy->speed = SPEED_1000;
-
- /* find out wether we are running half- or full duplex */
- phy_write(phy, MII_NCONFIG, 0x7000);
- phy_reg = phy_read(phy, MII_NCONFIG);
-
- if (phy_reg & BCM5461_FIBER_DUPLEX)
- phy->duplex |= DUPLEX_FULL;
- else
- phy->duplex |= DUPLEX_HALF;
-
- return 0;
-}
-
-static int bcm5461_enable_fiber(struct mii_phy* phy, int autoneg)
-{
- /* select fiber mode, enable 1000 base-X registers */
- phy_write(phy, MII_NCONFIG, 0xfc0b);
-
- if (autoneg) {
- /* enable fiber with no autonegotiation */
- phy_write(phy, MII_ADVERTISE, 0x01e0);
- phy_write(phy, MII_BMCR, 0x1140);
- } else {
- /* enable fiber with autonegotiation */
- phy_write(phy, MII_BMCR, 0x0140);
- }
-
- phy->autoneg = autoneg;
-
- return 0;
-}
-
-static int marvell_setup_aneg(struct mii_phy *phy, u32 advertise)
-{
- u16 ctl, adv;
-
- phy->autoneg = 1;
- phy->speed = SPEED_10;
- phy->duplex = DUPLEX_HALF;
- phy->pause = 0;
- phy->advertising = advertise;
-
- /* Setup standard advertise */
- adv = phy_read(phy, MII_ADVERTISE);
- adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
- if (advertise & ADVERTISED_10baseT_Half)
- adv |= ADVERTISE_10HALF;
- if (advertise & ADVERTISED_10baseT_Full)
- adv |= ADVERTISE_10FULL;
- if (advertise & ADVERTISED_100baseT_Half)
- adv |= ADVERTISE_100HALF;
- if (advertise & ADVERTISED_100baseT_Full)
- adv |= ADVERTISE_100FULL;
- if (advertise & ADVERTISED_Pause)
- adv |= ADVERTISE_PAUSE_CAP;
- if (advertise & ADVERTISED_Asym_Pause)
- adv |= ADVERTISE_PAUSE_ASYM;
- phy_write(phy, MII_ADVERTISE, adv);
-
- /* Setup 1000BT advertise & enable crossover detect
- * XXX How do we advertise 1000BT ? Darwin source is
- * confusing here, they read from specific control and
- * write to control... Someone has specs for those
- * beasts ?
- */
- adv = phy_read(phy, MII_M1011_PHY_SPEC_CONTROL);
- adv |= MII_M1011_PHY_SPEC_CONTROL_AUTO_MDIX;
- adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP |
- MII_1000BASETCONTROL_HALFDUPLEXCAP);
- if (advertise & SUPPORTED_1000baseT_Half)
- adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP;
- if (advertise & SUPPORTED_1000baseT_Full)
- adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP;
- phy_write(phy, MII_1000BASETCONTROL, adv);
-
- /* Start/Restart aneg */
- ctl = phy_read(phy, MII_BMCR);
- ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
- phy_write(phy, MII_BMCR, ctl);
-
- return 0;
-}
-
-static int marvell_setup_forced(struct mii_phy *phy, int speed, int fd)
-{
- u16 ctl, ctl2;
-
- phy->autoneg = 0;
- phy->speed = speed;
- phy->duplex = fd;
- phy->pause = 0;
-
- ctl = phy_read(phy, MII_BMCR);
- ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_SPD2|BMCR_ANENABLE);
- ctl |= BMCR_RESET;
-
- /* Select speed & duplex */
- switch(speed) {
- case SPEED_10:
- break;
- case SPEED_100:
- ctl |= BMCR_SPEED100;
- break;
- /* I'm not sure about the one below, again, Darwin source is
- * quite confusing and I lack chip specs
- */
- case SPEED_1000:
- ctl |= BMCR_SPD2;
- }
- if (fd == DUPLEX_FULL)
- ctl |= BMCR_FULLDPLX;
-
- /* Disable crossover. Again, the way Apple does it is strange,
- * though I don't assume they are wrong ;)
- */
- ctl2 = phy_read(phy, MII_M1011_PHY_SPEC_CONTROL);
- ctl2 &= ~(MII_M1011_PHY_SPEC_CONTROL_MANUAL_MDIX |
- MII_M1011_PHY_SPEC_CONTROL_AUTO_MDIX |
- MII_1000BASETCONTROL_FULLDUPLEXCAP |
- MII_1000BASETCONTROL_HALFDUPLEXCAP);
- if (speed == SPEED_1000)
- ctl2 |= (fd == DUPLEX_FULL) ?
- MII_1000BASETCONTROL_FULLDUPLEXCAP :
- MII_1000BASETCONTROL_HALFDUPLEXCAP;
- phy_write(phy, MII_1000BASETCONTROL, ctl2);
-
- // XXX Should we set the sungem to GII now on 1000BT ?
-
- phy_write(phy, MII_BMCR, ctl);
-
- return 0;
-}
-
-static int marvell_read_link(struct mii_phy *phy)
-{
- u16 status, pmask;
-
- if (phy->autoneg) {
- status = phy_read(phy, MII_M1011_PHY_SPEC_STATUS);
- if ((status & MII_M1011_PHY_SPEC_STATUS_RESOLVED) == 0)
- return -EAGAIN;
- if (status & MII_M1011_PHY_SPEC_STATUS_1000)
- phy->speed = SPEED_1000;
- else if (status & MII_M1011_PHY_SPEC_STATUS_100)
- phy->speed = SPEED_100;
- else
- phy->speed = SPEED_10;
- if (status & MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX)
- phy->duplex = DUPLEX_FULL;
- else
- phy->duplex = DUPLEX_HALF;
- pmask = MII_M1011_PHY_SPEC_STATUS_TX_PAUSE |
- MII_M1011_PHY_SPEC_STATUS_RX_PAUSE;
- phy->pause = (status & pmask) == pmask;
- }
- /* On non-aneg, we assume what we put in BMCR is the speed,
- * though magic-aneg shouldn't prevent this case from occurring
- */
-
- return 0;
-}
-
-#define MII_BASIC_FEATURES \
- (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | \
- SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | \
- SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII | \
- SUPPORTED_Pause)
-
-/* On gigabit capable PHYs, we advertise Pause support but not asym pause
- * support for now as I'm not sure it's supported and Darwin doesn't do
- * it neither. --BenH.
- */
-#define MII_GBIT_FEATURES \
- (MII_BASIC_FEATURES | \
- SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full)
-
-/* Broadcom BCM 5201 */
-static struct mii_phy_ops bcm5201_phy_ops = {
- .init = bcm5201_init,
- .suspend = bcm5201_suspend,
- .setup_aneg = genmii_setup_aneg,
- .setup_forced = genmii_setup_forced,
- .poll_link = genmii_poll_link,
- .read_link = genmii_read_link,
-};
-
-static struct mii_phy_def bcm5201_phy_def = {
- .phy_id = 0x00406210,
- .phy_id_mask = 0xfffffff0,
- .name = "BCM5201",
- .features = MII_BASIC_FEATURES,
- .magic_aneg = 1,
- .ops = &bcm5201_phy_ops
-};
-
-/* Broadcom BCM 5221 */
-static struct mii_phy_ops bcm5221_phy_ops = {
- .suspend = bcm5221_suspend,
- .init = bcm5221_init,
- .setup_aneg = genmii_setup_aneg,
- .setup_forced = genmii_setup_forced,
- .poll_link = genmii_poll_link,
- .read_link = genmii_read_link,
-};
-
-static struct mii_phy_def bcm5221_phy_def = {
- .phy_id = 0x004061e0,
- .phy_id_mask = 0xfffffff0,
- .name = "BCM5221",
- .features = MII_BASIC_FEATURES,
- .magic_aneg = 1,
- .ops = &bcm5221_phy_ops
-};
-
-/* Broadcom BCM 5241 */
-static struct mii_phy_ops bcm5241_phy_ops = {
- .suspend = bcm5241_suspend,
- .init = bcm5241_init,
- .setup_aneg = genmii_setup_aneg,
- .setup_forced = genmii_setup_forced,
- .poll_link = genmii_poll_link,
- .read_link = genmii_read_link,
-};
-static struct mii_phy_def bcm5241_phy_def = {
- .phy_id = 0x0143bc30,
- .phy_id_mask = 0xfffffff0,
- .name = "BCM5241",
- .features = MII_BASIC_FEATURES,
- .magic_aneg = 1,
- .ops = &bcm5241_phy_ops
-};
-
-/* Broadcom BCM 5400 */
-static struct mii_phy_ops bcm5400_phy_ops = {
- .init = bcm5400_init,
- .suspend = bcm5400_suspend,
- .setup_aneg = bcm54xx_setup_aneg,
- .setup_forced = bcm54xx_setup_forced,
- .poll_link = genmii_poll_link,
- .read_link = bcm54xx_read_link,
-};
-
-static struct mii_phy_def bcm5400_phy_def = {
- .phy_id = 0x00206040,
- .phy_id_mask = 0xfffffff0,
- .name = "BCM5400",
- .features = MII_GBIT_FEATURES,
- .magic_aneg = 1,
- .ops = &bcm5400_phy_ops
-};
-
-/* Broadcom BCM 5401 */
-static struct mii_phy_ops bcm5401_phy_ops = {
- .init = bcm5401_init,
- .suspend = bcm5401_suspend,
- .setup_aneg = bcm54xx_setup_aneg,
- .setup_forced = bcm54xx_setup_forced,
- .poll_link = genmii_poll_link,
- .read_link = bcm54xx_read_link,
-};
-
-static struct mii_phy_def bcm5401_phy_def = {
- .phy_id = 0x00206050,
- .phy_id_mask = 0xfffffff0,
- .name = "BCM5401",
- .features = MII_GBIT_FEATURES,
- .magic_aneg = 1,
- .ops = &bcm5401_phy_ops
-};
-
-/* Broadcom BCM 5411 */
-static struct mii_phy_ops bcm5411_phy_ops = {
- .init = bcm5411_init,
- .suspend = generic_suspend,
- .setup_aneg = bcm54xx_setup_aneg,
- .setup_forced = bcm54xx_setup_forced,
- .poll_link = genmii_poll_link,
- .read_link = bcm54xx_read_link,
-};
-
-static struct mii_phy_def bcm5411_phy_def = {
- .phy_id = 0x00206070,
- .phy_id_mask = 0xfffffff0,
- .name = "BCM5411",
- .features = MII_GBIT_FEATURES,
- .magic_aneg = 1,
- .ops = &bcm5411_phy_ops
-};
-
-/* Broadcom BCM 5421 */
-static struct mii_phy_ops bcm5421_phy_ops = {
- .init = bcm5421_init,
- .suspend = generic_suspend,
- .setup_aneg = bcm54xx_setup_aneg,
- .setup_forced = bcm54xx_setup_forced,
- .poll_link = bcm5421_poll_link,
- .read_link = bcm5421_read_link,
- .enable_fiber = bcm5421_enable_fiber,
-};
-
-static struct mii_phy_def bcm5421_phy_def = {
- .phy_id = 0x002060e0,
- .phy_id_mask = 0xfffffff0,
- .name = "BCM5421",
- .features = MII_GBIT_FEATURES,
- .magic_aneg = 1,
- .ops = &bcm5421_phy_ops
-};
-
-/* Broadcom BCM 5421 built-in K2 */
-static struct mii_phy_ops bcm5421k2_phy_ops = {
- .init = bcm5421_init,
- .suspend = generic_suspend,
- .setup_aneg = bcm54xx_setup_aneg,
- .setup_forced = bcm54xx_setup_forced,
- .poll_link = genmii_poll_link,
- .read_link = bcm54xx_read_link,
-};
-
-static struct mii_phy_def bcm5421k2_phy_def = {
- .phy_id = 0x002062e0,
- .phy_id_mask = 0xfffffff0,
- .name = "BCM5421-K2",
- .features = MII_GBIT_FEATURES,
- .magic_aneg = 1,
- .ops = &bcm5421k2_phy_ops
-};
-
-static struct mii_phy_ops bcm5461_phy_ops = {
- .init = bcm5421_init,
- .suspend = generic_suspend,
- .setup_aneg = bcm54xx_setup_aneg,
- .setup_forced = bcm54xx_setup_forced,
- .poll_link = bcm5461_poll_link,
- .read_link = bcm5461_read_link,
- .enable_fiber = bcm5461_enable_fiber,
-};
-
-static struct mii_phy_def bcm5461_phy_def = {
- .phy_id = 0x002060c0,
- .phy_id_mask = 0xfffffff0,
- .name = "BCM5461",
- .features = MII_GBIT_FEATURES,
- .magic_aneg = 1,
- .ops = &bcm5461_phy_ops
-};
-
-/* Broadcom BCM 5462 built-in Vesta */
-static struct mii_phy_ops bcm5462V_phy_ops = {
- .init = bcm5421_init,
- .suspend = generic_suspend,
- .setup_aneg = bcm54xx_setup_aneg,
- .setup_forced = bcm54xx_setup_forced,
- .poll_link = genmii_poll_link,
- .read_link = bcm54xx_read_link,
-};
-
-static struct mii_phy_def bcm5462V_phy_def = {
- .phy_id = 0x002060d0,
- .phy_id_mask = 0xfffffff0,
- .name = "BCM5462-Vesta",
- .features = MII_GBIT_FEATURES,
- .magic_aneg = 1,
- .ops = &bcm5462V_phy_ops
-};
-
-/* Marvell 88E1101 amd 88E1111 */
-static struct mii_phy_ops marvell88e1101_phy_ops = {
- .suspend = generic_suspend,
- .setup_aneg = marvell_setup_aneg,
- .setup_forced = marvell_setup_forced,
- .poll_link = genmii_poll_link,
- .read_link = marvell_read_link
-};
-
-static struct mii_phy_ops marvell88e1111_phy_ops = {
- .init = marvell88e1111_init,
- .suspend = generic_suspend,
- .setup_aneg = marvell_setup_aneg,
- .setup_forced = marvell_setup_forced,
- .poll_link = genmii_poll_link,
- .read_link = marvell_read_link
-};
-
-/* two revs in darwin for the 88e1101 ... I could use a datasheet
- * to get the proper names...
- */
-static struct mii_phy_def marvell88e1101v1_phy_def = {
- .phy_id = 0x01410c20,
- .phy_id_mask = 0xfffffff0,
- .name = "Marvell 88E1101v1",
- .features = MII_GBIT_FEATURES,
- .magic_aneg = 1,
- .ops = &marvell88e1101_phy_ops
-};
-static struct mii_phy_def marvell88e1101v2_phy_def = {
- .phy_id = 0x01410c60,
- .phy_id_mask = 0xfffffff0,
- .name = "Marvell 88E1101v2",
- .features = MII_GBIT_FEATURES,
- .magic_aneg = 1,
- .ops = &marvell88e1101_phy_ops
-};
-static struct mii_phy_def marvell88e1111_phy_def = {
- .phy_id = 0x01410cc0,
- .phy_id_mask = 0xfffffff0,
- .name = "Marvell 88E1111",
- .features = MII_GBIT_FEATURES,
- .magic_aneg = 1,
- .ops = &marvell88e1111_phy_ops
-};
-
-/* Generic implementation for most 10/100 PHYs */
-static struct mii_phy_ops generic_phy_ops = {
- .setup_aneg = genmii_setup_aneg,
- .setup_forced = genmii_setup_forced,
- .poll_link = genmii_poll_link,
- .read_link = genmii_read_link
-};
-
-static struct mii_phy_def genmii_phy_def = {
- .phy_id = 0x00000000,
- .phy_id_mask = 0x00000000,
- .name = "Generic MII",
- .features = MII_BASIC_FEATURES,
- .magic_aneg = 0,
- .ops = &generic_phy_ops
-};
-
-static struct mii_phy_def* mii_phy_table[] = {
- &bcm5201_phy_def,
- &bcm5221_phy_def,
- &bcm5241_phy_def,
- &bcm5400_phy_def,
- &bcm5401_phy_def,
- &bcm5411_phy_def,
- &bcm5421_phy_def,
- &bcm5421k2_phy_def,
- &bcm5461_phy_def,
- &bcm5462V_phy_def,
- &marvell88e1101v1_phy_def,
- &marvell88e1101v2_phy_def,
- &marvell88e1111_phy_def,
- &genmii_phy_def,
- NULL
-};
-
-int mii_phy_probe(struct mii_phy *phy, int mii_id)
-{
- int rc;
- u32 id;
- struct mii_phy_def* def;
- int i;
-
- /* We do not reset the mii_phy structure as the driver
- * may re-probe the PHY regulary
- */
- phy->mii_id = mii_id;
-
- /* Take PHY out of isloate mode and reset it. */
- rc = reset_one_mii_phy(phy, mii_id);
- if (rc)
- goto fail;
-
- /* Read ID and find matching entry */
- id = (phy_read(phy, MII_PHYSID1) << 16 | phy_read(phy, MII_PHYSID2));
- printk(KERN_DEBUG KBUILD_MODNAME ": " "PHY ID: %x, addr: %x\n",
- id, mii_id);
- for (i=0; (def = mii_phy_table[i]) != NULL; i++)
- if ((id & def->phy_id_mask) == def->phy_id)
- break;
- /* Should never be NULL (we have a generic entry), but... */
- if (def == NULL)
- goto fail;
-
- phy->def = def;
-
- return 0;
-fail:
- phy->speed = 0;
- phy->duplex = 0;
- phy->pause = 0;
- phy->advertising = 0;
- return -ENODEV;
-}
-
-EXPORT_SYMBOL(mii_phy_probe);
-MODULE_LICENSE("GPL");
-
diff --git a/drivers/net/ethernet/toshiba/Makefile b/drivers/net/ethernet/toshiba/Makefile
index 71d861f..a506900 100644
--- a/drivers/net/ethernet/toshiba/Makefile
+++ b/drivers/net/ethernet/toshiba/Makefile
@@ -6,5 +6,5 @@ obj-$(CONFIG_GELIC_NET) += ps3_gelic.o
gelic_wireless-$(CONFIG_GELIC_WIRELESS) += ps3_gelic_wireless.o
ps3_gelic-objs += ps3_gelic_net.o $(gelic_wireless-y)
spidernet-y += spider_net.o spider_net_ethtool.o
-obj-$(CONFIG_SPIDER_NET) += spidernet.o ethernet/sun/sungem_phy.o
+obj-$(CONFIG_SPIDER_NET) += spidernet.o
obj-$(CONFIG_TC35815) += tc35815.o
diff --git a/drivers/net/ethernet/toshiba/spider_net.c b/drivers/net/ethernet/toshiba/spider_net.c
index 1ff3491c..af345db 100644
--- a/drivers/net/ethernet/toshiba/spider_net.c
+++ b/drivers/net/ethernet/toshiba/spider_net.c
@@ -196,7 +196,7 @@ spider_net_setup_aneg(struct spider_net_card *card)
if ((bmsr & BMSR_ESTATEN) && (estat & ESTATUS_1000_THALF))
advertise |= SUPPORTED_1000baseT_Half;
- mii_phy_probe(phy, phy->mii_id);
+ sungem_phy_probe(phy, phy->mii_id);
phy->def->ops->setup_aneg(phy, advertise);
}
@@ -2120,7 +2120,7 @@ spider_net_setup_phy(struct spider_net_card *card)
unsigned short id;
id = spider_net_read_phy(card->netdev, phy->mii_id, MII_BMSR);
if (id != 0x0000 && id != 0xffff) {
- if (!mii_phy_probe(phy, phy->mii_id)) {
+ if (!sungem_phy_probe(phy, phy->mii_id)) {
pr_info("Found %s.\n", phy->def->name);
break;
}
diff --git a/drivers/net/sungem_phy.c b/drivers/net/sungem_phy.c
new file mode 100644
index 0000000..58f13ad
--- /dev/null
+++ b/drivers/net/sungem_phy.c
@@ -0,0 +1,1199 @@
+/*
+ * PHY drivers for the sungem ethernet driver.
+ *
+ * This file could be shared with other drivers.
+ *
+ * (c) 2002-2007, Benjamin Herrenscmidt (benh@kernel.crashing.org)
+ *
+ * TODO:
+ * - Add support for PHYs that provide an IRQ line
+ * - Eventually moved the entire polling state machine in
+ * there (out of the eth driver), so that it can easily be
+ * skipped on PHYs that implement it in hardware.
+ * - On LXT971 & BCM5201, Apple uses some chip specific regs
+ * to read the link status. Figure out why and if it makes
+ * sense to do the same (magic aneg ?)
+ * - Apple has some additional power management code for some
+ * Broadcom PHYs that they "hide" from the OpenSource version
+ * of darwin, still need to reverse engineer that
+ */
+
+
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/delay.h>
+
+#ifdef CONFIG_PPC_PMAC
+#include <asm/prom.h>
+#endif
+
+#include <linux/sungem_phy.h>
+
+/* Link modes of the BCM5400 PHY */
+static const int phy_BCM5400_link_table[8][3] = {
+ { 0, 0, 0 }, /* No link */
+ { 0, 0, 0 }, /* 10BT Half Duplex */
+ { 1, 0, 0 }, /* 10BT Full Duplex */
+ { 0, 1, 0 }, /* 100BT Half Duplex */
+ { 0, 1, 0 }, /* 100BT Half Duplex */
+ { 1, 1, 0 }, /* 100BT Full Duplex*/
+ { 1, 0, 1 }, /* 1000BT */
+ { 1, 0, 1 }, /* 1000BT */
+};
+
+static inline int __phy_read(struct mii_phy* phy, int id, int reg)
+{
+ return phy->mdio_read(phy->dev, id, reg);
+}
+
+static inline void __phy_write(struct mii_phy* phy, int id, int reg, int val)
+{
+ phy->mdio_write(phy->dev, id, reg, val);
+}
+
+static inline int phy_read(struct mii_phy* phy, int reg)
+{
+ return phy->mdio_read(phy->dev, phy->mii_id, reg);
+}
+
+static inline void phy_write(struct mii_phy* phy, int reg, int val)
+{
+ phy->mdio_write(phy->dev, phy->mii_id, reg, val);
+}
+
+static int reset_one_mii_phy(struct mii_phy* phy, int phy_id)
+{
+ u16 val;
+ int limit = 10000;
+
+ val = __phy_read(phy, phy_id, MII_BMCR);
+ val &= ~(BMCR_ISOLATE | BMCR_PDOWN);
+ val |= BMCR_RESET;
+ __phy_write(phy, phy_id, MII_BMCR, val);
+
+ udelay(100);
+
+ while (--limit) {
+ val = __phy_read(phy, phy_id, MII_BMCR);
+ if ((val & BMCR_RESET) == 0)
+ break;
+ udelay(10);
+ }
+ if ((val & BMCR_ISOLATE) && limit > 0)
+ __phy_write(phy, phy_id, MII_BMCR, val & ~BMCR_ISOLATE);
+
+ return limit <= 0;
+}
+
+static int bcm5201_init(struct mii_phy* phy)
+{
+ u16 data;
+
+ data = phy_read(phy, MII_BCM5201_MULTIPHY);
+ data &= ~MII_BCM5201_MULTIPHY_SUPERISOLATE;
+ phy_write(phy, MII_BCM5201_MULTIPHY, data);
+
+ phy_write(phy, MII_BCM5201_INTERRUPT, 0);
+
+ return 0;
+}
+
+static int bcm5201_suspend(struct mii_phy* phy)
+{
+ phy_write(phy, MII_BCM5201_INTERRUPT, 0);
+ phy_write(phy, MII_BCM5201_MULTIPHY, MII_BCM5201_MULTIPHY_SUPERISOLATE);
+
+ return 0;
+}
+
+static int bcm5221_init(struct mii_phy* phy)
+{
+ u16 data;
+
+ data = phy_read(phy, MII_BCM5221_TEST);
+ phy_write(phy, MII_BCM5221_TEST,
+ data | MII_BCM5221_TEST_ENABLE_SHADOWS);
+
+ data = phy_read(phy, MII_BCM5221_SHDOW_AUX_STAT2);
+ phy_write(phy, MII_BCM5221_SHDOW_AUX_STAT2,
+ data | MII_BCM5221_SHDOW_AUX_STAT2_APD);
+
+ data = phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
+ phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
+ data | MII_BCM5221_SHDOW_AUX_MODE4_CLKLOPWR);
+
+ data = phy_read(phy, MII_BCM5221_TEST);
+ phy_write(phy, MII_BCM5221_TEST,
+ data & ~MII_BCM5221_TEST_ENABLE_SHADOWS);
+
+ return 0;
+}
+
+static int bcm5221_suspend(struct mii_phy* phy)
+{
+ u16 data;
+
+ data = phy_read(phy, MII_BCM5221_TEST);
+ phy_write(phy, MII_BCM5221_TEST,
+ data | MII_BCM5221_TEST_ENABLE_SHADOWS);
+
+ data = phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
+ phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
+ data | MII_BCM5221_SHDOW_AUX_MODE4_IDDQMODE);
+
+ return 0;
+}
+
+static int bcm5241_init(struct mii_phy* phy)
+{
+ u16 data;
+
+ data = phy_read(phy, MII_BCM5221_TEST);
+ phy_write(phy, MII_BCM5221_TEST,
+ data | MII_BCM5221_TEST_ENABLE_SHADOWS);
+
+ data = phy_read(phy, MII_BCM5221_SHDOW_AUX_STAT2);
+ phy_write(phy, MII_BCM5221_SHDOW_AUX_STAT2,
+ data | MII_BCM5221_SHDOW_AUX_STAT2_APD);
+
+ data = phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
+ phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
+ data & ~MII_BCM5241_SHDOW_AUX_MODE4_STANDBYPWR);
+
+ data = phy_read(phy, MII_BCM5221_TEST);
+ phy_write(phy, MII_BCM5221_TEST,
+ data & ~MII_BCM5221_TEST_ENABLE_SHADOWS);
+
+ return 0;
+}
+
+static int bcm5241_suspend(struct mii_phy* phy)
+{
+ u16 data;
+
+ data = phy_read(phy, MII_BCM5221_TEST);
+ phy_write(phy, MII_BCM5221_TEST,
+ data | MII_BCM5221_TEST_ENABLE_SHADOWS);
+
+ data = phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
+ phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
+ data | MII_BCM5241_SHDOW_AUX_MODE4_STANDBYPWR);
+
+ return 0;
+}
+
+static int bcm5400_init(struct mii_phy* phy)
+{
+ u16 data;
+
+ /* Configure for gigabit full duplex */
+ data = phy_read(phy, MII_BCM5400_AUXCONTROL);
+ data |= MII_BCM5400_AUXCONTROL_PWR10BASET;
+ phy_write(phy, MII_BCM5400_AUXCONTROL, data);
+
+ data = phy_read(phy, MII_BCM5400_GB_CONTROL);
+ data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
+ phy_write(phy, MII_BCM5400_GB_CONTROL, data);
+
+ udelay(100);
+
+ /* Reset and configure cascaded 10/100 PHY */
+ (void)reset_one_mii_phy(phy, 0x1f);
+
+ data = __phy_read(phy, 0x1f, MII_BCM5201_MULTIPHY);
+ data |= MII_BCM5201_MULTIPHY_SERIALMODE;
+ __phy_write(phy, 0x1f, MII_BCM5201_MULTIPHY, data);
+
+ data = phy_read(phy, MII_BCM5400_AUXCONTROL);
+ data &= ~MII_BCM5400_AUXCONTROL_PWR10BASET;
+ phy_write(phy, MII_BCM5400_AUXCONTROL, data);
+
+ return 0;
+}
+
+static int bcm5400_suspend(struct mii_phy* phy)
+{
+#if 0 /* Commented out in Darwin... someone has those dawn docs ? */
+ phy_write(phy, MII_BMCR, BMCR_PDOWN);
+#endif
+ return 0;
+}
+
+static int bcm5401_init(struct mii_phy* phy)
+{
+ u16 data;
+ int rev;
+
+ rev = phy_read(phy, MII_PHYSID2) & 0x000f;
+ if (rev == 0 || rev == 3) {
+ /* Some revisions of 5401 appear to need this
+ * initialisation sequence to disable, according
+ * to OF, "tap power management"
+ *
+ * WARNING ! OF and Darwin don't agree on the
+ * register addresses. OF seem to interpret the
+ * register numbers below as decimal
+ *
+ * Note: This should (and does) match tg3_init_5401phy_dsp
+ * in the tg3.c driver. -DaveM
+ */
+ phy_write(phy, 0x18, 0x0c20);
+ phy_write(phy, 0x17, 0x0012);
+ phy_write(phy, 0x15, 0x1804);
+ phy_write(phy, 0x17, 0x0013);
+ phy_write(phy, 0x15, 0x1204);
+ phy_write(phy, 0x17, 0x8006);
+ phy_write(phy, 0x15, 0x0132);
+ phy_write(phy, 0x17, 0x8006);
+ phy_write(phy, 0x15, 0x0232);
+ phy_write(phy, 0x17, 0x201f);
+ phy_write(phy, 0x15, 0x0a20);
+ }
+
+ /* Configure for gigabit full duplex */
+ data = phy_read(phy, MII_BCM5400_GB_CONTROL);
+ data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
+ phy_write(phy, MII_BCM5400_GB_CONTROL, data);
+
+ udelay(10);
+
+ /* Reset and configure cascaded 10/100 PHY */
+ (void)reset_one_mii_phy(phy, 0x1f);
+
+ data = __phy_read(phy, 0x1f, MII_BCM5201_MULTIPHY);
+ data |= MII_BCM5201_MULTIPHY_SERIALMODE;
+ __phy_write(phy, 0x1f, MII_BCM5201_MULTIPHY, data);
+
+ return 0;
+}
+
+static int bcm5401_suspend(struct mii_phy* phy)
+{
+#if 0 /* Commented out in Darwin... someone has those dawn docs ? */
+ phy_write(phy, MII_BMCR, BMCR_PDOWN);
+#endif
+ return 0;
+}
+
+static int bcm5411_init(struct mii_phy* phy)
+{
+ u16 data;
+
+ /* Here's some more Apple black magic to setup
+ * some voltage stuffs.
+ */
+ phy_write(phy, 0x1c, 0x8c23);
+ phy_write(phy, 0x1c, 0x8ca3);
+ phy_write(phy, 0x1c, 0x8c23);
+
+ /* Here, Apple seems to want to reset it, do
+ * it as well
+ */
+ phy_write(phy, MII_BMCR, BMCR_RESET);
+ phy_write(phy, MII_BMCR, 0x1340);
+
+ data = phy_read(phy, MII_BCM5400_GB_CONTROL);
+ data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
+ phy_write(phy, MII_BCM5400_GB_CONTROL, data);
+
+ udelay(10);
+
+ /* Reset and configure cascaded 10/100 PHY */
+ (void)reset_one_mii_phy(phy, 0x1f);
+
+ return 0;
+}
+
+static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise)
+{
+ u16 ctl, adv;
+
+ phy->autoneg = 1;
+ phy->speed = SPEED_10;
+ phy->duplex = DUPLEX_HALF;
+ phy->pause = 0;
+ phy->advertising = advertise;
+
+ /* Setup standard advertise */
+ adv = phy_read(phy, MII_ADVERTISE);
+ adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
+ if (advertise & ADVERTISED_10baseT_Half)
+ adv |= ADVERTISE_10HALF;
+ if (advertise & ADVERTISED_10baseT_Full)
+ adv |= ADVERTISE_10FULL;
+ if (advertise & ADVERTISED_100baseT_Half)
+ adv |= ADVERTISE_100HALF;
+ if (advertise & ADVERTISED_100baseT_Full)
+ adv |= ADVERTISE_100FULL;
+ phy_write(phy, MII_ADVERTISE, adv);
+
+ /* Start/Restart aneg */
+ ctl = phy_read(phy, MII_BMCR);
+ ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
+ phy_write(phy, MII_BMCR, ctl);
+
+ return 0;
+}
+
+static int genmii_setup_forced(struct mii_phy *phy, int speed, int fd)
+{
+ u16 ctl;
+
+ phy->autoneg = 0;
+ phy->speed = speed;
+ phy->duplex = fd;
+ phy->pause = 0;
+
+ ctl = phy_read(phy, MII_BMCR);
+ ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_ANENABLE);
+
+ /* First reset the PHY */
+ phy_write(phy, MII_BMCR, ctl | BMCR_RESET);
+
+ /* Select speed & duplex */
+ switch(speed) {
+ case SPEED_10:
+ break;
+ case SPEED_100:
+ ctl |= BMCR_SPEED100;
+ break;
+ case SPEED_1000:
+ default:
+ return -EINVAL;
+ }
+ if (fd == DUPLEX_FULL)
+ ctl |= BMCR_FULLDPLX;
+ phy_write(phy, MII_BMCR, ctl);
+
+ return 0;
+}
+
+static int genmii_poll_link(struct mii_phy *phy)
+{
+ u16 status;
+
+ (void)phy_read(phy, MII_BMSR);
+ status = phy_read(phy, MII_BMSR);
+ if ((status & BMSR_LSTATUS) == 0)
+ return 0;
+ if (phy->autoneg && !(status & BMSR_ANEGCOMPLETE))
+ return 0;
+ return 1;
+}
+
+static int genmii_read_link(struct mii_phy *phy)
+{
+ u16 lpa;
+
+ if (phy->autoneg) {
+ lpa = phy_read(phy, MII_LPA);
+
+ if (lpa & (LPA_10FULL | LPA_100FULL))
+ phy->duplex = DUPLEX_FULL;
+ else
+ phy->duplex = DUPLEX_HALF;
+ if (lpa & (LPA_100FULL | LPA_100HALF))
+ phy->speed = SPEED_100;
+ else
+ phy->speed = SPEED_10;
+ phy->pause = 0;
+ }
+ /* On non-aneg, we assume what we put in BMCR is the speed,
+ * though magic-aneg shouldn't prevent this case from occurring
+ */
+
+ return 0;
+}
+
+static int generic_suspend(struct mii_phy* phy)
+{
+ phy_write(phy, MII_BMCR, BMCR_PDOWN);
+
+ return 0;
+}
+
+static int bcm5421_init(struct mii_phy* phy)
+{
+ u16 data;
+ unsigned int id;
+
+ id = (phy_read(phy, MII_PHYSID1) << 16 | phy_read(phy, MII_PHYSID2));
+
+ /* Revision 0 of 5421 needs some fixups */
+ if (id == 0x002060e0) {
+ /* This is borrowed from MacOS
+ */
+ phy_write(phy, 0x18, 0x1007);
+ data = phy_read(phy, 0x18);
+ phy_write(phy, 0x18, data | 0x0400);
+ phy_write(phy, 0x18, 0x0007);
+ data = phy_read(phy, 0x18);
+ phy_write(phy, 0x18, data | 0x0800);
+ phy_write(phy, 0x17, 0x000a);
+ data = phy_read(phy, 0x15);
+ phy_write(phy, 0x15, data | 0x0200);
+ }
+
+ /* Pick up some init code from OF for K2 version */
+ if ((id & 0xfffffff0) == 0x002062e0) {
+ phy_write(phy, 4, 0x01e1);
+ phy_write(phy, 9, 0x0300);
+ }
+
+ /* Check if we can enable automatic low power */
+#ifdef CONFIG_PPC_PMAC
+ if (phy->platform_data) {
+ struct device_node *np = of_get_parent(phy->platform_data);
+ int can_low_power = 1;
+ if (np == NULL || of_get_property(np, "no-autolowpower", NULL))
+ can_low_power = 0;
+ if (can_low_power) {
+ /* Enable automatic low-power */
+ phy_write(phy, 0x1c, 0x9002);
+ phy_write(phy, 0x1c, 0xa821);
+ phy_write(phy, 0x1c, 0x941d);
+ }
+ }
+#endif /* CONFIG_PPC_PMAC */
+
+ return 0;
+}
+
+static int bcm54xx_setup_aneg(struct mii_phy *phy, u32 advertise)
+{
+ u16 ctl, adv;
+
+ phy->autoneg = 1;
+ phy->speed = SPEED_10;
+ phy->duplex = DUPLEX_HALF;
+ phy->pause = 0;
+ phy->advertising = advertise;
+
+ /* Setup standard advertise */
+ adv = phy_read(phy, MII_ADVERTISE);
+ adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
+ if (advertise & ADVERTISED_10baseT_Half)
+ adv |= ADVERTISE_10HALF;
+ if (advertise & ADVERTISED_10baseT_Full)
+ adv |= ADVERTISE_10FULL;
+ if (advertise & ADVERTISED_100baseT_Half)
+ adv |= ADVERTISE_100HALF;
+ if (advertise & ADVERTISED_100baseT_Full)
+ adv |= ADVERTISE_100FULL;
+ if (advertise & ADVERTISED_Pause)
+ adv |= ADVERTISE_PAUSE_CAP;
+ if (advertise & ADVERTISED_Asym_Pause)
+ adv |= ADVERTISE_PAUSE_ASYM;
+ phy_write(phy, MII_ADVERTISE, adv);
+
+ /* Setup 1000BT advertise */
+ adv = phy_read(phy, MII_1000BASETCONTROL);
+ adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP|MII_1000BASETCONTROL_HALFDUPLEXCAP);
+ if (advertise & SUPPORTED_1000baseT_Half)
+ adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP;
+ if (advertise & SUPPORTED_1000baseT_Full)
+ adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP;
+ phy_write(phy, MII_1000BASETCONTROL, adv);
+
+ /* Start/Restart aneg */
+ ctl = phy_read(phy, MII_BMCR);
+ ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
+ phy_write(phy, MII_BMCR, ctl);
+
+ return 0;
+}
+
+static int bcm54xx_setup_forced(struct mii_phy *phy, int speed, int fd)
+{
+ u16 ctl;
+
+ phy->autoneg = 0;
+ phy->speed = speed;
+ phy->duplex = fd;
+ phy->pause = 0;
+
+ ctl = phy_read(phy, MII_BMCR);
+ ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_SPD2|BMCR_ANENABLE);
+
+ /* First reset the PHY */
+ phy_write(phy, MII_BMCR, ctl | BMCR_RESET);
+
+ /* Select speed & duplex */
+ switch(speed) {
+ case SPEED_10:
+ break;
+ case SPEED_100:
+ ctl |= BMCR_SPEED100;
+ break;
+ case SPEED_1000:
+ ctl |= BMCR_SPD2;
+ }
+ if (fd == DUPLEX_FULL)
+ ctl |= BMCR_FULLDPLX;
+
+ // XXX Should we set the sungem to GII now on 1000BT ?
+
+ phy_write(phy, MII_BMCR, ctl);
+
+ return 0;
+}
+
+static int bcm54xx_read_link(struct mii_phy *phy)
+{
+ int link_mode;
+ u16 val;
+
+ if (phy->autoneg) {
+ val = phy_read(phy, MII_BCM5400_AUXSTATUS);
+ link_mode = ((val & MII_BCM5400_AUXSTATUS_LINKMODE_MASK) >>
+ MII_BCM5400_AUXSTATUS_LINKMODE_SHIFT);
+ phy->duplex = phy_BCM5400_link_table[link_mode][0] ?
+ DUPLEX_FULL : DUPLEX_HALF;
+ phy->speed = phy_BCM5400_link_table[link_mode][2] ?
+ SPEED_1000 :
+ (phy_BCM5400_link_table[link_mode][1] ?
+ SPEED_100 : SPEED_10);
+ val = phy_read(phy, MII_LPA);
+ phy->pause = (phy->duplex == DUPLEX_FULL) &&
+ ((val & LPA_PAUSE) != 0);
+ }
+ /* On non-aneg, we assume what we put in BMCR is the speed,
+ * though magic-aneg shouldn't prevent this case from occurring
+ */
+
+ return 0;
+}
+
+static int marvell88e1111_init(struct mii_phy* phy)
+{
+ u16 rev;
+
+ /* magic init sequence for rev 0 */
+ rev = phy_read(phy, MII_PHYSID2) & 0x000f;
+ if (rev == 0) {
+ phy_write(phy, 0x1d, 0x000a);
+ phy_write(phy, 0x1e, 0x0821);
+
+ phy_write(phy, 0x1d, 0x0006);
+ phy_write(phy, 0x1e, 0x8600);
+
+ phy_write(phy, 0x1d, 0x000b);
+ phy_write(phy, 0x1e, 0x0100);
+
+ phy_write(phy, 0x1d, 0x0004);
+ phy_write(phy, 0x1e, 0x4850);
+ }
+ return 0;
+}
+
+#define BCM5421_MODE_MASK (1 << 5)
+
+static int bcm5421_poll_link(struct mii_phy* phy)
+{
+ u32 phy_reg;
+ int mode;
+
+ /* find out in what mode we are */
+ phy_write(phy, MII_NCONFIG, 0x1000);
+ phy_reg = phy_read(phy, MII_NCONFIG);
+
+ mode = (phy_reg & BCM5421_MODE_MASK) >> 5;
+
+ if ( mode == BCM54XX_COPPER)
+ return genmii_poll_link(phy);
+
+ /* try to find out wether we have a link */
+ phy_write(phy, MII_NCONFIG, 0x2000);
+ phy_reg = phy_read(phy, MII_NCONFIG);
+
+ if (phy_reg & 0x0020)
+ return 0;
+ else
+ return 1;
+}
+
+static int bcm5421_read_link(struct mii_phy* phy)
+{
+ u32 phy_reg;
+ int mode;
+
+ /* find out in what mode we are */
+ phy_write(phy, MII_NCONFIG, 0x1000);
+ phy_reg = phy_read(phy, MII_NCONFIG);
+
+ mode = (phy_reg & BCM5421_MODE_MASK ) >> 5;
+
+ if ( mode == BCM54XX_COPPER)
+ return bcm54xx_read_link(phy);
+
+ phy->speed = SPEED_1000;
+
+ /* find out wether we are running half- or full duplex */
+ phy_write(phy, MII_NCONFIG, 0x2000);
+ phy_reg = phy_read(phy, MII_NCONFIG);
+
+ if ( (phy_reg & 0x0080) >> 7)
+ phy->duplex |= DUPLEX_HALF;
+ else
+ phy->duplex |= DUPLEX_FULL;
+
+ return 0;
+}
+
+static int bcm5421_enable_fiber(struct mii_phy* phy, int autoneg)
+{
+ /* enable fiber mode */
+ phy_write(phy, MII_NCONFIG, 0x9020);
+ /* LEDs active in both modes, autosense prio = fiber */
+ phy_write(phy, MII_NCONFIG, 0x945f);
+
+ if (!autoneg) {
+ /* switch off fibre autoneg */
+ phy_write(phy, MII_NCONFIG, 0xfc01);
+ phy_write(phy, 0x0b, 0x0004);
+ }
+
+ phy->autoneg = autoneg;
+
+ return 0;
+}
+
+#define BCM5461_FIBER_LINK (1 << 2)
+#define BCM5461_MODE_MASK (3 << 1)
+
+static int bcm5461_poll_link(struct mii_phy* phy)
+{
+ u32 phy_reg;
+ int mode;
+
+ /* find out in what mode we are */
+ phy_write(phy, MII_NCONFIG, 0x7c00);
+ phy_reg = phy_read(phy, MII_NCONFIG);
+
+ mode = (phy_reg & BCM5461_MODE_MASK ) >> 1;
+
+ if ( mode == BCM54XX_COPPER)
+ return genmii_poll_link(phy);
+
+ /* find out wether we have a link */
+ phy_write(phy, MII_NCONFIG, 0x7000);
+ phy_reg = phy_read(phy, MII_NCONFIG);
+
+ if (phy_reg & BCM5461_FIBER_LINK)
+ return 1;
+ else
+ return 0;
+}
+
+#define BCM5461_FIBER_DUPLEX (1 << 3)
+
+static int bcm5461_read_link(struct mii_phy* phy)
+{
+ u32 phy_reg;
+ int mode;
+
+ /* find out in what mode we are */
+ phy_write(phy, MII_NCONFIG, 0x7c00);
+ phy_reg = phy_read(phy, MII_NCONFIG);
+
+ mode = (phy_reg & BCM5461_MODE_MASK ) >> 1;
+
+ if ( mode == BCM54XX_COPPER) {
+ return bcm54xx_read_link(phy);
+ }
+
+ phy->speed = SPEED_1000;
+
+ /* find out wether we are running half- or full duplex */
+ phy_write(phy, MII_NCONFIG, 0x7000);
+ phy_reg = phy_read(phy, MII_NCONFIG);
+
+ if (phy_reg & BCM5461_FIBER_DUPLEX)
+ phy->duplex |= DUPLEX_FULL;
+ else
+ phy->duplex |= DUPLEX_HALF;
+
+ return 0;
+}
+
+static int bcm5461_enable_fiber(struct mii_phy* phy, int autoneg)
+{
+ /* select fiber mode, enable 1000 base-X registers */
+ phy_write(phy, MII_NCONFIG, 0xfc0b);
+
+ if (autoneg) {
+ /* enable fiber with no autonegotiation */
+ phy_write(phy, MII_ADVERTISE, 0x01e0);
+ phy_write(phy, MII_BMCR, 0x1140);
+ } else {
+ /* enable fiber with autonegotiation */
+ phy_write(phy, MII_BMCR, 0x0140);
+ }
+
+ phy->autoneg = autoneg;
+
+ return 0;
+}
+
+static int marvell_setup_aneg(struct mii_phy *phy, u32 advertise)
+{
+ u16 ctl, adv;
+
+ phy->autoneg = 1;
+ phy->speed = SPEED_10;
+ phy->duplex = DUPLEX_HALF;
+ phy->pause = 0;
+ phy->advertising = advertise;
+
+ /* Setup standard advertise */
+ adv = phy_read(phy, MII_ADVERTISE);
+ adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
+ if (advertise & ADVERTISED_10baseT_Half)
+ adv |= ADVERTISE_10HALF;
+ if (advertise & ADVERTISED_10baseT_Full)
+ adv |= ADVERTISE_10FULL;
+ if (advertise & ADVERTISED_100baseT_Half)
+ adv |= ADVERTISE_100HALF;
+ if (advertise & ADVERTISED_100baseT_Full)
+ adv |= ADVERTISE_100FULL;
+ if (advertise & ADVERTISED_Pause)
+ adv |= ADVERTISE_PAUSE_CAP;
+ if (advertise & ADVERTISED_Asym_Pause)
+ adv |= ADVERTISE_PAUSE_ASYM;
+ phy_write(phy, MII_ADVERTISE, adv);
+
+ /* Setup 1000BT advertise & enable crossover detect
+ * XXX How do we advertise 1000BT ? Darwin source is
+ * confusing here, they read from specific control and
+ * write to control... Someone has specs for those
+ * beasts ?
+ */
+ adv = phy_read(phy, MII_M1011_PHY_SPEC_CONTROL);
+ adv |= MII_M1011_PHY_SPEC_CONTROL_AUTO_MDIX;
+ adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP |
+ MII_1000BASETCONTROL_HALFDUPLEXCAP);
+ if (advertise & SUPPORTED_1000baseT_Half)
+ adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP;
+ if (advertise & SUPPORTED_1000baseT_Full)
+ adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP;
+ phy_write(phy, MII_1000BASETCONTROL, adv);
+
+ /* Start/Restart aneg */
+ ctl = phy_read(phy, MII_BMCR);
+ ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
+ phy_write(phy, MII_BMCR, ctl);
+
+ return 0;
+}
+
+static int marvell_setup_forced(struct mii_phy *phy, int speed, int fd)
+{
+ u16 ctl, ctl2;
+
+ phy->autoneg = 0;
+ phy->speed = speed;
+ phy->duplex = fd;
+ phy->pause = 0;
+
+ ctl = phy_read(phy, MII_BMCR);
+ ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_SPD2|BMCR_ANENABLE);
+ ctl |= BMCR_RESET;
+
+ /* Select speed & duplex */
+ switch(speed) {
+ case SPEED_10:
+ break;
+ case SPEED_100:
+ ctl |= BMCR_SPEED100;
+ break;
+ /* I'm not sure about the one below, again, Darwin source is
+ * quite confusing and I lack chip specs
+ */
+ case SPEED_1000:
+ ctl |= BMCR_SPD2;
+ }
+ if (fd == DUPLEX_FULL)
+ ctl |= BMCR_FULLDPLX;
+
+ /* Disable crossover. Again, the way Apple does it is strange,
+ * though I don't assume they are wrong ;)
+ */
+ ctl2 = phy_read(phy, MII_M1011_PHY_SPEC_CONTROL);
+ ctl2 &= ~(MII_M1011_PHY_SPEC_CONTROL_MANUAL_MDIX |
+ MII_M1011_PHY_SPEC_CONTROL_AUTO_MDIX |
+ MII_1000BASETCONTROL_FULLDUPLEXCAP |
+ MII_1000BASETCONTROL_HALFDUPLEXCAP);
+ if (speed == SPEED_1000)
+ ctl2 |= (fd == DUPLEX_FULL) ?
+ MII_1000BASETCONTROL_FULLDUPLEXCAP :
+ MII_1000BASETCONTROL_HALFDUPLEXCAP;
+ phy_write(phy, MII_1000BASETCONTROL, ctl2);
+
+ // XXX Should we set the sungem to GII now on 1000BT ?
+
+ phy_write(phy, MII_BMCR, ctl);
+
+ return 0;
+}
+
+static int marvell_read_link(struct mii_phy *phy)
+{
+ u16 status, pmask;
+
+ if (phy->autoneg) {
+ status = phy_read(phy, MII_M1011_PHY_SPEC_STATUS);
+ if ((status & MII_M1011_PHY_SPEC_STATUS_RESOLVED) == 0)
+ return -EAGAIN;
+ if (status & MII_M1011_PHY_SPEC_STATUS_1000)
+ phy->speed = SPEED_1000;
+ else if (status & MII_M1011_PHY_SPEC_STATUS_100)
+ phy->speed = SPEED_100;
+ else
+ phy->speed = SPEED_10;
+ if (status & MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX)
+ phy->duplex = DUPLEX_FULL;
+ else
+ phy->duplex = DUPLEX_HALF;
+ pmask = MII_M1011_PHY_SPEC_STATUS_TX_PAUSE |
+ MII_M1011_PHY_SPEC_STATUS_RX_PAUSE;
+ phy->pause = (status & pmask) == pmask;
+ }
+ /* On non-aneg, we assume what we put in BMCR is the speed,
+ * though magic-aneg shouldn't prevent this case from occurring
+ */
+
+ return 0;
+}
+
+#define MII_BASIC_FEATURES \
+ (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | \
+ SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | \
+ SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII | \
+ SUPPORTED_Pause)
+
+/* On gigabit capable PHYs, we advertise Pause support but not asym pause
+ * support for now as I'm not sure it's supported and Darwin doesn't do
+ * it neither. --BenH.
+ */
+#define MII_GBIT_FEATURES \
+ (MII_BASIC_FEATURES | \
+ SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full)
+
+/* Broadcom BCM 5201 */
+static struct mii_phy_ops bcm5201_phy_ops = {
+ .init = bcm5201_init,
+ .suspend = bcm5201_suspend,
+ .setup_aneg = genmii_setup_aneg,
+ .setup_forced = genmii_setup_forced,
+ .poll_link = genmii_poll_link,
+ .read_link = genmii_read_link,
+};
+
+static struct mii_phy_def bcm5201_phy_def = {
+ .phy_id = 0x00406210,
+ .phy_id_mask = 0xfffffff0,
+ .name = "BCM5201",
+ .features = MII_BASIC_FEATURES,
+ .magic_aneg = 1,
+ .ops = &bcm5201_phy_ops
+};
+
+/* Broadcom BCM 5221 */
+static struct mii_phy_ops bcm5221_phy_ops = {
+ .suspend = bcm5221_suspend,
+ .init = bcm5221_init,
+ .setup_aneg = genmii_setup_aneg,
+ .setup_forced = genmii_setup_forced,
+ .poll_link = genmii_poll_link,
+ .read_link = genmii_read_link,
+};
+
+static struct mii_phy_def bcm5221_phy_def = {
+ .phy_id = 0x004061e0,
+ .phy_id_mask = 0xfffffff0,
+ .name = "BCM5221",
+ .features = MII_BASIC_FEATURES,
+ .magic_aneg = 1,
+ .ops = &bcm5221_phy_ops
+};
+
+/* Broadcom BCM 5241 */
+static struct mii_phy_ops bcm5241_phy_ops = {
+ .suspend = bcm5241_suspend,
+ .init = bcm5241_init,
+ .setup_aneg = genmii_setup_aneg,
+ .setup_forced = genmii_setup_forced,
+ .poll_link = genmii_poll_link,
+ .read_link = genmii_read_link,
+};
+static struct mii_phy_def bcm5241_phy_def = {
+ .phy_id = 0x0143bc30,
+ .phy_id_mask = 0xfffffff0,
+ .name = "BCM5241",
+ .features = MII_BASIC_FEATURES,
+ .magic_aneg = 1,
+ .ops = &bcm5241_phy_ops
+};
+
+/* Broadcom BCM 5400 */
+static struct mii_phy_ops bcm5400_phy_ops = {
+ .init = bcm5400_init,
+ .suspend = bcm5400_suspend,
+ .setup_aneg = bcm54xx_setup_aneg,
+ .setup_forced = bcm54xx_setup_forced,
+ .poll_link = genmii_poll_link,
+ .read_link = bcm54xx_read_link,
+};
+
+static struct mii_phy_def bcm5400_phy_def = {
+ .phy_id = 0x00206040,
+ .phy_id_mask = 0xfffffff0,
+ .name = "BCM5400",
+ .features = MII_GBIT_FEATURES,
+ .magic_aneg = 1,
+ .ops = &bcm5400_phy_ops
+};
+
+/* Broadcom BCM 5401 */
+static struct mii_phy_ops bcm5401_phy_ops = {
+ .init = bcm5401_init,
+ .suspend = bcm5401_suspend,
+ .setup_aneg = bcm54xx_setup_aneg,
+ .setup_forced = bcm54xx_setup_forced,
+ .poll_link = genmii_poll_link,
+ .read_link = bcm54xx_read_link,
+};
+
+static struct mii_phy_def bcm5401_phy_def = {
+ .phy_id = 0x00206050,
+ .phy_id_mask = 0xfffffff0,
+ .name = "BCM5401",
+ .features = MII_GBIT_FEATURES,
+ .magic_aneg = 1,
+ .ops = &bcm5401_phy_ops
+};
+
+/* Broadcom BCM 5411 */
+static struct mii_phy_ops bcm5411_phy_ops = {
+ .init = bcm5411_init,
+ .suspend = generic_suspend,
+ .setup_aneg = bcm54xx_setup_aneg,
+ .setup_forced = bcm54xx_setup_forced,
+ .poll_link = genmii_poll_link,
+ .read_link = bcm54xx_read_link,
+};
+
+static struct mii_phy_def bcm5411_phy_def = {
+ .phy_id = 0x00206070,
+ .phy_id_mask = 0xfffffff0,
+ .name = "BCM5411",
+ .features = MII_GBIT_FEATURES,
+ .magic_aneg = 1,
+ .ops = &bcm5411_phy_ops
+};
+
+/* Broadcom BCM 5421 */
+static struct mii_phy_ops bcm5421_phy_ops = {
+ .init = bcm5421_init,
+ .suspend = generic_suspend,
+ .setup_aneg = bcm54xx_setup_aneg,
+ .setup_forced = bcm54xx_setup_forced,
+ .poll_link = bcm5421_poll_link,
+ .read_link = bcm5421_read_link,
+ .enable_fiber = bcm5421_enable_fiber,
+};
+
+static struct mii_phy_def bcm5421_phy_def = {
+ .phy_id = 0x002060e0,
+ .phy_id_mask = 0xfffffff0,
+ .name = "BCM5421",
+ .features = MII_GBIT_FEATURES,
+ .magic_aneg = 1,
+ .ops = &bcm5421_phy_ops
+};
+
+/* Broadcom BCM 5421 built-in K2 */
+static struct mii_phy_ops bcm5421k2_phy_ops = {
+ .init = bcm5421_init,
+ .suspend = generic_suspend,
+ .setup_aneg = bcm54xx_setup_aneg,
+ .setup_forced = bcm54xx_setup_forced,
+ .poll_link = genmii_poll_link,
+ .read_link = bcm54xx_read_link,
+};
+
+static struct mii_phy_def bcm5421k2_phy_def = {
+ .phy_id = 0x002062e0,
+ .phy_id_mask = 0xfffffff0,
+ .name = "BCM5421-K2",
+ .features = MII_GBIT_FEATURES,
+ .magic_aneg = 1,
+ .ops = &bcm5421k2_phy_ops
+};
+
+static struct mii_phy_ops bcm5461_phy_ops = {
+ .init = bcm5421_init,
+ .suspend = generic_suspend,
+ .setup_aneg = bcm54xx_setup_aneg,
+ .setup_forced = bcm54xx_setup_forced,
+ .poll_link = bcm5461_poll_link,
+ .read_link = bcm5461_read_link,
+ .enable_fiber = bcm5461_enable_fiber,
+};
+
+static struct mii_phy_def bcm5461_phy_def = {
+ .phy_id = 0x002060c0,
+ .phy_id_mask = 0xfffffff0,
+ .name = "BCM5461",
+ .features = MII_GBIT_FEATURES,
+ .magic_aneg = 1,
+ .ops = &bcm5461_phy_ops
+};
+
+/* Broadcom BCM 5462 built-in Vesta */
+static struct mii_phy_ops bcm5462V_phy_ops = {
+ .init = bcm5421_init,
+ .suspend = generic_suspend,
+ .setup_aneg = bcm54xx_setup_aneg,
+ .setup_forced = bcm54xx_setup_forced,
+ .poll_link = genmii_poll_link,
+ .read_link = bcm54xx_read_link,
+};
+
+static struct mii_phy_def bcm5462V_phy_def = {
+ .phy_id = 0x002060d0,
+ .phy_id_mask = 0xfffffff0,
+ .name = "BCM5462-Vesta",
+ .features = MII_GBIT_FEATURES,
+ .magic_aneg = 1,
+ .ops = &bcm5462V_phy_ops
+};
+
+/* Marvell 88E1101 amd 88E1111 */
+static struct mii_phy_ops marvell88e1101_phy_ops = {
+ .suspend = generic_suspend,
+ .setup_aneg = marvell_setup_aneg,
+ .setup_forced = marvell_setup_forced,
+ .poll_link = genmii_poll_link,
+ .read_link = marvell_read_link
+};
+
+static struct mii_phy_ops marvell88e1111_phy_ops = {
+ .init = marvell88e1111_init,
+ .suspend = generic_suspend,
+ .setup_aneg = marvell_setup_aneg,
+ .setup_forced = marvell_setup_forced,
+ .poll_link = genmii_poll_link,
+ .read_link = marvell_read_link
+};
+
+/* two revs in darwin for the 88e1101 ... I could use a datasheet
+ * to get the proper names...
+ */
+static struct mii_phy_def marvell88e1101v1_phy_def = {
+ .phy_id = 0x01410c20,
+ .phy_id_mask = 0xfffffff0,
+ .name = "Marvell 88E1101v1",
+ .features = MII_GBIT_FEATURES,
+ .magic_aneg = 1,
+ .ops = &marvell88e1101_phy_ops
+};
+static struct mii_phy_def marvell88e1101v2_phy_def = {
+ .phy_id = 0x01410c60,
+ .phy_id_mask = 0xfffffff0,
+ .name = "Marvell 88E1101v2",
+ .features = MII_GBIT_FEATURES,
+ .magic_aneg = 1,
+ .ops = &marvell88e1101_phy_ops
+};
+static struct mii_phy_def marvell88e1111_phy_def = {
+ .phy_id = 0x01410cc0,
+ .phy_id_mask = 0xfffffff0,
+ .name = "Marvell 88E1111",
+ .features = MII_GBIT_FEATURES,
+ .magic_aneg = 1,
+ .ops = &marvell88e1111_phy_ops
+};
+
+/* Generic implementation for most 10/100 PHYs */
+static struct mii_phy_ops generic_phy_ops = {
+ .setup_aneg = genmii_setup_aneg,
+ .setup_forced = genmii_setup_forced,
+ .poll_link = genmii_poll_link,
+ .read_link = genmii_read_link
+};
+
+static struct mii_phy_def genmii_phy_def = {
+ .phy_id = 0x00000000,
+ .phy_id_mask = 0x00000000,
+ .name = "Generic MII",
+ .features = MII_BASIC_FEATURES,
+ .magic_aneg = 0,
+ .ops = &generic_phy_ops
+};
+
+static struct mii_phy_def* mii_phy_table[] = {
+ &bcm5201_phy_def,
+ &bcm5221_phy_def,
+ &bcm5241_phy_def,
+ &bcm5400_phy_def,
+ &bcm5401_phy_def,
+ &bcm5411_phy_def,
+ &bcm5421_phy_def,
+ &bcm5421k2_phy_def,
+ &bcm5461_phy_def,
+ &bcm5462V_phy_def,
+ &marvell88e1101v1_phy_def,
+ &marvell88e1101v2_phy_def,
+ &marvell88e1111_phy_def,
+ &genmii_phy_def,
+ NULL
+};
+
+int sungem_phy_probe(struct mii_phy *phy, int mii_id)
+{
+ int rc;
+ u32 id;
+ struct mii_phy_def* def;
+ int i;
+
+ /* We do not reset the mii_phy structure as the driver
+ * may re-probe the PHY regulary
+ */
+ phy->mii_id = mii_id;
+
+ /* Take PHY out of isloate mode and reset it. */
+ rc = reset_one_mii_phy(phy, mii_id);
+ if (rc)
+ goto fail;
+
+ /* Read ID and find matching entry */
+ id = (phy_read(phy, MII_PHYSID1) << 16 | phy_read(phy, MII_PHYSID2));
+ printk(KERN_DEBUG KBUILD_MODNAME ": " "PHY ID: %x, addr: %x\n",
+ id, mii_id);
+ for (i=0; (def = mii_phy_table[i]) != NULL; i++)
+ if ((id & def->phy_id_mask) == def->phy_id)
+ break;
+ /* Should never be NULL (we have a generic entry), but... */
+ if (def == NULL)
+ goto fail;
+
+ phy->def = def;
+
+ return 0;
+fail:
+ phy->speed = 0;
+ phy->duplex = 0;
+ phy->pause = 0;
+ phy->advertising = 0;
+ return -ENODEV;
+}
+
+EXPORT_SYMBOL(sungem_phy_probe);
+MODULE_LICENSE("GPL");
diff --git a/include/linux/sungem_phy.h b/include/linux/sungem_phy.h
index af02f94..bd9be9f 100644
--- a/include/linux/sungem_phy.h
+++ b/include/linux/sungem_phy.h
@@ -61,7 +61,7 @@ struct mii_phy
/* Pass in a struct mii_phy with dev, mdio_read and mdio_write
* filled, the remaining fields will be filled on return
*/
-extern int mii_phy_probe(struct mii_phy *phy, int mii_id);
+extern int sungem_phy_probe(struct mii_phy *phy, int mii_id);
/* MII definitions missing from mii.h */
--
1.7.6
^ permalink raw reply related
* Re: linux-next: build failure after merge of the final tree (net tree related)
From: Stephen Rothwell @ 2011-08-16 6:57 UTC (permalink / raw)
To: David Miller; +Cc: netdev, linux-next, linux-kernel, jeffrey.t.kirsher
In-Reply-To: <20110815.231116.1728582609642497613.davem@davemloft.net>
[-- Attachment #1: Type: text/plain, Size: 428 bytes --]
Hi Dave,
On Mon, 15 Aug 2011 23:11:16 -0700 (PDT) David Miller <davem@davemloft.net> wrote:
>
> Please test this patch:
>
> --------------------
> net: Fix sungem_phy sharing.
This fixes my allyesconfig build (and doesn't break any of the others :-)).
Tested-by: Stephen Rothwell <sfr@canb.auug.org.au>
--
Cheers,
Stephen Rothwell sfr@canb.auug.org.au
http://www.canb.auug.org.au/~sfr/
[-- Attachment #2: Type: application/pgp-signature, Size: 490 bytes --]
^ permalink raw reply
* Re: linux-next: build failure after merge of the final tree (net tree related)
From: David Miller @ 2011-08-16 7:17 UTC (permalink / raw)
To: sfr; +Cc: netdev, linux-next, linux-kernel, jeffrey.t.kirsher
In-Reply-To: <20110816165744.5c069b0c9f2e329e48ecd7d0@canb.auug.org.au>
From: Stephen Rothwell <sfr@canb.auug.org.au>
Date: Tue, 16 Aug 2011 16:57:44 +1000
> Hi Dave,
>
> On Mon, 15 Aug 2011 23:11:16 -0700 (PDT) David Miller <davem@davemloft.net> wrote:
>>
>> Please test this patch:
>>
>> --------------------
>> net: Fix sungem_phy sharing.
>
> This fixes my allyesconfig build (and doesn't break any of the others :-)).
>
> Tested-by: Stephen Rothwell <sfr@canb.auug.org.au>
Thanks a lot for testing.
^ permalink raw reply
* [patch net-2.6] via-velocity: remove non-tagged packet filtering
From: Jiri Pirko @ 2011-08-16 8:33 UTC (permalink / raw)
To: netdev; +Cc: davem, shemminger, romieu, stephan.baerwolf
It's undesired to filter untagged packets at any time. So simply remove this.
Reported-by: Stephan Bärwolf <stephan.baerwolf@tu-ilmenau.de>
Tested-by: Stephan Bärwolf <stephan.baerwolf@tu-ilmenau.de>
Signed-off-by: Jiri Pirko <jpirko@redhat.com>
---
drivers/net/via-velocity.c | 4 ----
1 files changed, 0 insertions(+), 4 deletions(-)
diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
index deb1eca..7c5336c 100644
--- a/drivers/net/via-velocity.c
+++ b/drivers/net/via-velocity.c
@@ -515,10 +515,6 @@ static void velocity_init_cam_filter(struct velocity_info *vptr)
mac_set_cam_mask(regs, vptr->mCAMmask);
/* Enable VCAMs */
-
- if (test_bit(0, vptr->active_vlans))
- WORD_REG_BITS_ON(MCFG_RTGOPT, ®s->MCFG);
-
for_each_set_bit(vid, vptr->active_vlans, VLAN_N_VID) {
mac_set_vlan_cam(regs, i, (u8 *) &vid);
vptr->vCAMmask[i / 8] |= 0x1 << (i % 8);
--
1.7.6
^ permalink raw reply related
* get_random_int() should use hash[1]
From: George Spelvin @ 2011-08-16 9:07 UTC (permalink / raw)
To: davem; +Cc: linux, netdev
Re: commit e997d47bff5a467262ef224b4cf8cbba2d3eceea
As long as you're using MD5, you should know that each round only
modifies one word of the state. The order is [0], [3], [2], [1],
repeating 64 times. Thus, on output, word [1] is the "most hashed"
word. If you really wanted word [0], you could just skip the last
3 rounds.
It's not really critical, but as long as you're performing the
rounds, you might as well use them...
--- drivers/char/random.c.1 2011-08-16 05:02:09.000000000 -0400
+++ drivers/char/random.c.2 2011-08-16 05:02:43.000000000 -0400
@@ -1323,7 +1323,7 @@
hash[0] += current->pid + jiffies + get_cycles();
md5_transform(hash, random_int_secret);
- ret = hash[0];
+ ret = hash[1];
put_cpu_var(get_random_int_hash);
return ret;
Me, I'd also put jiffies and get_cycles into different words
just on general principles, but that's up to you:
- hash[0] += current->pid + jiffies + get_cycles();
+ hash[1] += current->pid + jiffies;
+ hash[2] += get_cycles();
^ permalink raw reply
* Re: get_random_int() should use hash[1]
From: David Miller @ 2011-08-16 9:09 UTC (permalink / raw)
To: linux; +Cc: netdev
In-Reply-To: <20110816090723.18492.qmail@science.horizon.com>
From: "George Spelvin" <linux@horizon.com>
Date: 16 Aug 2011 05:07:23 -0400
> Re: commit e997d47bff5a467262ef224b4cf8cbba2d3eceea
>
> As long as you're using MD5, you should know that each round only
> modifies one word of the state. The order is [0], [3], [2], [1],
> repeating 64 times. Thus, on output, word [1] is the "most hashed"
> word. If you really wanted word [0], you could just skip the last
> 3 rounds.
>
> It's not really critical, but as long as you're performing the
> rounds, you might as well use them...
Please provide a proper signoff with your change and properly
"-p1" base your patch.
Thanks.
^ permalink raw reply
* Re: get_random_int() should use hash[1]
From: David Miller @ 2011-08-16 9:10 UTC (permalink / raw)
To: linux; +Cc: netdev
In-Reply-To: <20110816.020935.717525957035990843.davem@davemloft.net>
From: David Miller <davem@davemloft.net>
Date: Tue, 16 Aug 2011 02:09:35 -0700 (PDT)
> From: "George Spelvin" <linux@horizon.com>
> Date: 16 Aug 2011 05:07:23 -0400
>
>> Re: commit e997d47bff5a467262ef224b4cf8cbba2d3eceea
>>
>> As long as you're using MD5, you should know that each round only
>> modifies one word of the state. The order is [0], [3], [2], [1],
>> repeating 64 times. Thus, on output, word [1] is the "most hashed"
>> word. If you really wanted word [0], you could just skip the last
>> 3 rounds.
>>
>> It's not really critical, but as long as you're performing the
>> rounds, you might as well use them...
>
> Please provide a proper signoff with your change and properly
> "-p1" base your patch.
>
> Thanks.
Also this change is of interest to, and effects, folks outside of
networking. So probably want to CC: linux-kernel when you respin
this.
^ permalink raw reply
* [patch net-next-2.6] bonding: use ndo_change_rx_flags callback
From: Jiri Pirko @ 2011-08-16 9:30 UTC (permalink / raw)
To: netdev; +Cc: davem, fubar, andy
Benefit from use of ndo_change_rx_flags in handling change of promisc
and allmulti. No need to store previous state locally.
Signed-off-by: Jiri Pirko <jpirko@redhat.com>
---
drivers/net/bonding/bond_main.c | 44 ++++++++++++--------------------------
drivers/net/bonding/bonding.h | 1 -
2 files changed, 14 insertions(+), 31 deletions(-)
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 854aa8d..731763a 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -3686,44 +3686,27 @@ static bool bond_addr_in_mc_list(unsigned char *addr,
return false;
}
-static void bond_set_multicast_list(struct net_device *bond_dev)
+static void bond_change_rx_flags(struct net_device *bond_dev, int change)
{
struct bonding *bond = netdev_priv(bond_dev);
- struct netdev_hw_addr *ha;
- bool found;
- /*
- * Do promisc before checking multicast_mode
- */
- if ((bond_dev->flags & IFF_PROMISC) && !(bond->flags & IFF_PROMISC))
- /*
- * FIXME: Need to handle the error when one of the multi-slaves
- * encounters error.
- */
- bond_set_promiscuity(bond, 1);
-
-
- if (!(bond_dev->flags & IFF_PROMISC) && (bond->flags & IFF_PROMISC))
- bond_set_promiscuity(bond, -1);
+ if (change & IFF_PROMISC)
+ bond_set_promiscuity(bond,
+ bond_dev->flags & IFF_ALLMULTI ? 1 : -1);
+ if (change & IFF_ALLMULTI)
+ bond_set_allmulti(bond,
+ bond_dev->flags & IFF_ALLMULTI ? 1 : -1);
+}
- /* set allmulti flag to slaves */
- if ((bond_dev->flags & IFF_ALLMULTI) && !(bond->flags & IFF_ALLMULTI))
- /*
- * FIXME: Need to handle the error when one of the multi-slaves
- * encounters error.
- */
- bond_set_allmulti(bond, 1);
-
-
- if (!(bond_dev->flags & IFF_ALLMULTI) && (bond->flags & IFF_ALLMULTI))
- bond_set_allmulti(bond, -1);
-
+static void bond_set_multicast_list(struct net_device *bond_dev)
+{
+ struct bonding *bond = netdev_priv(bond_dev);
+ struct netdev_hw_addr *ha;
+ bool found;
read_lock(&bond->lock);
- bond->flags = bond_dev->flags;
-
/* looking for addresses to add to slaves' mc list */
netdev_for_each_mc_addr(ha, bond_dev) {
found = bond_addr_in_mc_list(ha->addr, &bond->mc_list,
@@ -4282,6 +4265,7 @@ static const struct net_device_ops bond_netdev_ops = {
.ndo_select_queue = bond_select_queue,
.ndo_get_stats64 = bond_get_stats,
.ndo_do_ioctl = bond_do_ioctl,
+ .ndo_change_rx_flags = bond_change_rx_flags,
.ndo_set_multicast_list = bond_set_multicast_list,
.ndo_change_mtu = bond_change_mtu,
.ndo_set_mac_address = bond_set_mac_address,
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index 43526a2..e823366 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -234,7 +234,6 @@ struct bonding {
struct netdev_hw_addr_list mc_list;
int (*xmit_hash_policy)(struct sk_buff *, int);
__be32 master_ip;
- u16 flags;
u16 rr_tx_counter;
struct ad_bond_info ad_info;
struct alb_bond_info alb_info;
--
1.7.6
^ permalink raw reply related
* Re: [patch net-next-2.6] bonding: use ndo_change_rx_flags callback
From: Michał Mirosław @ 2011-08-16 10:03 UTC (permalink / raw)
To: Jiri Pirko; +Cc: netdev, davem, fubar, andy
In-Reply-To: <1313487050-4048-1-git-send-email-jpirko@redhat.com>
2011/8/16 Jiri Pirko <jpirko@redhat.com>:
> Benefit from use of ndo_change_rx_flags in handling change of promisc
> and allmulti. No need to store previous state locally.
[...]
> diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
> index 854aa8d..731763a 100644
> --- a/drivers/net/bonding/bond_main.c
> +++ b/drivers/net/bonding/bond_main.c
[...]
> -static void bond_set_multicast_list(struct net_device *bond_dev)
> +static void bond_change_rx_flags(struct net_device *bond_dev, int change)
> {
[...]
> + if (change & IFF_PROMISC)
> + bond_set_promiscuity(bond,
> + bond_dev->flags & IFF_ALLMULTI ? 1 : -1);
Typo: flags & IFF_PROMISC ?
Best Regards,
Michał Mirosław
^ permalink raw reply
* Re: get_random_int() should use hash[1]
From: George Spelvin @ 2011-08-16 10:30 UTC (permalink / raw)
To: davem, linux, mpm; +Cc: linux-kernel, netdev
In-Reply-To: <20110816.021031.1778295949152117484.davem@davemloft.net>
>From davem@davemloft.net Tue Aug 16 09:10:35 2011
Date: Tue, 16 Aug 2011 02:10:31 -0700 (PDT)
To: linux@horizon.com
Cc: netdev@vger.kernel.org
Subject: Re: get_random_int() should use hash[1]
From: David Miller <davem@davemloft.net>
In-Reply-To: <20110816.020935.717525957035990843.davem@davemloft.net>
References: <20110816090723.18492.qmail@science.horizon.com>
<20110816.020935.717525957035990843.davem@davemloft.net>
X-Mailer: Mew version 6.3 on Emacs 23.2 / Mule 6.0 (HANACHIRUSATO)
Mime-Version: 1.0
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
X-Greylist: Sender succeeded SMTP AUTH, not delayed by milter-greylist-4.2.6 (shards.monkeyblade.net [198.137.202.13]); Tue, 16 Aug 2011 02:10:33 -0700 (PDT)
From: David Miller <davem@davemloft.net>
Date: Tue, 16 Aug 2011 02:09:35 -0700 (PDT)
> From: "George Spelvin" <linux@horizon.com>
> Date: 16 Aug 2011 05:07:23 -0400
>
>> Re: commit e997d47bff5a467262ef224b4cf8cbba2d3eceea
>>
>> As long as you're using MD5, you should know that each round only
>> modifies one word of the state. The order is [0], [3], [2], [1],
>> repeating 64 times. Thus, on output, word [1] is the "most hashed"
>> word. If you really wanted word [0], you could just skip the last
>> 3 rounds.
>>
>> It's not really critical, but as long as you're performing the
>> rounds, you might as well use them...
>
> Please provide a proper signoff with your change and properly
> "-p1" base your patch.
Not a problem. This came up in the middle of a rebase operation so I
didn't have a tree immediately at hand to work with.
I'll also get the various uses in net/core/secure_seq.c.
One thing about that commit I'm becoming more concerneed by: I notice that
it eliminates the periodic reseeding of the secret.
While the reduction in the number of random bits was a tradeoff (and it
can be increased to 28 or so), it had two great advantages:
- The usefulness of an attack drops off sharply after 5 minutes (you
can still attack connections established during the attack window,
but then you have to guess how much data has been sent across them).
- An initial shortage of seed entropy does not become a persistent
problem. Note that late_initcall() is still before any device
activity, much less entropy pool re-seeding from init scripts.
Put together, an attacker has the system uptime to try to guess
the low-entropy boot seed. That's not clearly a security improvement.
What I *really* wonder is whether such a change is really -stable
material. Cc: to Matt Mackall for comment.
It seems at least worth figuring out a way to defer seeding until
after /dev/random reseeding. (E.g. until first non-loopback
connection is made.)
(There are also both better and faster algorithms than MD5 for
the job, but that's a separate issue.)
Just for example, as long as you're actually willing to spend more CPU
time, you could do *both*. Compute both a fixed-secret 32-bit value and a
changing-secret 24-bit value and add them together. Best of both worlds.
^ permalink raw reply
* Re: [Bug 41212] New: [regression] [3.1-git] ipoib causes kernel panic (NULL pointer dereference)
From: Bernd Schubert @ 2011-08-16 10:34 UTC (permalink / raw)
To: Erez Shitrit
Cc: linux-rdma-u79uwXL29TY76Z2rM5mHXA, netdev-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <CAAk-MO8EToGY4OhmX1xPN01iAXR9WSsJXWxHG9EVyrSGYP3h5w-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
Hello Erez,
are you sure? Commit 69cce1d1404968f78b177a0314f5822d5afdbbfb is not in
3.0 yet and I also don't see how 3.0 should fail there, as it tests
immediately for "if (likely(skb_dst(skb)"
Thanks,
Bernd
On 08/16/2011 10:06 AM, Erez Shitrit wrote:
> Hi,
> it happened in 3.0 also, if you take the git tag v3.0-rc7 and below it
> will work.
>
> Thanks, Erez
>
> On Mon, Aug 15, 2011 at 6:40 PM, <bugzilla-daemon-590EEB7GvNiWaY/ihj7yzEB+6BGkLq7r@public.gmane.org
> <mailto:bugzilla-daemon-590EEB7GvNiWaY/ihj7yzEB+6BGkLq7r@public.gmane.org>> wrote:
>
> https://bugzilla.kernel.org/show_bug.cgi?id=41212
>
> Summary: [regression] [3.1-git] ipoib causes kernel panic
> (NULL
> pointer dereference)
> Product: Networking
> Version: 2.5
> Kernel Version: 3.1-git
> Platform: All
> OS/Version: Linux
> Tree: Mainline
> Status: NEW
> Severity: normal
> Priority: P1
> Component: Other
> AssignedTo: acme-f8uhVLnGfZaxAyOMLChx1axOck334EZe@public.gmane.org
> <mailto:acme-f8uhVLnGfZaxAyOMLChx1axOck334EZe@public.gmane.org>
> ReportedBy: bernd.schubert-97jfqw80gc6171pxa8y+qA@public.gmane.org
> <mailto:bernd.schubert-97jfqw80gc6171pxa8y+qA@public.gmane.org>
> CC: linux-rdma-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> <mailto:linux-rdma-u79uwXL29TY76Z2rM5mHXA@public.gmane.org>
> Regression: Yes
>
>
> Each time when I start IPoIB with any 3.1-rcX git version I tested
> so far I get
> a kernel panic. This didn't happen in 3.0 yet.
>
>
> fslab2 login: [ 114.392408] EXT4-fs (sdc): barriers disabled
> [ 114.449737] EXT4-fs (sdc): mounted filesystem with writeback data
> mode.
> Opts: journal_async_commit,barrier=0,data=writeback
> [ 240.944030] BUG: unable to handle kernel NULL pointer dereference at
> 0000000000000040
> [ 240.948007] IP: [<ffffffffa0366ce9>] ipoib_start_xmit+0x39/0x280
> [ib_ipoib]
> [ 240.948007] PGD 1f964f067 PUD 1f9bf2067 PMD 0
> [ 240.948007] Oops: 0000 [#1] SMP
> [ 240.948007] CPU 1
> [ 240.948007] Modules linked in: ext4 mbcache jbd2 crc16 nfsd
> ib_umad rdma_ucm
> rdma_cm iw_cm ib_addr ib_uverbs ib_ipoib sg ib_cm ib_sa ipv6 sd_mod
> crc_t10dif
> loop arcmsr md_mod pcspkr ib_mthca ib_mad ib_core 8250_pnp fuse
> af_packet nfs
> lockd fscache auth_rpcgss nfs_acl sunrpc btrfs lzo_decompress
> lzo_compress
> zlib_deflate crc32c libcrc32c crypto_hash crypto_algapi ata_generic
> pata_acpi
> e1000 pata_amd sata_nv libata scsi_mod unix [last unloaded:
> scsi_wait_scan]
> [ 240.948007]
> [ 240.948007] Pid: 0, comm: kworker/0:0 Not tainted 3.1.0-rc2+ #29
> Supermicro
> H8DCE/H8DCE
> [ 240.948007] RIP: 0010:[<ffffffffa0366ce9>] [<ffffffffa0366ce9>]
> ipoib_start_xmit+0x39/0x280 [ib_ipoib]
> [ 240.948007] RSP: 0018:ffff8801ffc03c10 EFLAGS: 00010246
> [ 240.948007] RAX: 0000000000000000 RBX: ffff8801f99ea000 RCX:
> 0000000000004420
> [ 240.948007] RDX: 0000000000000000 RSI: ffff8801f99ea000 RDI:
> ffff8801f9afd500
> [ 240.948007] RBP: ffff8801ffc03c40 R08: ffff8801f940d49c R09:
> ffff8801f9852240
> [ 240.948007] R10: 0000000000000000 R11: 0000000000000020 R12:
> ffff8801f9afd500
> [ 240.948007] R13: 0000000000000050 R14: ffff8801f99ea600 R15:
> ffff8801f9852280
> [ 240.948007] FS: 00007f0b66016700(0000) GS:ffff8801ffc00000(0000)
> knlGS:0000000000000000
> [ 240.948007] CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b
> [ 240.948007] CR2: 0000000000000040 CR3: 00000001f9a65000 CR4:
> 00000000000006e0
> [ 240.948007] DR0: 0000000000000000 DR1: 0000000000000000 DR2:
> 0000000000000000
> [ 240.948007] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7:
> 0000000000000400
> [ 240.948007] Process kworker/0:0 (pid: 0, threadinfo
> ffff8800bfe82000, task
> ffff8800bfe6f1a0)
> [ 240.948007] Stack:
> [ 240.948007] 0000000000000010 ffff8801f9afd500 0000000000004420
> 0000000000000050
> [ 240.948007] ffff8801f99ea000 ffff8801f9852280 ffff8801ffc03ca0
> ffffffff812cd5e0
> [ 240.948007] 0000000000000001 ffffffffa03721a0 ffffffff8131f680
> ffff8801fa110540
> [ 240.948007] Call Trace:
> [ 240.948007] <IRQ>
> [ 240.948007] [<ffffffff812cd5e0>] dev_hard_start_xmit+0x2a0/0x590
> [ 240.948007] [<ffffffff8131f680>] ? arp_create+0x70/0x200
> [ 240.948007] [<ffffffff812e8e1f>] sch_direct_xmit+0xef/0x1c0
> [ 240.948007] [<ffffffff812cd9f9>] dev_queue_xmit+0x129/0x3b0
> [ 240.948007] [<ffffffff8131f853>] arp_send+0x43/0x50
> [ 240.948007] [<ffffffff8131f96b>] arp_solicit+0x10b/0x240
>
> --
> Configure bugmail: https://bugzilla.kernel.org/userprefs.cgi?tab=email
> ------- You are receiving this mail because: -------
> You are on the CC list for the bug.
> --
> To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> <mailto:majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org>
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
>
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH 0/2] 3.1-git ipoib: fix NULL pointer dereference
From: Bernd Schubert @ 2011-08-16 10:56 UTC (permalink / raw)
To: netdev-u79uwXL29TY76Z2rM5mHXA; +Cc: linux-rdma-u79uwXL29TY76Z2rM5mHXA
The following series
- fixes a NULL pointer dereferences in ipoib_start_xmit()
- renames variable 'n' to 'dst_neigh' to make the code better readable
Question: I am unsure about the usage of likely() here, as I run into the else branch,
maybe it is not that unlikely and likely() should be removed?
---
Bernd Schubert (2):
Fix possible Null pointer dereference in ipoib_start_xmit()
Rename 'n' into a longer variable name.
drivers/infiniband/ulp/ipoib/ipoib_main.c | 17 ++++++++++-------
1 files changed, 10 insertions(+), 7 deletions(-)
--
Bernd Schubert
Fraunhofer ITWM / FhGFS
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH 1/2] Fix possible Null pointer dereference in ipoib_start_xmit()
From: Bernd Schubert @ 2011-08-16 10:56 UTC (permalink / raw)
To: netdev-u79uwXL29TY76Z2rM5mHXA; +Cc: linux-rdma-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20110816105648.1805137.35191.stgit@fsdevel3>
This will fix https://bugzilla.kernel.org/show_bug.cgi?id=41212
fslab2 login: [ 114.392408] EXT4-fs (sdc): barriers disabled
[ 114.449737] EXT4-fs (sdc): mounted filesystem with writeback data mode.
Opts: journal_async_commit,barrier=0,data=writeback
[ 240.944030] BUG: unable to handle kernel NULL pointer dereference at
0000000000000040
[ 240.948007] IP: [<ffffffffa0366ce9>] ipoib_start_xmit+0x39/0x280 [ib_ipoib]
[...]
[ 240.948007] Call Trace:
[ 240.948007] <IRQ>
[ 240.948007] [<ffffffff812cd5e0>] dev_hard_start_xmit+0x2a0/0x590
[ 240.948007] [<ffffffff8131f680>] ? arp_create+0x70/0x200
[ 240.948007] [<ffffffff812e8e1f>] sch_direct_xmit+0xef/0x1c0
Signed-off-by: Bernd Schubert <bernd.schubert-mPn0NPGs4xGatNDF+KUbs4QuADTiUCJX@public.gmane.org>
---
drivers/infiniband/ulp/ipoib/ipoib_main.c | 8 +++++---
1 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c
index 43f89ba..fe89c46 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -717,11 +717,13 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct ipoib_dev_priv *priv = netdev_priv(dev);
struct ipoib_neigh *neigh;
- struct neighbour *n;
+ struct neighbour *n = NULL;
unsigned long flags;
- n = dst_get_neighbour(skb_dst(skb));
- if (likely(skb_dst(skb) && n)) {
+ if (likely(skb_dst(skb)))
+ n = dst_get_neighbour(skb_dst(skb));
+
+ if (likely(n)) {
if (unlikely(!*to_ipoib_neigh(n))) {
ipoib_path_lookup(skb, dev);
return NETDEV_TX_OK;
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH 2/2] Rename 'n' into a longer variable name.
From: Bernd Schubert @ 2011-08-16 10:56 UTC (permalink / raw)
To: netdev-u79uwXL29TY76Z2rM5mHXA; +Cc: linux-rdma-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20110816105648.1805137.35191.stgit@fsdevel3>
When it comes to me variable names consisting of a single letter
should be forbidden by coding style guide lines, as it is rather
difficult to search for single letter, such as 'n'.
Rename struct neighbour *n to dst_neigh
Signed-off-by: Bernd Schubert <bernd.schubert-mPn0NPGs4xGatNDF+KUbs4QuADTiUCJX@public.gmane.org>
---
drivers/infiniband/ulp/ipoib/ipoib_main.c | 15 ++++++++-------
1 files changed, 8 insertions(+), 7 deletions(-)
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c
index fe89c46..189d4cb 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -717,22 +717,22 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct ipoib_dev_priv *priv = netdev_priv(dev);
struct ipoib_neigh *neigh;
- struct neighbour *n = NULL;
+ struct neighbour *dst_neigh = NULL;
unsigned long flags;
if (likely(skb_dst(skb)))
- n = dst_get_neighbour(skb_dst(skb));
+ dst_neigh = dst_get_neighbour(skb_dst(skb));
- if (likely(n)) {
- if (unlikely(!*to_ipoib_neigh(n))) {
+ if (likely(dst_neigh)) {
+ if (unlikely(!*to_ipoib_neigh(dst_neigh))) {
ipoib_path_lookup(skb, dev);
return NETDEV_TX_OK;
}
- neigh = *to_ipoib_neigh(n);
+ neigh = *to_ipoib_neigh(dst_neigh);
if (unlikely((memcmp(&neigh->dgid.raw,
- n->ha + 4,
+ dst_neigh->ha + 4,
sizeof(union ib_gid))) ||
(neigh->dev != dev))) {
spin_lock_irqsave(&priv->lock, flags);
@@ -758,7 +758,8 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev)
return NETDEV_TX_OK;
}
} else if (neigh->ah) {
- ipoib_send(dev, skb, neigh->ah, IPOIB_QPN(n->ha));
+ ipoib_send(dev, skb, neigh->ah,
+ IPOIB_QPN(dst_neigh->ha));
return NETDEV_TX_OK;
}
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
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