* Re: [PATCH V6 5/9] net/bonding: Enable IP multicast for bonding IPoIB devices
From: Stephen Hemminger @ 2007-09-24 16:04 UTC (permalink / raw)
To: Moni Shoua; +Cc: Roland Dreier, Jay Vosburgh, netdev, OpenFabrics General
In-Reply-To: <46F7D99C.3030602@voltaire.com>
On Mon, 24 Sep 2007 17:37:00 +0200
Moni Shoua <monis@voltaire.com> wrote:
> Allow to enslave devices when the bonding device is not up. Over the discussion
> held at the previous post this seemed to be the most clean way to go, where it
> is not expected to cause instabilities.
>
> Normally, the bonding driver is UP before any enslavement takes place.
> Once a netdevice is UP, the network stack acts to have it join some multicast groups
> (eg the all-hosts 224.0.0.1). Now, since ether_setup() have set the bonding device
> type to be ARPHRD_ETHER and address len to be ETHER_ALEN, the net core code
> computes a wrong multicast link address. This is b/c ip_eth_mc_map() is called
> where for multicast joins taking place after the enslavement another ip_xxx_mc_map()
> is called (eg ip_ib_mc_map() when the bond type is ARPHRD_INFINIBAND)
>
> Signed-off-by: Moni Shoua <monis at voltaire.com>
> Signed-off-by: Or Gerlitz <ogerlitz at voltaire.com>
> ---
> drivers/net/bonding/bond_main.c | 5 +++--
> drivers/net/bonding/bond_sysfs.c | 6 ++----
> 2 files changed, 5 insertions(+), 6 deletions(-)
>
> Index: net-2.6/drivers/net/bonding/bond_main.c
> ===================================================================
> --- net-2.6.orig/drivers/net/bonding/bond_main.c 2007-08-15 10:54:41.000000000 +0300
> +++ net-2.6/drivers/net/bonding/bond_main.c 2007-08-15 10:55:48.431862446 +0300
> @@ -1285,8 +1285,9 @@ int bond_enslave(struct net_device *bond
>
> /* bond must be initialized by bond_open() before enslaving */
> if (!(bond_dev->flags & IFF_UP)) {
> - dprintk("Error, master_dev is not up\n");
> - return -EPERM;
> + printk(KERN_WARNING DRV_NAME
> + " %s: master_dev is not up in bond_enslave\n",
> + bond_dev->name);
> }
>
> /* already enslaved */
> Index: net-2.6/drivers/net/bonding/bond_sysfs.c
> ===================================================================
> --- net-2.6.orig/drivers/net/bonding/bond_sysfs.c 2007-08-15 10:08:58.000000000 +0300
> +++ net-2.6/drivers/net/bonding/bond_sysfs.c 2007-08-15 10:55:48.432862269 +0300
> @@ -266,11 +266,9 @@ static ssize_t bonding_store_slaves(stru
>
> /* Quick sanity check -- is the bond interface up? */
> if (!(bond->dev->flags & IFF_UP)) {
> - printk(KERN_ERR DRV_NAME
> - ": %s: Unable to update slaves because interface is down.\n",
> + printk(KERN_WARNING DRV_NAME
> + ": %s: doing slave updates when interface is down.\n",
> bond->dev->name);
> - ret = -EPERM;
> - goto out;
> }
>
Please get rid of the warning. Make bonding work correctly and allow enslave/remove
of device when bonding is down.
^ permalink raw reply
* Re: [PATCH] sb1250-mac: Driver model & phylib update
From: Andrew Morton @ 2007-09-24 16:55 UTC (permalink / raw)
To: Maciej W. Rozycki; +Cc: Jeff Garzik, netdev, linux-mips, linux-kernel
In-Reply-To: <Pine.LNX.4.64N.0709241529570.22491@blysk.ds.pg.gda.pl>
On Mon, 24 Sep 2007 15:41:54 +0100 (BST) "Maciej W. Rozycki" <macro@linux-mips.org> wrote:
> On Fri, 21 Sep 2007, Andrew Morton wrote:
>
> > > A driver model and phylib update.
> >
> > akpm:/usr/src/25> diffstat patches/git-net.patch | tail -n 1
> > 1013 files changed, 187667 insertions(+), 23587 deletions(-)
> >
> > Sorry, but raising networking patches against Linus's crufty
> > old mainline tree just isn't viable at present.
>
> Well, this is against Jeff's netdev-2.6 tree which hopefully is not as
> crufty as Linus's old mainline; if it is not possible to queue this change
> for 2.6.25 or suchlike, then I will try to resubmit later.
Most of Jeff's netdev tree got dumped into Dave's net-2.6.24 tree. That's
the one you want to be raising patches against for the next few weeks.
^ permalink raw reply
* Re: [PATCH net-2.6.24] introduce MAC_FMT/MAC_ARG
From: Joe Perches @ 2007-09-24 17:28 UTC (permalink / raw)
To: David Miller; +Cc: johannes, netdev, akpm, jgarzik
In-Reply-To: <20070919.125451.112289690.davem@davemloft.net>
On Wed, 2007-09-19 at 12:54 -0700, David Miller wrote:
> Applied to net-2.6.24, thanks Joe!
Here is a patch that adds some type safety to print_mac
by using a struct print_mac_buf * instead of char *.
It also reduces the defconfig vmlinux size by 8 bytes.
Signed-off-by: Joe Perches <joe@perches.com>
--
include/linux/if_ether.h | 12 ++++++++++--
net/ethernet/eth.c | 6 +++---
2 files changed, 13 insertions(+), 5 deletions(-)
diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h
index 57abca1..620d6b1 100644
--- a/include/linux/if_ether.h
+++ b/include/linux/if_ether.h
@@ -126,7 +126,15 @@ extern struct ctl_table ether_table[];
* Display a 6 byte device address (MAC) in a readable format.
*/
#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
-extern char *print_mac(char *buf, const u8 *addr);
-#define DECLARE_MAC_BUF(var) char var[18] __maybe_unused
+
+struct print_mac_buf {
+ char formatted_mac_addr[18];
+};
+
+#define DECLARE_MAC_BUF(var) \
+ struct print_mac_buf __maybe_unused _##var; \
+ struct print_mac_buf __maybe_unused *var = &_##var
+
+extern char *print_mac(struct print_mac_buf *buf, const u8 *addr);
#endif /* _LINUX_IF_ETHER_H */
diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c
index 2aaf6fa..ad82613 100644
--- a/net/ethernet/eth.c
+++ b/net/ethernet/eth.c
@@ -338,10 +338,10 @@ struct net_device *alloc_etherdev_mq(int sizeof_priv, unsigned int queue_count)
}
EXPORT_SYMBOL(alloc_etherdev_mq);
-char *print_mac(char *buf, const u8 *addr)
+char *print_mac(struct print_mac_buf *buf, const u8 *addr)
{
- sprintf(buf, MAC_FMT,
+ sprintf(buf->formatted_mac_addr, MAC_FMT,
addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
- return buf;
+ return buf->formatted_mac_addr;
}
EXPORT_SYMBOL(print_mac);
^ permalink raw reply related
* Re: [PATCH 1/2] bnx2: factor out gzip unpacker
From: Lennart Sorensen @ 2007-09-24 17:32 UTC (permalink / raw)
To: Denys Vlasenko
Cc: Andi Kleen, David Miller, jeff, mchan, linux-kernel, netdev
In-Reply-To: <200709212337.53043.vda.linux@googlemail.com>
On Fri, Sep 21, 2007 at 11:37:52PM +0100, Denys Vlasenko wrote:
> But I compile net/* into bzImage. I like netbooting :)
Isn't it possible to netboot with an initramfs image? I am pretty sure
I have seen some systems do exactly that.
--
Len Sorensen
^ permalink raw reply
* Re: pktgen question
From: David Miller @ 2007-09-24 17:40 UTC (permalink / raw)
To: swise; +Cc: greearb, hadi, johnpol, netdev, Robert.Olsson
In-Reply-To: <46F7C185.1030202@opengridcomputing.com>
From: Steve Wise <swise@opengridcomputing.com>
Date: Mon, 24 Sep 2007 08:54:13 -0500
> I think pktgen should be cloning the skbs using skb_clone(). Then it
> will work for all devices, eh?
The problem is that skb_clone() is (relatively) expensive and
pktgen is trying to just grab a reference to the SKB in
the absolutely cheapest way possible.
In my personal opinion, I think what the drivers that don't
work with pktgen are doing is wrong and they should find
another way to pass state around other than to depend upon
being able to use the ->cb[] area at-will.
^ permalink raw reply
* Re: pktgen question
From: Rick Jones @ 2007-09-24 18:02 UTC (permalink / raw)
To: Ben Greear; +Cc: Steve Wise, hadi, Evgeniy Polyakov, netdev, Robert Olsson
In-Reply-To: <46F7D9C8.7020101@candelatech.com>
>> Perf-wise, you could clone the skbs up front, then deliver them to the
>> nic in a tight loop. This would mitigate the added overhead
>> introduced by calling skb_clone() in the loop doing transmits...
>
> That only works if you are sending a small number of skbs. You can't
> pre-clone several minutes worth of 10Gbe traffic
> with any normal amount of RAM.
Does pktgen really need to allocate anything more than some smallish fraction
more than the depth of the driver's transmit queue?
Of course, even that won't fit in the L1 cache of a processor, so if one is
really just trying to max-out the NIC it might still have too much overhead, but
then does pktgen+driver et al actually fit in an L1 cache?
rick jones
^ permalink raw reply
* Re: pktgen question
From: Ben Greear @ 2007-09-24 18:22 UTC (permalink / raw)
To: Rick Jones; +Cc: Steve Wise, hadi, Evgeniy Polyakov, netdev, Robert Olsson
In-Reply-To: <46F7FBBC.6080401@hp.com>
Rick Jones wrote:
>>> Perf-wise, you could clone the skbs up front, then deliver them to
>>> the nic in a tight loop. This would mitigate the added overhead
>>> introduced by calling skb_clone() in the loop doing transmits...
>>
>> That only works if you are sending a small number of skbs. You can't
>> pre-clone several minutes worth of 10Gbe traffic
>> with any normal amount of RAM.
>
> Does pktgen really need to allocate anything more than some smallish
> fraction more than the depth of the driver's transmit queue?
If you want to send sustained high rates of traffic, for more than
just a trivial amount of time, then you either have to play the current
trick with the skb_get(), or you have to allocate a real packet each time
(maybe with skb_clone() or similar, but it's still more overhead than the skb_get
which only bumps a reference count.)
I see no other way, but if you can think of one, please let me know.
Thanks,
Ben
--
Ben Greear <greearb@candelatech.com>
Candela Technologies Inc http://www.candelatech.com
^ permalink raw reply
* [ofa-general] RE: [PATCH 1/4] [NET_SCHED] explict hold dev tx lock
From: Waskiewicz Jr, Peter P @ 2007-09-24 19:12 UTC (permalink / raw)
To: hadi, David Miller
Cc: johnpol, kumarkr, herbert, gaagaan, Robert.Olsson, netdev,
rdreier, mcarlson, randy.dunlap, jagana, general, mchan, tgraf,
jeff, sri, shemminger, kaber
In-Reply-To: <1190570205.4256.56.camel@localhost>
> I have submitted this before; but here it is again.
> Against net-2.6.24 from yesterday for this and all following patches.
>
>
> cheers,
> jamal
Hi Jamal,
I've been (slowly) working on resurrecting the original design
of my multiqueue patches to address this exact issue of the queue_lock
being a hot item. I added a queue_lock to each queue in the subqueue
struct, and in the enqueue and dequeue, just lock that queue instead of
the global device queue_lock. The only two issues to overcome are the
QDISC_RUNNING state flag, since that also serializes entry into the
qdisc_restart() function, and the qdisc statistics maintenance, which
needs to be serialized. Do you think this work along with your patch
will benefit from one another? I apologize for not having working
patches right now, but I am working on them slowly as I have some blips
of spare time.
Thanks,
-PJ Waskiewicz
^ permalink raw reply
* Re: [PATCH 2/7] CAN: Add PF_CAN core module
From: Urs Thuermann @ 2007-09-24 19:23 UTC (permalink / raw)
To: Joe Perches
Cc: netdev, David Miller, Patrick McHardy, Thomas Gleixner,
Oliver Hartkopp, Oliver Hartkopp
In-Reply-To: <1190318781.26101.148.camel@localhost>
Joe Perches <joe@perches.com> writes:
> I'd prefer something like this, which removes the unnecessary
> kmalloc/kfree pairs or the equivalent conversions to functions.
I have changed this to a static buffer. Since this is only in
#ifdef CONFIG_CAN_DEBUG_CORE, it shouldn't hurt.
> #define can_debug_cframe(cf, fmt, arg...) \
> do { \
> char buf[20]; \
> int dlc = cf->can_dlc; \
> if (dlc > 8) \
> dlc = 8; \
> if (cf->can_id & CAN_EFF_FLAG) \
> sprintf(buf, "<%08X> [%X] ", cf->can_id & CAN_EFF_MASK, dlc); \
> else \
> sprintf(buf, "<%03X> [%X] ", cf->can_id & CAN_SFF_MASK, dlc); \
> printk(KERN_DEBUG fmt, ##arg); \
> print_hex_dump(buf, DUMP_PREFIX_NONE, cf->data, dlc); \
> } while (0)
The line isn't printed atomically, i.e. it could happen that something
is printed between the fmt+args and the hexdump, i.e inbetween the
line.
> and
>
> #define can_debug_skb(skb) \
> do { \
> pr_debug("skbuff at %p, dev: %d, proto: %04x\n", \
> skb, skb->dev ? skb->dev->ifindex : -1, \
> ntohs(skb->protocol)); \
> pr_debug("users: %d, dataref: %d, nr_frags: %d, " \
> "h,d,t,e,l: %p %+d %+d %+d, %d\n", \
> atomic_read(&skb->users), \
> atomic_read(&(skb_shinfo(skb)->dataref)), \
> skb_shinfo(skb)->nr_frags, \
> skb->head, skb->data - skb->head, \
> skb->tail - skb->head, skb->end - skb->head, skb->len); \
> print_hex_dump(KERN_DEBUG, "skb_head: ", DUMP_PREFIX_NONE, \
> 16, 1, skb->head, skb->end - skb->head); \
> } while (0)
Here, the consecutive lines aren't printed atomically.
I think sprintf() to a buffer first and the do one printk() is
better. But I will use hex_dump_to_buffer().
urs
^ permalink raw reply
* deadlink in genetlink?
From: Ben Pfaff @ 2007-09-24 19:46 UTC (permalink / raw)
To: netdev; +Cc: Thomas Graf
[Sorry about the duplicate mail, Thomas: I got the netdev address
wrong on the first try.]
lockdep reported a circular dependency between cb_mutex and
genl_mutex, as follows:
-> #1 (nlk->cb_mutex){--..}:
[<c0127b5d>] __lock_acquire+0x9c8/0xb98
[<c01280f6>] lock_acquire+0x5d/0x75
[<c027adc1>] __mutex_lock_slowpath+0xdb/0x247
[<c027af49>] mutex_lock+0x1c/0x1f
[<c0236aa0>] netlink_dump_start+0xa9/0x12f
---> takes cb_mutex
[<c0237fa6>] genl_rcv_msg+0xa3/0x14c
[<c0235aa5>] netlink_run_queue+0x6f/0xe1
[<c0237772>] genl_rcv+0x2d/0x4e
---> trylocks genl_mutex
[<c0235ef0>] netlink_data_ready+0x15/0x55
[<c0234e98>] netlink_sendskb+0x1f/0x36
[<c0235772>] netlink_unicast+0x1a6/0x1c0
[<c0235ecf>] netlink_sendmsg+0x238/0x244
[<c021a92e>] sock_sendmsg+0xcb/0xe4
[<c021aa98>] sys_sendmsg+0x151/0x1af
[<c021b850>] sys_socketcall+0x203/0x222
[<c01025d2>] syscall_call+0x7/0xb
[<ffffffff>] 0xffffffff
-> #0 (genl_mutex){--..}:
[<c0127a46>] __lock_acquire+0x8b1/0xb98
[<c01280f6>] lock_acquire+0x5d/0x75
[<c027adc1>] __mutex_lock_slowpath+0xdb/0x247
[<c027af49>] mutex_lock+0x1c/0x1f
[<c023717d>] genl_lock+0xd/0xf
[<c023806f>] ctrl_dumpfamily+0x20/0xdd
---> takes genl_mutex
[<c0234bfa>] netlink_dump+0x50/0x168
---> takes cb_mutex
[<c02360f2>] netlink_recvmsg+0x15f/0x22f
[<c021a84a>] sock_recvmsg+0xd5/0xee
[<c021b24e>] sys_recvmsg+0xf5/0x187
[<c021b865>] sys_socketcall+0x218/0x222
[<c01025d2>] syscall_call+0x7/0xb
[<ffffffff>] 0xffffffff
The "trylock" in genl_rcv doesn't prevent the deadlock, because
it's not the last lock acquired. Perhaps this can be fixed by
not acquiring the genl_mutex in ctrl_dumpfamily; it silences
lockdep, at least. It is not clear to me what the value of
taking the mutex is there.
If this is an appropriate fix, here is a patch for it.
Signed-off-by: Ben Pfaff <blp@nicira.com>
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c
index 8c11ca4..2e79035 100644
--- a/net/netlink/genetlink.c
+++ b/net/netlink/genetlink.c
@@ -616,9 +616,6 @@ static int ctrl_dumpfamily(struct sk_buff *skb, struct netlink_callback *cb)
int chains_to_skip = cb->args[0];
int fams_to_skip = cb->args[1];
- if (chains_to_skip != 0)
- genl_lock();
-
for (i = 0; i < GENL_FAM_TAB_SIZE; i++) {
if (i < chains_to_skip)
continue;
@@ -636,9 +633,6 @@ static int ctrl_dumpfamily(struct sk_buff *skb, struct netlink_callback *cb)
}
errout:
- if (chains_to_skip != 0)
- genl_unlock();
-
cb->args[0] = i;
cb->args[1] = n;
--
Ben Pfaff
Nicira Networks, Inc.
^ permalink raw reply related
* [PATCH 6/9] fs_enet: Be an of_platform device when CONFIG_PPC_CPM_NEW_BINDING is set.
From: Scott Wood @ 2007-09-24 20:08 UTC (permalink / raw)
To: jgarzik; +Cc: netdev, linuxppc-dev
The existing OF glue code was crufty and broken. Rather than fix it, it
will be removed, and the ethernet driver now talks to the device tree
directly.
The old, non-CONFIG_PPC_CPM_NEW_BINDING code can go away once CPM
platforms are dropped from arch/ppc (which will hopefully be soon), and
existing arch/powerpc boards that I wasn't able to test on for this
patchset get converted (which should be even sooner).
Signed-off-by: Scott Wood <scottwood@freescale.com>
---
Resent, with linux/of_platform.h instead of asm/of_platform.h
drivers/net/fs_enet/Kconfig | 1 +
drivers/net/fs_enet/fs_enet-main.c | 259 ++++++++++++++++++++++++++++++++---
drivers/net/fs_enet/fs_enet.h | 55 +-------
drivers/net/fs_enet/mac-fcc.c | 89 +++++++++----
drivers/net/fs_enet/mac-fec.c | 19 +++-
drivers/net/fs_enet/mac-scc.c | 53 +++++--
drivers/net/fs_enet/mii-bitbang.c | 269 +++++++++++++++++++++++++++---------
drivers/net/fs_enet/mii-fec.c | 143 +++++++++++++++++++-
include/linux/fs_enet_pd.h | 5 +
9 files changed, 714 insertions(+), 179 deletions(-)
diff --git a/drivers/net/fs_enet/Kconfig b/drivers/net/fs_enet/Kconfig
index e27ee21..2765e49 100644
--- a/drivers/net/fs_enet/Kconfig
+++ b/drivers/net/fs_enet/Kconfig
@@ -11,6 +11,7 @@ config FS_ENET_HAS_SCC
config FS_ENET_HAS_FCC
bool "Chip has an FCC usable for ethernet"
depends on FS_ENET && CPM2
+ select MDIO_BITBANG
default y
config FS_ENET_HAS_FEC
diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c
index a4b76cd..c5abdea 100644
--- a/drivers/net/fs_enet/fs_enet-main.c
+++ b/drivers/net/fs_enet/fs_enet-main.c
@@ -44,12 +44,18 @@
#include <asm/irq.h>
#include <asm/uaccess.h>
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+#include <linux/of_platform.h>
+#endif
+
#include "fs_enet.h"
/*************************************************/
+#ifndef CONFIG_PPC_CPM_NEW_BINDING
static char version[] __devinitdata =
DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")" "\n";
+#endif
MODULE_AUTHOR("Pantelis Antoniou <panto@intracom.gr>");
MODULE_DESCRIPTION("Freescale Ethernet Driver");
@@ -953,6 +959,7 @@ static int fs_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
extern int fs_mii_connect(struct net_device *dev);
extern void fs_mii_disconnect(struct net_device *dev);
+#ifndef CONFIG_PPC_CPM_NEW_BINDING
static struct net_device *fs_init_instance(struct device *dev,
struct fs_platform_info *fpi)
{
@@ -1132,6 +1139,7 @@ static int fs_cleanup_instance(struct net_device *ndev)
return 0;
}
+#endif
/**************************************************************************************/
@@ -1140,35 +1148,250 @@ void *fs_enet_immap = NULL;
static int setup_immap(void)
{
- phys_addr_t paddr = 0;
- unsigned long size = 0;
-
#ifdef CONFIG_CPM1
- paddr = IMAP_ADDR;
- size = 0x10000; /* map 64K */
-#endif
-
-#ifdef CONFIG_CPM2
- paddr = CPM_MAP_ADDR;
- size = 0x40000; /* map 256 K */
+ fs_enet_immap = ioremap(IMAP_ADDR, 0x4000);
+ WARN_ON(!fs_enet_immap);
+#elif defined(CONFIG_CPM2)
+ fs_enet_immap = cpm2_immr;
#endif
- fs_enet_immap = ioremap(paddr, size);
- if (fs_enet_immap == NULL)
- return -EBADF; /* XXX ahem; maybe just BUG_ON? */
return 0;
}
static void cleanup_immap(void)
{
- if (fs_enet_immap != NULL) {
- iounmap(fs_enet_immap);
- fs_enet_immap = NULL;
- }
+#if defined(CONFIG_CPM1)
+ iounmap(fs_enet_immap);
+#endif
}
/**************************************************************************************/
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+static int __devinit find_phy(struct device_node *np,
+ struct fs_platform_info *fpi)
+{
+ struct device_node *phynode, *mdionode;
+ struct resource res;
+ int ret = 0, len;
+
+ const u32 *data = of_get_property(np, "phy-handle", &len);
+ if (!data || len != 4)
+ return -EINVAL;
+
+ phynode = of_find_node_by_phandle(*data);
+ if (!phynode)
+ return -EINVAL;
+
+ mdionode = of_get_parent(phynode);
+ if (!phynode)
+ goto out_put_phy;
+
+ ret = of_address_to_resource(mdionode, 0, &res);
+ if (ret)
+ goto out_put_mdio;
+
+ data = of_get_property(phynode, "reg", &len);
+ if (!data || len != 4)
+ goto out_put_mdio;
+
+ snprintf(fpi->bus_id, 16, PHY_ID_FMT, res.start, *data);
+
+out_put_mdio:
+ of_node_put(mdionode);
+out_put_phy:
+ of_node_put(phynode);
+ return ret;
+}
+
+#ifdef CONFIG_FS_ENET_HAS_FEC
+#define IS_FEC(match) ((match)->data == &fs_fec_ops)
+#else
+#define IS_FEC(match) 0
+#endif
+
+static int __devinit fs_enet_probe(struct of_device *ofdev,
+ const struct of_device_id *match)
+{
+ struct net_device *ndev;
+ struct fs_enet_private *fep;
+ struct fs_platform_info *fpi;
+ const u32 *data;
+ const u8 *mac_addr;
+ int privsize, len, ret = -ENODEV;
+
+ fpi = kzalloc(sizeof(*fpi), GFP_KERNEL);
+ if (!fpi)
+ return -ENOMEM;
+
+ if (!IS_FEC(match)) {
+ data = of_get_property(ofdev->node, "fsl,cpm-command", &len);
+ if (!data || len != 4)
+ goto out_free_fpi;
+
+ fpi->cp_command = *data;
+ }
+
+ fpi->rx_ring = 32;
+ fpi->tx_ring = 32;
+ fpi->rx_copybreak = 240;
+ fpi->use_napi = 0;
+ fpi->napi_weight = 17;
+
+ ret = find_phy(ofdev->node, fpi);
+ if (ret)
+ goto out_free_fpi;
+
+ privsize = sizeof(*fep) +
+ sizeof(struct sk_buff **) *
+ (fpi->rx_ring + fpi->tx_ring);
+
+ ndev = alloc_etherdev(privsize);
+ if (!ndev) {
+ ret = -ENOMEM;
+ goto out_free_fpi;
+ }
+
+ SET_MODULE_OWNER(ndev);
+ dev_set_drvdata(&ofdev->dev, ndev);
+
+ fep = netdev_priv(ndev);
+ fep->dev = &ofdev->dev;
+ fep->fpi = fpi;
+ fep->ops = match->data;
+
+ ret = fep->ops->setup_data(ndev);
+ if (ret)
+ goto out_free_dev;
+
+ fep->rx_skbuff = (struct sk_buff **)&fep[1];
+ fep->tx_skbuff = fep->rx_skbuff + fpi->rx_ring;
+
+ spin_lock_init(&fep->lock);
+ spin_lock_init(&fep->tx_lock);
+
+ mac_addr = of_get_mac_address(ofdev->node);
+ if (mac_addr)
+ memcpy(ndev->dev_addr, mac_addr, 6);
+
+ ret = fep->ops->allocate_bd(ndev);
+ if (ret)
+ goto out_cleanup_data;
+
+ fep->rx_bd_base = fep->ring_base;
+ fep->tx_bd_base = fep->rx_bd_base + fpi->rx_ring;
+
+ fep->tx_ring = fpi->tx_ring;
+ fep->rx_ring = fpi->rx_ring;
+
+ ndev->open = fs_enet_open;
+ ndev->hard_start_xmit = fs_enet_start_xmit;
+ ndev->tx_timeout = fs_timeout;
+ ndev->watchdog_timeo = 2 * HZ;
+ ndev->stop = fs_enet_close;
+ ndev->get_stats = fs_enet_get_stats;
+ ndev->set_multicast_list = fs_set_multicast_list;
+ if (fpi->use_napi) {
+ ndev->poll = fs_enet_rx_napi;
+ ndev->weight = fpi->napi_weight;
+ }
+ ndev->ethtool_ops = &fs_ethtool_ops;
+ ndev->do_ioctl = fs_ioctl;
+
+ init_timer(&fep->phy_timer_list);
+
+ netif_carrier_off(ndev);
+
+ ret = register_netdev(ndev);
+ if (ret)
+ goto out_free_bd;
+
+ printk(KERN_INFO "%s: fs_enet: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ ndev->name,
+ ndev->dev_addr[0], ndev->dev_addr[1], ndev->dev_addr[2],
+ ndev->dev_addr[3], ndev->dev_addr[4], ndev->dev_addr[5]);
+
+ return 0;
+
+out_free_bd:
+ fep->ops->free_bd(ndev);
+out_cleanup_data:
+ fep->ops->cleanup_data(ndev);
+out_free_dev:
+ free_netdev(ndev);
+ dev_set_drvdata(&ofdev->dev, NULL);
+out_free_fpi:
+ kfree(fpi);
+ return ret;
+}
+
+static int fs_enet_remove(struct of_device *ofdev)
+{
+ struct net_device *ndev = dev_get_drvdata(&ofdev->dev);
+ struct fs_enet_private *fep = netdev_priv(ndev);
+
+ unregister_netdev(ndev);
+
+ fep->ops->free_bd(ndev);
+ fep->ops->cleanup_data(ndev);
+ dev_set_drvdata(fep->dev, NULL);
+
+ free_netdev(ndev);
+ return 0;
+}
+
+static struct of_device_id fs_enet_match[] = {
+#ifdef CONFIG_FS_ENET_HAS_SCC
+ {
+ .compatible = "fsl,cpm1-scc-enet",
+ .data = (void *)&fs_scc_ops,
+ },
+#endif
+#ifdef CONFIG_FS_ENET_HAS_FCC
+ {
+ .compatible = "fsl,cpm2-fcc-enet",
+ .data = (void *)&fs_fcc_ops,
+ },
+#endif
+#ifdef CONFIG_FS_ENET_HAS_FEC
+ {
+ .compatible = "fsl,pq1-fec-enet",
+ .data = (void *)&fs_fec_ops,
+ },
+#endif
+ {}
+};
+
+static struct of_platform_driver fs_enet_driver = {
+ .name = "fs_enet",
+ .match_table = fs_enet_match,
+ .probe = fs_enet_probe,
+ .remove = fs_enet_remove,
+};
+
+static int __init fs_init(void)
+{
+ int r = setup_immap();
+ if (r != 0)
+ return r;
+
+ r = of_register_platform_driver(&fs_enet_driver);
+ if (r != 0)
+ goto out;
+
+ return 0;
+
+out:
+ cleanup_immap();
+ return r;
+}
+
+static void __exit fs_cleanup(void)
+{
+ of_unregister_platform_driver(&fs_enet_driver);
+ cleanup_immap();
+}
+#else
static int __devinit fs_enet_probe(struct device *dev)
{
struct net_device *ndev;
@@ -1282,7 +1505,7 @@ static void __exit fs_cleanup(void)
driver_unregister(&fs_enet_scc_driver);
cleanup_immap();
}
-
+#endif
/**************************************************************************************/
module_init(fs_init);
diff --git a/drivers/net/fs_enet/fs_enet.h b/drivers/net/fs_enet/fs_enet.h
index f8c7ee8..14ebba8 100644
--- a/drivers/net/fs_enet/fs_enet.h
+++ b/drivers/net/fs_enet/fs_enet.h
@@ -24,19 +24,6 @@ struct fec_info {
#include <asm/cpm2.h>
#endif
-/* This is used to operate with pins.
- Note that the actual port size may
- be different; cpm(s) handle it OK */
-struct bb_info {
- u8 mdio_dat_msk;
- u8 mdio_dir_msk;
- u8 *mdio_dir;
- u8 *mdio_dat;
- u8 mdc_msk;
- u8 *mdc_dat;
- int delay;
-};
-
/* hw driver ops */
struct fs_ops {
int (*setup_data)(struct net_device *dev);
@@ -85,47 +72,11 @@ struct phy_info {
#define ENET_RX_ALIGN 16
#define ENET_RX_FRSIZE L1_CACHE_ALIGN(PKT_MAXBUF_SIZE + ENET_RX_ALIGN - 1)
-struct fs_enet_mii_bus {
- struct list_head list;
- spinlock_t mii_lock;
- const struct fs_mii_bus_info *bus_info;
- int refs;
- u32 usage_map;
-
- int (*mii_read)(struct fs_enet_mii_bus *bus,
- int phy_id, int location);
-
- void (*mii_write)(struct fs_enet_mii_bus *bus,
- int phy_id, int location, int value);
-
- union {
- struct {
- unsigned int mii_speed;
- void *fecp;
- } fec;
-
- struct {
- /* note that the actual port size may */
- /* be different; cpm(s) handle it OK */
- u8 mdio_msk;
- u8 *mdio_dir;
- u8 *mdio_dat;
- u8 mdc_msk;
- u8 *mdc_dir;
- u8 *mdc_dat;
- } bitbang;
-
- struct {
- u16 lpa;
- } fixed;
- };
-};
-
struct fs_enet_private {
struct device *dev; /* pointer back to the device (must be initialized first) */
spinlock_t lock; /* during all ops except TX pckt processing */
spinlock_t tx_lock; /* during fs_start_xmit and fs_tx */
- const struct fs_platform_info *fpi;
+ struct fs_platform_info *fpi;
const struct fs_ops *ops;
int rx_ring, tx_ring;
dma_addr_t ring_mem_addr;
@@ -144,7 +95,6 @@ struct fs_enet_private {
u32 msg_enable;
struct mii_if_info mii_if;
unsigned int last_mii_status;
- struct fs_enet_mii_bus *mii_bus;
int interrupt;
struct phy_device *phydev;
@@ -186,9 +136,10 @@ struct fs_enet_private {
};
/***************************************************************************/
+#ifndef CONFIG_PPC_CPM_NEW_BINDING
int fs_enet_mdio_bb_init(void);
-int fs_mii_fixed_init(struct fs_enet_mii_bus *bus);
int fs_enet_mdio_fec_init(void);
+#endif
void fs_init_bds(struct net_device *dev);
void fs_cleanup_bds(struct net_device *dev);
diff --git a/drivers/net/fs_enet/mac-fcc.c b/drivers/net/fs_enet/mac-fcc.c
index 8b30361..dc943fd 100644
--- a/drivers/net/fs_enet/mac-fcc.c
+++ b/drivers/net/fs_enet/mac-fcc.c
@@ -42,6 +42,10 @@
#include <asm/irq.h>
#include <asm/uaccess.h>
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+#include <linux/of_device.h>
+#endif
+
#include "fs_enet.h"
/*************************************************/
@@ -74,33 +78,64 @@
#define MAX_CR_CMD_LOOPS 10000
-static inline int fcc_cr_cmd(struct fs_enet_private *fep, u32 mcn, u32 op)
+static inline int fcc_cr_cmd(struct fs_enet_private *fep, u32 op)
{
const struct fs_platform_info *fpi = fep->fpi;
cpm2_map_t *immap = fs_enet_immap;
cpm_cpm2_t *cpmp = &immap->im_cpm;
- u32 v;
int i;
- /* Currently I don't know what feature call will look like. But
- I guess there'd be something like do_cpm_cmd() which will require page & sblock */
- v = mk_cr_cmd(fpi->cp_page, fpi->cp_block, mcn, op);
- W32(cpmp, cp_cpcr, v | CPM_CR_FLG);
+ W32(cpmp, cp_cpcr, fpi->cp_command | op | CPM_CR_FLG);
for (i = 0; i < MAX_CR_CMD_LOOPS; i++)
if ((R32(cpmp, cp_cpcr) & CPM_CR_FLG) == 0)
- break;
-
- if (i >= MAX_CR_CMD_LOOPS) {
- printk(KERN_ERR "%s(): Not able to issue CPM command\n",
- __FUNCTION__);
- return 1;
- }
+ return 0;
- return 0;
+ printk(KERN_ERR "%s(): Not able to issue CPM command\n",
+ __FUNCTION__);
+ return 1;
}
static int do_pd_setup(struct fs_enet_private *fep)
{
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+ struct of_device *ofdev = to_of_device(fep->dev);
+ struct fs_platform_info *fpi = fep->fpi;
+ int ret = -EINVAL;
+
+ fep->interrupt = of_irq_to_resource(ofdev->node, 0, NULL);
+ if (fep->interrupt == NO_IRQ)
+ goto out;
+
+ fep->fcc.fccp = of_iomap(ofdev->node, 0);
+ if (!fep->fcc.fccp)
+ goto out;
+
+ fep->fcc.ep = of_iomap(ofdev->node, 1);
+ if (!fep->fcc.ep)
+ goto out_fccp;
+
+ fep->fcc.fcccp = of_iomap(ofdev->node, 2);
+ if (!fep->fcc.fcccp)
+ goto out_ep;
+
+ fep->fcc.mem = (void *)cpm_dpalloc(128, 8);
+ fpi->dpram_offset = (u32)cpm2_immr;
+ if (IS_ERR_VALUE(fpi->dpram_offset)) {
+ ret = fpi->dpram_offset;
+ goto out_fcccp;
+ }
+
+ return 0;
+
+out_fcccp:
+ iounmap(fep->fcc.fcccp);
+out_ep:
+ iounmap(fep->fcc.ep);
+out_fccp:
+ iounmap(fep->fcc.fccp);
+out:
+ return ret;
+#else
struct platform_device *pdev = to_platform_device(fep->dev);
struct resource *r;
@@ -138,6 +173,7 @@ static int do_pd_setup(struct fs_enet_private *fep)
return -EINVAL;
return 0;
+#endif
}
#define FCC_NAPI_RX_EVENT_MSK (FCC_ENET_RXF | FCC_ENET_RXB)
@@ -148,11 +184,17 @@ static int do_pd_setup(struct fs_enet_private *fep)
static int setup_data(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- const struct fs_platform_info *fpi = fep->fpi;
+#ifndef CONFIG_PPC_CPM_NEW_BINDING
+ struct fs_platform_info *fpi = fep->fpi;
+
+ fpi->cp_command = (fpi->cp_page << 26) |
+ (fpi->cp_block << 21) |
+ (12 << 6);
fep->fcc.idx = fs_get_fcc_index(fpi->fs_no);
if ((unsigned int)fep->fcc.idx >= 3) /* max 3 FCCs */
return -EINVAL;
+#endif
if (do_pd_setup(fep) != 0)
return -EINVAL;
@@ -226,7 +268,7 @@ static void set_multicast_one(struct net_device *dev, const u8 *mac)
W16(ep, fen_taddrh, taddrh);
W16(ep, fen_taddrm, taddrm);
W16(ep, fen_taddrl, taddrl);
- fcc_cr_cmd(fep, 0x0C, CPM_CR_SET_GADDR);
+ fcc_cr_cmd(fep, CPM_CR_SET_GADDR);
}
static void set_multicast_finish(struct net_device *dev)
@@ -281,7 +323,7 @@ static void restart(struct net_device *dev)
/* clear everything (slow & steady does it) */
for (i = 0; i < sizeof(*ep); i++)
- out_8((char *)ep + i, 0);
+ out_8((u8 __iomem *)ep + i, 0);
/* get physical address */
rx_bd_base_phys = fep->ring_mem_addr;
@@ -397,7 +439,7 @@ static void restart(struct net_device *dev)
S8(fcccp, fcc_gfemr, 0x20);
}
- fcc_cr_cmd(fep, 0x0c, CPM_CR_INIT_TRX);
+ fcc_cr_cmd(fep, CPM_CR_INIT_TRX);
/* clear events */
W16(fccp, fcc_fcce, 0xffff);
@@ -515,23 +557,22 @@ int get_regs(struct net_device *dev, void *p, int *sizep)
{
struct fs_enet_private *fep = netdev_priv(dev);
- if (*sizep < sizeof(fcc_t) + sizeof(fcc_c_t) + sizeof(fcc_enet_t))
+ if (*sizep < sizeof(fcc_t) + sizeof(fcc_enet_t) + 1)
return -EINVAL;
memcpy_fromio(p, fep->fcc.fccp, sizeof(fcc_t));
p = (char *)p + sizeof(fcc_t);
- memcpy_fromio(p, fep->fcc.fcccp, sizeof(fcc_c_t));
- p = (char *)p + sizeof(fcc_c_t);
-
memcpy_fromio(p, fep->fcc.ep, sizeof(fcc_enet_t));
+ p = (char *)p + sizeof(fcc_enet_t);
+ memcpy_fromio(p, fep->fcc.fcccp, 1);
return 0;
}
int get_regs_len(struct net_device *dev)
{
- return sizeof(fcc_t) + sizeof(fcc_c_t) + sizeof(fcc_enet_t);
+ return sizeof(fcc_t) + sizeof(fcc_enet_t) + 1;
}
/* Some transmit errors cause the transmitter to shut
@@ -551,7 +592,7 @@ void tx_restart(struct net_device *dev)
udelay(10);
S32(fccp, fcc_gfmr, FCC_GFMR_ENT);
- fcc_cr_cmd(fep, 0x0C, CPM_CR_RESTART_TX);
+ fcc_cr_cmd(fep, CPM_CR_RESTART_TX);
}
/*************************************************************************/
diff --git a/drivers/net/fs_enet/mac-fec.c b/drivers/net/fs_enet/mac-fec.c
index 04b4f80..7477da0 100644
--- a/drivers/net/fs_enet/mac-fec.c
+++ b/drivers/net/fs_enet/mac-fec.c
@@ -43,6 +43,10 @@
#include <asm/commproc.h>
#endif
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+#include <linux/of_device.h>
+#endif
+
#include "fs_enet.h"
#include "fec.h"
@@ -95,6 +99,19 @@ static int whack_reset(fec_t * fecp)
static int do_pd_setup(struct fs_enet_private *fep)
{
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+ struct of_device *ofdev = to_of_device(fep->dev);
+
+ fep->interrupt = of_irq_to_resource(ofdev->node, 0, NULL);
+ if (fep->interrupt == NO_IRQ)
+ return -EINVAL;
+
+ fep->fec.fecp = of_iomap(ofdev->node, 0);
+ if (!fep->fcc.fccp)
+ return -EINVAL;
+
+ return 0;
+#else
struct platform_device *pdev = to_platform_device(fep->dev);
struct resource *r;
@@ -110,7 +127,7 @@ static int do_pd_setup(struct fs_enet_private *fep)
return -EINVAL;
return 0;
-
+#endif
}
#define FEC_NAPI_RX_EVENT_MSK (FEC_ENET_RXF | FEC_ENET_RXB)
diff --git a/drivers/net/fs_enet/mac-scc.c b/drivers/net/fs_enet/mac-scc.c
index 7540966..59e0d1d 100644
--- a/drivers/net/fs_enet/mac-scc.c
+++ b/drivers/net/fs_enet/mac-scc.c
@@ -43,6 +43,10 @@
#include <asm/commproc.h>
#endif
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+#include <linux/of_platform.h>
+#endif
+
#include "fs_enet.h"
/*************************************************/
@@ -89,27 +93,38 @@
static inline int scc_cr_cmd(struct fs_enet_private *fep, u32 op)
{
- cpm8xx_t *cpmp = &((immap_t *)fs_enet_immap)->im_cpm;
- u32 v, ch;
- int i = 0;
+ const struct fs_platform_info *fpi = fep->fpi;
+ int i;
- ch = fep->scc.idx << 2;
- v = mk_cr_cmd(ch, op);
- W16(cpmp, cp_cpcr, v | CPM_CR_FLG);
+ W16(cpmp, cp_cpcr, fpi->cp_command | CPM_CR_FLG | (op << 8));
for (i = 0; i < MAX_CR_CMD_LOOPS; i++)
if ((R16(cpmp, cp_cpcr) & CPM_CR_FLG) == 0)
- break;
+ return 0;
- if (i >= MAX_CR_CMD_LOOPS) {
- printk(KERN_ERR "%s(): Not able to issue CPM command\n",
- __FUNCTION__);
- return 1;
- }
- return 0;
+ printk(KERN_ERR "%s(): Not able to issue CPM command\n",
+ __FUNCTION__);
+ return 1;
}
static int do_pd_setup(struct fs_enet_private *fep)
{
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+ struct of_device *ofdev = to_of_device(fep->dev);
+
+ fep->interrupt = of_irq_to_resource(ofdev->node, 0, NULL);
+ if (fep->interrupt == NO_IRQ)
+ return -EINVAL;
+
+ fep->scc.sccp = of_iomap(ofdev->node, 0);
+ if (!fep->scc.sccp)
+ return -EINVAL;
+
+ fep->scc.ep = of_iomap(ofdev->node, 1);
+ if (!fep->scc.ep) {
+ iounmap(fep->scc.sccp);
+ return -EINVAL;
+ }
+#else
struct platform_device *pdev = to_platform_device(fep->dev);
struct resource *r;
@@ -129,6 +144,7 @@ static int do_pd_setup(struct fs_enet_private *fep)
if (fep->scc.ep == NULL)
return -EINVAL;
+#endif
return 0;
}
@@ -141,12 +157,17 @@ static int do_pd_setup(struct fs_enet_private *fep)
static int setup_data(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- const struct fs_platform_info *fpi = fep->fpi;
+
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+ struct fs_platform_info *fpi = fep->fpi;
fep->scc.idx = fs_get_scc_index(fpi->fs_no);
- if ((unsigned int)fep->fcc.idx > 4) /* max 4 SCCs */
+ if ((unsigned int)fep->fcc.idx >= 4) /* max 4 SCCs */
return -EINVAL;
+ fpi->cp_command = fep->fcc.idx << 6;
+#endif
+
do_pd_setup(fep);
fep->scc.hthi = 0;
@@ -154,7 +175,7 @@ static int setup_data(struct net_device *dev)
fep->ev_napi_rx = SCC_NAPI_RX_EVENT_MSK;
fep->ev_rx = SCC_RX_EVENT;
- fep->ev_tx = SCC_TX_EVENT;
+ fep->ev_tx = SCC_TX_EVENT | SCCE_ENET_TXE;
fep->ev_err = SCC_ERR_EVENT_MSK;
return 0;
diff --git a/drivers/net/fs_enet/mii-bitbang.c b/drivers/net/fs_enet/mii-bitbang.c
index 8f766a5..2b9c44c 100644
--- a/drivers/net/fs_enet/mii-bitbang.c
+++ b/drivers/net/fs_enet/mii-bitbang.c
@@ -13,11 +13,6 @@
*/
#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/ptrace.h>
-#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
@@ -25,86 +20,77 @@
#include <linux/delay.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/spinlock.h>
#include <linux/mii.h>
#include <linux/ethtool.h>
#include <linux/bitops.h>
#include <linux/platform_device.h>
-#include <asm/pgtable.h>
-#include <asm/irq.h>
-#include <asm/uaccess.h>
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+#include <linux/of_platform.h>
+#endif
#include "fs_enet.h"
-static int bitbang_prep_bit(u8 **datp, u8 *mskp,
- struct fs_mii_bit *mii_bit)
-{
- void *dat;
- int adv;
- u8 msk;
-
- dat = (void*) mii_bit->offset;
-
- adv = mii_bit->bit >> 3;
- dat = (char *)dat + adv;
-
- msk = 1 << (7 - (mii_bit->bit & 7));
-
- *datp = dat;
- *mskp = msk;
-
- return 0;
-}
+struct bb_info {
+ __be32 __iomem *dir;
+ __be32 __iomem *dat;
+ u32 mdio_msk;
+ u32 mdc_msk;
+ int delay;
+};
-static inline void bb_set(u8 *p, u8 m)
+/* FIXME: If any other users of GPIO crop up, then these will have to
+ * have some sort of global synchronization to avoid races with other
+ * pins on the same port. The ideal solution would probably be to
+ * bind the ports to a GPIO driver, and have this be a client of it.
+ */
+static inline void bb_set(u32 __iomem *p, u32 m)
{
- out_8(p, in_8(p) | m);
+ out_be32(p, in_be32(p) | m);
}
-static inline void bb_clr(u8 *p, u8 m)
+static inline void bb_clr(u32 __iomem *p, u32 m)
{
- out_8(p, in_8(p) & ~m);
+ out_be32(p, in_be32(p) & ~m);
}
-static inline int bb_read(u8 *p, u8 m)
+static inline int bb_read(u32 __iomem *p, u32 m)
{
- return (in_8(p) & m) != 0;
+ return (in_be32(p) & m) != 0;
}
static inline void mdio_active(struct bb_info *bitbang)
{
- bb_set(bitbang->mdio_dir, bitbang->mdio_dir_msk);
+ bb_set(bitbang->dir, bitbang->mdio_msk);
}
-static inline void mdio_tristate(struct bb_info *bitbang )
+static inline void mdio_tristate(struct bb_info *bitbang)
{
- bb_clr(bitbang->mdio_dir, bitbang->mdio_dir_msk);
+ bb_clr(bitbang->dir, bitbang->mdio_msk);
}
-static inline int mdio_read(struct bb_info *bitbang )
+static inline int mdio_read(struct bb_info *bitbang)
{
- return bb_read(bitbang->mdio_dat, bitbang->mdio_dat_msk);
+ return bb_read(bitbang->dat, bitbang->mdio_msk);
}
-static inline void mdio(struct bb_info *bitbang , int what)
+static inline void mdio(struct bb_info *bitbang, int what)
{
if (what)
- bb_set(bitbang->mdio_dat, bitbang->mdio_dat_msk);
+ bb_set(bitbang->dat, bitbang->mdio_msk);
else
- bb_clr(bitbang->mdio_dat, bitbang->mdio_dat_msk);
+ bb_clr(bitbang->dat, bitbang->mdio_msk);
}
-static inline void mdc(struct bb_info *bitbang , int what)
+static inline void mdc(struct bb_info *bitbang, int what)
{
if (what)
- bb_set(bitbang->mdc_dat, bitbang->mdc_msk);
+ bb_set(bitbang->dat, bitbang->mdc_msk);
else
- bb_clr(bitbang->mdc_dat, bitbang->mdc_msk);
+ bb_clr(bitbang->dat, bitbang->mdc_msk);
}
-static inline void mii_delay(struct bb_info *bitbang )
+static inline void mii_delay(struct bb_info *bitbang)
{
udelay(bitbang->delay);
}
@@ -280,29 +266,178 @@ static int fs_enet_mii_bb_reset(struct mii_bus *bus)
return 0;
}
-static int fs_mii_bitbang_init(struct bb_info *bitbang, struct fs_mii_bb_platform_info* fmpi)
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+static int __devinit fs_mii_bitbang_init(struct mii_bus *bus,
+ struct device_node *np)
{
- int r;
+ struct resource res;
+ const u32 *data;
+ int mdio_pin, mdc_pin, len;
+ struct bb_info *bitbang = bus->priv;
- bitbang->delay = fmpi->delay;
+ int ret = of_address_to_resource(np, 0, &res);
+ if (ret)
+ return ret;
+
+ if (res.end - res.start < 13)
+ return -ENODEV;
+
+ /* This should really encode the pin number as well, but all
+ * we get is an int, and the odds of multiple bitbang mdio buses
+ * is low enough that it's not worth going too crazy.
+ */
+ bus->id = res.start;
+
+ data = of_get_property(np, "fsl,mdio-pin", &len);
+ if (!data || len != 4)
+ return -ENODEV;
+ mdio_pin = *data;
+
+ data = of_get_property(np, "fsl,mdc-pin", &len);
+ if (!data || len != 4)
+ return -ENODEV;
+ mdc_pin = *data;
+
+ bitbang->dir = ioremap(res.start, res.end - res.start + 1);
+ if (!bitbang->dir)
+ return -ENOMEM;
+
+ bitbang->dat = bitbang->dir + 4;
+ bitbang->mdio_msk = 1 << (31 - mdio_pin);
+ bitbang->mdc_msk = 1 << (31 - mdc_pin);
+ bitbang->delay = 1; /* 1 us between operations */
- r = bitbang_prep_bit(&bitbang->mdio_dir,
- &bitbang->mdio_dir_msk,
- &fmpi->mdio_dir);
- if (r != 0)
- return r;
-
- r = bitbang_prep_bit(&bitbang->mdio_dat,
- &bitbang->mdio_dat_msk,
- &fmpi->mdio_dat);
- if (r != 0)
- return r;
-
- r = bitbang_prep_bit(&bitbang->mdc_dat,
- &bitbang->mdc_msk,
- &fmpi->mdc_dat);
- if (r != 0)
- return r;
+ return 0;
+}
+
+static void __devinit add_phy(struct mii_bus *bus, struct device_node *np)
+{
+ const u32 *data;
+ int len, id, irq;
+
+ data = of_get_property(np, "reg", &len);
+ if (!data || len != 4)
+ return;
+
+ id = *data;
+ bus->phy_mask &= ~(1 << id);
+
+ irq = of_irq_to_resource(np, 0, NULL);
+ if (irq != NO_IRQ)
+ bus->irq[id] = irq;
+}
+
+static int __devinit fs_enet_mdio_probe(struct of_device *ofdev,
+ const struct of_device_id *match)
+{
+ struct device_node *np = NULL;
+ struct mii_bus *new_bus;
+ struct bb_info *bitbang;
+ int ret = -ENOMEM;
+ int i;
+
+ new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL);
+ if (!new_bus)
+ goto out;
+
+ bitbang = kzalloc(sizeof(struct bb_info), GFP_KERNEL);
+ if (!bitbang)
+ goto out_free_bus;
+
+ new_bus->priv = bitbang;
+ new_bus->name = "CPM2 Bitbanged MII",
+ new_bus->read = &fs_enet_mii_bb_read,
+ new_bus->write = &fs_enet_mii_bb_write,
+ new_bus->reset = &fs_enet_mii_bb_reset,
+
+ ret = fs_mii_bitbang_init(new_bus, ofdev->node);
+ if (ret)
+ goto out_free_bitbang;
+
+ new_bus->phy_mask = ~0;
+ new_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
+ if (!new_bus->irq)
+ goto out_unmap_regs;
+
+ for (i = 0; i < PHY_MAX_ADDR; i++)
+ new_bus->irq[i] = -1;
+
+ while ((np = of_get_next_child(ofdev->node, np)))
+ if (!strcmp(np->type, "ethernet-phy"))
+ add_phy(new_bus, np);
+
+ new_bus->dev = &ofdev->dev;
+ dev_set_drvdata(&ofdev->dev, new_bus);
+
+ ret = mdiobus_register(new_bus);
+ if (ret)
+ goto out_free_irqs;
+
+ return 0;
+
+out_free_irqs:
+ dev_set_drvdata(&ofdev->dev, NULL);
+ kfree(new_bus->irq);
+out_unmap_regs:
+ iounmap(bitbang->dir);
+out_free_bitbang:
+ kfree(bitbang);
+out_free_bus:
+ kfree(new_bus);
+out:
+ return ret;
+}
+
+static int fs_enet_mdio_remove(struct of_device *ofdev)
+{
+ struct mii_bus *bus = dev_get_drvdata(&ofdev->dev);
+ struct bb_info *bitbang = bus->priv;
+
+ mdiobus_unregister(bus);
+ dev_set_drvdata(&ofdev->dev, NULL);
+ kfree(bus->irq);
+ iounmap(bitbang->dir);
+ kfree(bitbang);
+ kfree(bus);
+
+ return 0;
+}
+
+static struct of_device_id fs_enet_mdio_bb_match[] = {
+ {
+ .compatible = "fsl,cpm2-mdio-bitbang",
+ },
+ {},
+};
+
+static struct of_platform_driver fs_enet_bb_mdio_driver = {
+ .name = "fsl-bb-mdio",
+ .match_table = fs_enet_mdio_bb_match,
+ .probe = fs_enet_mdio_probe,
+ .remove = fs_enet_mdio_remove,
+};
+
+int fs_enet_mdio_bb_init(void)
+{
+ return of_register_platform_driver(&fs_enet_bb_mdio_driver);
+}
+
+void fs_enet_mdio_bb_exit(void)
+{
+ of_unregister_platform_driver(&fs_enet_bb_mdio_driver);
+}
+
+module_init(fs_enet_mdio_bb_init);
+module_exit(fs_enet_mdio_bb_exit);
+#else
+static int __devinit fs_mii_bitbang_init(struct bb_info *bitbang,
+ struct fs_mii_bb_platform_info *fmpi)
+{
+ bitbang->dir = (u32 __iomem *)fmpi->mdio_dir.offset;
+ bitbang->dat = (u32 __iomem *)fmpi->mdio_dat.offset;
+ bitbang->mdio_msk = 1U << (31 - fmpi->mdio_dat.bit);
+ bitbang->mdc_msk = 1U << (31 - fmpi->mdc_dat.bit);
+ bitbang->delay = fmpi->delay;
return 0;
}
diff --git a/drivers/net/fs_enet/mii-fec.c b/drivers/net/fs_enet/mii-fec.c
index 53db696..07b6f20 100644
--- a/drivers/net/fs_enet/mii-fec.c
+++ b/drivers/net/fs_enet/mii-fec.c
@@ -36,6 +36,10 @@
#include <asm/irq.h>
#include <asm/uaccess.h>
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+#include <linux/of_platform.h>
+#endif
+
#include "fs_enet.h"
#include "fec.h"
@@ -47,6 +51,7 @@
#define FEC_MII_LOOPS 10000
+#ifndef CONFIG_PPC_CPM_NEW_BINDING
static int match_has_phy (struct device *dev, void* data)
{
struct platform_device* pdev = container_of(dev, struct platform_device, dev);
@@ -90,6 +95,7 @@ static int fs_mii_fec_init(struct fec_info* fec, struct fs_mii_fec_platform_info
return 0;
}
+#endif
static int fs_enet_fec_mii_read(struct mii_bus *bus , int phy_id, int location)
{
@@ -145,6 +151,141 @@ static int fs_enet_fec_mii_reset(struct mii_bus *bus)
return 0;
}
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+static void __devinit add_phy(struct mii_bus *bus, struct device_node *np)
+{
+ const u32 *data;
+ int len, id, irq;
+
+ data = of_get_property(np, "reg", &len);
+ if (!data || len != 4)
+ return;
+
+ id = *data;
+ bus->phy_mask &= ~(1 << id);
+
+ irq = of_irq_to_resource(np, 0, NULL);
+ if (irq != NO_IRQ)
+ bus->irq[id] = irq;
+}
+
+static int __devinit fs_enet_mdio_probe(struct of_device *ofdev,
+ const struct of_device_id *match)
+{
+ struct device_node *np = NULL;
+ struct resource res;
+ struct mii_bus *new_bus;
+ struct fec_info *fec;
+ int ret = -ENOMEM, i;
+
+ new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL);
+ if (!new_bus)
+ goto out;
+
+ fec = kzalloc(sizeof(struct fec_info), GFP_KERNEL);
+ if (!fec)
+ goto out_mii;
+
+ new_bus->priv = fec;
+ new_bus->name = "FEC MII Bus";
+ new_bus->read = &fs_enet_fec_mii_read;
+ new_bus->write = &fs_enet_fec_mii_write;
+ new_bus->reset = &fs_enet_fec_mii_reset;
+
+ ret = of_address_to_resource(ofdev->node, 0, &res);
+ if (ret)
+ return ret;
+
+ new_bus->id = res.start;
+
+ fec->fecp = ioremap(res.start, res.end - res.start + 1);
+ if (!fec->fecp)
+ goto out_fec;
+
+ fec->mii_speed = ((ppc_proc_freq + 4999999) / 5000000) << 1;
+
+ setbits32(&fec->fecp->fec_r_cntrl, FEC_RCNTRL_MII_MODE);
+ setbits32(&fec->fecp->fec_ecntrl, FEC_ECNTRL_PINMUX |
+ FEC_ECNTRL_ETHER_EN);
+ out_be32(&fec->fecp->fec_ievent, FEC_ENET_MII);
+ out_be32(&fec->fecp->fec_mii_speed, fec->mii_speed);
+
+ new_bus->phy_mask = ~0;
+ new_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
+ if (!new_bus->irq)
+ goto out_unmap_regs;
+
+ for (i = 0; i < PHY_MAX_ADDR; i++)
+ new_bus->irq[i] = -1;
+
+ while ((np = of_get_next_child(ofdev->node, np)))
+ if (!strcmp(np->type, "ethernet-phy"))
+ add_phy(new_bus, np);
+
+ new_bus->dev = &ofdev->dev;
+ dev_set_drvdata(&ofdev->dev, new_bus);
+
+ ret = mdiobus_register(new_bus);
+ if (ret)
+ goto out_free_irqs;
+
+ return 0;
+
+out_free_irqs:
+ dev_set_drvdata(&ofdev->dev, NULL);
+ kfree(new_bus->irq);
+out_unmap_regs:
+ iounmap(fec->fecp);
+out_fec:
+ kfree(fec);
+out_mii:
+ kfree(new_bus);
+out:
+ return ret;
+}
+
+static int fs_enet_mdio_remove(struct of_device *ofdev)
+{
+ struct mii_bus *bus = dev_get_drvdata(&ofdev->dev);
+ struct fec_info *fec = bus->priv;
+
+ mdiobus_unregister(bus);
+ dev_set_drvdata(&ofdev->dev, NULL);
+ kfree(bus->irq);
+ iounmap(fec->fecp);
+ kfree(fec);
+ kfree(bus);
+
+ return 0;
+}
+
+static struct of_device_id fs_enet_mdio_fec_match[] = {
+ {
+ .compatible = "fsl,pq1-fec-mdio",
+ },
+ {},
+};
+
+static struct of_platform_driver fs_enet_fec_mdio_driver = {
+ .name = "fsl-fec-mdio",
+ .match_table = fs_enet_mdio_fec_match,
+ .probe = fs_enet_mdio_probe,
+ .remove = fs_enet_mdio_remove,
+};
+
+static int fs_enet_mdio_fec_init(void)
+{
+ return of_register_platform_driver(&fs_enet_fec_mdio_driver);
+}
+
+static void fs_enet_mdio_fec_exit(void)
+{
+ of_unregister_platform_driver(&fs_enet_fec_mdio_driver);
+}
+
+module_init(fs_enet_mdio_fec_init);
+module_exit(fs_enet_mdio_fec_exit);
+#else
static int __devinit fs_enet_fec_mdio_probe(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
@@ -235,4 +376,4 @@ void fs_enet_mdio_fec_exit(void)
{
driver_unregister(&fs_enet_fec_mdio_driver);
}
-
+#endif
diff --git a/include/linux/fs_enet_pd.h b/include/linux/fs_enet_pd.h
index 815c6f9..9bc045b 100644
--- a/include/linux/fs_enet_pd.h
+++ b/include/linux/fs_enet_pd.h
@@ -120,6 +120,7 @@ struct fs_platform_info {
u32 cp_page; /* CPM page */
u32 cp_block; /* CPM sblock */
+ u32 cp_command; /* CPM page/sblock/mcn */
u32 clk_trx; /* some stuff for pins & mux configuration*/
u32 clk_rx;
@@ -134,7 +135,11 @@ struct fs_platform_info {
u32 device_flags;
int phy_addr; /* the phy address (-1 no phy) */
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+ char bus_id[16];
+#else
const char* bus_id;
+#endif
int phy_irq; /* the phy irq (if it exists) */
const struct fs_mii_bus_info *bus_info;
--
1.5.3.1
^ permalink raw reply related
* [SCTP PULL Request]: Bug fixes for 2.6.23
From: Vlad Yasevich @ 2007-09-24 20:59 UTC (permalink / raw)
To: David Miller; +Cc: netdev, lksctp-developers@lists.sourceforge.net
Hi David
Can you please pull the following changes since commit a41d3015c11a4e864b95cb57f579f2d8f40cd41b:
David S. Miller (1):
Revert "PCI: disable MSI by default on systems with Serverworks HT1000 chips"
which are available in the git repository at:
vxy@master.kernel.org:/pub/scm/linux/kernel/git/vxy/lksctp-dev.git master
Vlad Yasevich (4):
SCTP: Validate buffer room when processing sequential chunks
SCTP: Explicitly discard OOTB chunks
SCTP: Clean up OOTB handling and fix infinite loop processing
SCTP: Discard OOTB packets with bundled INIT early.
Wei Yongjun (2):
SCTP: Send ABORT chunk with correct tag in response to INIT ACK
SCTP : Add paramters validity check for ASCONF chunk
include/net/sctp/sm.h | 4 +-
include/net/sctp/structs.h | 1 +
net/sctp/input.c | 8 ++
net/sctp/inqueue.c | 8 ++
net/sctp/sm_make_chunk.c | 46 ++++++++
net/sctp/sm_statefuns.c | 243 +++++++++++++++++++++++++++++++++++++-------
net/sctp/sm_statetable.c | 16 ++--
7 files changed, 278 insertions(+), 48 deletions(-)
^ permalink raw reply
* [RFC] Zero-length write() does not generate a datagram on connected socket
From: Stephen Hemminger @ 2007-09-24 22:34 UTC (permalink / raw)
To: netdev
In-Reply-To: <20070922094432.E9BEA108010@picon.linux-foundation.org>
The bug http://bugzilla.kernel.org/show_bug.cgi?id=5731
describes an issue where write() can't be used to generate a zero-length
datagram (but send, and sendto do work).
I think the following is needed:
--- a/net/socket.c 2007-08-20 09:54:28.000000000 -0700
+++ b/net/socket.c 2007-09-24 15:31:25.000000000 -0700
@@ -777,8 +777,11 @@ static ssize_t sock_aio_write(struct kio
if (pos != 0)
return -ESPIPE;
- if (iocb->ki_left == 0) /* Match SYS5 behaviour */
- return 0;
+ if (unlikely(iocb->ki_left == 0)) {
+ struct socket *sock = iocb->ki_filp->private_data;
+ if (sock->type == SOCK_STREAM)
+ return 0;
+ }
x = alloc_sock_iocb(iocb, &siocb);
if (!x)
^ permalink raw reply
* Re: [PATCHES] TX batching
From: jamal @ 2007-09-24 22:38 UTC (permalink / raw)
To: Kok, Auke
Cc: Jeff Garzik, David Miller, krkumar2, johnpol, herbert, kaber,
shemminger, jagana, Robert.Olsson, rick.jones2, xma, gaagaan,
netdev, rdreier, peter.p.waskiewicz.jr, mcarlson, mchan, general,
kumarkr, tgraf, randy.dunlap, sri
In-Reply-To: <46F76087.8030109@intel.com>
On Mon, 2007-24-09 at 00:00 -0700, Kok, Auke wrote:
> that's bad to begin with :) - please send those separately so I can fasttrack them
> into e1000e and e1000 where applicable.
Ive been CCing you ;-> Most of the changes are readability and
reusability with the batching.
> But yes, I'm very inclined to merge more features into e1000e than e1000. I intend
> to put multiqueue support into e1000e, as *all* of the hardware that it will
> support has multiple queues. Putting in any other performance feature like tx
> batching would absolutely be interesting.
I looked at the e1000e and it is very close to e1000 so i should be able
to move the changes easily. Most importantly, can i kill LLTX?
For tx batching, we have to wait to see how Dave wants to move forward;
i will have the patches but it is not something you need to push until
we see where that is going.
cheers,
jamal
^ permalink raw reply
* RE: [PATCH 1/4] [NET_SCHED] explict hold dev tx lock
From: jamal @ 2007-09-24 22:51 UTC (permalink / raw)
To: Waskiewicz Jr, Peter P
Cc: David Miller, krkumar2, johnpol, herbert, kaber, shemminger,
jagana, Robert.Olsson, rick.jones2, xma, gaagaan, netdev, rdreier,
mcarlson, jeff, mchan, general, kumarkr, tgraf, randy.dunlap, sri
In-Reply-To: <D5C1322C3E673F459512FB59E0DDC32903A51122@orsmsx414.amr.corp.intel.com>
On Mon, 2007-24-09 at 12:12 -0700, Waskiewicz Jr, Peter P wrote:
> Hi Jamal,
> I've been (slowly) working on resurrecting the original design
> of my multiqueue patches to address this exact issue of the queue_lock
> being a hot item. I added a queue_lock to each queue in the subqueue
> struct, and in the enqueue and dequeue, just lock that queue instead of
> the global device queue_lock. The only two issues to overcome are the
> QDISC_RUNNING state flag, since that also serializes entry into the
> qdisc_restart() function, and the qdisc statistics maintenance, which
> needs to be serialized. Do you think this work along with your patch
> will benefit from one another?
The one thing that seems obvious is to use dev->hard_prep_xmit() in the
patches i posted to select the xmit ring. You should be able to do
figure out the txmit ring without holding any lock.
I lost track of how/where things went since the last discussion; so i
need to wrap my mind around it to make sensisble suggestions - I know
the core patches are in the kernel but havent paid attention to details
and if you look at my second patch youd see a comment in
dev_batch_xmit() which says i need to scrutinize multiqueue more.
cheers,
jamal
^ permalink raw reply
* [ofa-general] Re: [PATCHES] TX batching
From: Kok, Auke @ 2007-09-24 22:52 UTC (permalink / raw)
To: hadi
Cc: randy.dunlap, Robert.Olsson, gaagaan, kumarkr,
peter.p.waskiewicz.jr, shemminger, johnpol, herbert, Jeff Garzik,
rdreier, mcarlson, general, sri, jagana, mchan, Kok, Auke, netdev,
David Miller, tgraf, kaber
In-Reply-To: <1190673505.4264.11.camel@localhost>
jamal wrote:
> On Mon, 2007-24-09 at 00:00 -0700, Kok, Auke wrote:
>
>> that's bad to begin with :) - please send those separately so I can fasttrack them
>> into e1000e and e1000 where applicable.
>
> Ive been CCing you ;-> Most of the changes are readability and
> reusability with the batching.
>
>> But yes, I'm very inclined to merge more features into e1000e than e1000. I intend
>> to put multiqueue support into e1000e, as *all* of the hardware that it will
>> support has multiple queues. Putting in any other performance feature like tx
>> batching would absolutely be interesting.
>
> I looked at the e1000e and it is very close to e1000 so i should be able
> to move the changes easily. Most importantly, can i kill LLTX?
> For tx batching, we have to wait to see how Dave wants to move forward;
> i will have the patches but it is not something you need to push until
> we see where that is going.
hmm, I though I already removed that, but now I see some remnants from that.
By all means, please send a separate patch for that!
Auke
^ permalink raw reply
* [DOC] Net batching driver howto
From: jamal @ 2007-09-24 22:54 UTC (permalink / raw)
To: Jeff Garzik
Cc: David Miller, krkumar2, johnpol, herbert, kaber, shemminger,
jagana, Robert.Olsson, rick.jones2, xma, gaagaan, netdev, rdreier,
peter.p.waskiewicz.jr, mcarlson, mchan, general, kumarkr, tgraf,
randy.dunlap, sri
In-Reply-To: <1190574713.5030.4.camel@localhost>
[-- Attachment #1: Type: text/plain, Size: 100 bytes --]
I have updated the driver howto to match the patches i posted yesterday.
attached.
cheers,
jamal
[-- Attachment #2: batch-driver-howto.txt --]
[-- Type: text/plain, Size: 9307 bytes --]
Heres the begining of a howto for driver authors.
The intended audience for this howto is people already
familiar with netdevices.
1.0 Netdevice Pre-requisites
------------------------------
For hardware based netdevices, you must have at least hardware that
is capable of doing DMA with many descriptors; i.e having hardware
with a queue length of 3 (as in some fscked ethernet hardware) is
not very useful in this case.
2.0 What is new in the driver API
-----------------------------------
There are 3 new methods and one new variable introduced. These are:
1)dev->hard_prep_xmit()
2)dev->hard_end_xmit()
3)dev->hard_batch_xmit()
4)dev->xmit_win
2.1 Using Core driver changes
-----------------------------
To provide context, lets look at a typical driver abstraction
for dev->hard_start_xmit(). It has 4 parts:
a) packet formating (example vlan, mss, descriptor counting etc)
b) chip specific formatting
c) enqueueing the packet on a DMA ring
d) IO operations to complete packet transmit, tell DMA engine to chew
on, tx completion interupts etc
[For code cleanliness/readability sake, regardless of this work,
one should break the dev->hard_start_xmit() into those 4 functions
anyways].
A driver which has all 4 parts and needing to support batching is
advised to split its dev->hard_start_xmit() in the following manner:
1)use its dev->hard_prep_xmit() method to achieve #a
2)use its dev->hard_end_xmit() method to achieve #d
3)#b and #c can stay in ->hard_start_xmit() (or whichever way you
want to do this)
Note: There are drivers which may need not support any of the two
methods (example the tun driver i patched) so the two methods are
essentially optional.
2.1.1 Theory of operation
--------------------------
The core will first do the packet formatting by invoking your
supplied dev->hard_prep_xmit() method. It will then pass you the packet
via your dev->hard_start_xmit() method for as many as packets you
have advertised (via dev->xmit_win) you can consume. Lastly it will
invoke your dev->hard_end_xmit() when it completes passing you all the
packets queued for you.
2.1.1.1 Locking rules
---------------------
dev->hard_prep_xmit() is invoked without holding any
tx lock but the rest are under TX_LOCK(). So you have to ensure that
whatever you put it dev->hard_prep_xmit() doesnt require locking.
2.1.1.2 The slippery LLTX
-------------------------
LLTX drivers present a challenge in that we have to introduce a deviation
from the norm and require the ->hard_batch_xmit() method. An LLTX
driver presents us with ->hard_batch_xmit() to which we pass it a list
of packets in a dev->blist skb queue. It is then the responsibility
of the ->hard_batch_xmit() to exercise steps #b and #c for all packets
passed in the dev->blist.
Step #a and #d are done by the core should you register presence of
dev->hard_prep_xmit() and dev->hard_end_xmit() in your setup.
2.1.1.3 xmit_win
----------------
dev->xmit_win variable is set by the driver to tell us how
much space it has in its rings/queues. dev->xmit_win is introduced to
ensure that when we pass the driver a list of packets it will swallow
all of them - which is useful because we dont requeue to the qdisc (and
avoids burning unnecessary cpu cycles or introducing any strange
re-ordering). The driver tells us, whenever it invokes netif_wake_queue,
how much space it has for descriptors by setting this variable.
3.0 Driver Essentials
---------------------
The typical driver tx state machine is:
----
-1-> +Core sends packets
+--> Driver puts packet onto hardware queue
+ if hardware queue is full, netif_stop_queue(dev)
+
-2-> +core stops sending because of netif_stop_queue(dev)
..
.. time passes ...
..
-3-> +---> driver has transmitted packets, opens up tx path by
invoking netif_wake_queue(dev)
-1-> +Cycle repeats and core sends more packets (step 1).
----
3.1 Driver pre-requisite
--------------------------
This is _a very important_ requirement in making batching useful.
The pre-requisite for batching changes is that the driver should
provide a low threshold to open up the tx path.
Drivers such as tg3 and e1000 already do this.
Before you invoke netif_wake_queue(dev) you check if there is a
threshold of space reached to insert new packets.
Heres an example of how i added it to tun driver. Observe the
setting of dev->xmit_win
---
+#define NETDEV_LTT 4 /* the low threshold to open up the tx path */
..
..
u32 t = skb_queue_len(&tun->readq);
if (netif_queue_stopped(tun->dev) && t < NETDEV_LTT) {
tun->dev->xmit_win = tun->dev->tx_queue_len;
netif_wake_queue(tun->dev);
}
---
Heres how the batching e1000 driver does it:
--
if (unlikely(cleaned && netif_carrier_ok(netdev) &&
E1000_DESC_UNUSED(tx_ring) >= TX_WAKE_THRESHOLD)) {
if (netif_queue_stopped(netdev)) {
int rspace = E1000_DESC_UNUSED(tx_ring) - (MAX_SKB_FRAGS + 2);
netdev->xmit_win = rspace;
netif_wake_queue(netdev);
}
---
in tg3 code (with no batching changes) looks like:
-----
if (netif_queue_stopped(tp->dev) &&
(tg3_tx_avail(tp) > TG3_TX_WAKEUP_THRESH(tp)))
netif_wake_queue(tp->dev);
---
3.2 Driver Setup
-----------------
a) On initialization (before netdev registration)
i) set NETIF_F_BTX in dev->features
i.e dev->features |= NETIF_F_BTX
This makes the core do proper initialization.
ii) set dev->xmit_win to something reasonable like
maybe half the tx DMA ring size etc.
b) create proper pointer to the new methods desribed above if
you need them.
3.3 Annotation on the different methods
----------------------------------------
This section shows examples and offers suggestions on how the different
methods and variable could be used.
3.3.1 The dev->hard_prep_xmit() method
---------------------------------------
Use this method to only do pre-processing of the skb passed.
If in the current dev->hard_start_xmit() you are pre-processing
packets before holding any locks (eg formating them to be put in
any descriptor etc).
Look at e1000_prep_queue_frame() for an example.
You may use the skb->cb to store any state that you need to know
of later when batching.
PS: I have found when discussing with Michael Chan and Matt Carlson
that skb->cb[0] (8bytes of it) is used by the VLAN code to pass VLAN
info to the driver.
I think this is a violation of the usage of the cb scratch pad.
To work around this, you could use skb->cb[8] or do what the broadcom
tg3 bacthing driver does which is to glean the vlan info first then
re-use the skb->cb.
3.3.2 dev->hard_start_xmit()
----------------------------
Heres an example of tx routine that is similar to the one i added
to the current tun driver. bxmit suffix is kept so that you can turn
off batching if needed via and call already existing interface.
----
static int xxx_net_bxmit(struct net_device *dev)
{
....
....
enqueue onto hardware ring
if (hardware ring full) {
netif_stop_queue(dev);
dev->xmit_win = 1;
}
.......
..
.
}
------
All return codes like NETDEV_TX_OK etc still apply.
3.3.3 The LLTX batching method, dev->batch_xmit()
-------------------------------------------------
Heres an example of a batch tx routine that is similar
to the one i added to the older tun driver. Essentially
this is what youd do if you wanted to support LLTX.
----
static int xxx_net_bxmit(struct net_device *dev)
{
....
....
while (skb_queue_len(dev->blist)) {
dequeue from dev->blist
enqueue onto hardware ring
if hardware ring full break
}
if (hardware ring full) {
netif_stop_queue(dev);
dev->xmit_win = 1;
}
.......
..
.
}
------
All return codes like NETDEV_TX_OK etc still apply.
3.3.4 The tx complete, dev->hard_end_xmit()
-------------------------------------------------
In this method, if there are any IO operations that apply to a
set of packets such as kicking DMA, setting of interupt thresholds etc,
leave them to the end and apply them once if you have successfully enqueued.
This provides a mechanism for saving a lot of cpu cycles since IO
is cycle expensive.
For an example of this look e1000 driver e1000_kick_DMA() function.
3.3.5 setting the dev->xmit_win
-----------------------------
As mentioned earlier this variable provides hints on how much
data to send from the core to the driver. Here are the obvious ways:
a)on doing a netif_stop, set it to 1. By default all drivers have
this value set to 1 to emulate old behavior where a driver only
receives one packet at a time.
b)on netif_wake_queue set it to the max available space. You have
to be careful if your hardware does scatter-gather since the core
will pass you scatter-gatherable skbs and so you want to at least
leave enough space for the maximum allowed. Look at the tg3 and
e1000 to see how this is implemented.
The variable is important because it avoids the core sending
any more than what the driver can handle therefore avoiding
any need to muck with packet scheduling mechanisms.
Appendix 1: History
-------------------
June 11/2007: Initial revision
June 11/2007: Fixed typo on e1000 netif_wake description ..
Aug 08/2007: Added info on VLAN and the skb->cb[] danger ..
Sep 24/2007: Revised and cleaned up
^ permalink raw reply
* RE: [PATCH 1/4] [NET_SCHED] explict hold dev tx lock
From: Waskiewicz Jr, Peter P @ 2007-09-24 22:57 UTC (permalink / raw)
To: hadi
Cc: David Miller, krkumar2, johnpol, herbert, kaber, shemminger,
jagana, Robert.Olsson, rick.jones2, xma, gaagaan, netdev, rdreier,
mcarlson, jeff, mchan, general, kumarkr, tgraf, randy.dunlap, sri
In-Reply-To: <1190674298.4264.24.camel@localhost>
> The one thing that seems obvious is to use
> dev->hard_prep_xmit() in the patches i posted to select the
> xmit ring. You should be able to do figure out the txmit ring
> without holding any lock.
I've looked at that as a candidate to use. The lock for enqueue would
be needed when actually placing the skb into the appropriate software
queue for the qdisc, so it'd be quick.
> I lost track of how/where things went since the last
> discussion; so i need to wrap my mind around it to make
> sensisble suggestions - I know the core patches are in the
> kernel but havent paid attention to details and if you look
> at my second patch youd see a comment in
> dev_batch_xmit() which says i need to scrutinize multiqueue more.
No worries. I'll try to get things together on my end and provide some
patches to add a per-queue lock. In the meantime, I'll take a much
closer look at the batching code, since I've stopped looking at the
patches in-depth about a month ago. :-(
Thanks,
-PJ Waskiewicz
^ permalink raw reply
* [ofa-general] RE: [PATCH 1/4] [NET_SCHED] explict hold dev tx lock
From: jamal @ 2007-09-24 23:38 UTC (permalink / raw)
To: Waskiewicz Jr, Peter P
Cc: johnpol, kumarkr, herbert, gaagaan, Robert.Olsson, netdev,
rdreier, mcarlson, kaber, randy.dunlap, jagana, general, mchan,
tgraf, jeff, sri, shemminger, David Miller
In-Reply-To: <D5C1322C3E673F459512FB59E0DDC32903A51462@orsmsx414.amr.corp.intel.com>
On Mon, 2007-24-09 at 15:57 -0700, Waskiewicz Jr, Peter P wrote:
> I've looked at that as a candidate to use. The lock for enqueue would
> be needed when actually placing the skb into the appropriate software
> queue for the qdisc, so it'd be quick.
The enqueue is easy to comprehend. The single device queue lock should
suffice. The dequeue is interesting:
Maybe you can point me to some doc or describe to me the dequeue aspect;
are you planning to have an array of txlocks per, one per ring?
How is the policy to define the qdisc queues locked/mapped to tx rings?
cheers,
jamal
^ permalink raw reply
* RE: [PATCH 1/4] [NET_SCHED] explict hold dev tx lock
From: Waskiewicz Jr, Peter P @ 2007-09-24 23:47 UTC (permalink / raw)
To: hadi
Cc: David Miller, krkumar2, johnpol, herbert, kaber, shemminger,
jagana, Robert.Olsson, rick.jones2, xma, gaagaan, netdev, rdreier,
mcarlson, jeff, mchan, general, kumarkr, tgraf, randy.dunlap, sri
In-Reply-To: <1190677099.4264.37.camel@localhost>
> On Mon, 2007-24-09 at 15:57 -0700, Waskiewicz Jr, Peter P wrote:
>
> > I've looked at that as a candidate to use. The lock for
> enqueue would
> > be needed when actually placing the skb into the
> appropriate software
> > queue for the qdisc, so it'd be quick.
>
> The enqueue is easy to comprehend. The single device queue
> lock should suffice. The dequeue is interesting:
We should make sure we're symmetric with the locking on enqueue to
dequeue. If we use the single device queue lock on enqueue, then
dequeue will also need to check that lock in addition to the individual
queue lock. The details of this are more trivial than the actual
dequeue to make it efficient though.
> Maybe you can point me to some doc or describe to me the
> dequeue aspect; are you planning to have an array of txlocks
> per, one per ring?
> How is the policy to define the qdisc queues locked/mapped to
> tx rings?
The dequeue locking would be pushed into the qdisc itself. This is how
I had it originally, and it did make the code more complex, but it was
successful at breaking the heavily-contended queue_lock apart. I have a
subqueue structure right now in netdev, which only has queue_state (for
netif_{start|stop}_subqueue). This state is checked in sch_prio right
now in the dequeue for both prio and rr. My approach is to add a
queue_lock in that struct, so each queue allocated by the driver would
have a lock per queue. Then in dequeue, that lock would be taken when
the skb is about to be dequeued.
The skb->queue_mapping field also maps directly to the queue index
itself, so it can be unlocked easily outside of the context of the
dequeue function. The policy would be to use a spin_trylock() in
dequeue, so that dequeue can still do work if enqueue or another dequeue
is busy. And the allocation of qdisc queues to device queues is assumed
to be one-to-one (that's how the qdisc behaves now).
I really just need to put my nose to the grindstone and get the patches
together and to the list...stay tuned.
Thanks,
-PJ Waskiewicz
^ permalink raw reply
* [ofa-general] Re: [PATCH 1/4] [NET_SCHED] explict hold dev tx lock
From: Stephen Hemminger @ 2007-09-25 0:14 UTC (permalink / raw)
To: Waskiewicz Jr, Peter P
Cc: johnpol, jeff, kumarkr, herbert, gaagaan, Robert.Olsson, netdev,
rdreier, hadi, kaber, randy.dunlap, jagana, general, mchan, tgraf,
mcarlson, sri, David Miller
In-Reply-To: <D5C1322C3E673F459512FB59E0DDC32903A5151B@orsmsx414.amr.corp.intel.com>
On Mon, 24 Sep 2007 16:47:06 -0700
"Waskiewicz Jr, Peter P" <peter.p.waskiewicz.jr@intel.com> wrote:
> > On Mon, 2007-24-09 at 15:57 -0700, Waskiewicz Jr, Peter P wrote:
> >
> > > I've looked at that as a candidate to use. The lock for
> > enqueue would
> > > be needed when actually placing the skb into the
> > appropriate software
> > > queue for the qdisc, so it'd be quick.
> >
> > The enqueue is easy to comprehend. The single device queue
> > lock should suffice. The dequeue is interesting:
>
> We should make sure we're symmetric with the locking on enqueue to
> dequeue. If we use the single device queue lock on enqueue, then
> dequeue will also need to check that lock in addition to the individual
> queue lock. The details of this are more trivial than the actual
> dequeue to make it efficient though.
>
> > Maybe you can point me to some doc or describe to me the
> > dequeue aspect; are you planning to have an array of txlocks
> > per, one per ring?
> > How is the policy to define the qdisc queues locked/mapped to
> > tx rings?
>
> The dequeue locking would be pushed into the qdisc itself. This is how
> I had it originally, and it did make the code more complex, but it was
> successful at breaking the heavily-contended queue_lock apart. I have a
> subqueue structure right now in netdev, which only has queue_state (for
> netif_{start|stop}_subqueue). This state is checked in sch_prio right
> now in the dequeue for both prio and rr. My approach is to add a
> queue_lock in that struct, so each queue allocated by the driver would
> have a lock per queue. Then in dequeue, that lock would be taken when
> the skb is about to be dequeued.
>
> The skb->queue_mapping field also maps directly to the queue index
> itself, so it can be unlocked easily outside of the context of the
> dequeue function. The policy would be to use a spin_trylock() in
> dequeue, so that dequeue can still do work if enqueue or another dequeue
> is busy. And the allocation of qdisc queues to device queues is assumed
> to be one-to-one (that's how the qdisc behaves now).
>
> I really just need to put my nose to the grindstone and get the patches
> together and to the list...stay tuned.
>
> Thanks,
> -PJ Waskiewicz
> -
Since we are redoing this, is there any way to make the whole TX path
more lockless? The existing model seems to be more of a monitor than
a real locking model.
--
Stephen Hemminger <shemminger@linux-foundation.org>
^ permalink raw reply
* Re: [PATCHES] TX batching
From: Jeff Garzik @ 2007-09-25 0:15 UTC (permalink / raw)
To: hadi, David Miller
Cc: krkumar2, johnpol, herbert, kaber, shemminger, jagana,
Robert.Olsson, rick.jones2, xma, gaagaan, netdev, rdreier,
peter.p.waskiewicz.jr, mcarlson, mchan, general, kumarkr, tgraf,
randy.dunlap, sri
In-Reply-To: <1190574713.5030.4.camel@localhost>
jamal wrote:
> If the intel folks will accept the patch i'd really like to kill
> the e1000 LLTX interface.
If I understood DaveM correctly, it is sounding like we want to
deprecate all of use LLTX on "real" hardware? If so, several such
projects might be considered, as well as possibly simplifying TX
batching work perhaps.
Also, WRT e1000 specifically, I was hoping to minimize changes, and
focus people on e1000e.
e1000e replaces (deprecates) large portions of e1000, namely the support
for the PCI Express modern chips. When e1000e has proven itself in the
field, we can potentially look at several e1000 simplifications, during
the large scale code removal that becomes possible.
Jeff
^ permalink raw reply
* [ofa-general] RE: [PATCH 1/4] [NET_SCHED] explict hold dev tx lock
From: Waskiewicz Jr, Peter P @ 2007-09-25 0:31 UTC (permalink / raw)
To: Stephen Hemminger
Cc: johnpol, jeff, kumarkr, herbert, gaagaan, Robert.Olsson, netdev,
rdreier, hadi, kaber, randy.dunlap, jagana, general, mchan, tgraf,
mcarlson, sri, David Miller
In-Reply-To: <20070924171411.36494656@freepuppy.rosehill>
> > I really just need to put my nose to the grindstone and get the
> > patches together and to the list...stay tuned.
> >
> > Thanks,
> > -PJ Waskiewicz
> > -
>
>
> Since we are redoing this, is there any way to make the whole
> TX path more lockless? The existing model seems to be more
> of a monitor than a real locking model.
That seems quite reasonable. I will certainly see what I can do.
Thanks Stephen,
-PJ Waskiewicz
^ permalink raw reply
* [PATCH] sky2: FE+ Phy initialization
From: Stephen Hemminger @ 2007-09-25 2:34 UTC (permalink / raw)
To: Jeff Garzik; +Cc: netdev
One more snippet of PHY initialization required for FE+ chips.
Discovered in latest sk98lin 10.21.1.3 driver.
Please apply to 2.6.23.
Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
--- a/drivers/net/sky2.c 2007-09-24 09:10:36.000000000 -0700
+++ b/drivers/net/sky2.c 2007-09-24 10:22:28.000000000 -0700
@@ -338,6 +338,16 @@ static void sky2_phy_init(struct sky2_hw
if (!(hw->flags & SKY2_HW_GIGABIT)) {
/* enable automatic crossover */
ctrl |= PHY_M_PC_MDI_XMODE(PHY_M_PC_ENA_AUTO) >> 1;
+
+ if (hw->chip_id == CHIP_ID_YUKON_FE_P &&
+ hw->chip_rev == CHIP_REV_YU_FE2_A0) {
+ u16 spec;
+
+ /* Enable Class A driver for FE+ A0 */
+ spec = gm_phy_read(hw, port, PHY_MARV_FE_SPEC_2);
+ spec |= PHY_M_FESC_SEL_CL_A;
+ gm_phy_write(hw, port, PHY_MARV_FE_SPEC_2, spec);
+ }
} else {
/* disable energy detect */
ctrl &= ~PHY_M_PC_EN_DET_MSK;
^ permalink raw reply
* Re: [PATCH] sky2: FE+ Phy initialization
From: Jeff Garzik @ 2007-09-25 4:09 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: netdev
In-Reply-To: <20070924193451.7552b9e9@freepuppy.rosehill>
Stephen Hemminger wrote:
> One more snippet of PHY initialization required for FE+ chips.
> Discovered in latest sk98lin 10.21.1.3 driver.
>
> Please apply to 2.6.23.
>
> Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
applied
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox