* Re: [PATCH 2/2] NET: Accurate packet scheduling for ATM/ADSL (userspace)
From: jamal @ 2006-06-20 14:06 UTC (permalink / raw)
To: Jesper Dangaard Brouer
Cc: netdev, Stephen Hemminger, Alan Cox, Russell Stuart
In-Reply-To: <Pine.LNX.4.61.0606192048270.31662@ask.diku.dk>
took off lartc off the list because it doesnt allow me to post
and i refuse to subscribe.
On Mon, 2006-19-06 at 21:31 +0200, Jesper Dangaard Brouer wrote:
>
> On Thu, 15 Jun 2006, jamal wrote:
> > It is probably doable by just looking at netdevice->type and figuring
> > the link layer technology. Totally in user space and building the
> > compensated for tables there before telling the kernel (advantage is no
> > kernel changes and therefore it would work with older kernels as well).
>
> I think you have got the setup all wrong.
>
> The linux middlebox/router has two ethernet interfaces, one of the
> ethernet interfaces is connected to the ADSL modem. Thus, the linux
> ethernet card cannot determine that it is connected to an ADSL line.
>
Actually you may be making my point for me.
Heres the standard setup as i understand it(at least in north america, I
know Europeans love their ATM with a little gravy on top):
|Linux| --ethernet-- |Modem| --DSL-- |DSLAM| --ATM-- |BRAS|
What this means is that Linux computes based on ethernet
headers. Somewhere downstream ATM (refer to above) comes in and that
causes mismatch in what Linux expects to be the bandwidth and what
your service provider who doesnt account for the ATM overhead when
they sell you "1.5Mbps".
Reminds me of hard disk vendors who define 1K to be 1000 to show
how large their drives are.
Yes, Linux cant tell if your service provider is lying to you.
>
> The patch is the solution to the classical problem people
> have when tryng to configure traffic control on an ADSL link?
>
> Q: The packet scheduling does not work all the time?
> A: Try to decrease to bandwidth.
>
>
> The issue here is, that ATM does not have fixed overhead (due to alignment
> and padding). This means that a fixed reduction of the bandwidth is not
> the solution. We could reduce the bandwidth to the worst-case overhead,
> which is 62%, I do not think that is a good solution...
>
I dont see it as wrong to be honest with you. Your mileage may vary.
> With the patch, you can now simply configure HTB to use the rate that was
> specified by the ISP.
>
Dont have time to read your doc and dont get me wrong, there is a
"quark" practical problem: As practical as the hard disk manufacturer
who claims that they have 11G drive when it is 10G. It needs to be
resolved - but not in an intrusive way in my opinion.
cheers,
jamal
^ permalink raw reply
* Re: [RFT] pcnet32 NAPI changes
From: Jon Mason @ 2006-06-20 13:53 UTC (permalink / raw)
To: Lennart Sorensen; +Cc: Don Fry, netdev
In-Reply-To: <20060619204933.GH26952@csclub.uwaterloo.ca>
On Mon, Jun 19, 2006 at 04:49:33PM -0400, Lennart Sorensen wrote:
> On Mon, Jun 19, 2006 at 03:41:40PM -0500, Jon Mason wrote:
> > I believe it is preferred to be a compile option for non-gigabit
> > drivers, given that it will be eating a lot of cycles for infrequent
> > packets (especially for the 10Mb). I believe there was a thread about
> > this last year when e100 was having NAPI problems.
>
> How does NAPI eat cycles? It goes back to interrupt mode when the queue
> is empty, and only on RX interrupt does it turn on polling again.
The amount of polls per received packet is very low, thus removing the
benefit of NAPI. A compile time option would allow those users who know
better to DTRT.
> It is certainly possible that there are bugs in a NAPI conversion, which
> I guess could be a reason to have the option to stick with the old
> method, although then again not having the option ensures the bugs get
> found sooner.
>
> > A general nit. There are ALOT of magic numbers in the code, most
> > existing prior to this patch. The driver would benefit from a little
> > clean-up.
> >
> > Also nothing to do with this patch, but I noticed it when the code was
> > moved. A comment about why the following is necessary might be nice:
> > lp->rx_ring[i].buf_length = le16_to_cpu(2 - PKT_BUF_SZ);
>
> I suspect many drivers are in need of some cleanup.
Yup, but the "everyone else is doing it" argument never worked with my
parents. All it takes is one brave soul to determine the reasoning
behind the magic numbers and convert them into #define's. Shouldn't be
more than one day's work.
>
> Len Sorensen
> -
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [DOC]: generic netlink
From: jamal @ 2006-06-20 13:19 UTC (permalink / raw)
To: Shailabh Nagar
Cc: James Morris, Per Liden, Jay Lan, Thomas Graf, David S. Miller,
netdev
In-Reply-To: <4496C98E.8030407@watson.ibm.com>
On Mon, 2006-19-06 at 11:58 -0400, Shailabh Nagar wrote:
> jamal wrote:
[..]
> But I'm not too clear about what are the advantages of trying to limit the
> number of commands registered by a given exploiter of genetlink (say TIPC or taskstats),
> other than the conventional usage of netlink.
>
> e.g in the taskstats code, userspace needs to GET data on a per-pid and per-tgid basis
> from the kernel and supplies the specific pid or tgid. We could either have registered
> two commands (say GET_PID and GET_TGID) and then the parsing of the supplied uint32 would
> be implicit in the command. But we went with the model where we have only one GET command
> and the type of the parameter is specified via netlink attributes.
The idea is for fine grain access control(ACL) of what user process can
do (as managed by SELinux not genetlink). As an example even in your
case, you may wanna allow user program "shailab1" to be able to get
information on a groupid but not pid. We should be able to add that
level of granularity easily since we have flags per command.
> In our case, it didn't matter and since the type of data returned is very similar and so is
> the parameter supplied (pid/tgid), one GET suffices. But I'm wondering if userspace should
> consciously try and limit the commands or would it be better from a performance standpoint,
> to permit a reasonably larger "fan-out" to happen at the genetlink command level (for each exploiter).
> I guess this introduces more overhead for in-kernel structures (the linked list of command structures
> that needs to be kept around) while saving time on doing a second level of parsing within the
> exploiter-defined function that services the GET command.
>
> The "small" set model looks like a good compromise. Reducing number of commands to one is not a good
> idea IMHO....for reasons similar to why ioctl type syscalls aren't encouraged...since the genetlink
> layer anyway has code for demultiplexing, might as well use it and avoid an extra level of indirection.
>
indeed.
cheers,
jamal
^ permalink raw reply
* Re: [DOC]: generic netlink
From: jamal @ 2006-06-20 12:59 UTC (permalink / raw)
To: James Morris
Cc: netdev, David S. Miller, Thomas Graf, Jay Lan, Shailabh Nagar,
Per Liden
In-Reply-To: <Pine.LNX.4.64.0606191143540.21525@d.namei>
On Mon, 2006-19-06 at 11:54 -0400, James Morris wrote:
> On Mon, 19 Jun 2006, jamal wrote:
>
> > Other that TIPC the two other users i have seen use it in this manner.
> > But, you are right if usage tends to lean in some other way we could get
> > rid of it (I think TIPC is a bad example).
>
> Ok, perhaps make a note in the docs about this and keep an eye out when
> new code is submitted, and encourage people not to do this.
Will do.
> Actually, what would help SELinux is the opposite, forcing everyone to use
> separate commands and assigning security attributes to each one. But
> because TIPC is already multiplexing, it's not feasible.
>
Then i would say they loose the fine level granularity that would have
otherwise been provided to them. Unless you are saying that choice is
not for them to make?
> Instead, I think the way to go for SELinux is to have each nl family
> provide a permission callback, so SELinux can pass the skb back to the nl
> module which then returns a type of permission ('read', 'write',
> 'readpriv'). This way, the nl module can create and manage its own
> internal table of command permissions and also know exactly where in the
> message to dig for the command specifier.
>
makes sense.
> > My view: If you want to have ACLs against such commands then it becomes
> > easier to say "can only do ADD but not DEL" for example (We need to
> > resolve genl_rcv_msg() check on commands to be in sync with SELinux as
> > was pointed by Thomas)
>
> This already exists, to some extent, but only for some protocols. You can
> see examples of existing permission tables managed by SELinux in:
> security/selinux/nlmsgtab.c
>
> The hope move this out of SELinux and into each nl module, which is much
> more manageable and scalable.
agreed.
cheers,
jamal
^ permalink raw reply
* Re: [Bugme-new] [Bug 6682] New: BUG: soft lockup detected on CPU#0! / ksoftirqd takse 100% CPU
From: Herbert Xu @ 2006-06-20 12:32 UTC (permalink / raw)
To: Andrew Morton
Cc: netdev, Dipankar Sarma, Paul E. McKenney,
bugme-daemon@kernel-bugs.osdl.org, alchemyx, Robert Olsson
In-Reply-To: <20060619152010.5c648b97.akpm@osdl.org>
On Mon, Jun 19, 2006 at 10:20:10PM +0000, Andrew Morton wrote:
>
> > [<c02396f9>] dev_queue_xmit+0xe0/0x203
> > [<c0250de8>] ip_output+0x1e1/0x237
> > [<c024f3f5>] ip_forward+0x181/0x1df
> > [<c024e21a>] ip_rcv+0x40c/0x485
> > [<c0239bd0>] netif_receive_skb+0x12f/0x165
> > [<f885aa4c>] e1000_clean_rx_irq+0x389/0x410 [e1000]
> > [<f885a1ca>] e1000_clean+0x94/0x12f [e1000]
> > [<c0239d5a>] net_rx_action+0x69/0xf0
> > [<c011a305>] __do_softirq+0x55/0xbd
> > [<c011a39a>] do_softirq+0x2d/0x31
> > [<c011a3f8>] local_bh_enable+0x5a/0x65
> > [<c024a0a1>] rt_run_flush+0x5f/0x80
Could you tell us the frequency of route updates on this machine?
Route updates are pretty expensive especially when a large number
of flows hits your machine right afterwards.
You can monitor this by running ip mon. You might just be getting
bogus route updates causing unnecessary flushes to the routing cache.
Cheers,
--
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply
* Re: [0/5] GSO: Generic Segmentation Offload
From: David Miller @ 2006-06-20 10:40 UTC (permalink / raw)
To: herbert; +Cc: netdev
In-Reply-To: <20060620093219.GF31854@gondor.apana.org.au>
From: Herbert Xu <herbert@gondor.apana.org.au>
Date: Tue, 20 Jun 2006 19:32:19 +1000
> On Tue, Jun 20, 2006 at 07:09:19PM +1000, herbert wrote:
> >
> > I've attached some numbers to demonstrate the savings brought on by
> > doing this. The best scenario is obviously the case where the underlying
> > NIC supports SG. This means that we simply have to manipulate the SG
> > entries and place them into individual skb's before passing them to the
> > driver. The attached file lo-res shows this.
>
> Obviously I forgot to attach them :)
:-)
The changes look good on first scan, I'll look more deeply and
meanwhile we'll let the patches ferment for a few days so others
can comment too :-)
^ permalink raw reply
* [PATCH 2.6.17] AT91RM9200 Ethernet #4: Suspend/Resume
From: Andrew Victor @ 2006-06-20 10:19 UTC (permalink / raw)
To: jgarzik; +Cc: netdev
Adds power-management (suspend/resume) support to the AT91RM9200
Ethernet driver.
Patch from David Brownell.
Signed-off-by: Andrew Victor <andrew@sanpeople.com>
diff -urN linux-2.6.17-rmk.orig/drivers/net/arm/at91_ether.c linux-2.6.17-rmk/drivers/net/arm/at91_ether.c
--- linux-2.6.17-rmk.orig/drivers/net/arm/at91_ether.c Tue Jun 20 11:16:31 2006
+++ linux-2.6.17-rmk/drivers/net/arm/at91_ether.c Tue Jun 20 11:18:45 2006
@@ -1128,10 +1128,54 @@
return 0;
}
+#ifdef CONFIG_PM
+
+static int at91ether_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+ struct at91_private *lp = (struct at91_private *) at91_dev->priv;
+ struct net_device *net_dev = platform_get_drvdata(pdev);
+ int phy_irq = lp->board_data.phy_irq_pin;
+
+ if (netif_running(net_dev)) {
+ if (phy_irq)
+ disable_irq(phy_irq);
+
+ netif_stop_queue(net_dev);
+ netif_device_detach(net_dev);
+
+ clk_disable(lp->ether_clk);
+ }
+ return 0;
+}
+
+static int at91ether_resume(struct platform_device *pdev)
+{
+ struct at91_private *lp = (struct at91_private *) at91_dev->priv;
+ struct net_device *net_dev = platform_get_drvdata(pdev);
+ int phy_irq = lp->board_data.phy_irq_pin;
+
+ if (netif_running(net_dev)) {
+ clk_enable(lp->ether_clk);
+
+ netif_device_attach(net_dev);
+ netif_start_queue(net_dev);
+
+ if (phy_irq)
+ enable_irq(phy_irq);
+ }
+ return 0;
+}
+
+#else
+#define at91ether_suspend NULL
+#define at91ether_resume NULL
+#endif
+
static struct platform_driver at91ether_driver = {
.probe = at91ether_probe,
.remove = __devexit_p(at91ether_remove),
- /* FIXME: support suspend and resume */
+ .suspend = at91ether_suspend,
+ .resume = at91ether_resume,
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
^ permalink raw reply
* [PATCH 2.6.17] AT91RM9200 Ethernet #3: Cleanup
From: Andrew Victor @ 2006-06-20 10:10 UTC (permalink / raw)
To: jgarzik; +Cc: netdev
Moved global ether_clk variable into controller data structure.
Patch from David Brownell.
Davicom 9161 PHY was being incorrectly displayed as "9196".
Patch from Brian Stafford.
clk_get() doesn't return NULL on error, so the return value needs to be
tested with IS_ERR().
Whitespace cleanup.
Signed-off-by: Andrew Victor <andrew@sanpeople.com>
diff -urN linux-2.6.17-rmk.orig/drivers/net/arm/at91_ether.c linux-2.6.17-rmk/drivers/net/arm/at91_ether.c
--- linux-2.6.17-rmk.orig/drivers/net/arm/at91_ether.c Tue Jun 20 11:08:36 2006
+++ linux-2.6.17-rmk/drivers/net/arm/at91_ether.c Tue Jun 20 11:11:41 2006
@@ -43,7 +43,6 @@
#define DRV_VERSION "1.0"
static struct net_device *at91_dev;
-static struct clk *ether_clk;
static struct timer_list check_timer;
#define LINK_POLL_INTERVAL (HZ)
@@ -519,7 +518,7 @@
hash_index |= (bitval << j);
}
- return hash_index;
+ return hash_index;
}
/*
@@ -575,10 +574,8 @@
at91_emac_write(AT91_EMAC_CFG, cfg);
}
-
/* ......................... ETHTOOL SUPPORT ........................... */
-
static int mdio_read(struct net_device *dev, int phy_id, int location)
{
unsigned int value;
@@ -719,10 +716,10 @@
struct at91_private *lp = (struct at91_private *) dev->priv;
unsigned long ctl;
- if (!is_valid_ether_addr(dev->dev_addr))
- return -EADDRNOTAVAIL;
+ if (!is_valid_ether_addr(dev->dev_addr))
+ return -EADDRNOTAVAIL;
- clk_enable(ether_clk); /* Re-enable Peripheral clock */
+ clk_enable(lp->ether_clk); /* Re-enable Peripheral clock */
/* Clear internal statistics */
ctl = at91_emac_read(AT91_EMAC_CTL);
@@ -756,6 +753,7 @@
*/
static int at91ether_close(struct net_device *dev)
{
+ struct at91_private *lp = (struct at91_private *) dev->priv;
unsigned long ctl;
/* Disable Receiver and Transmitter */
@@ -772,7 +770,7 @@
netif_stop_queue(dev);
- clk_disable(ether_clk); /* Disable Peripheral clock */
+ clk_disable(lp->ether_clk); /* Disable Peripheral clock */
return 0;
}
@@ -904,7 +902,7 @@
if (intstatus & AT91_EMAC_RCOM) /* Receive complete */
at91ether_rx(dev);
- if (intstatus & AT91_EMAC_TCOM) { /* Transmit complete */
+ if (intstatus & AT91_EMAC_TCOM) { /* Transmit complete */
/* The TCOM bit is set even if the transmission failed. */
if (intstatus & (AT91_EMAC_TUND | AT91_EMAC_RTRY))
lp->stats.tx_errors += 1;
@@ -933,7 +931,8 @@
/*
* Initialize the ethernet interface
*/
-static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_address, struct platform_device *pdev)
+static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_address,
+ struct platform_device *pdev, struct clk *ether_clk)
{
struct at91_eth_data *board_data = pdev->dev.platform_data;
struct net_device *dev;
@@ -967,6 +966,7 @@
return -ENOMEM;
}
lp->board_data = *board_data;
+ lp->ether_clk = ether_clk;
platform_set_drvdata(pdev, dev);
spin_lock_init(&lp->lock);
@@ -1050,7 +1050,7 @@
dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
if ((phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID))
- printk(KERN_INFO "%s: Davicom 9196 PHY %s\n", dev->name, (lp->phy_media == PORT_FIBRE) ? "(Fiber)" : "(Copper)");
+ printk(KERN_INFO "%s: Davicom 9161 PHY %s\n", dev->name, (lp->phy_media == PORT_FIBRE) ? "(Fiber)" : "(Copper)");
else if (phy_type == MII_LXT971A_ID)
printk(KERN_INFO "%s: Intel LXT971A PHY\n", dev->name);
else if (phy_type == MII_RTL8201_ID)
@@ -1076,9 +1076,10 @@
int detected = -1;
unsigned long phy_id;
unsigned short phy_address = 0;
+ struct clk *ether_clk;
ether_clk = clk_get(&pdev->dev, "ether_clk");
- if (!ether_clk) {
+ if (IS_ERR(ether_clk)) {
printk(KERN_ERR "at91_ether: no clock defined\n");
return -ENODEV;
}
@@ -1101,7 +1102,7 @@
case MII_DP83847_ID: /* National Semiconductor DP83847: */
case MII_AC101L_ID: /* Altima AC101L: PHY_ID1 = 0x22, PHY_ID2 = 0x5520 */
case MII_KS8721_ID: /* Micrel KS8721: PHY_ID1 = 0x22, PHY_ID2 = 0x1610 */
- detected = at91ether_setup(phy_id, phy_address, pdev);
+ detected = at91ether_setup(phy_id, phy_address, pdev, ether_clk);
break;
}
@@ -1120,7 +1121,7 @@
unregister_netdev(at91_dev);
free_irq(at91_dev->irq, at91_dev);
dma_free_coherent(NULL, sizeof(struct recv_desc_bufs), lp->dlist, (dma_addr_t)lp->dlist_phys);
- clk_put(ether_clk);
+ clk_put(lp->ether_clk);
free_netdev(at91_dev);
at91_dev = NULL;
diff -urN linux-2.6.17-rmk.orig/drivers/net/arm/at91_ether.h linux-2.6.17-rmk/drivers/net/arm/at91_ether.h
--- linux-2.6.17-rmk.orig/drivers/net/arm/at91_ether.h Tue Jun 20 08:53:55 2006
+++ linux-2.6.17-rmk/drivers/net/arm/at91_ether.h Tue Jun 20 11:10:45 2006
@@ -80,6 +80,7 @@
struct net_device_stats stats;
struct mii_if_info mii; /* ethtool support */
struct at91_eth_data board_data; /* board-specific configuration */
+ struct clk *ether_clk; /* clock */
/* PHY */
unsigned long phy_type; /* type of PHY (PHY_ID) */
^ permalink raw reply
* Re: rtl8150 usb driver, needs more vendor ids?
From: Petko Manolov @ 2006-06-20 10:13 UTC (permalink / raw)
To: Ben Greear; +Cc: NetDev, petkan
In-Reply-To: <449799BA.1050303@candelatech.com>
Hi Ben,
What you have sent me is a bit of a puzzle.
Looking at the device's details i can see it is not RTL8150 based device,
but ADMtek's ADM8511. Both vendor and device IDs have been listed in
pegasus.c for a long long time.
Using rtl8150.c will not help at all since it talks to a different device.
I suggest using pegasus.c ...
Petko
On Mon, 19 Jun 2006, Ben Greear wrote:
> Someone put a wired usb-to-ethernet adapter into a system running
> the 2.6.13.5 kernel. The driver is evidently the rtl8150, and this
> person sent me what appeared to be a modified version of the rtl8150
> that is in the kernel. The kernel driver does not appear to even attempt
> to use this device.
>
> Here is the output from /proc/bus/usb/devices:
>
> T: Bus=01 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 4 Spd=12 MxCh= 0
> D: Ver= 1.10 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1
> P: Vendor=07a6 ProdID=8511 Rev= 1.01
> S: Manufacturer=ADMtek
> S: Product=USB To LAN Converter
> S: SerialNumber=0001
> C:* #Ifs= 1 Cfg#= 1 Atr=a0 MxPwr=160mA
> I: If#= 0 Alt= 0 #EPs= 3 Cls=00(>ifc ) Sub=00 Prot=00 Driver=(none)
> E: Ad=81(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms
> E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms
> E: Ad=83(I) Atr=03(Int.) MxPS= 8 Ivl=1ms
>
> The vendor driver (GPL) I received is available here:
> http://www.candelatech.com/oss/RTL8150.C
>
> When I get a chance later this week, I plan to add this vendor id
> and see if it works. Since the physical equipment is half a world
> away, I'd welcome any conjecture as to whether simply adding the
> device ID will work or not...
>
> Thanks,
> Ben
>
> --
> Ben Greear <greearb@candelatech.com>
> Candela Technologies Inc http://www.candelatech.com
>
>
^ permalink raw reply
* [PATCH 2.6.17] AT91RM9200 Ethernet #2: MII interface
From: Andrew Victor @ 2006-06-20 9:59 UTC (permalink / raw)
To: jgarzik; +Cc: netdev
Adds support for the MII ioctls via generic_mii_ioctl().
Patch from Brian Stafford.
Set the mii.phy_id to the detected PHY address, otherwise ethtool cannot
access PHYs other than 0.
Patch from Roman Kolesnikov.
Signed-off-by: Andrew Victor <andrew@sanpeople.com>
diff -urN linux-2.6.17-rmk.orig/drivers/net/arm/at91_ether.c linux-2.6.17-rmk/drivers/net/arm/at91_ether.c
--- linux-2.6.17-rmk.orig/drivers/net/arm/at91_ether.c Tue Jun 20 11:03:13 2006
+++ linux-2.6.17-rmk/drivers/net/arm/at91_ether.c Tue Jun 20 11:03:00 2006
@@ -660,6 +660,22 @@
.get_link = ethtool_op_get_link,
};
+static int at91ether_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+ struct at91_private *lp = (struct at91_private *) dev->priv;
+ int res;
+
+ if (!netif_running(dev))
+ return -EINVAL;
+
+ spin_lock_irq(&lp->lock);
+ enable_mdi();
+ res = generic_mii_ioctl(&lp->mii, if_mii(rq), cmd, NULL);
+ disable_mdi();
+ spin_unlock_irq(&lp->lock);
+
+ return res;
+}
/* ................................ MAC ................................ */
@@ -963,6 +979,7 @@
dev->set_multicast_list = at91ether_set_rx_mode;
dev->set_mac_address = set_mac_address;
dev->ethtool_ops = &at91ether_ethtool_ops;
+ dev->do_ioctl = at91ether_ioctl;
SET_NETDEV_DEV(dev, &pdev->dev);
@@ -993,6 +1010,9 @@
lp->mii.dev = dev; /* Support for ethtool */
lp->mii.mdio_read = mdio_read;
lp->mii.mdio_write = mdio_write;
+ lp->mii.phy_id = phy_address;
+ lp->mii.phy_id_mask = 0x1f;
+ lp->mii.reg_num_mask = 0x1f;
lp->phy_type = phy_type; /* Type of PHY connected */
lp->phy_address = phy_address; /* MDI address of PHY */
^ permalink raw reply
* Re: [IOC3] IP27: Really set PCI64_ATTR_VIRTUAL, not PCI64_ATTR_PREC.
From: Ralf Baechle @ 2006-06-20 10:02 UTC (permalink / raw)
To: Ingo Oeser; +Cc: netdev, Jeff Garzik
In-Reply-To: <200606201015.01323.netdev@axxeo.de>
On Tue, Jun 20, 2006 at 10:15:01AM +0200, Ingo Oeser wrote:
> From: Ingo Oeser <netdev@axxeo.de>
> To: Ralf Baechle <ralf@linux-mips.org>
> Subject: Re: [IOC3] IP27: Really set PCI64_ATTR_VIRTUAL, not PCI64_ATTR_PREC.
> Date: Tue, 20 Jun 2006 10:15:01 +0200
> Cc: netdev@vger.kernel.org, Jeff Garzik <jeff@garzik.org>
> Content-Type: text/plain;
> charset="iso-8859-1"
>
> Hi Ralf,
>
> Ralf Baechle :
> > IOC3's homegrown DMA mapping functions that are used to optimize things
> > a little on IP27 set the wrong bit.
>
> What about using a symbol instead of magic numbers?
> That way one at least sees the intention of the coder.
>
> > Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
> >
> > diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c
> > index ae71ed5..e76e6e7 100644
> > --- a/drivers/net/ioc3-eth.c
> > +++ b/drivers/net/ioc3-eth.c
> > @@ -145,7 +145,7 @@ static inline struct sk_buff * ioc3_allo
> > static inline unsigned long ioc3_map(void *ptr, unsigned long vdev)
> > {
> > #ifdef CONFIG_SGI_IP27
> > - vdev <<= 58; /* Shift to PCI64_ATTR_VIRTUAL */
> > + vdev <<= 57; /* Shift to PCI64_ATTR_VIRTUAL */
>
> So please use a symbolic value here.
It is a hack and meant to look like one, loudly marked with #ifdef.
Ralf
^ permalink raw reply
* [PATCH 2.6.17] AT91RM9200 Ethernet #1: Link poll
From: Andrew Victor @ 2006-06-20 9:50 UTC (permalink / raw)
To: jgarzik; +Cc: netdev
For Ethernet PHYs that don't have an IRQ pin or boards that don't
connect the IRQ pin to the processor, we enable a timer to poll the
PHY's link state.
Patch originally supplied by Eric Benard and Roman Kolesnikov.
Signed-off-by: Andrew Victor <andrew@sanpeople.com>
diff -urN linux-2.6.17.orig/drivers/net/arm/at91_ether.c linux-2.6.17/drivers/net/arm/at91_ether.c
--- linux-2.6.17.orig/drivers/net/arm/at91_ether.c Tue Jun 20 11:27:37 2006
+++ linux-2.6.17/drivers/net/arm/at91_ether.c Tue Jun 20 11:31:06 2006
@@ -45,6 +45,9 @@
static struct net_device *at91_dev;
static struct clk *ether_clk;
+static struct timer_list check_timer;
+#define LINK_POLL_INTERVAL (HZ)
+
/* ..................................................................... */
/*
@@ -143,7 +146,7 @@
* MAC accordingly.
* If no link or auto-negotiation is busy, then no changes are made.
*/
-static void update_linkspeed(struct net_device *dev)
+static void update_linkspeed(struct net_device *dev, int silent)
{
struct at91_private *lp = (struct at91_private *) dev->priv;
unsigned int bmsr, bmcr, lpa, mac_cfg;
@@ -151,7 +154,8 @@
if (!mii_link_ok(&lp->mii)) { /* no link */
netif_carrier_off(dev);
- printk(KERN_INFO "%s: Link down.\n", dev->name);
+ if (!silent)
+ printk(KERN_INFO "%s: Link down.\n", dev->name);
return;
}
@@ -186,7 +190,8 @@
}
at91_emac_write(AT91_EMAC_CFG, mac_cfg);
- printk(KERN_INFO "%s: Link now %i-%s\n", dev->name, speed, (duplex == DUPLEX_FULL) ? "FullDuplex" : "HalfDuplex");
+ if (!silent)
+ printk(KERN_INFO "%s: Link now %i-%s\n", dev->name, speed, (duplex == DUPLEX_FULL) ? "FullDuplex" : "HalfDuplex");
netif_carrier_on(dev);
}
@@ -226,7 +231,7 @@
goto done;
}
- update_linkspeed(dev);
+ update_linkspeed(dev, 0);
done:
disable_mdi();
@@ -243,14 +248,17 @@
unsigned int dsintr, irq_number;
int status;
- if (lp->phy_type == MII_RTL8201_ID) /* RTL8201 does not have an interrupt */
- return;
- if (lp->phy_type == MII_DP83847_ID) /* DP83847 does not have an interrupt */
- return;
- if (lp->phy_type == MII_AC101L_ID) /* AC101L interrupt not supported yet */
+ irq_number = lp->board_data.phy_irq_pin;
+ if (!irq_number) {
+ /*
+ * PHY doesn't have an IRQ pin (RTL8201, DP83847, AC101L),
+ * or board does not have it connected.
+ */
+ check_timer.expires = jiffies + LINK_POLL_INTERVAL;
+ add_timer(&check_timer);
return;
+ }
- irq_number = lp->board_data.phy_irq_pin;
status = request_irq(irq_number, at91ether_phy_interrupt, 0, dev->name, dev);
if (status) {
printk(KERN_ERR "at91_ether: PHY IRQ %d request failed - status %d!\n", irq_number, status);
@@ -292,12 +300,11 @@
unsigned int dsintr;
unsigned int irq_number;
- if (lp->phy_type == MII_RTL8201_ID) /* RTL8201 does not have an interrupt */
- return;
- if (lp->phy_type == MII_DP83847_ID) /* DP83847 does not have an interrupt */
- return;
- if (lp->phy_type == MII_AC101L_ID) /* AC101L interrupt not supported yet */
+ irq_number = lp->board_data.phy_irq_pin;
+ if (!irq_number) {
+ del_timer_sync(&check_timer);
return;
+ }
spin_lock_irq(&lp->lock);
enable_mdi();
@@ -326,7 +333,6 @@
disable_mdi();
spin_unlock_irq(&lp->lock);
- irq_number = lp->board_data.phy_irq_pin;
free_irq(irq_number, dev); /* Free interrupt handler */
}
@@ -355,6 +361,18 @@
}
#endif
+static void at91ether_check_link(unsigned long dev_id)
+{
+ struct net_device *dev = (struct net_device *) dev_id;
+
+ enable_mdi();
+ update_linkspeed(dev, 1);
+ disable_mdi();
+
+ check_timer.expires = jiffies + LINK_POLL_INTERVAL;
+ add_timer(&check_timer);
+}
+
/* ......................... ADDRESS MANAGEMENT ........................ */
/*
@@ -708,7 +727,7 @@
/* Determine current link speed */
spin_lock_irq(&lp->lock);
enable_mdi();
- update_linkspeed(dev);
+ update_linkspeed(dev, 0);
disable_mdi();
spin_unlock_irq(&lp->lock);
@@ -992,11 +1011,18 @@
/* Determine current link speed */
spin_lock_irq(&lp->lock);
enable_mdi();
- update_linkspeed(dev);
+ update_linkspeed(dev, 0);
disable_mdi();
spin_unlock_irq(&lp->lock);
netif_carrier_off(dev); /* will be enabled in open() */
+ /* If board has no PHY IRQ, use a timer to poll the PHY */
+ if (!lp->board_data.phy_irq_pin) {
+ init_timer(&check_timer);
+ check_timer.data = (unsigned long)dev;
+ check_timer.function = at91ether_check_link;
+ }
+
/* Display ethernet banner */
printk(KERN_INFO "%s: AT91 ethernet at 0x%08x int=%d %s%s (%02x:%02x:%02x:%02x:%02x:%02x)\n",
dev->name, (uint) dev->base_addr, dev->irq,
^ permalink raw reply
* Re: [0/5] GSO: Generic Segmentation Offload
From: Herbert Xu @ 2006-06-20 9:32 UTC (permalink / raw)
To: David S. Miller, netdev
In-Reply-To: <20060620090919.GA31613@gondor.apana.org.au>
[-- Attachment #1: Type: text/plain, Size: 647 bytes --]
On Tue, Jun 20, 2006 at 07:09:19PM +1000, herbert wrote:
>
> I've attached some numbers to demonstrate the savings brought on by
> doing this. The best scenario is obviously the case where the underlying
> NIC supports SG. This means that we simply have to manipulate the SG
> entries and place them into individual skb's before passing them to the
> driver. The attached file lo-res shows this.
Obviously I forgot to attach them :)
--
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
[-- Attachment #2: lo-res --]
[-- Type: text/plain, Size: 1632 bytes --]
$ sudo ./ethtool -K lo gso on
$ sudo ifconfig lo mtu 1500
$ netperf -t TCP_STREAM
TCP STREAM TEST to localhost
Recv Send Send
Socket Socket Message Elapsed
Size Size Size Time Throughput
bytes bytes bytes secs. 10^6bits/sec
87380 16384 16384 10.00 3598.17
$ sudo ./ethtool -K lo gso off
$ netperf -t TCP_STREAM
TCP STREAM TEST to localhost
Recv Send Send
Socket Socket Message Elapsed
Size Size Size Time Throughput
bytes bytes bytes secs. 10^6bits/sec
87380 16384 16384 10.00 3061.05
$ sudo ifconfig lo mtu 60000
$ netperf -t TCP_STREAM
TCP STREAM TEST to localhost
Recv Send Send
Socket Socket Message Elapsed
Size Size Size Time Throughput
bytes bytes bytes secs. 10^6bits/sec
87380 16384 16384 10.00 8245.05
$ sudo ./ethtool -K lo gso on
$ netperf -t TCP_STREAM
TCP STREAM TEST to localhost
Recv Send Send
Socket Socket Message Elapsed
Size Size Size Time Throughput
bytes bytes bytes secs. 10^6bits/sec
87380 16384 16384 10.00 8563.36
$ sudo ifconfig lo mtu 16436
$ netperf -t TCP_STREAM
TCP STREAM TEST to localhost
Recv Send Send
Socket Socket Message Elapsed
Size Size Size Time Throughput
bytes bytes bytes secs. 10^6bits/sec
87380 16384 16384 10.00 7359.95
$ sudo ./ethtool -K lo gso off
$ netperf -t TCP_STREAM
TCP STREAM TEST to localhost
Recv Send Send
Socket Socket Message Elapsed
Size Size Size Time Throughput
bytes bytes bytes secs. 10^6bits/sec
87380 16384 16384 10.00 7535.04
$
[-- Attachment #3: gso-off --]
[-- Type: text/plain, Size: 12446 bytes --]
CPU: PIII, speed 1200 MHz (estimated)
Counted CPU_CLK_UNHALTED events (clocks processor is not halted) with a unit mask of 0x00 (No unit mask) count 100000
samples % symbol name
1247 21.7551 csum_partial_copy_generic
294 5.1291 prep_new_page
240 4.1870 __alloc_skb
120 2.0935 tcp_sendmsg
113 1.9714 get_offset_pmtmr
113 1.9714 kfree
103 1.7969 skb_release_data
103 1.7969 timer_interrupt
101 1.7620 ip_queue_xmit
96 1.6748 skb_clone
94 1.6399 __kmalloc
94 1.6399 net_rx_action
86 1.5003 tcp_transmit_skb
80 1.3957 kmem_cache_free
76 1.3259 tcp_clean_rtx_queue
67 1.1689 ip_output
66 1.1514 mark_offset_pmtmr
65 1.1340 tcp_v4_rcv
64 1.1165 local_bh_enable
62 1.0816 kmem_cache_alloc
59 1.0293 irq_entries_start
59 1.0293 page_fault
57 0.9944 tcp_push_one
52 0.9072 kfree_skbmem
47 0.8200 __qdisc_run
47 0.8200 csum_partial
47 0.8200 netif_receive_skb
46 0.8025 __kfree_skb
46 0.8025 tcp_init_tso_segs
44 0.7676 __copy_to_user_ll
44 0.7676 dev_queue_xmit
39 0.6804 pfifo_fast_enqueue
39 0.6804 system_call
37 0.6455 __copy_from_user_ll
37 0.6455 ip_rcv
36 0.6281 __tcp_select_window
33 0.5757 sock_wfree
31 0.5408 __do_softirq
31 0.5408 tcp_v4_send_check
30 0.5234 eth_header
28 0.4885 tcp_rcv_established
27 0.4710 restore_nocheck
26 0.4536 pfifo_fast_dequeue
25 0.4361 __do_IRQ
25 0.4361 do_softirq
25 0.4361 tcp_build_and_update_options
25 0.4361 tcp_snd_test
23 0.4013 cache_alloc_refill
23 0.4013 handle_IRQ_event
23 0.4013 tcp_ack
22 0.3838 free_block
22 0.3838 ip_route_input
21 0.3664 __netif_rx_schedule
21 0.3664 schedule
20 0.3489 do_wp_page
20 0.3489 neigh_resolve_output
19 0.3315 do_IRQ
19 0.3315 do_page_fault
19 0.3315 do_select
19 0.3315 fget_light
19 0.3315 ip_local_deliver
18 0.3140 __tcp_push_pending_frames
18 0.3140 end_level_ioapic_irq
17 0.2966 cpu_idle
17 0.2966 delay_pmtmr
17 0.2966 tcp_select_window
16 0.2791 add_wait_queue
16 0.2791 rt_hash_code
16 0.2791 tcp_set_skb_tso_segs
15 0.2617 find_vma
15 0.2617 irq_exit
15 0.2617 update_send_head
14 0.2442 __switch_to
13 0.2268 __skb_checksum_complete
13 0.2268 common_interrupt
13 0.2268 dev_kfree_skb_any
13 0.2268 tcp_event_data_sent
13 0.2268 zap_pte_range
12 0.2094 __d_lookup
12 0.2094 __page_set_anon_rmap
12 0.2094 mod_timer
12 0.2094 ret_from_intr
12 0.2094 sock_poll
12 0.2094 tcp_current_mss
12 0.2094 tcp_write_xmit
11 0.1919 do_no_page
11 0.1919 error_code
11 0.1919 free_hot_cold_page
11 0.1919 i8042_interrupt
10 0.1745 __link_path_walk
10 0.1745 buffered_rmqueue
10 0.1745 sk_reset_timer
9 0.1570 __rmqueue
9 0.1570 dev_hard_start_xmit
9 0.1570 free_pages_bulk
9 0.1570 resume_kernel
9 0.1570 skb_checksum
9 0.1570 tcp_cong_avoid
9 0.1570 tcp_rtt_estimator
8 0.1396 do_anonymous_page
8 0.1396 eth_type_trans
8 0.1396 get_page_from_freelist
8 0.1396 tcp_ack_saw_tstamp
8 0.1396 tcp_v4_checksum_init
7 0.1221 __wake_up
7 0.1221 atomic_notifier_call_chain
7 0.1221 normal_poll
7 0.1221 sk_stream_write_space
7 0.1221 tcp_ack_packets_out
7 0.1221 tcp_check_space
7 0.1221 tcp_cwnd_validate
7 0.1221 tcp_reno_cong_avoid
6 0.1047 __pagevec_lru_add_active
6 0.1047 copy_from_user
6 0.1047 hrtimer_get_softirq_time
6 0.1047 lock_sock
6 0.1047 lookup_bh_lru
6 0.1047 net_tx_action
6 0.1047 remove_wait_queue
6 0.1047 tcp_new_space
6 0.1047 unmap_vmas
5 0.0872 __copy_user_intel
5 0.0872 __handle_mm_fault
5 0.0872 __page_cache_release
5 0.0872 core_sys_select
5 0.0872 del_timer
5 0.0872 dnotify_parent
5 0.0872 filemap_nopage
5 0.0872 find_get_page
5 0.0872 kfree_skb
5 0.0872 lru_cache_add_active
5 0.0872 max_select_fd
5 0.0872 mod_page_state_offset
5 0.0872 note_interrupt
5 0.0872 pipe_poll
5 0.0872 prepare_to_wait
5 0.0872 restore_all
5 0.0872 scheduler_tick
5 0.0872 slab_put_obj
5 0.0872 syscall_exit
5 0.0872 try_to_wake_up
5 0.0872 zone_watermark_ok
4 0.0698 __sk_dst_check
4 0.0698 copy_to_user
4 0.0698 do_poll
4 0.0698 do_pollfd
4 0.0698 fput
4 0.0698 inotify_dentry_parent_queue_event
4 0.0698 inotify_inode_queue_event
4 0.0698 memcpy
4 0.0698 sk_stream_wait_memory
4 0.0698 slab_get_obj
4 0.0698 sock_sendmsg
4 0.0698 strncpy_from_user
4 0.0698 strnlen_user
4 0.0698 tcp_should_expand_sndbuf
4 0.0698 tty_poll
3 0.0523 __alloc_pages
3 0.0523 __copy_user_zeroing_intel
3 0.0523 __d_path
3 0.0523 __find_get_block
3 0.0523 __follow_mount
3 0.0523 __netif_schedule
3 0.0523 __wake_up_bit
3 0.0523 __wake_up_common
3 0.0523 _atomic_dec_and_lock
3 0.0523 activate_task
3 0.0523 anon_vma_prepare
3 0.0523 bh_lru_install
3 0.0523 cond_resched
3 0.0523 do_lookup
3 0.0523 do_path_lookup
3 0.0523 do_readv_writev
3 0.0523 dup_fd
3 0.0523 effective_prio
3 0.0523 hrtimer_run_queues
3 0.0523 ing_filter
3 0.0523 link_path_walk
3 0.0523 notifier_call_chain
3 0.0523 preempt_schedule
3 0.0523 radix_tree_lookup
3 0.0523 release_pages
3 0.0523 run_timer_softirq
3 0.0523 run_workqueue
3 0.0523 sys_sendto
3 0.0523 sys_writev
3 0.0523 tty_ldisc_deref
3 0.0523 unmap_page_range
3 0.0523 vm_normal_page
2 0.0349 __brelse
2 0.0349 __find_get_block_slow
2 0.0349 __getblk
2 0.0349 __mod_page_state_offset
2 0.0349 __mod_timer
2 0.0349 acct_update_integrals
2 0.0349 adjtime_adjustment
2 0.0349 alloc_sock_iocb
2 0.0349 apic_timer_interrupt
2 0.0349 bit_waitqueue
2 0.0349 cache_flusharray
2 0.0349 cache_reap
2 0.0349 d_alloc
2 0.0349 dput
2 0.0349 fget
2 0.0349 finish_wait
2 0.0349 init_timer
2 0.0349 lock_timer_base
2 0.0349 opost_block
2 0.0349 page_remove_rmap
2 0.0349 permission
2 0.0349 poll_get_entry
2 0.0349 poll_initwait
2 0.0349 profile_munmap
2 0.0349 pty_chars_in_buffer
2 0.0349 put_page
2 0.0349 raise_softirq
2 0.0349 recalc_task_prio
2 0.0349 resume_userspace
2 0.0349 ret_from_exception
2 0.0349 rmqueue_bulk
2 0.0349 rw_verify_area
2 0.0349 sched_clock
2 0.0349 setup_frame
2 0.0349 skb_queue_head
2 0.0349 sock_aio_read
2 0.0349 sock_def_readable
2 0.0349 sys_ioctl
2 0.0349 sys_read
2 0.0349 task_curr
2 0.0349 task_timeslice
2 0.0349 tty_ldisc_try
2 0.0349 vfs_read
2 0.0349 vma_adjust
2 0.0349 vma_link
1 0.0174 __block_write_full_page
1 0.0174 __dentry_open
1 0.0174 __dequeue_signal
1 0.0174 __do_page_cache_readahead
1 0.0174 __fput
1 0.0174 __generic_file_aio_read
1 0.0174 __group_complete_signal
1 0.0174 __ip_route_output_key
1 0.0174 __lookup_mnt
1 0.0174 __mark_inode_dirty
1 0.0174 __pollwait
1 0.0174 __put_task_struct
1 0.0174 __put_user_4
1 0.0174 __queue_work
1 0.0174 __rcu_pending
1 0.0174 __sigqueue_alloc
1 0.0174 __vma_link_rb
1 0.0174 alloc_inode
1 0.0174 alloc_slabmgmt
1 0.0174 arch_unmap_area_topdown
1 0.0174 as_add_request
1 0.0174 as_fifo_expired
1 0.0174 as_find_next_arq
1 0.0174 autoremove_wake_function
1 0.0174 bio_init
1 0.0174 block_read_full_page
1 0.0174 cached_lookup
1 0.0174 can_vma_merge_before
1 0.0174 con_chars_in_buffer
1 0.0174 convert_fxsr_from_user
1 0.0174 copy_from_read_buf
1 0.0174 copy_pte_range
1 0.0174 cp_new_stat64
1 0.0174 d_splice_alias
1 0.0174 do_exit
1 0.0174 do_filp_open
1 0.0174 do_fork
1 0.0174 do_getname
1 0.0174 do_gettimeofday
1 0.0174 do_mpage_readpage
1 0.0174 do_sigaction
1 0.0174 do_sock_read
1 0.0174 do_sock_write
1 0.0174 do_sync_write
1 0.0174 do_timer
1 0.0174 drain_array
1 0.0174 dummy_inode_permission
1 0.0174 dup_mm
1 0.0174 dup_task_struct
1 0.0174 elv_queue_empty
1 0.0174 enqueue_hrtimer
1 0.0174 enqueue_task
1 0.0174 exit_mmap
1 0.0174 file_ra_state_init
1 0.0174 filesystems_read_proc
1 0.0174 find_vma_prev
1 0.0174 free_poll_entry
1 0.0174 generic_permission
1 0.0174 get_index
1 0.0174 get_signal_to_deliver
1 0.0174 get_vmalloc_info
1 0.0174 getname
1 0.0174 handle_signal
1 0.0174 hrtimer_try_to_cancel
1 0.0174 inet_csk_init_xmit_timers
1 0.0174 init_buffer_head
1 0.0174 inode_change_ok
1 0.0174 inode_init_once
1 0.0174 kbd_bh
1 0.0174 kmem_cache_zalloc
1 0.0174 kmem_getpages
1 0.0174 load_elf_binary
1 0.0174 locks_remove_posix
1 0.0174 memmove
1 0.0174 mempool_free
1 0.0174 mmput
1 0.0174 mutex_lock
1 0.0174 netlink_insert
1 0.0174 no_singlestep
1 0.0174 nr_blockdev_pages
1 0.0174 number
1 0.0174 open_namei
1 0.0174 page_add_new_anon_rmap
1 0.0174 path_release
1 0.0174 pipe_release
1 0.0174 poke_blanked_console
1 0.0174 proc_pid_readlink
1 0.0174 pty_unthrottle
1 0.0174 put_filp
1 0.0174 radix_tree_insert
1 0.0174 raise_softirq_irqoff
1 0.0174 rb_insert_color
1 0.0174 rcu_do_batch
1 0.0174 rcu_pending
1 0.0174 release_sock
1 0.0174 remove_vma
1 0.0174 restore_sigcontext
1 0.0174 search_binary_handler
1 0.0174 sk_wait_data
1 0.0174 skb_dequeue
1 0.0174 skb_queue_tail
1 0.0174 sock_aio_write
1 0.0174 sock_alloc_send_pskb
1 0.0174 sock_def_write_space
1 0.0174 sock_from_file
1 0.0174 sock_ioctl
1 0.0174 submit_bio
1 0.0174 sys_fcntl64
1 0.0174 sys_fstat64
1 0.0174 sys_rt_sigaction
1 0.0174 sys_rt_sigprocmask
1 0.0174 sys_send
1 0.0174 sys_sigreturn
1 0.0174 sys_socketcall
1 0.0174 sys_waitpid
1 0.0174 tcp_close
1 0.0174 tcp_data_queue
1 0.0174 tcp_fastretrans_alert
1 0.0174 tcp_grow_window
1 0.0174 tcp_mtu_probe
1 0.0174 tcp_v4_do_rcv
1 0.0174 tty_hung_up_p
1 0.0174 tty_insert_flip_string_flags
1 0.0174 tty_paranoia_check
1 0.0174 tty_wakeup
1 0.0174 tty_write
1 0.0174 unlock_buffer
1 0.0174 unmap_region
1 0.0174 update_process_times
1 0.0174 update_wall_time
1 0.0174 update_wall_time_one_tick
1 0.0174 vfs_ioctl
1 0.0174 vfs_permission
1 0.0174 vma_prio_tree_add
1 0.0174 wait_task_zombie
[-- Attachment #4: gso-on --]
[-- Type: text/plain, Size: 12774 bytes --]
CPU: PIII, speed 1200 MHz (estimated)
Counted CPU_CLK_UNHALTED events (clocks processor is not halted) with a unit mask of 0x00 (No unit mask) count 100000
samples % symbol name
1255 21.6865 csum_partial_copy_generic
398 6.8775 __copy_from_user_ll
343 5.9271 __alloc_skb
254 4.3891 prep_new_page
243 4.1991 skb_segment
110 1.9008 __kmalloc
106 1.8317 kfree
106 1.8317 timer_interrupt
105 1.8144 skb_copy_and_csum_bits
94 1.6243 net_rx_action
77 1.3306 kmem_cache_free
75 1.2960 tcp_v4_rcv
72 1.2442 kmem_cache_alloc
63 1.0886 page_fault
55 0.9504 mark_offset_pmtmr
54 0.9331 __kfree_skb
52 0.8986 skb_release_data
51 0.8813 csum_partial
50 0.8640 do_softirq
50 0.8640 inet_gso_segment
47 0.8122 get_offset_pmtmr
47 0.8122 irq_entries_start
45 0.7776 netif_receive_skb
43 0.7430 tcp_current_mss
41 0.7085 free_hot_cold_page
40 0.6912 tcp_clean_rtx_queue
36 0.6221 kfree_skbmem
35 0.6048 tcp_sendmsg
35 0.6048 tcp_write_xmit
34 0.5875 __do_softirq
31 0.5357 __do_IRQ
31 0.5357 ip_rcv
31 0.5357 tcp_rcv_established
30 0.5184 __pskb_trim_head
29 0.5011 system_call
28 0.4838 tcp_ack
28 0.4838 tcp_tso_segment
28 0.4838 tcp_tso_should_defer
27 0.4666 __copy_to_user_ll
26 0.4493 restore_nocheck
26 0.4493 rt_hash_code
25 0.4320 do_wp_page
24 0.4147 handle_IRQ_event
24 0.4147 schedule
23 0.3974 do_select
23 0.3974 tcp_tso_acked
22 0.3802 ip_local_deliver
22 0.3802 ip_route_input
21 0.3629 buffered_rmqueue
21 0.3629 free_block
20 0.3456 end_level_ioapic_irq
20 0.3456 tcp_init_tso_segs
19 0.3283 __netif_rx_schedule
19 0.3283 cache_alloc_refill
19 0.3283 dev_kfree_skb_any
18 0.3110 skb_split
17 0.2938 ret_from_intr
17 0.2938 tcp_mark_head_lost
16 0.2765 common_interrupt
16 0.2765 do_page_fault
16 0.2765 get_page_from_freelist
16 0.2765 slab_put_obj
15 0.2592 do_IRQ
15 0.2592 sock_poll
15 0.2592 zap_pte_range
14 0.2419 irq_exit
14 0.2419 tcp_trim_head
14 0.2419 tcp_v4_checksum_init
13 0.2246 __link_path_walk
13 0.2246 add_wait_queue
13 0.2246 delay_pmtmr
13 0.2246 tcp_rtt_estimator
12 0.2074 __skb_checksum_complete
12 0.2074 cpu_idle
12 0.2074 fget_light
12 0.2074 find_vma
12 0.2074 skb_checksum
12 0.2074 tcp_new_space
11 0.1901 copy_from_user
11 0.1901 put_page
11 0.1901 tcp_set_skb_tso_segs
10 0.1728 __d_lookup
10 0.1728 __switch_to
10 0.1728 error_code
10 0.1728 eth_type_trans
10 0.1728 i8042_interrupt
10 0.1728 skb_copy_bits
10 0.1728 tcp_transmit_skb
9 0.1555 dev_hard_start_xmit
9 0.1555 mod_page_state_offset
9 0.1555 strnlen_user
8 0.1382 __page_set_anon_rmap
8 0.1382 do_no_page
8 0.1382 ip_output
8 0.1382 resume_kernel
8 0.1382 skb_clone
8 0.1382 tcp_check_space
8 0.1382 tcp_xmit_retransmit_queue
7 0.1210 __mod_timer
7 0.1210 __tcp_push_pending_frames
7 0.1210 __tcp_select_window
7 0.1210 ip_queue_xmit
7 0.1210 mod_timer
7 0.1210 pipe_poll
7 0.1210 remove_wait_queue
7 0.1210 zone_watermark_ok
6 0.1037 __pagevec_lru_add_active
6 0.1037 core_sys_select
6 0.1037 do_pollfd
6 0.1037 find_get_page
6 0.1037 note_interrupt
6 0.1037 sk_stream_write_space
6 0.1037 skb_gso_segment
6 0.1037 sys_read
6 0.1037 tcp_ack_packets_out
6 0.1037 tcp_cong_avoid
6 0.1037 tcp_reno_cong_avoid
5 0.0864 __rmqueue
5 0.0864 __wake_up
5 0.0864 __wake_up_common
5 0.0864 dev_queue_xmit
5 0.0864 eth_header
5 0.0864 filemap_nopage
5 0.0864 fput
5 0.0864 free_pages_bulk
5 0.0864 internal_add_timer
5 0.0864 local_bh_enable
5 0.0864 lookup_bh_lru
5 0.0864 sys_socketcall
5 0.0864 syscall_exit
5 0.0864 tcp_mtu_probe
5 0.0864 tcp_v4_do_rcv
4 0.0691 __copy_user_intel
4 0.0691 __handle_mm_fault
4 0.0691 __mod_page_state_offset
4 0.0691 __page_cache_release
4 0.0691 __pollwait
4 0.0691 __qdisc_run
4 0.0691 adjtime_adjustment
4 0.0691 apic_timer_interrupt
4 0.0691 cond_resched
4 0.0691 hrtimer_run_queues
4 0.0691 kfree_skb
4 0.0691 lock_timer_base
4 0.0691 normal_poll
4 0.0691 opost_block
4 0.0691 pfifo_fast_enqueue
4 0.0691 preempt_schedule
4 0.0691 pskb_expand_head
4 0.0691 radix_tree_lookup
4 0.0691 resume_userspace
4 0.0691 sk_reset_timer
4 0.0691 skb_dequeue
4 0.0691 sys_send
4 0.0691 tcp_sacktag_write_queue
4 0.0691 tty_ldisc_try
4 0.0691 vfs_permission
3 0.0518 __alloc_pages
3 0.0518 __find_get_block
3 0.0518 __sk_dst_check
3 0.0518 anon_vma_prepare
3 0.0518 do_mmap_pgoff
3 0.0518 do_readv_writev
3 0.0518 do_sock_read
3 0.0518 dup_mm
3 0.0518 generic_permission
3 0.0518 hrtimer_get_softirq_time
3 0.0518 ing_filter
3 0.0518 lru_cache_add_active
3 0.0518 page_add_new_anon_rmap
3 0.0518 permission
3 0.0518 pfifo_fast_dequeue
3 0.0518 pty_chars_in_buffer
3 0.0518 raise_softirq
3 0.0518 rb_insert_color
3 0.0518 release_pages
3 0.0518 restore_all
3 0.0518 run_timer_softirq
3 0.0518 rw_verify_area
3 0.0518 slab_get_obj
3 0.0518 sock_wfree
3 0.0518 tcp_ack_saw_tstamp
3 0.0518 tcp_build_and_update_options
3 0.0518 tcp_event_data_sent
3 0.0518 tcp_should_expand_sndbuf
3 0.0518 tcp_v4_send_check
3 0.0518 tso_fragment
3 0.0518 unmap_vmas
3 0.0518 update_wall_time
3 0.0518 vsnprintf
2 0.0346 __rcu_pending
2 0.0346 _atomic_dec_and_lock
2 0.0346 account_system_time
2 0.0346 acct_update_integrals
2 0.0346 blk_recount_segments
2 0.0346 cache_flusharray
2 0.0346 cleanup_timers
2 0.0346 copy_pte_range
2 0.0346 cp_new_stat64
2 0.0346 current_fs_time
2 0.0346 d_instantiate
2 0.0346 default_wake_function
2 0.0346 dequeue_task
2 0.0346 dnotify_parent
2 0.0346 do_anonymous_page
2 0.0346 do_gettimeofday
2 0.0346 do_path_lookup
2 0.0346 do_setitimer
2 0.0346 do_sys_poll
2 0.0346 drain_array
2 0.0346 effective_prio
2 0.0346 find_next_zero_bit
2 0.0346 inode_init_once
2 0.0346 input_event
2 0.0346 max_select_fd
2 0.0346 memcpy
2 0.0346 memmove
2 0.0346 need_resched
2 0.0346 neigh_resolve_output
2 0.0346 no_singlestep
2 0.0346 notifier_call_chain
2 0.0346 page_remove_rmap
2 0.0346 poll_freewait
2 0.0346 prepare_to_wait
2 0.0346 recalc_task_prio
2 0.0346 rmqueue_bulk
2 0.0346 schedule_timeout
2 0.0346 scheduler_tick
2 0.0346 skb_queue_tail
2 0.0346 sock_aio_read
2 0.0346 sock_aio_write
2 0.0346 sock_from_file
2 0.0346 sock_sendmsg
2 0.0346 strncpy_from_user
2 0.0346 sys_gettimeofday
2 0.0346 sys_sendto
2 0.0346 tcp_cwnd_down
2 0.0346 tcp_data_queue
2 0.0346 tcp_fastretrans_alert
2 0.0346 tcp_parse_options
2 0.0346 tcp_push_one
2 0.0346 tcp_select_window
2 0.0346 tcp_snd_test
2 0.0346 transfer_objects
2 0.0346 try_to_wake_up
2 0.0346 tty_write
2 0.0346 unmap_page_range
2 0.0346 vfs_ioctl
2 0.0346 vma_adjust
1 0.0173 __bread
1 0.0173 __brelse
1 0.0173 __dentry_open
1 0.0173 __dequeue_signal
1 0.0173 __exit_signal
1 0.0173 __find_get_block_slow
1 0.0173 __group_complete_signal
1 0.0173 __insert_inode_hash
1 0.0173 __lookup_mnt
1 0.0173 __netif_schedule
1 0.0173 __pskb_pull_tail
1 0.0173 __pte_alloc
1 0.0173 __tasklet_schedule
1 0.0173 __wake_up_bit
1 0.0173 acct_process
1 0.0173 ack_edge_ioapic_irq
1 0.0173 acquire_console_sem
1 0.0173 activate_task
1 0.0173 alarm_setitimer
1 0.0173 alloc_new_pmd
1 0.0173 as_dispatch_request
1 0.0173 as_merged_request
1 0.0173 autoremove_wake_function
1 0.0173 bh_lru_install
1 0.0173 bit_waitqueue
1 0.0173 block_read_full_page
1 0.0173 cache_reap
1 0.0173 check_itimerval
1 0.0173 clear_user
1 0.0173 con_chars_in_buffer
1 0.0173 convert_fxsr_to_user
1 0.0173 copy_semundo
1 0.0173 copy_strings
1 0.0173 copy_to_user
1 0.0173 d_rehash
1 0.0173 deactivate_task
1 0.0173 dev_gso_segment
1 0.0173 do_fcntl
1 0.0173 do_generic_mapping_read
1 0.0173 do_lookup
1 0.0173 do_poll
1 0.0173 do_sigaction
1 0.0173 do_sync_read
1 0.0173 do_sys_open
1 0.0173 dummy_vm_enough_memory
1 0.0173 dup_fd
1 0.0173 enqueue_task
1 0.0173 exec_permission_lite
1 0.0173 file_ra_state_init
1 0.0173 file_update_time
1 0.0173 filp_close
1 0.0173 find_task_by_pid_type
1 0.0173 finish_wait
1 0.0173 flush_old_exec
1 0.0173 free_one_page
1 0.0173 free_page_and_swap_cache
1 0.0173 free_poll_entry
1 0.0173 free_uid
1 0.0173 get_empty_filp
1 0.0173 get_index
1 0.0173 get_signal_to_deliver
1 0.0173 get_task_mm
1 0.0173 get_vmalloc_info
1 0.0173 getname
1 0.0173 group_send_sig_info
1 0.0173 groups_search
1 0.0173 handle_signal
1 0.0173 hrtimer_try_to_cancel
1 0.0173 inode_setattr
1 0.0173 inode_sub_bytes
1 0.0173 inotify_dentry_parent_queue_event
1 0.0173 inotify_inode_queue_event
1 0.0173 kbd_keycode
1 0.0173 kmem_cache_zalloc
1 0.0173 kthread_should_stop
1 0.0173 locks_remove_flock
1 0.0173 lookup_create
1 0.0173 make_ahead_window
1 0.0173 mark_page_accessed
1 0.0173 math_state_restore
1 0.0173 may_expand_vm
1 0.0173 n_tty_receive_buf
1 0.0173 nameidata_to_filp
1 0.0173 opost
1 0.0173 page_waitqueue
1 0.0173 prio_tree_remove
1 0.0173 proc_file_read
1 0.0173 profile_munmap
1 0.0173 profile_tick
1 0.0173 put_io_context
1 0.0173 rb_next
1 0.0173 rcu_do_batch
1 0.0173 rcu_pending
1 0.0173 recalc_sigpending_tsk
1 0.0173 run_local_timers
1 0.0173 run_posix_cpu_timers
1 0.0173 save_i387
1 0.0173 sched_clock
1 0.0173 setup_frame
1 0.0173 signal_wake_up
1 0.0173 sk_stream_wait_memory
1 0.0173 skb_checksum_help
1 0.0173 slab_destroy
1 0.0173 smp_send_timer_broadcast_ipi
1 0.0173 sock_def_readable
1 0.0173 sock_ioctl
1 0.0173 sys_getpid
1 0.0173 sys_munmap
1 0.0173 syscall_call
1 0.0173 tcp_ack_update_window
1 0.0173 tcp_check_sack_reneging
1 0.0173 tcp_fast_parse_options
1 0.0173 tcp_fragment
1 0.0173 tcp_mtu_to_mss
1 0.0173 tcp_window_allows
1 0.0173 timespec_trunc
1 0.0173 tty_hung_up_p
1 0.0173 tty_ldisc_deref
1 0.0173 tty_poll
1 0.0173 unlink_file_vma
1 0.0173 vfs_getattr
1 0.0173 vfs_read
1 0.0173 vfs_write
1 0.0173 vm_normal_page
1 0.0173 vm_stat_account
1 0.0173 vma_prio_tree_add
1 0.0173 zone_statistics
^ permalink raw reply
* [5/5] [IPSEC]: Handle GSO packets
From: Herbert Xu @ 2006-06-20 9:30 UTC (permalink / raw)
To: David S. Miller, netdev
In-Reply-To: <20060620090919.GA31613@gondor.apana.org.au>
[-- Attachment #1: Type: text/plain, Size: 767 bytes --]
Hi:
[IPSEC]: Handle GSO packets
This patch segments GSO packets received by the IPsec stack. This can
happen when a NIC driver injects GSO packets into the stack which are
then forwarded to another host.
The primary application of this is going to be Xen where its backend
driver may inject GSO packets into dom0.
Of course this also can be used by other virtualisation schemes such as
VMWare or UML since the tap device could be modified to inject GSO packets
received through splice.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Cheers,
--
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
[-- Attachment #2: p5.patch --]
[-- Type: text/plain, Size: 3351 bytes --]
diff --git a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c
--- a/net/ipv4/xfrm4_output.c
+++ b/net/ipv4/xfrm4_output.c
@@ -9,6 +9,8 @@
*/
#include <linux/compiler.h>
+#include <linux/if_ether.h>
+#include <linux/kernel.h>
#include <linux/skbuff.h>
#include <linux/spinlock.h>
#include <linux/netfilter_ipv4.h>
@@ -97,16 +99,10 @@ error_nolock:
goto out_exit;
}
-static int xfrm4_output_finish(struct sk_buff *skb)
+static int xfrm4_output_finish2(struct sk_buff *skb)
{
int err;
-#ifdef CONFIG_NETFILTER
- if (!skb->dst->xfrm) {
- IPCB(skb)->flags |= IPSKB_REROUTED;
- return dst_output(skb);
- }
-#endif
while (likely((err = xfrm4_output_one(skb)) == 0)) {
nf_reset(skb);
@@ -119,7 +115,7 @@ static int xfrm4_output_finish(struct sk
return dst_output(skb);
err = nf_hook(PF_INET, NF_IP_POST_ROUTING, &skb, NULL,
- skb->dst->dev, xfrm4_output_finish);
+ skb->dst->dev, xfrm4_output_finish2);
if (unlikely(err != 1))
break;
}
@@ -127,6 +123,48 @@ static int xfrm4_output_finish(struct sk
return err;
}
+static int xfrm4_output_finish(struct sk_buff *skb)
+{
+ struct sk_buff *segs;
+
+#ifdef CONFIG_NETFILTER
+ if (!skb->dst->xfrm) {
+ IPCB(skb)->flags |= IPSKB_REROUTED;
+ return dst_output(skb);
+ }
+#endif
+
+ if (!skb_shinfo(skb)->gso_size)
+ return xfrm4_output_finish2(skb);
+
+ skb->protocol = htons(ETH_P_IP);
+ segs = skb_gso_segment(skb, 0);
+ kfree_skb(skb);
+ if (unlikely(IS_ERR(segs)))
+ return PTR_ERR(segs);
+
+ do {
+ struct sk_buff *nskb = segs->next;
+ int err;
+
+ segs->next = NULL;
+ err = xfrm4_output_finish2(segs);
+
+ if (unlikely(err)) {
+ while ((segs = nskb)) {
+ nskb = segs->next;
+ segs->next = NULL;
+ kfree_skb(segs);
+ }
+ return err;
+ }
+
+ segs = nskb;
+ } while (segs);
+
+ return 0;
+}
+
int xfrm4_output(struct sk_buff *skb)
{
return NF_HOOK_COND(PF_INET, NF_IP_POST_ROUTING, skb, NULL, skb->dst->dev,
diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c
--- a/net/ipv6/xfrm6_output.c
+++ b/net/ipv6/xfrm6_output.c
@@ -94,7 +94,7 @@ error_nolock:
goto out_exit;
}
-static int xfrm6_output_finish(struct sk_buff *skb)
+static int xfrm6_output_finish2(struct sk_buff *skb)
{
int err;
@@ -110,7 +110,7 @@ static int xfrm6_output_finish(struct sk
return dst_output(skb);
err = nf_hook(PF_INET6, NF_IP6_POST_ROUTING, &skb, NULL,
- skb->dst->dev, xfrm6_output_finish);
+ skb->dst->dev, xfrm6_output_finish2);
if (unlikely(err != 1))
break;
}
@@ -118,6 +118,41 @@ static int xfrm6_output_finish(struct sk
return err;
}
+static int xfrm6_output_finish(struct sk_buff *skb)
+{
+ struct sk_buff *segs;
+
+ if (!skb_shinfo(skb)->gso_size)
+ return xfrm6_output_finish2(skb);
+
+ skb->protocol = htons(ETH_P_IP);
+ segs = skb_gso_segment(skb, 0);
+ kfree_skb(skb);
+ if (unlikely(IS_ERR(segs)))
+ return PTR_ERR(segs);
+
+ do {
+ struct sk_buff *nskb = segs->next;
+ int err;
+
+ segs->next = NULL;
+ err = xfrm6_output_finish2(segs);
+
+ if (unlikely(err)) {
+ while ((segs = nskb)) {
+ nskb = segs->next;
+ segs->next = NULL;
+ kfree_skb(segs);
+ }
+ return err;
+ }
+
+ segs = nskb;
+ } while (segs);
+
+ return 0;
+}
+
int xfrm6_output(struct sk_buff *skb)
{
return NF_HOOK(PF_INET6, NF_IP6_POST_ROUTING, skb, NULL, skb->dst->dev,
^ permalink raw reply
* [4/5] [NET]: Added GSO toggle
From: Herbert Xu @ 2006-06-20 9:30 UTC (permalink / raw)
To: David S. Miller, netdev
In-Reply-To: <20060620090919.GA31613@gondor.apana.org.au>
[-- Attachment #1: Type: text/plain, Size: 443 bytes --]
Hi:
[NET]: Added GSO toggle
This patch adds a generic segmentation offload toggle that can be turned
on/off for each net device. For now it only supports in TCPv4.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Cheers,
--
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
[-- Attachment #2: p4.patch --]
[-- Type: text/plain, Size: 3869 bytes --]
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -408,6 +408,8 @@ struct ethtool_ops {
#define ETHTOOL_GPERMADDR 0x00000020 /* Get permanent hardware address */
#define ETHTOOL_GUFO 0x00000021 /* Get UFO enable (ethtool_value) */
#define ETHTOOL_SUFO 0x00000022 /* Set UFO enable (ethtool_value) */
+#define ETHTOOL_GGSO 0x00000023 /* Get GSO enable (ethtool_value) */
+#define ETHTOOL_SGSO 0x00000024 /* Set GSO enable (ethtool_value) */
/* compatibility with older code */
#define SPARC_ETH_GSET ETHTOOL_GSET
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -309,6 +309,7 @@ struct net_device
#define NETIF_F_HW_VLAN_RX 256 /* Receive VLAN hw acceleration */
#define NETIF_F_HW_VLAN_FILTER 512 /* Receive filtering on VLAN */
#define NETIF_F_VLAN_CHALLENGED 1024 /* Device cannot handle VLAN packets */
+#define NETIF_F_GSO 2048 /* Enable software GSO. */
#define NETIF_F_LLTX 4096 /* LockLess TX */
/* Segmentation offload features */
diff --git a/include/net/sock.h b/include/net/sock.h
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -1031,9 +1031,13 @@ static inline void sk_setup_caps(struct
{
__sk_dst_set(sk, dst);
sk->sk_route_caps = dst->dev->features;
+ if (sk->sk_route_caps & NETIF_F_GSO)
+ sk->sk_route_caps |= NETIF_F_TSO;
if (sk->sk_route_caps & NETIF_F_TSO) {
if (sock_flag(sk, SOCK_NO_LARGESEND) || dst->header_len)
sk->sk_route_caps &= ~NETIF_F_TSO;
+ else
+ sk->sk_route_caps |= NETIF_F_SG | NETIF_F_HW_CSUM;
}
}
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -376,15 +376,20 @@ void br_features_recompute(struct net_br
features = br->feature_mask & ~NETIF_F_ALL_CSUM;
list_for_each_entry(p, &br->port_list, list) {
- if (checksum & NETIF_F_NO_CSUM &&
- !(p->dev->features & NETIF_F_NO_CSUM))
+ unsigned long feature = p->dev->features;
+
+ if (checksum & NETIF_F_NO_CSUM && !(feature & NETIF_F_NO_CSUM))
checksum ^= NETIF_F_NO_CSUM | NETIF_F_HW_CSUM;
- if (checksum & NETIF_F_HW_CSUM &&
- !(p->dev->features & NETIF_F_HW_CSUM))
+ if (checksum & NETIF_F_HW_CSUM && !(feature & NETIF_F_HW_CSUM))
checksum ^= NETIF_F_HW_CSUM | NETIF_F_IP_CSUM;
- if (!(p->dev->features & NETIF_F_IP_CSUM))
+ if (!(feature & NETIF_F_IP_CSUM))
checksum = 0;
- features &= p->dev->features;
+
+ if (feature & NETIF_F_GSO)
+ feature |= NETIF_F_TSO;
+ feature |= NETIF_F_GSO;
+
+ features &= feature;
}
br->dev->features = features | checksum | NETIF_F_LLTX;
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -614,6 +614,29 @@ static int ethtool_set_ufo(struct net_de
return dev->ethtool_ops->set_ufo(dev, edata.data);
}
+static int ethtool_get_gso(struct net_device *dev, char __user *useraddr)
+{
+ struct ethtool_value edata = { ETHTOOL_GGSO };
+
+ edata.data = dev->features & NETIF_F_GSO;
+ if (copy_to_user(useraddr, &edata, sizeof(edata)))
+ return -EFAULT;
+ return 0;
+}
+
+static int ethtool_set_gso(struct net_device *dev, char __user *useraddr)
+{
+ struct ethtool_value edata;
+
+ if (copy_from_user(&edata, useraddr, sizeof(edata)))
+ return -EFAULT;
+ if (edata.data)
+ dev->features |= NETIF_F_GSO;
+ else
+ dev->features &= ~NETIF_F_GSO;
+ return 0;
+}
+
static int ethtool_self_test(struct net_device *dev, char __user *useraddr)
{
struct ethtool_test test;
@@ -905,6 +928,12 @@ int dev_ethtool(struct ifreq *ifr)
case ETHTOOL_SUFO:
rc = ethtool_set_ufo(dev, useraddr);
break;
+ case ETHTOOL_GGSO:
+ rc = ethtool_get_gso(dev, useraddr);
+ break;
+ case ETHTOOL_SGSO:
+ rc = ethtool_set_gso(dev, useraddr);
+ break;
default:
rc = -EOPNOTSUPP;
}
^ permalink raw reply
* [3/5] [NET]: Add software TSOv4
From: Herbert Xu @ 2006-06-20 9:29 UTC (permalink / raw)
To: David S. Miller, netdev
In-Reply-To: <20060620090919.GA31613@gondor.apana.org.au>
[-- Attachment #1: Type: text/plain, Size: 361 bytes --]
Hi:
[NET]: Add software TSOv4
This patch adds the GSO implementation for IPv4 TCP.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Cheers,
--
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
[-- Attachment #2: p3.patch --]
[-- Type: text/plain, Size: 7982 bytes --]
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -1299,6 +1299,7 @@ extern void skb_split(struct sk_b
struct sk_buff *skb1, const u32 len);
extern void skb_release_data(struct sk_buff *skb);
+extern struct sk_buff *skb_segment(struct sk_buff *skb, int sg);
static inline void *skb_header_pointer(const struct sk_buff *skb, int offset,
int len, void *buffer)
diff --git a/include/net/protocol.h b/include/net/protocol.h
--- a/include/net/protocol.h
+++ b/include/net/protocol.h
@@ -37,6 +37,7 @@
struct net_protocol {
int (*handler)(struct sk_buff *skb);
void (*err_handler)(struct sk_buff *skb, u32 info);
+ struct sk_buff *(*gso_segment)(struct sk_buff *skb, int sg);
int no_policy;
};
diff --git a/include/net/tcp.h b/include/net/tcp.h
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -1087,6 +1087,8 @@ extern struct request_sock_ops tcp_reque
extern int tcp_v4_destroy_sock(struct sock *sk);
+extern struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int sg);
+
#ifdef CONFIG_PROC_FS
extern int tcp4_proc_init(void);
extern void tcp4_proc_exit(void);
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -1826,6 +1826,132 @@ unsigned char *skb_pull_rcsum(struct sk_
EXPORT_SYMBOL_GPL(skb_pull_rcsum);
+/**
+ * skb_segment - Perform protocol segmentation on skb.
+ * @skb: buffer to segment
+ * @sg: whether scatter-gather can be used for generated segments
+ *
+ * This function performs segmentation on the given skb. It returns
+ * the segment at the given position. It returns NULL if there are
+ * no more segments to generate, or when an error is encountered.
+ */
+struct sk_buff *skb_segment(struct sk_buff *skb, int sg)
+{
+ struct sk_buff *segs = NULL;
+ struct sk_buff *tail = NULL;
+ unsigned int mss = skb_shinfo(skb)->gso_size;
+ unsigned int doffset = skb->data - skb->mac.raw;
+ unsigned int offset = doffset;
+ unsigned int headroom;
+ unsigned int len;
+ int nfrags = skb_shinfo(skb)->nr_frags;
+ int err = -ENOMEM;
+ int i = 0;
+ int pos;
+
+ __skb_push(skb, doffset);
+ headroom = skb_headroom(skb);
+ pos = skb_headlen(skb);
+
+ do {
+ struct sk_buff *nskb;
+ skb_frag_t *frag;
+ int hsize, nsize;
+ int k;
+ int size;
+
+ len = skb->len - offset;
+ if (len > mss)
+ len = mss;
+
+ hsize = skb_headlen(skb) - offset;
+ if (hsize < 0)
+ hsize = 0;
+ nsize = hsize + doffset;
+ if (nsize > len + doffset || !sg)
+ nsize = len + doffset;
+
+ nskb = alloc_skb(nsize + headroom, GFP_ATOMIC);
+ if (unlikely(!nskb))
+ goto err;
+
+ if (segs)
+ tail->next = nskb;
+ else
+ segs = nskb;
+ tail = nskb;
+
+ nskb->dev = skb->dev;
+ nskb->priority = skb->priority;
+ nskb->protocol = skb->protocol;
+ nskb->dst = dst_clone(skb->dst);
+ memcpy(nskb->cb, skb->cb, sizeof(skb->cb));
+ nskb->pkt_type = skb->pkt_type;
+ nskb->mac_len = skb->mac_len;
+
+ skb_reserve(nskb, headroom);
+ nskb->mac.raw = nskb->data;
+ nskb->nh.raw = nskb->data + skb->mac_len;
+ nskb->h.raw = nskb->nh.raw + (skb->h.raw - skb->nh.raw);
+ memcpy(skb_put(nskb, doffset), skb->data, doffset);
+
+ if (!sg) {
+ nskb->csum = skb_copy_and_csum_bits(skb, offset,
+ skb_put(nskb, len),
+ len, 0);
+ continue;
+ }
+
+ frag = skb_shinfo(nskb)->frags;
+ k = 0;
+
+ nskb->ip_summed = CHECKSUM_HW;
+ nskb->csum = skb->csum;
+ memcpy(skb_put(nskb, hsize), skb->data + offset, hsize);
+
+ while (pos < offset + len) {
+ BUG_ON(i >= nfrags);
+
+ *frag = skb_shinfo(skb)->frags[i];
+ get_page(frag->page);
+ size = frag->size;
+
+ if (pos < offset) {
+ frag->page_offset += offset - pos;
+ frag->size -= offset - pos;
+ }
+
+ k++;
+
+ if (pos + size <= offset + len) {
+ i++;
+ pos += size;
+ } else {
+ frag->size -= pos + size - (offset + len);
+ break;
+ }
+
+ frag++;
+ }
+
+ skb_shinfo(nskb)->nr_frags = k;
+ nskb->data_len = len - hsize;
+ nskb->len += nskb->data_len;
+ nskb->truesize += nskb->data_len;
+ } while ((offset += len) < skb->len);
+
+ return segs;
+
+err:
+ while ((skb = segs)) {
+ segs = skb->next;
+ kfree(skb);
+ }
+ return ERR_PTR(err);
+}
+
+EXPORT_SYMBOL_GPL(skb_segment);
+
void __init skb_init(void)
{
skbuff_head_cache = kmem_cache_create("skbuff_head_cache",
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -68,6 +68,7 @@
*/
#include <linux/config.h>
+#include <linux/err.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
@@ -1096,6 +1097,54 @@ int inet_sk_rebuild_header(struct sock *
EXPORT_SYMBOL(inet_sk_rebuild_header);
+static struct sk_buff *inet_gso_segment(struct sk_buff *skb, int sg)
+{
+ struct sk_buff *segs = ERR_PTR(-EINVAL);
+ struct iphdr *iph;
+ struct net_protocol *ops;
+ int proto;
+ int ihl;
+ int id;
+
+ if (!pskb_may_pull(skb, sizeof(*iph)))
+ goto out;
+
+ iph = skb->nh.iph;
+ ihl = iph->ihl * 4;
+ if (ihl < sizeof(*iph))
+ goto out;
+
+ if (!pskb_may_pull(skb, ihl))
+ goto out;
+
+ skb->h.raw = __skb_pull(skb, ihl);
+ iph = skb->nh.iph;
+ id = ntohs(iph->id);
+ proto = iph->protocol & (MAX_INET_PROTOS - 1);
+ segs = ERR_PTR(-EPROTONOSUPPORT);
+
+ rcu_read_lock();
+ ops = rcu_dereference(inet_protos[proto]);
+ if (ops && ops->gso_segment)
+ segs = ops->gso_segment(skb, sg);
+ rcu_read_unlock();
+
+ if (IS_ERR(segs))
+ goto out;
+
+ skb = segs;
+ do {
+ iph = skb->nh.iph;
+ iph->id = htons(id++);
+ iph->tot_len = htons(skb->len - skb->mac_len);
+ iph->check = 0;
+ iph->check = ip_fast_csum(skb->nh.raw, iph->ihl);
+ } while ((skb = skb->next));
+
+out:
+ return segs;
+}
+
#ifdef CONFIG_IP_MULTICAST
static struct net_protocol igmp_protocol = {
.handler = igmp_rcv,
@@ -1105,6 +1154,7 @@ static struct net_protocol igmp_protocol
static struct net_protocol tcp_protocol = {
.handler = tcp_v4_rcv,
.err_handler = tcp_v4_err,
+ .gso_segment = tcp_tso_segment,
.no_policy = 1,
};
@@ -1150,6 +1200,7 @@ static int ipv4_proc_init(void);
static struct packet_type ip_packet_type = {
.type = __constant_htons(ETH_P_IP),
.func = ip_rcv,
+ .gso_segment = inet_gso_segment,
};
static int __init inet_init(void)
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -258,6 +258,7 @@
#include <linux/random.h>
#include <linux/bootmem.h>
#include <linux/cache.h>
+#include <linux/err.h>
#include <net/icmp.h>
#include <net/tcp.h>
@@ -2144,6 +2145,67 @@ int compat_tcp_getsockopt(struct sock *s
EXPORT_SYMBOL(compat_tcp_getsockopt);
#endif
+struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int sg)
+{
+ struct sk_buff *segs = ERR_PTR(-EINVAL);
+ struct tcphdr *th;
+ unsigned thlen;
+ unsigned int seq;
+ unsigned int delta;
+ unsigned int oldlen;
+ unsigned int len;
+
+ if (!pskb_may_pull(skb, sizeof(*th)))
+ goto out;
+
+ th = skb->h.th;
+ thlen = th->doff * 4;
+ if (thlen < sizeof(*th))
+ goto out;
+
+ if (!pskb_may_pull(skb, thlen))
+ goto out;
+
+ oldlen = ~htonl(skb->len);
+ __skb_pull(skb, thlen);
+
+ segs = skb_segment(skb, sg);
+ if (IS_ERR(segs))
+ goto out;
+
+ len = skb_shinfo(skb)->gso_size;
+ delta = csum_add(oldlen, htonl(thlen + len));
+
+ skb = segs;
+ th = skb->h.th;
+ seq = ntohl(th->seq);
+
+ do {
+ th->fin = th->psh = 0;
+
+ if (skb->ip_summed == CHECKSUM_NONE) {
+ th->check = csum_fold(csum_partial(
+ skb->h.raw, thlen, csum_add(skb->csum, delta)));
+ }
+
+ seq += len;
+ skb = skb->next;
+ th = skb->h.th;
+
+ th->seq = htonl(seq);
+ th->cwr = 0;
+ } while (skb->next);
+
+ if (skb->ip_summed == CHECKSUM_NONE) {
+ delta = csum_add(oldlen, htonl(skb->tail - skb->h.raw));
+ th->check = csum_fold(csum_partial(
+ skb->h.raw, thlen, csum_add(skb->csum, delta)));
+ }
+
+out:
+ return segs;
+}
+
extern void __skb_cb_too_small_for_tcp(int, int);
extern struct tcp_congestion_ops tcp_reno;
^ permalink raw reply
* [2/5] [NET]: Add generic segmentation offload
From: Herbert Xu @ 2006-06-20 9:28 UTC (permalink / raw)
To: David S. Miller, netdev
In-Reply-To: <20060620090919.GA31613@gondor.apana.org.au>
[-- Attachment #1: Type: text/plain, Size: 716 bytes --]
Hi:
[NET]: Add generic segmentation offload
This patch adds the infrastructure for generic segmentation offload.
The idea is to tap into the potential savings of TSO without hardware
support by postponing the allocation of segmented skb's until just
before the entry point into the NIC driver.
The same structure can be used to support software IPv6 TSO, as well as
UFO and segmentation offload for other relevant protocols, e.g., DCCP.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Cheers,
--
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
[-- Attachment #2: p2.patch --]
[-- Type: text/plain, Size: 7421 bytes --]
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -406,6 +406,9 @@ struct net_device
struct list_head qdisc_list;
unsigned long tx_queue_len; /* Max frames per queue allowed */
+ /* Partially transmitted GSO packet. */
+ struct sk_buff *gso_skb;
+
/* ingress path synchronizer */
spinlock_t ingress_lock;
struct Qdisc *qdisc_ingress;
@@ -540,6 +543,7 @@ struct packet_type {
struct net_device *,
struct packet_type *,
struct net_device *);
+ struct sk_buff *(*gso_segment)(struct sk_buff *skb, int sg);
void *af_packet_priv;
struct list_head list;
};
@@ -690,7 +694,8 @@ extern int dev_change_name(struct net_d
extern int dev_set_mtu(struct net_device *, int);
extern int dev_set_mac_address(struct net_device *,
struct sockaddr *);
-extern void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev);
+extern int dev_hard_start_xmit(struct sk_buff *skb,
+ struct net_device *dev);
extern void dev_init(void);
@@ -964,6 +969,7 @@ extern int netdev_max_backlog;
extern int weight_p;
extern int netdev_set_master(struct net_device *dev, struct net_device *master);
extern int skb_checksum_help(struct sk_buff *skb, int inward);
+extern struct sk_buff *skb_gso_segment(struct sk_buff *skb, int sg);
#ifdef CONFIG_BUG
extern void netdev_rx_csum_fault(struct net_device *dev);
#else
diff --git a/net/core/dev.c b/net/core/dev.c
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -116,6 +116,7 @@
#include <asm/current.h>
#include <linux/audit.h>
#include <linux/dmaengine.h>
+#include <linux/err.h>
/*
* The list of packet types we will receive (as opposed to discard)
@@ -1048,7 +1049,7 @@ static inline void net_timestamp(struct
* taps currently in use.
*/
-void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev)
+static void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev)
{
struct packet_type *ptype;
@@ -1186,6 +1187,40 @@ out:
return ret;
}
+/**
+ * skb_gso_segment - Perform segmentation on skb.
+ * @skb: buffer to segment
+ * @sg: whether scatter-gather is supported on the target.
+ *
+ * This function segments the given skb and returns a list of segments.
+ */
+struct sk_buff *skb_gso_segment(struct sk_buff *skb, int sg)
+{
+ struct sk_buff *segs = ERR_PTR(-EPROTONOSUPPORT);
+ struct packet_type *ptype;
+ int type = skb->protocol;
+
+ BUG_ON(skb_shinfo(skb)->frag_list);
+ BUG_ON(skb->ip_summed != CHECKSUM_HW);
+
+ skb->mac.raw = skb->data;
+ skb->mac_len = skb->nh.raw - skb->data;
+ __skb_pull(skb, skb->mac_len);
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(ptype, &ptype_base[ntohs(type) & 15], list) {
+ if (ptype->type == type && !ptype->dev && ptype->gso_segment) {
+ segs = ptype->gso_segment(skb, sg);
+ break;
+ }
+ }
+ rcu_read_unlock();
+
+ return segs;
+}
+
+EXPORT_SYMBOL(skb_gso_segment);
+
/* Take action when hardware reception checksum errors are detected. */
#ifdef CONFIG_BUG
void netdev_rx_csum_fault(struct net_device *dev)
@@ -1222,6 +1257,85 @@ static inline int illegal_highdma(struct
#define illegal_highdma(dev, skb) (0)
#endif
+struct dev_gso_cb {
+ void (*destructor)(struct sk_buff *skb);
+};
+
+#define DEV_GSO_CB(skb) ((struct dev_gso_cb *)(skb)->cb)
+
+static void dev_gso_skb_destructor(struct sk_buff *skb)
+{
+ struct dev_gso_cb *cb;
+
+ do {
+ struct sk_buff *nskb = skb->next;
+
+ skb->next = nskb->next;
+ nskb->next = NULL;
+ kfree_skb(nskb);
+ } while (skb->next);
+
+ cb = DEV_GSO_CB(skb);
+ if (cb->destructor)
+ cb->destructor(skb);
+}
+
+/**
+ * dev_gso_segment - Perform emulated hardware segmentation on skb.
+ * @skb: buffer to segment
+ *
+ * This function segments the given skb and stores the list of segments
+ * in skb->next.
+ */
+static int dev_gso_segment(struct sk_buff *skb)
+{
+ struct sk_buff *segs;
+
+ segs = skb_gso_segment(skb, skb->dev->features & NETIF_F_SG &&
+ !illegal_highdma(dev, skb));
+ if (unlikely(IS_ERR(segs)))
+ return PTR_ERR(segs);
+
+ skb->next = segs;
+ DEV_GSO_CB(skb)->destructor = skb->destructor;
+ skb->destructor = dev_gso_skb_destructor;
+
+ return 0;
+}
+
+int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ if (likely(!skb->next)) {
+ if (netdev_nit)
+ dev_queue_xmit_nit(skb, dev);
+
+ if (!netif_needs_gso(dev, skb))
+ return dev->hard_start_xmit(skb, dev);
+
+ if (unlikely(dev_gso_segment(skb)))
+ goto out_kfree_skb;
+ }
+
+ do {
+ struct sk_buff *nskb = skb->next;
+ int rc;
+
+ skb->next = nskb->next;
+ nskb->next = NULL;
+ rc = dev->hard_start_xmit(nskb, dev);
+ if (unlikely(rc)) {
+ skb->next = nskb;
+ return rc;
+ }
+ } while (skb->next);
+
+ skb->destructor = DEV_GSO_CB(skb)->destructor;
+
+out_kfree_skb:
+ kfree_skb(skb);
+ return 0;
+}
+
#define HARD_TX_LOCK(dev, cpu) { \
if ((dev->features & NETIF_F_LLTX) == 0) { \
netif_tx_lock(dev); \
@@ -1266,6 +1380,10 @@ int dev_queue_xmit(struct sk_buff *skb)
struct Qdisc *q;
int rc = -ENOMEM;
+ /* GSO will handle the following emulations directly. */
+ if (netif_needs_gso(dev, skb))
+ goto gso;
+
if (skb_shinfo(skb)->frag_list &&
!(dev->features & NETIF_F_FRAGLIST) &&
__skb_linearize(skb))
@@ -1290,6 +1408,7 @@ int dev_queue_xmit(struct sk_buff *skb)
if (skb_checksum_help(skb, 0))
goto out_kfree_skb;
+gso:
spin_lock_prefetch(&dev->queue_lock);
/* Disable soft irqs for various locks below. Also
@@ -1346,11 +1465,8 @@ int dev_queue_xmit(struct sk_buff *skb)
HARD_TX_LOCK(dev, cpu);
if (!netif_queue_stopped(dev)) {
- if (netdev_nit)
- dev_queue_xmit_nit(skb, dev);
-
rc = 0;
- if (!dev->hard_start_xmit(skb, dev)) {
+ if (!dev_hard_start_xmit(skb, dev)) {
HARD_TX_UNLOCK(dev);
goto out;
}
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -96,8 +96,11 @@ static inline int qdisc_restart(struct n
struct sk_buff *skb;
/* Dequeue packet */
- if ((skb = q->dequeue(q)) != NULL) {
+ if (((skb = dev->gso_skb)) || ((skb = q->dequeue(q)))) {
unsigned nolock = (dev->features & NETIF_F_LLTX);
+
+ dev->gso_skb = NULL;
+
/*
* When the driver has LLTX set it does its own locking
* in start_xmit. No need to add additional overhead by
@@ -134,10 +137,8 @@ static inline int qdisc_restart(struct n
if (!netif_queue_stopped(dev)) {
int ret;
- if (netdev_nit)
- dev_queue_xmit_nit(skb, dev);
- ret = dev->hard_start_xmit(skb, dev);
+ ret = dev_hard_start_xmit(skb, dev);
if (ret == NETDEV_TX_OK) {
if (!nolock) {
netif_tx_unlock(dev);
@@ -171,7 +172,10 @@ static inline int qdisc_restart(struct n
*/
requeue:
- q->ops->requeue(skb, q);
+ if (skb->next)
+ dev->gso_skb = skb;
+ else
+ q->ops->requeue(skb, q);
netif_schedule(dev);
return 1;
}
@@ -572,15 +576,19 @@ void dev_activate(struct net_device *dev
void dev_deactivate(struct net_device *dev)
{
struct Qdisc *qdisc;
+ struct sk_buff *skb;
spin_lock_bh(&dev->queue_lock);
qdisc = dev->qdisc;
dev->qdisc = &noop_qdisc;
+ skb = dev->gso_skb;
+ dev->gso_skb = NULL;
qdisc_reset(qdisc);
spin_unlock_bh(&dev->queue_lock);
+ kfree_skb(skb);
dev_watchdog_down(dev);
while (test_bit(__LINK_STATE_SCHED, &dev->state))
^ permalink raw reply
* [1/5] [NET]: Merge TSO/UFO fields in sk_buff
From: Herbert Xu @ 2006-06-20 9:10 UTC (permalink / raw)
To: David S. Miller, netdev
In-Reply-To: <20060620090919.GA31613@gondor.apana.org.au>
[-- Attachment #1: Type: text/plain, Size: 1451 bytes --]
Hi:
[NET]: Merge TSO/UFO fields in sk_buff
Having separate fields in sk_buff for TSO/UFO (tso_size/ufo_size) is not
going to scale if we add any more segmentation methods (e.g., DCCP). So
let's merge them.
They were used to tell the protocol of a packet. This function has been
subsumed by the new gso_type field. This is essentially a set of netdev
feature bits (shifted by 16 bits) that are required to process a specific
skb. As such it's easy to tell whether a given device can process a GSO
skb: you just have to and the gso_type field and the netdev's features
field.
I've made gso_type a conjunction. The idea is that you have a base type
(e.g., SKB_GSO_TCPV4) that can be modified further to support new features.
For example, if we add a hardware TSO type that supports ECN, they would
declare NETIF_F_TSO | NETIF_F_TSO_ECN. All TSO packets with CWR set would
have a gso_type of SKB_GSO_TCPV4 | SKB_GSO_TCPV4_ECN while all other TSO
packets would be SKB_GSO_TCPV4. This means that only the CWR packets need
to be emulated in software. The emulation could even chop it up into one
CWR fragment and another super-packet to be further segmented by the NIC.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Cheers,
--
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
[-- Attachment #2: p1.patch --]
[-- Type: text/plain, Size: 25944 bytes --]
diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c
--- a/drivers/net/8139cp.c
+++ b/drivers/net/8139cp.c
@@ -792,7 +792,7 @@ static int cp_start_xmit (struct sk_buff
entry = cp->tx_head;
eor = (entry == (CP_TX_RING_SIZE - 1)) ? RingEnd : 0;
if (dev->features & NETIF_F_TSO)
- mss = skb_shinfo(skb)->tso_size;
+ mss = skb_shinfo(skb)->gso_size;
if (skb_shinfo(skb)->nr_frags == 0) {
struct cp_desc *txd = &cp->tx_ring[entry];
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -1640,7 +1640,7 @@ bnx2_tx_int(struct bnx2 *bp)
skb = tx_buf->skb;
#ifdef BCM_TSO
/* partial BD completions possible with TSO packets */
- if (skb_shinfo(skb)->tso_size) {
+ if (skb_shinfo(skb)->gso_size) {
u16 last_idx, last_ring_idx;
last_idx = sw_cons +
@@ -4428,7 +4428,7 @@ bnx2_start_xmit(struct sk_buff *skb, str
(TX_BD_FLAGS_VLAN_TAG | (vlan_tx_tag_get(skb) << 16));
}
#ifdef BCM_TSO
- if ((mss = skb_shinfo(skb)->tso_size) &&
+ if ((mss = skb_shinfo(skb)->gso_size) &&
(skb->len > (bp->dev->mtu + ETH_HLEN))) {
u32 tcp_opt_len, ip_tcp_len;
diff --git a/drivers/net/chelsio/sge.c b/drivers/net/chelsio/sge.c
--- a/drivers/net/chelsio/sge.c
+++ b/drivers/net/chelsio/sge.c
@@ -1418,7 +1418,7 @@ int t1_start_xmit(struct sk_buff *skb, s
struct cpl_tx_pkt *cpl;
#ifdef NETIF_F_TSO
- if (skb_shinfo(skb)->tso_size) {
+ if (skb_shinfo(skb)->gso_size) {
int eth_type;
struct cpl_tx_pkt_lso *hdr;
@@ -1433,7 +1433,7 @@ int t1_start_xmit(struct sk_buff *skb, s
hdr->ip_hdr_words = skb->nh.iph->ihl;
hdr->tcp_hdr_words = skb->h.th->doff;
hdr->eth_type_mss = htons(MK_ETH_TYPE_MSS(eth_type,
- skb_shinfo(skb)->tso_size));
+ skb_shinfo(skb)->gso_size));
hdr->len = htonl(skb->len - sizeof(*hdr));
cpl = (struct cpl_tx_pkt *)hdr;
sge->stats.tx_lso_pkts++;
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -2394,7 +2394,7 @@ e1000_tso(struct e1000_adapter *adapter,
uint8_t ipcss, ipcso, tucss, tucso, hdr_len;
int err;
- if (skb_shinfo(skb)->tso_size) {
+ if (skb_shinfo(skb)->gso_size) {
if (skb_header_cloned(skb)) {
err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
if (err)
@@ -2402,7 +2402,7 @@ e1000_tso(struct e1000_adapter *adapter,
}
hdr_len = ((skb->h.raw - skb->data) + (skb->h.th->doff << 2));
- mss = skb_shinfo(skb)->tso_size;
+ mss = skb_shinfo(skb)->gso_size;
if (skb->protocol == htons(ETH_P_IP)) {
skb->nh.iph->tot_len = 0;
skb->nh.iph->check = 0;
@@ -2519,7 +2519,7 @@ e1000_tx_map(struct e1000_adapter *adapt
* tso gets written back prematurely before the data is fully
* DMA'd to the controller */
if (!skb->data_len && tx_ring->last_tx_tso &&
- !skb_shinfo(skb)->tso_size) {
+ !skb_shinfo(skb)->gso_size) {
tx_ring->last_tx_tso = 0;
size -= 4;
}
@@ -2757,7 +2757,7 @@ e1000_xmit_frame(struct sk_buff *skb, st
}
#ifdef NETIF_F_TSO
- mss = skb_shinfo(skb)->tso_size;
+ mss = skb_shinfo(skb)->gso_size;
/* The controller does a simple calculation to
* make sure there is enough room in the FIFO before
* initiating the DMA for each buffer. The calc is:
@@ -2807,7 +2807,7 @@ e1000_xmit_frame(struct sk_buff *skb, st
#ifdef NETIF_F_TSO
/* Controller Erratum workaround */
if (!skb->data_len && tx_ring->last_tx_tso &&
- !skb_shinfo(skb)->tso_size)
+ !skb_shinfo(skb)->gso_size)
count++;
#endif
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
--- a/drivers/net/forcedeth.c
+++ b/drivers/net/forcedeth.c
@@ -1495,8 +1495,8 @@ static int nv_start_xmit(struct sk_buff
np->tx_skbuff[nr] = skb;
#ifdef NETIF_F_TSO
- if (skb_shinfo(skb)->tso_size)
- tx_flags_extra = NV_TX2_TSO | (skb_shinfo(skb)->tso_size << NV_TX2_TSO_SHIFT);
+ if (skb_shinfo(skb)->gso_size)
+ tx_flags_extra = NV_TX2_TSO | (skb_shinfo(skb)->gso_size << NV_TX2_TSO_SHIFT);
else
#endif
tx_flags_extra = (skb->ip_summed == CHECKSUM_HW ? (NV_TX2_CHECKSUM_L3|NV_TX2_CHECKSUM_L4) : 0);
diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c
--- a/drivers/net/ixgb/ixgb_main.c
+++ b/drivers/net/ixgb/ixgb_main.c
@@ -1173,7 +1173,7 @@ ixgb_tso(struct ixgb_adapter *adapter, s
uint16_t ipcse, tucse, mss;
int err;
- if(likely(skb_shinfo(skb)->tso_size)) {
+ if(likely(skb_shinfo(skb)->gso_size)) {
if (skb_header_cloned(skb)) {
err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
if (err)
@@ -1181,7 +1181,7 @@ ixgb_tso(struct ixgb_adapter *adapter, s
}
hdr_len = ((skb->h.raw - skb->data) + (skb->h.th->doff << 2));
- mss = skb_shinfo(skb)->tso_size;
+ mss = skb_shinfo(skb)->gso_size;
skb->nh.iph->tot_len = 0;
skb->nh.iph->check = 0;
skb->h.th->check = ~csum_tcpudp_magic(skb->nh.iph->saddr,
diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
--- a/drivers/net/loopback.c
+++ b/drivers/net/loopback.c
@@ -74,7 +74,7 @@ static void emulate_large_send_offload(s
struct iphdr *iph = skb->nh.iph;
struct tcphdr *th = (struct tcphdr*)(skb->nh.raw + (iph->ihl * 4));
unsigned int doffset = (iph->ihl + th->doff) * 4;
- unsigned int mtu = skb_shinfo(skb)->tso_size + doffset;
+ unsigned int mtu = skb_shinfo(skb)->gso_size + doffset;
unsigned int offset = 0;
u32 seq = ntohl(th->seq);
u16 id = ntohs(iph->id);
@@ -139,7 +139,7 @@ static int loopback_xmit(struct sk_buff
#endif
#ifdef LOOPBACK_TSO
- if (skb_shinfo(skb)->tso_size) {
+ if (skb_shinfo(skb)->gso_size) {
BUG_ON(skb->protocol != htons(ETH_P_IP));
BUG_ON(skb->nh.iph->protocol != IPPROTO_TCP);
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c
--- a/drivers/net/myri10ge/myri10ge.c
+++ b/drivers/net/myri10ge/myri10ge.c
@@ -1879,7 +1879,7 @@ again:
#ifdef NETIF_F_TSO
if (skb->len > (dev->mtu + ETH_HLEN)) {
- mss = skb_shinfo(skb)->tso_size;
+ mss = skb_shinfo(skb)->gso_size;
if (mss != 0)
max_segments = MYRI10GE_MAX_SEND_DESC_TSO;
}
@@ -2113,7 +2113,7 @@ abort_linearize:
}
idx = (idx + 1) & tx->mask;
} while (idx != last_idx);
- if (skb_shinfo(skb)->tso_size) {
+ if (skb_shinfo(skb)->gso_size) {
printk(KERN_ERR
"myri10ge: %s: TSO but wanted to linearize?!?!?\n",
mgp->dev->name);
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
--- a/drivers/net/r8169.c
+++ b/drivers/net/r8169.c
@@ -2172,7 +2172,7 @@ static int rtl8169_xmit_frags(struct rtl
static inline u32 rtl8169_tso_csum(struct sk_buff *skb, struct net_device *dev)
{
if (dev->features & NETIF_F_TSO) {
- u32 mss = skb_shinfo(skb)->tso_size;
+ u32 mss = skb_shinfo(skb)->gso_size;
if (mss)
return LargeSend | ((mss & MSSMask) << MSSShift);
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c
--- a/drivers/net/s2io.c
+++ b/drivers/net/s2io.c
@@ -3915,8 +3915,8 @@ static int s2io_xmit(struct sk_buff *skb
txdp->Control_1 = 0;
txdp->Control_2 = 0;
#ifdef NETIF_F_TSO
- mss = skb_shinfo(skb)->tso_size;
- if (mss) {
+ mss = skb_shinfo(skb)->gso_size;
+ if (skb_shinfo(skb)->gso_type == SKB_GSO_TCPV4) {
txdp->Control_1 |= TXD_TCP_LSO_EN;
txdp->Control_1 |= TXD_TCP_LSO_MSS(mss);
}
@@ -3936,10 +3936,10 @@ static int s2io_xmit(struct sk_buff *skb
}
frg_len = skb->len - skb->data_len;
- if (skb_shinfo(skb)->ufo_size) {
+ if (skb_shinfo(skb)->gso_type == SKB_GSO_UDPV4) {
int ufo_size;
- ufo_size = skb_shinfo(skb)->ufo_size;
+ ufo_size = skb_shinfo(skb)->gso_size;
ufo_size &= ~7;
txdp->Control_1 |= TXD_UFO_EN;
txdp->Control_1 |= TXD_UFO_MSS(ufo_size);
@@ -3965,7 +3965,7 @@ static int s2io_xmit(struct sk_buff *skb
txdp->Host_Control = (unsigned long) skb;
txdp->Control_1 |= TXD_BUFFER0_SIZE(frg_len);
- if (skb_shinfo(skb)->ufo_size)
+ if (skb_shinfo(skb)->gso_type == SKB_GSO_UDPV4)
txdp->Control_1 |= TXD_UFO_EN;
frg_cnt = skb_shinfo(skb)->nr_frags;
@@ -3980,12 +3980,12 @@ static int s2io_xmit(struct sk_buff *skb
(sp->pdev, frag->page, frag->page_offset,
frag->size, PCI_DMA_TODEVICE);
txdp->Control_1 = TXD_BUFFER0_SIZE(frag->size);
- if (skb_shinfo(skb)->ufo_size)
+ if (skb_shinfo(skb)->gso_type == SKB_GSO_UDPV4)
txdp->Control_1 |= TXD_UFO_EN;
}
txdp->Control_1 |= TXD_GATHER_CODE_LAST;
- if (skb_shinfo(skb)->ufo_size)
+ if (skb_shinfo(skb)->gso_type == SKB_GSO_UDPV4)
frg_cnt++; /* as Txd0 was used for inband header */
tx_fifo = mac_control->tx_FIFO_start[queue];
@@ -3999,7 +3999,7 @@ static int s2io_xmit(struct sk_buff *skb
if (mss)
val64 |= TX_FIFO_SPECIAL_FUNC;
#endif
- if (skb_shinfo(skb)->ufo_size)
+ if (skb_shinfo(skb)->gso_type == SKB_GSO_UDPV4)
val64 |= TX_FIFO_SPECIAL_FUNC;
writeq(val64, &tx_fifo->List_Control);
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -1160,7 +1160,7 @@ static unsigned tx_le_req(const struct s
count = sizeof(dma_addr_t) / sizeof(u32);
count += skb_shinfo(skb)->nr_frags * count;
- if (skb_shinfo(skb)->tso_size)
+ if (skb_shinfo(skb)->gso_size)
++count;
if (skb->ip_summed == CHECKSUM_HW)
@@ -1232,7 +1232,7 @@ static int sky2_xmit_frame(struct sk_buf
}
/* Check for TCP Segmentation Offload */
- mss = skb_shinfo(skb)->tso_size;
+ mss = skb_shinfo(skb)->gso_size;
if (mss != 0) {
/* just drop the packet if non-linear expansion fails */
if (skb_header_cloned(skb) &&
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -3780,7 +3780,7 @@ static int tg3_start_xmit(struct sk_buff
#if TG3_TSO_SUPPORT != 0
mss = 0;
if (skb->len > (tp->dev->mtu + ETH_HLEN) &&
- (mss = skb_shinfo(skb)->tso_size) != 0) {
+ (mss = skb_shinfo(skb)->gso_size) != 0) {
int tcp_opt_len, ip_tcp_len;
if (skb_header_cloned(skb) &&
@@ -3905,7 +3905,7 @@ static int tg3_start_xmit_dma_bug(struct
#if TG3_TSO_SUPPORT != 0
mss = 0;
if (skb->len > (tp->dev->mtu + ETH_HLEN) &&
- (mss = skb_shinfo(skb)->tso_size) != 0) {
+ (mss = skb_shinfo(skb)->gso_size) != 0) {
int tcp_opt_len, ip_tcp_len;
if (skb_header_cloned(skb) &&
diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c
--- a/drivers/net/typhoon.c
+++ b/drivers/net/typhoon.c
@@ -340,7 +340,7 @@ enum state_values {
#endif
#if defined(NETIF_F_TSO)
-#define skb_tso_size(x) (skb_shinfo(x)->tso_size)
+#define skb_tso_size(x) (skb_shinfo(x)->gso_size)
#define TSO_NUM_DESCRIPTORS 2
#define TSO_OFFLOAD_ON TYPHOON_OFFLOAD_TCP_SEGMENT
#else
diff --git a/drivers/s390/net/qeth_eddp.c b/drivers/s390/net/qeth_eddp.c
--- a/drivers/s390/net/qeth_eddp.c
+++ b/drivers/s390/net/qeth_eddp.c
@@ -420,7 +420,7 @@ __qeth_eddp_fill_context_tcp(struct qeth
}
tcph = eddp->skb->h.th;
while (eddp->skb_offset < eddp->skb->len) {
- data_len = min((int)skb_shinfo(eddp->skb)->tso_size,
+ data_len = min((int)skb_shinfo(eddp->skb)->gso_size,
(int)(eddp->skb->len - eddp->skb_offset));
/* prepare qdio hdr */
if (eddp->qh.hdr.l2.id == QETH_HEADER_TYPE_LAYER2){
@@ -515,20 +515,20 @@ qeth_eddp_calc_num_pages(struct qeth_edd
QETH_DBF_TEXT(trace, 5, "eddpcanp");
/* can we put multiple skbs in one page? */
- skbs_per_page = PAGE_SIZE / (skb_shinfo(skb)->tso_size + hdr_len);
+ skbs_per_page = PAGE_SIZE / (skb_shinfo(skb)->gso_size + hdr_len);
if (skbs_per_page > 1){
- ctx->num_pages = (skb_shinfo(skb)->tso_segs + 1) /
+ ctx->num_pages = (skb_shinfo(skb)->gso_segs + 1) /
skbs_per_page + 1;
ctx->elements_per_skb = 1;
} else {
/* no -> how many elements per skb? */
- ctx->elements_per_skb = (skb_shinfo(skb)->tso_size + hdr_len +
+ ctx->elements_per_skb = (skb_shinfo(skb)->gso_size + hdr_len +
PAGE_SIZE) >> PAGE_SHIFT;
ctx->num_pages = ctx->elements_per_skb *
- (skb_shinfo(skb)->tso_segs + 1);
+ (skb_shinfo(skb)->gso_segs + 1);
}
ctx->num_elements = ctx->elements_per_skb *
- (skb_shinfo(skb)->tso_segs + 1);
+ (skb_shinfo(skb)->gso_segs + 1);
}
static inline struct qeth_eddp_context *
diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c
--- a/drivers/s390/net/qeth_main.c
+++ b/drivers/s390/net/qeth_main.c
@@ -4417,7 +4417,7 @@ qeth_send_packet(struct qeth_card *card,
struct qeth_eddp_context *ctx = NULL;
int tx_bytes = skb->len;
unsigned short nr_frags = skb_shinfo(skb)->nr_frags;
- unsigned short tso_size = skb_shinfo(skb)->tso_size;
+ unsigned short tso_size = skb_shinfo(skb)->gso_size;
int rc;
QETH_DBF_TEXT(trace, 6, "sendpkt");
@@ -4453,7 +4453,7 @@ qeth_send_packet(struct qeth_card *card,
queue = card->qdio.out_qs
[qeth_get_priority_queue(card, skb, ipv, cast_type)];
- if (skb_shinfo(skb)->tso_size)
+ if (skb_shinfo(skb)->gso_size)
large_send = card->options.large_send;
/*are we able to do TSO ? If so ,prepare and send it from here */
diff --git a/drivers/s390/net/qeth_tso.h b/drivers/s390/net/qeth_tso.h
--- a/drivers/s390/net/qeth_tso.h
+++ b/drivers/s390/net/qeth_tso.h
@@ -51,7 +51,7 @@ qeth_tso_fill_header(struct qeth_card *c
hdr->ext.hdr_version = 1;
hdr->ext.hdr_len = 28;
/*insert non-fix values */
- hdr->ext.mss = skb_shinfo(skb)->tso_size;
+ hdr->ext.mss = skb_shinfo(skb)->gso_size;
hdr->ext.dg_hdr_len = (__u16)(iph->ihl*4 + tcph->doff*4);
hdr->ext.payload_len = (__u16)(skb->len - hdr->ext.dg_hdr_len -
sizeof(struct qeth_hdr_tso));
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -309,9 +309,12 @@ struct net_device
#define NETIF_F_HW_VLAN_RX 256 /* Receive VLAN hw acceleration */
#define NETIF_F_HW_VLAN_FILTER 512 /* Receive filtering on VLAN */
#define NETIF_F_VLAN_CHALLENGED 1024 /* Device cannot handle VLAN packets */
-#define NETIF_F_TSO 2048 /* Can offload TCP/IP segmentation */
#define NETIF_F_LLTX 4096 /* LockLess TX */
-#define NETIF_F_UFO 8192 /* Can offload UDP Large Send*/
+
+ /* Segmentation offload features */
+#define NETIF_F_GSO_SHIFT 16
+#define NETIF_F_TSO (SKB_GSO_TCPV4 << NETIF_F_GSO_SHIFT)
+#define NETIF_F_UFO (SKB_GSO_UDPV4 << NETIF_F_GSO_SHIFT)
#define NETIF_F_GEN_CSUM (NETIF_F_NO_CSUM | NETIF_F_HW_CSUM)
#define NETIF_F_ALL_CSUM (NETIF_F_IP_CSUM | NETIF_F_GEN_CSUM)
@@ -980,6 +983,13 @@ extern void dev_seq_stop(struct seq_file
extern void linkwatch_run_queue(void);
+static inline int netif_needs_gso(struct net_device *dev, struct sk_buff *skb)
+{
+ int feature = skb_shinfo(skb)->gso_type << NETIF_F_GSO_SHIFT;
+ return skb_shinfo(skb)->gso_size &&
+ (dev->features & feature) != feature;
+}
+
#endif /* __KERNEL__ */
#endif /* _LINUX_DEV_H */
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -135,9 +135,10 @@ struct skb_frag_struct {
struct skb_shared_info {
atomic_t dataref;
unsigned short nr_frags;
- unsigned short tso_size;
- unsigned short tso_segs;
- unsigned short ufo_size;
+ unsigned short gso_size;
+ /* Warning: this field is not always filled in (UFO)! */
+ unsigned short gso_segs;
+ unsigned short gso_type;
unsigned int ip6_frag_id;
struct sk_buff *frag_list;
skb_frag_t frags[MAX_SKB_FRAGS];
@@ -169,6 +170,11 @@ enum {
SKB_FCLONE_CLONE,
};
+enum {
+ SKB_GSO_TCPV4 = 1 << 0,
+ SKB_GSO_UDPV4 = 1 << 1,
+};
+
/**
* struct sk_buff - socket buffer
* @next: Next buffer in list
diff --git a/include/net/tcp.h b/include/net/tcp.h
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -570,13 +570,13 @@ struct tcp_skb_cb {
*/
static inline int tcp_skb_pcount(const struct sk_buff *skb)
{
- return skb_shinfo(skb)->tso_segs;
+ return skb_shinfo(skb)->gso_segs;
}
/* This is valid iff tcp_skb_pcount() > 1. */
static inline int tcp_skb_mss(const struct sk_buff *skb)
{
- return skb_shinfo(skb)->tso_size;
+ return skb_shinfo(skb)->gso_size;
}
static inline void tcp_dec_pcount_approx(__u32 *count,
diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c
--- a/net/bridge/br_forward.c
+++ b/net/bridge/br_forward.c
@@ -34,8 +34,8 @@ static inline unsigned packet_length(con
int br_dev_queue_push_xmit(struct sk_buff *skb)
{
- /* drop mtu oversized packets except tso */
- if (packet_length(skb) > skb->dev->mtu && !skb_shinfo(skb)->tso_size)
+ /* drop mtu oversized packets except gso */
+ if (packet_length(skb) > skb->dev->mtu && !skb_shinfo(skb)->gso_size)
kfree_skb(skb);
else {
#ifdef CONFIG_BRIDGE_NETFILTER
diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c
--- a/net/bridge/br_netfilter.c
+++ b/net/bridge/br_netfilter.c
@@ -761,7 +761,7 @@ static int br_nf_dev_queue_xmit(struct s
{
if (skb->protocol == htons(ETH_P_IP) &&
skb->len > skb->dev->mtu &&
- !(skb_shinfo(skb)->ufo_size || skb_shinfo(skb)->tso_size))
+ !skb_shinfo(skb)->gso_size)
return ip_fragment(skb, br_dev_queue_push_xmit);
else
return br_dev_queue_push_xmit(skb);
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -172,9 +172,9 @@ struct sk_buff *__alloc_skb(unsigned int
shinfo = skb_shinfo(skb);
atomic_set(&shinfo->dataref, 1);
shinfo->nr_frags = 0;
- shinfo->tso_size = 0;
- shinfo->tso_segs = 0;
- shinfo->ufo_size = 0;
+ shinfo->gso_size = 0;
+ shinfo->gso_segs = 0;
+ shinfo->gso_type = 0;
shinfo->ip6_frag_id = 0;
shinfo->frag_list = NULL;
@@ -238,8 +238,9 @@ struct sk_buff *alloc_skb_from_cache(kme
atomic_set(&(skb_shinfo(skb)->dataref), 1);
skb_shinfo(skb)->nr_frags = 0;
- skb_shinfo(skb)->tso_size = 0;
- skb_shinfo(skb)->tso_segs = 0;
+ skb_shinfo(skb)->gso_size = 0;
+ skb_shinfo(skb)->gso_segs = 0;
+ skb_shinfo(skb)->gso_type = 0;
skb_shinfo(skb)->frag_list = NULL;
out:
return skb;
@@ -528,8 +529,9 @@ static void copy_skb_header(struct sk_bu
#endif
skb_copy_secmark(new, old);
atomic_set(&new->users, 1);
- skb_shinfo(new)->tso_size = skb_shinfo(old)->tso_size;
- skb_shinfo(new)->tso_segs = skb_shinfo(old)->tso_segs;
+ skb_shinfo(new)->gso_size = skb_shinfo(old)->gso_size;
+ skb_shinfo(new)->gso_segs = skb_shinfo(old)->gso_segs;
+ skb_shinfo(new)->gso_type = skb_shinfo(old)->gso_type;
}
/**
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -210,8 +210,7 @@ static inline int ip_finish_output(struc
return dst_output(skb);
}
#endif
- if (skb->len > dst_mtu(skb->dst) &&
- !(skb_shinfo(skb)->ufo_size || skb_shinfo(skb)->tso_size))
+ if (skb->len > dst_mtu(skb->dst) && !skb_shinfo(skb)->gso_size)
return ip_fragment(skb, ip_finish_output2);
else
return ip_finish_output2(skb);
@@ -362,7 +361,7 @@ packet_routed:
}
ip_select_ident_more(iph, &rt->u.dst, sk,
- (skb_shinfo(skb)->tso_segs ?: 1) - 1);
+ (skb_shinfo(skb)->gso_segs ?: 1) - 1);
/* Add an IP checksum. */
ip_send_check(iph);
@@ -744,7 +743,8 @@ static inline int ip_ufo_append_data(str
(length - transhdrlen));
if (!err) {
/* specify the length of each IP datagram fragment*/
- skb_shinfo(skb)->ufo_size = (mtu - fragheaderlen);
+ skb_shinfo(skb)->gso_size = mtu - fragheaderlen;
+ skb_shinfo(skb)->gso_type = SKB_GSO_UDPV4;
__skb_queue_tail(&sk->sk_write_queue, skb);
return 0;
@@ -1087,14 +1087,16 @@ ssize_t ip_append_page(struct sock *sk,
inet->cork.length += size;
if ((sk->sk_protocol == IPPROTO_UDP) &&
- (rt->u.dst.dev->features & NETIF_F_UFO))
- skb_shinfo(skb)->ufo_size = (mtu - fragheaderlen);
+ (rt->u.dst.dev->features & NETIF_F_UFO)) {
+ skb_shinfo(skb)->gso_size = mtu - fragheaderlen;
+ skb_shinfo(skb)->gso_type = SKB_GSO_UDPV4;
+ }
while (size > 0) {
int i;
- if (skb_shinfo(skb)->ufo_size)
+ if (skb_shinfo(skb)->gso_size)
len = size;
else {
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -571,7 +571,7 @@ new_segment:
skb->ip_summed = CHECKSUM_HW;
tp->write_seq += copy;
TCP_SKB_CB(skb)->end_seq += copy;
- skb_shinfo(skb)->tso_segs = 0;
+ skb_shinfo(skb)->gso_segs = 0;
if (!copied)
TCP_SKB_CB(skb)->flags &= ~TCPCB_FLAG_PSH;
@@ -818,7 +818,7 @@ new_segment:
tp->write_seq += copy;
TCP_SKB_CB(skb)->end_seq += copy;
- skb_shinfo(skb)->tso_segs = 0;
+ skb_shinfo(skb)->gso_segs = 0;
from += copy;
copied += copy;
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -1073,7 +1073,7 @@ tcp_sacktag_write_queue(struct sock *sk,
else
pkt_len = (end_seq -
TCP_SKB_CB(skb)->seq);
- if (tcp_fragment(sk, skb, pkt_len, skb_shinfo(skb)->tso_size))
+ if (tcp_fragment(sk, skb, pkt_len, skb_shinfo(skb)->gso_size))
break;
pcount = tcp_skb_pcount(skb);
}
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -515,15 +515,17 @@ static void tcp_set_skb_tso_segs(struct
/* Avoid the costly divide in the normal
* non-TSO case.
*/
- skb_shinfo(skb)->tso_segs = 1;
- skb_shinfo(skb)->tso_size = 0;
+ skb_shinfo(skb)->gso_segs = 1;
+ skb_shinfo(skb)->gso_size = 0;
+ skb_shinfo(skb)->gso_type = 0;
} else {
unsigned int factor;
factor = skb->len + (mss_now - 1);
factor /= mss_now;
- skb_shinfo(skb)->tso_segs = factor;
- skb_shinfo(skb)->tso_size = mss_now;
+ skb_shinfo(skb)->gso_segs = factor;
+ skb_shinfo(skb)->gso_size = mss_now;
+ skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
}
}
@@ -914,7 +916,7 @@ static int tcp_init_tso_segs(struct sock
if (!tso_segs ||
(tso_segs > 1 &&
- skb_shinfo(skb)->tso_size != mss_now)) {
+ tcp_skb_mss(skb) != mss_now)) {
tcp_set_skb_tso_segs(sk, skb, mss_now);
tso_segs = tcp_skb_pcount(skb);
}
@@ -1724,8 +1726,9 @@ int tcp_retransmit_skb(struct sock *sk,
tp->snd_una == (TCP_SKB_CB(skb)->end_seq - 1)) {
if (!pskb_trim(skb, 0)) {
TCP_SKB_CB(skb)->seq = TCP_SKB_CB(skb)->end_seq - 1;
- skb_shinfo(skb)->tso_segs = 1;
- skb_shinfo(skb)->tso_size = 0;
+ skb_shinfo(skb)->gso_segs = 1;
+ skb_shinfo(skb)->gso_size = 0;
+ skb_shinfo(skb)->gso_type = 0;
skb->ip_summed = CHECKSUM_NONE;
skb->csum = 0;
}
@@ -1930,8 +1933,9 @@ void tcp_send_fin(struct sock *sk)
skb->csum = 0;
TCP_SKB_CB(skb)->flags = (TCPCB_FLAG_ACK | TCPCB_FLAG_FIN);
TCP_SKB_CB(skb)->sacked = 0;
- skb_shinfo(skb)->tso_segs = 1;
- skb_shinfo(skb)->tso_size = 0;
+ skb_shinfo(skb)->gso_segs = 1;
+ skb_shinfo(skb)->gso_size = 0;
+ skb_shinfo(skb)->gso_type = 0;
/* FIN eats a sequence byte, write_seq advanced by tcp_queue_skb(). */
TCP_SKB_CB(skb)->seq = tp->write_seq;
@@ -1963,8 +1967,9 @@ void tcp_send_active_reset(struct sock *
skb->csum = 0;
TCP_SKB_CB(skb)->flags = (TCPCB_FLAG_ACK | TCPCB_FLAG_RST);
TCP_SKB_CB(skb)->sacked = 0;
- skb_shinfo(skb)->tso_segs = 1;
- skb_shinfo(skb)->tso_size = 0;
+ skb_shinfo(skb)->gso_segs = 1;
+ skb_shinfo(skb)->gso_size = 0;
+ skb_shinfo(skb)->gso_type = 0;
/* Send it off. */
TCP_SKB_CB(skb)->seq = tcp_acceptable_seq(sk, tp);
@@ -2047,8 +2052,9 @@ struct sk_buff * tcp_make_synack(struct
TCP_SKB_CB(skb)->seq = tcp_rsk(req)->snt_isn;
TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(skb)->seq + 1;
TCP_SKB_CB(skb)->sacked = 0;
- skb_shinfo(skb)->tso_segs = 1;
- skb_shinfo(skb)->tso_size = 0;
+ skb_shinfo(skb)->gso_segs = 1;
+ skb_shinfo(skb)->gso_size = 0;
+ skb_shinfo(skb)->gso_type = 0;
th->seq = htonl(TCP_SKB_CB(skb)->seq);
th->ack_seq = htonl(tcp_rsk(req)->rcv_isn + 1);
if (req->rcv_wnd == 0) { /* ignored for retransmitted syns */
@@ -2152,8 +2158,9 @@ int tcp_connect(struct sock *sk)
TCP_SKB_CB(buff)->flags = TCPCB_FLAG_SYN;
TCP_ECN_send_syn(sk, tp, buff);
TCP_SKB_CB(buff)->sacked = 0;
- skb_shinfo(buff)->tso_segs = 1;
- skb_shinfo(buff)->tso_size = 0;
+ skb_shinfo(buff)->gso_segs = 1;
+ skb_shinfo(buff)->gso_size = 0;
+ skb_shinfo(buff)->gso_type = 0;
buff->csum = 0;
TCP_SKB_CB(buff)->seq = tp->write_seq++;
TCP_SKB_CB(buff)->end_seq = tp->write_seq;
@@ -2257,8 +2264,9 @@ void tcp_send_ack(struct sock *sk)
buff->csum = 0;
TCP_SKB_CB(buff)->flags = TCPCB_FLAG_ACK;
TCP_SKB_CB(buff)->sacked = 0;
- skb_shinfo(buff)->tso_segs = 1;
- skb_shinfo(buff)->tso_size = 0;
+ skb_shinfo(buff)->gso_segs = 1;
+ skb_shinfo(buff)->gso_size = 0;
+ skb_shinfo(buff)->gso_type = 0;
/* Send it off, this clears delayed acks for us. */
TCP_SKB_CB(buff)->seq = TCP_SKB_CB(buff)->end_seq = tcp_acceptable_seq(sk, tp);
@@ -2293,8 +2301,9 @@ static int tcp_xmit_probe_skb(struct soc
skb->csum = 0;
TCP_SKB_CB(skb)->flags = TCPCB_FLAG_ACK;
TCP_SKB_CB(skb)->sacked = urgent;
- skb_shinfo(skb)->tso_segs = 1;
- skb_shinfo(skb)->tso_size = 0;
+ skb_shinfo(skb)->gso_segs = 1;
+ skb_shinfo(skb)->gso_size = 0;
+ skb_shinfo(skb)->gso_type = 0;
/* Use a previous sequence. This should cause the other
* end to send an ack. Don't queue or clone SKB, just
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -148,7 +148,7 @@ static int ip6_output2(struct sk_buff *s
int ip6_output(struct sk_buff *skb)
{
- if ((skb->len > dst_mtu(skb->dst) && !skb_shinfo(skb)->ufo_size) ||
+ if ((skb->len > dst_mtu(skb->dst) && !skb_shinfo(skb)->gso_size) ||
dst_allfrag(skb->dst))
return ip6_fragment(skb, ip6_output2);
else
@@ -833,8 +833,9 @@ static inline int ip6_ufo_append_data(st
struct frag_hdr fhdr;
/* specify the length of each IP datagram fragment*/
- skb_shinfo(skb)->ufo_size = (mtu - fragheaderlen) -
- sizeof(struct frag_hdr);
+ skb_shinfo(skb)->gso_size = mtu - fragheaderlen -
+ sizeof(struct frag_hdr);
+ skb_shinfo(skb)->gso_type = SKB_GSO_UDPV4;
ipv6_select_ident(skb, &fhdr);
skb_shinfo(skb)->ip6_frag_id = fhdr.identification;
__skb_queue_tail(&sk->sk_write_queue, skb);
^ permalink raw reply
* [0/5] GSO: Generic Segmentation Offload
From: Herbert Xu @ 2006-06-20 9:09 UTC (permalink / raw)
To: David S. Miller, netdev
Hi:
This series adds Generic Segmentation Offload (GSO) support to the Linux
networking stack.
Many people have observed that a lot of the savings in TSO come from
traversing the networking stack once rather than many times for each
super-packet. These savings can be obtained without hardware support.
In fact, the concept can be applied to other protocols such as TCPv6,
UDP, or even DCCP.
The key to minimising the cost in implementing this is to postpone the
segmentation as late as possible. In the ideal world, the segmentation
would occur inside each NIC driver where they would rip the super-packet
apart and either produce SG lists which are directly fed to the hardware,
or linearise each segment into pre-allocated memory to be fed to the NIC.
This would elminate segmented skb's altogether.
Unfortunately this requires modifying each and every NIC driver so it
would take quite some time. A much easier solution is to perform the
segmentation just before the entry into the driver's xmit routine. This
series of patches does this.
I've attached some numbers to demonstrate the savings brought on by
doing this. The best scenario is obviously the case where the underlying
NIC supports SG. This means that we simply have to manipulate the SG
entries and place them into individual skb's before passing them to the
driver. The attached file lo-res shows this.
The test was performed through the loopback device which is a fairly good
approxmiation of an SG-capable NIC.
GSO like TSO is only effective if the MTU is significantly less than the
maximum value of 64K. So only the case where the MTU was set to 1500 is
of interest. There we can see that the throughput improved by 17.5%
(3061.05Mb/s => 3598.17Mb/s). The actual saving in transmission cost is
in fact a lot more than that as the majority of the time here is spent on
the RX side which still has to deal with 1500-byte packets.
The worst-case scenario is where the NIC does not support SG and the user
uses write(2) which means that we have to copy the data twice. The files
gso-off/gso-on provide data for this case (the test was carried out on
e100). As you can see, the cost of the extra copy is mostly offset by the
reduction in the cost of going through the networking stack.
For now GSO is off by default but can be enabled through ethtool. It is
conceivable that with enough optimisation GSO could be a win in most cases
and we could enable it by default.
However, even without enabling GSO explicitly it can still function on
bridged and forwarded packets. As it is, passing TSO packets through a
bridge only works if all constiuents support TSO. With GSO, it provides
a fallback so that we may enable TSO for a bridge even if some of its
constituents do not support TSO.
This provides massive savings for Xen as it uses a bridge-based architecture
and TSO/GSO produces a much larger effective MTU for internal traffic between
domains.
Cheers,
--
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply
* Re: [PATCH 1/2] 8139cp: fix eeprom read command length
From: Jeff Garzik @ 2006-06-20 8:52 UTC (permalink / raw)
To: Philip Craig; +Cc: netdev
In-Reply-To: <448FAFF5.7040701@snapgear.com>
Philip Craig wrote:
> The read command for the 93C46/93C56 EEPROMS should be 3 bits plus
> the address. This doesn't appear to affect the operation of the
> read command, but similar errors for write commands do cause failures.
>
> Signed-off-by: Philip Craig <philipc@snapgear.com>
ACK patches 1-2, but patch appears corrupted:
[jgarzik@pretzel netdev-2.6]$ git-applymbox /g/tmp/mbox ~/info/signoff.txt
2 patch(es) to process.
Applying '8139cp: fix eeprom read command length'
fatal: corrupt patch at line 7
^ permalink raw reply
* Re: Please pull 'upstream' branch of wireless-2.6
From: Jeff Garzik @ 2006-06-20 8:46 UTC (permalink / raw)
To: John W. Linville; +Cc: netdev
In-Reply-To: <20060615200257.GB32582@tuxdriver.com>
John W. Linville wrote:
> The following changes since commit 76df73ff90e99681a99e457aec4cfe0a240b7982:
> John W. Linville:
> Merge branch 'from-linus' into upstream
>
> are found in the git repository at:
>
> git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git upstream
>
> Jiri Slaby:
> pci: bcm43xx avoid pci_find_device
>
> Larry Finger:
> wireless: Changes to ieee80211.h for user space regulatory daemon
> wireless: correct dump of WPA IE
>
> Michael Buesch:
> bcm43xx: redesign locking
> bcm43xx: preemptible periodic work
>
> Zhu Yi:
> ipw2200 locking fix
pulled
^ permalink raw reply
* Re: Pull request for 'upstream' branch
From: Jeff Garzik @ 2006-06-20 8:45 UTC (permalink / raw)
To: Francois Romieu; +Cc: jeff, netdev, palopezv, nacc
In-Reply-To: <20060615212109.GA6817@electric-eye.fr.zoreil.com>
Francois Romieu wrote:
> Please pull from branch 'upstream' to get the change below:
>
> git://electric-eye.fr.zoreil.com/home/romieu/linux-2.6.git
>
> Patch applies both to jeff#upstream and jeff#upstream-fixes
>
> Shortlog
> --------
>
> Pedro Alejandro López-Valencia:
> sundance: PCI ID for ip100a
pulled, thanks
^ permalink raw reply
* Re: [PATCH 1/6] b44: fix manual speed/duplex/autoneg settings
From: Jeff Garzik @ 2006-06-20 8:42 UTC (permalink / raw)
To: Gary Zambrano; +Cc: netdev
In-Reply-To: <1150485545.8716.50.camel@dhcp-10-7-81-7.broadcom.com>
Gary Zambrano wrote:
> Fixes for speed/duplex/autoneg settings and driver settings info.
> This is a redo of a previous patch thanks to feedback from Jeff Garzik.
ACK patches 1-6, but unfortunately failed to apply against latest
linux-2.6.git:
> [jgarzik@pretzel netdev-2.6]$ git-applymbox /g/tmp/mbox ~/info/signoff.txt
> 6 patch(es) to process.
>
> Applying 'b44: fix manual speed/duplex/autoneg settings'
>
> fatal: corrupt patch at line 8
Also, I think I misunderstood the code in our last discussion. You may
be right about the advertise-all logic.
Jeff
^ permalink raw reply
* Re: [PATCH 1/2] e1000: fix netpoll with NAPI
From: Andrew Grover @ 2006-06-20 8:28 UTC (permalink / raw)
To: linville; +Cc: netdev
In-Reply-To: <Pine.CYG.4.58.0606151344120.928@mawilli1-desk2.amr.corp.intel.com>
(trimmed CC to just netdev)
> > > One of our engineers (on the I/O AT team) has been tasked with modifying
> > > the Linux kernel to properly support multiple hardware queues (both TX and
> > > RX). We'll make sure that he looks at the netpoll interface as part of
> > > that process.
> >
> > Might I ask who this is? I might like to ping him/her on this topic.
> > There is potentially some overlap with wireless, at least on the
> > transmit side.
> > John W. Linville
Hi John, so yeah we want multiple TX queues on wired ethernet for QoS,
same as wireless. Also for SMP scaling (maybe not needed until 10G+).
Did wireless people settle on a design since the email thread in
January?
Regards -- Andy
^ permalink raw reply
* Re: [IOC3] IP27: Really set PCI64_ATTR_VIRTUAL, not PCI64_ATTR_PREC.
From: Ingo Oeser @ 2006-06-20 8:15 UTC (permalink / raw)
To: Ralf Baechle; +Cc: netdev, Jeff Garzik
In-Reply-To: <20060617175738.GA4346@linux-mips.org>
Hi Ralf,
Ralf Baechle :
> IOC3's homegrown DMA mapping functions that are used to optimize things
> a little on IP27 set the wrong bit.
What about using a symbol instead of magic numbers?
That way one at least sees the intention of the coder.
> Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
>
> diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c
> index ae71ed5..e76e6e7 100644
> --- a/drivers/net/ioc3-eth.c
> +++ b/drivers/net/ioc3-eth.c
> @@ -145,7 +145,7 @@ static inline struct sk_buff * ioc3_allo
> static inline unsigned long ioc3_map(void *ptr, unsigned long vdev)
> {
> #ifdef CONFIG_SGI_IP27
> - vdev <<= 58; /* Shift to PCI64_ATTR_VIRTUAL */
> + vdev <<= 57; /* Shift to PCI64_ATTR_VIRTUAL */
So please use a symbolic value here.
Regards
Ingo Oeser
^ 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