* Re: [PATCH] [CAIF-RFC 7/8-v2] CAIF Protocol Stack
From: Stefano Babic @ 2009-10-12 13:43 UTC (permalink / raw)
To: sjur.brandeland
Cc: netdev, kim.xx.lilliestierna, christian.bejram, daniel.martensson
In-Reply-To: <1255095571-6501-8-git-send-email-sjur.brandeland@stericsson.com>
sjur.brandeland@stericsson.com wrote:
> From: Sjur Braendeland <sjur.brandeland@stericsson.com>
>
Hi Sjur,
> +ST-Ericsson modems support a number of transports between modem
> +and host,
> +currently Uart and Shared Memory are available for Linux.
Shared Memory was removed in this patchset.
> +== CAIF structure ==
> +
> +The goal is to have caif as system independent as possible.
> +All caif code can be found under GenCaif/src and GenCaif/inc.
The path are wrong, I think you mean net/caif/generic and include/net/caif.
> +The actual linux module implementation is under src/kernel.
> +There is also a user space program that is not up to date to run the stack in
> +user space for testing.
I think you can remove these phrases.
> +
> +We have tested the kernel implementation on the emulator with a modem and we
> +are able to enumerate and make a link setup.
Only as comment: I tested this patchset again on an ARM platform and I
am able to send successfully AT commands to the Ericsson Test Device "B26".
> + - CFSHML CAIF Shared Memory layer.
Again, this layer was removed and there is no track about SPI Layer.
> +To achieve this we need the help of a daemon program called ldiscd.
> +The benefit is that we can hook up to any TTY, the downside is that we need
> +an extra operation in order to install the line discipline.
I understand the reason, it looks only a quite odd that we need to start
only for this purpose a user space program. And there is no hint if the
daemon is not started, simply caif does not work. What do you think to
set up the line discipline directly in kernel ?
> +Install the line discipline (daemon)
> +$ ldisc
> +
> +Install the VEI channel (this will enumerate and do the linksetup of the first VEI channel. If this goes well you should see /dev/chn*) (There are printks logging all buffers that can be checked with dmesg):
> +$ modprobe chnl_chr
> +
> +The AT (VEI) channel is ready to use (you can now send AT commands on it):
Not really. at this point, the channels are not configured if we do not
use chardevconfig (or we do the same in kernel).
> diff --git a/Documentation/CAIF/caif_user_config.dox b/Documentation/CAIF/caif_user_config.dox
> +The hardware drivers for the physical links to the modems is configured by \b ACTIVATE or \b DEACTIVATE commands.
> +CAIF PHY Drivers and Channel configuration must be done before any CAIF Channels can be accessed from Linux User Space.
> +
> +\section Defined commands
> +The following commands are defined:
> +- \b CREATE - Create a new Net or Character device.
> +- \b DELETE - Delete a Net or Character device
> +- \b ACTIVATE - Activate a CAIF PHY interface.
> +- \b DEACTIVATE - De-activate a CAIF PHY interface.
This file seems obsolete. There is no track about ACTIVATE/DEACTIVATE.
> +
> +\remark
> +Character type devices will show up in /dev/ once they are configured.
If you have udev running on your system....
> +Note also that configured channels are not opened before a file handle is opened from user space.
> +
> +\section Examples
> +The examples below uses the chardevconfig utility as an example on creating channels
> +
> +\subsection Configuration of an AT type Channel:
> +\code
> +$ echo "CREATE TYPE=AT DEV=CHAR NAME=chnlat1" | chrdevconfig /dev/caifconfig
This does not work, PHYPREF is missing.
> +$ echo "CREATE TYPE=RFM DEV=CHAR NAME=rfm01 CONNID=1 VOLUME=/rfm" | chrdevconfig /dev/caifconfig
This does not work, too
> +$ echo "CONFIG-PHY TYPE=MSL NAME=PHYMSL8 INSTANCE=1 CHECKSUM=no HEAD-ALIGN=2 TAIL-ALIGN=2 TRANSFER-ALIGN=16
...and this one does not work.
> +ACTIVATE Activates a new CAIF PHY Instance
> +PHYTYPE=[UART|SPI|MSL|SHM|LOOP] Type of CAIF PHY Instance to configure
> +NAME=<phy-name> Name of the CAIF PHY Device
> +INSTANCE=<id> Instance ID of the device
> +CHECKSUM=[yes|no] Frame Checksum is used for this PHY
> +PARAM=... Other PHY Specific configuration parameters
> +
> +
> +DEACTIVATE NAME=<phy-name> De-activates a PHY Instance
Not implemented ?
> diff --git a/Documentation/CAIF/ldiscd/ldiscd.c b/Documentation/CAIF/ldiscd/ldiscd.c
> +#define CAIF_LDISC_TTY "/dev/ttyS0"
I think it should not be bad to avoid a fixed device name and take it as
program parameter.
Stefano
--
stefano <stefano.babic@babic.homelinux.org>
GPG Key: 0x55814DDE
Fingerprint 4E85 2A66 4CBA 497A 2A7B D3BF 5973 F216 5581 4DDE
^ permalink raw reply
* [PATCH 1/3] sky2: Refactor sky2_get_regs into two functions
From: Mike McCormack @ 2009-10-12 14:06 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: netdev
Separate code deciding which registers can be accessed out of sky2_get_regs
in preparation for adding more conditions into it.
Signed-off-by: Mike McCormack <mikem@ring3k.org>
---
drivers/net/sky2.c | 94 ++++++++++++++++++++++++++-------------------------
1 files changed, 48 insertions(+), 46 deletions(-)
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index 2ab5c39..9713527 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -3730,6 +3730,50 @@ static int sky2_get_regs_len(struct net_device *dev)
return 0x4000;
}
+static int sky2_reg_access_ok(struct sky2_hw *hw, unsigned int b)
+{
+ /* This complicated switch statement is to make sure and
+ * only access regions that are unreserved.
+ * Some blocks are only valid on dual port cards.
+ */
+ switch (b) {
+ /* second port */
+ case 5: /* Tx Arbiter 2 */
+ case 9: /* RX2 */
+ case 14 ... 15: /* TX2 */
+ case 17: case 19: /* Ram Buffer 2 */
+ case 22 ... 23: /* Tx Ram Buffer 2 */
+ case 25: /* Rx MAC Fifo 1 */
+ case 27: /* Tx MAC Fifo 2 */
+ case 31: /* GPHY 2 */
+ case 40 ... 47: /* Pattern Ram 2 */
+ case 52: case 54: /* TCP Segmentation 2 */
+ case 112 ... 116: /* GMAC 2 */
+ return hw->ports > 1;
+
+ case 0: /* Control */
+ case 2: /* Mac address */
+ case 4: /* Tx Arbiter 1 */
+ case 7: /* PCI express reg */
+ case 8: /* RX1 */
+ case 12 ... 13: /* TX1 */
+ case 16: case 18:/* Rx Ram Buffer 1 */
+ case 20 ... 21: /* Tx Ram Buffer 1 */
+ case 24: /* Rx MAC Fifo 1 */
+ case 26: /* Tx MAC Fifo 1 */
+ case 28 ... 29: /* Descriptor and status unit */
+ case 30: /* GPHY 1*/
+ case 32 ... 39: /* Pattern Ram 1 */
+ case 48: case 50: /* TCP Segmentation 1 */
+ case 56 ... 60: /* PCI space */
+ case 80 ... 84: /* GMAC 1 */
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
/*
* Returns copy of control register region
* Note: ethtool_get_regs always provides full size (16k) buffer
@@ -3744,55 +3788,13 @@ static void sky2_get_regs(struct net_device *dev, struct ethtool_regs *regs,
regs->version = 1;
for (b = 0; b < 128; b++) {
- /* This complicated switch statement is to make sure and
- * only access regions that are unreserved.
- * Some blocks are only valid on dual port cards.
- * and block 3 has some special diagnostic registers that
- * are poison.
- */
- switch (b) {
- case 3:
- /* skip diagnostic ram region */
+ /* skip poisonous diagnostic ram region in block 3 */
+ if (b == 3)
memcpy_fromio(p + 0x10, io + 0x10, 128 - 0x10);
- break;
-
- /* dual port cards only */
- case 5: /* Tx Arbiter 2 */
- case 9: /* RX2 */
- case 14 ... 15: /* TX2 */
- case 17: case 19: /* Ram Buffer 2 */
- case 22 ... 23: /* Tx Ram Buffer 2 */
- case 25: /* Rx MAC Fifo 1 */
- case 27: /* Tx MAC Fifo 2 */
- case 31: /* GPHY 2 */
- case 40 ... 47: /* Pattern Ram 2 */
- case 52: case 54: /* TCP Segmentation 2 */
- case 112 ... 116: /* GMAC 2 */
- if (sky2->hw->ports == 1)
- goto reserved;
- /* fall through */
- case 0: /* Control */
- case 2: /* Mac address */
- case 4: /* Tx Arbiter 1 */
- case 7: /* PCI express reg */
- case 8: /* RX1 */
- case 12 ... 13: /* TX1 */
- case 16: case 18:/* Rx Ram Buffer 1 */
- case 20 ... 21: /* Tx Ram Buffer 1 */
- case 24: /* Rx MAC Fifo 1 */
- case 26: /* Tx MAC Fifo 1 */
- case 28 ... 29: /* Descriptor and status unit */
- case 30: /* GPHY 1*/
- case 32 ... 39: /* Pattern Ram 1 */
- case 48: case 50: /* TCP Segmentation 1 */
- case 56 ... 60: /* PCI space */
- case 80 ... 84: /* GMAC 1 */
+ else if (sky2_reg_access_ok(sky2->hw, b))
memcpy_fromio(p, io, 128);
- break;
- default:
-reserved:
+ else
memset(p, 0, 128);
- }
p += 128;
io += 128;
--
1.5.6.5
^ permalink raw reply related
* [PATCH 2/3] sky2: Reading registers in reset causes a hang
From: Mike McCormack @ 2009-10-12 14:06 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: netdev
When sky2 hardware is in reset, reading registers with ethtool -d
causes a hard system hang. eg.
ifconfig eth1 down
ethtool -d eth1
Avoid reading FIFOs, descriptor and status unit, etc. after we've
bought the interface down, as these seem to cause the issue.
Assume the same is true for the second port, as my port only has
one card.
Signed-off-by: Mike McCormack <mikem@ring3k.org>
---
drivers/net/sky2.c | 18 ++++++++++++++----
1 files changed, 14 insertions(+), 4 deletions(-)
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index 9713527..67c8478 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -3735,22 +3735,27 @@ static int sky2_reg_access_ok(struct sky2_hw *hw, unsigned int b)
/* This complicated switch statement is to make sure and
* only access regions that are unreserved.
* Some blocks are only valid on dual port cards.
+ * Some blocks can only be accessed when the hardware is not in reset,
*/
switch (b) {
- /* second port */
+ /* second port, when it exists */
case 5: /* Tx Arbiter 2 */
case 9: /* RX2 */
case 14 ... 15: /* TX2 */
case 17: case 19: /* Ram Buffer 2 */
case 22 ... 23: /* Tx Ram Buffer 2 */
- case 25: /* Rx MAC Fifo 1 */
+ return hw->ports > 1;
+
+ /* second port, when it exists and is not in reset */
+ case 25: /* Rx MAC Fifo 2 */
case 27: /* Tx MAC Fifo 2 */
case 31: /* GPHY 2 */
case 40 ... 47: /* Pattern Ram 2 */
case 52: case 54: /* TCP Segmentation 2 */
case 112 ... 116: /* GMAC 2 */
- return hw->ports > 1;
+ return hw->ports > 1 && netif_running(hw->dev[1]);
+ /* first port and common registers */
case 0: /* Control */
case 2: /* Mac address */
case 4: /* Tx Arbiter 1 */
@@ -3759,14 +3764,19 @@ static int sky2_reg_access_ok(struct sky2_hw *hw, unsigned int b)
case 12 ... 13: /* TX1 */
case 16: case 18:/* Rx Ram Buffer 1 */
case 20 ... 21: /* Tx Ram Buffer 1 */
+ return 1;
+
+ /* first port, when not in reset */
case 24: /* Rx MAC Fifo 1 */
case 26: /* Tx MAC Fifo 1 */
case 28 ... 29: /* Descriptor and status unit */
case 30: /* GPHY 1*/
case 32 ... 39: /* Pattern Ram 1 */
case 48: case 50: /* TCP Segmentation 1 */
- case 56 ... 60: /* PCI space */
case 80 ... 84: /* GMAC 1 */
+ return netif_running(hw->dev[0]);
+
+ case 56 ... 60: /* PCI space */
return 1;
default:
--
1.5.6.5
^ permalink raw reply related
* [PATCH 3/3] sky2: Hold phy lock when accessing phy registers
From: Mike McCormack @ 2009-10-12 14:06 UTC (permalink / raw)
To: netdev; +Cc: Stephen Hemminger
The phy lock should be held around gm_phy_read.
This is probably another theoretical problem, however
we should do this for consistency purposes.
Signed-off-by: Mike McCormack <mikem@ring3k.org>
---
drivers/net/sky2.c | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index 67c8478..0e1a4bc 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -830,6 +830,7 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port)
if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev == 0 && port == 1) {
/* WA DEV_472 -- looks like crossed wires on port 2 */
/* clear GMAC 1 Control reset */
+ spin_lock_bh(&sky2->phy_lock);
sky2_write8(hw, SK_REG(0, GMAC_CTRL), GMC_RST_CLR);
do {
sky2_write8(hw, SK_REG(1, GMAC_CTRL), GMC_RST_SET);
@@ -837,6 +838,7 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port)
} while (gm_phy_read(hw, 1, PHY_MARV_ID0) != PHY_MARV_ID0_VAL ||
gm_phy_read(hw, 1, PHY_MARV_ID1) != PHY_MARV_ID1_Y2 ||
gm_phy_read(hw, 1, PHY_MARV_INT_MASK) != 0);
+ spin_unlock_bh(&sky2->phy_lock);
}
sky2_read16(hw, SK_REG(port, GMAC_IRQ_SRC));
--
1.5.6.5
^ permalink raw reply related
* Re: kernel mode pppoe ppp if + ifb + mirred redirect, ethernet packets in ifb?!
From: Denys Fedoryschenko @ 2009-10-12 14:15 UTC (permalink / raw)
To: hadi; +Cc: netdev
In-Reply-To: <1255353047.5406.12.camel@dogo.mojatatu.com>
How it can be ethernet packets (with PPPoE headers) if i am redirecting from
ppp interface, not ethernet interface?
PPPoE_146 ~ # tcpdump -ni ppp0 -e -vvv -s 1500 -c 4
tcpdump: WARNING:
tcpdump: listening on ppp0, link-type LINUX_SLL (Linux cooked), capture size
1500 bytes
17:03:17.015598 Out ethertype IPv4 (0x0800), length 68: (tos 0x0, ttl 111, id
45623, offset 0, flags [DF], proto TCP (6), length 52)
68.231.189.241.24800 > 172.16.131.199.1060: Flags [.], cksum 0xd208
(correct), seq 783840165, ack 1980178761, win 32748, options [nop,nop,sack 1
{1441:8741}], length 0
PPPoE_146 ~ # tcpdump -ni ifb0 -e -vvv -s 1500 -c 4
tcpdump: WARNING:
tcpdump: WARNING: ifb0: no IPv4 address assigned
tcpdump: listening on ifb0, link-type EN10MB (Ethernet), capture size 1500
bytes
17:04:01.625547 00:0a:cd:17:5e:08 > 00:0a:cd:14:6b:67, ethertype PPPoE S
(0x8864), length 70: PPPoE [ses 0xb] IP (0x0021), length 50: (tos 0x0, ttl
128, id 51706, offset 0, flags [DF], proto TCP (6), length 48)
Btw i test, if i use userspace pppoe (synchronous) i will get different output
in tcpdump
PPPoE_146 ~ # tcpdump -ni ifb0 -vvvv
tcpdump: WARNING:
tcpdump: WARNING: ifb0: no IPv4 address assigned
tcpdump: listening on ifb0, link-type EN10MB (Ethernet), capture size 96 bytes
17:15:41.512553 00:28:00:d6:40:00 > ff:03:00:21:45:00, ethertype Unknown
(0x8006), length 44:
0x0000: df49 ac10 8320 cf2e 1c51 0416 0050 ce7b .I.......Q...P.{
0x0010: e177 1caf 491d 5010 ffff 7afe 0000 .w..I.P...z...
17:15:41.520802 00:34:00:d7:40:00 > ff:03:00:21:45:00, ethertype Unknown
(0x8006), length 112:
0x0000: df3c ac10 8320 cf2e 1c51 0416 0050 ce7b .<.......Q...P.{
0x0010: e177 1caf 491d 8010 ffff 686e 0000 0101 .w..I.....hn....
0x0020: 050a 1caf 4ebd 1caf 545d ff03 0021 4500 ....N...T]...!E.
0x0030: 0034 00d8 4000 8006 df3b ac10 8320 cf2e .4..@....;......
0x0040: 1c51 0416 0050 ce7b e177 1caf 491d 8010 .Q...P.{.w..I...
0x0050: ffff ..
17:15:41.528825 00:34:00:d9:40:00 > ff:03:00:21:45:00, ethertype Unknown
(0x8006), length 56:
0x0000: df3a ac10 8320 cf2e 1c51 0416 0050 ce7b .:.......Q...P.{
0x0010: e177 1caf 491d 8010 ffff 5d2e 0000 0101 .w..I.....].....
0x0020: 050a 1caf 4ebd 1caf 5f9d ....N..._.
With PPTP it is as expected, IP packets (like in ppp interface tcpdump).
On Monday 12 October 2009 16:10:47 jamal wrote:
> On Mon, 2009-10-12 at 11:43 +0300, Denys Fedoryschenko wrote:
> > Is it expected that redirecting ppp interface, that supposed to be clean
> > IP traffic is becoming eth encapsulated traffic?
>
> No. Imagine if there were other types of packets non-ip for example,
> what do you do then?
> this feature is as close as you can get when you do switch level
> mirroring or redirection. If you want to edit header before redirect
> etc, use pedit (refer to recent discussion with someone who wanted to
> replicate packets for redundant routing purposes);
>
> cheers,
> jamal
^ permalink raw reply
* Moving drivers into staging (was Re: [GIT PULL] SCSI fixes for 2.6.32-rc3)
From: Greg KH @ 2009-10-12 15:09 UTC (permalink / raw)
To: Ingo Molnar
Cc: James Bottomley, Linus Torvalds, Theodore Tso, Andrew Morton,
linux-scsi, linux-kernel, Jing Huang, netdev, linux-wireless
In-Reply-To: <20091012145453.GD4565@elte.hu>
adding David Miller and the wireless developers who had this idea as
well...
On Mon, Oct 12, 2009 at 04:54:53PM +0200, Ingo Molnar wrote:
> I think your interpretation is arbitrary - where did you get that ABI
> rule from? I'm sure it cannot be from any of the drivers/staging/
> discussions on lkml, i've followed them quite closely. If 'has a messy
> ABI' was the only requirement for drivers/staging/ then we could move
> 90% of drivers/staging/ into drivers/ straight away - and that would be
> counter-productive IMHO.
I agree with this, and the other points you raised that I snipped out.
> Sidenote, in fact i think we should expand on that: drivers/staging/
> should be used in the _other_ direction as well - to un-upstream stale
> drivers that are abandoned and unused, in a gradual fashion. 'git mv' is
> cheap.
Ok, this is about the 3rd or 4th time I've heard this, from totally
different people lately. It seems that I'm the only one that has the
ability to drop drivers out of the kernel tree, which is a funny
situation :)
In thinking about this a lot more, I don't really mind it. If people
want to push stuff out of "real" places in the kernel, into
drivers/staging/ and give the original authors and maintainers notice
about what is going on, _and_ provide a TODO file for what needs to
happen to get the code back into the main portion of the kernel tree,
then I'll be happy to help out with this and manage it.
I think a 6-9 month window (basically 3 kernel releases) should be
sufficient time to have a driver that has been in drivers/staging/ be
cleaned up enough to move back into the main kernel tree. If not, it
could be easily dropped.
Any objections to this?
> Basically, drivers/staging/ gives us an excellent opportunity to
> _increase_ the quality of drivers by applying stronger upstream
> inclusion filters, without having to hurt users/developers in the
> process. We just have to start using it that way as well.
I totally agree. And so far, it does seem to be working well for this.
A number of companies have used it to successfully get their code into
the main kernel, as well as driving them to clean up their code better
to keep it from having to go into the staging tree.
thanks,
greg k-h
^ permalink raw reply
* [PATCH 1/2] libertas: fix build
From: Alan Cox @ 2009-10-12 15:27 UTC (permalink / raw)
To: netdev, linux-kernel
In-Reply-To: <20091012152247.5694.77290.stgit@localhost.localdomain>
drivers/net/wireless/libertas/cmdresp.c: In function ‘lbs_process_event’:
drivers/net/wireless/libertas/cmdresp.c:519: error: ‘TASK_INTERRUPTIBLE’
undeclared (first use in this function)
drivers/net/wireless/libertas/cmdresp.c:519: error: (Each undeclared
identifier is reported only once
drivers/net/wireless/libertas/cmdresp.c:519: error: for each function it
appears in.)
Signed-off-by: Alan Cox <alan@linux.intel.com>
---
drivers/net/wireless/libertas/cmdresp.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c
index 47d2b19..9ee8bd1 100644
--- a/drivers/net/wireless/libertas/cmdresp.c
+++ b/drivers/net/wireless/libertas/cmdresp.c
@@ -3,6 +3,7 @@
* responses as well as events generated by firmware.
*/
#include <linux/delay.h>
+#include <linux/sched.h>
#include <linux/if_arp.h>
#include <linux/netdevice.h>
#include <asm/unaligned.h>
^ permalink raw reply related
* [PATCH 2/2] ethoc: fix warning from 32bit build
From: Alan Cox @ 2009-10-12 15:27 UTC (permalink / raw)
To: netdev, linux-kernel
In-Reply-To: <20091012152247.5694.77290.stgit@localhost.localdomain>
drivers/net/ethoc.c: In function ‘ethoc_open’:
drivers/net/ethoc.c:667: warning: comparison of distinct pointer types
lacks a cast
Signed-off-by: Alan Cox <alan@linux.intel.com>
---
drivers/net/ethoc.c | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)
diff --git a/drivers/net/ethoc.c b/drivers/net/ethoc.c
index 96f5b2a..402a507 100644
--- a/drivers/net/ethoc.c
+++ b/drivers/net/ethoc.c
@@ -664,7 +664,8 @@ static int ethoc_open(struct net_device *dev)
return ret;
/* calculate the number of TX/RX buffers, maximum 128 supported */
- num_bd = min(128, (dev->mem_end - dev->mem_start + 1) / ETHOC_BUFSIZ);
+ num_bd = min_t(unsigned int,
+ 128, (dev->mem_end - dev->mem_start + 1) / ETHOC_BUFSIZ);
priv->num_tx = max(min_tx, num_bd / 4);
priv->num_rx = num_bd - priv->num_tx;
ethoc_write(priv, TX_BD_NUM, priv->num_tx);
^ permalink raw reply related
* [PATCH 0/2] Build fixes for todays next tree
From: Alan Cox @ 2009-10-12 15:27 UTC (permalink / raw)
To: netdev, linux-kernel
Couple of networking warns/build fails
---
Alan Cox (2):
ethoc: fix warning from 32bit build
libertas: fix build
drivers/net/ethoc.c | 3 ++-
drivers/net/wireless/libertas/cmdresp.c | 1 +
2 files changed, 3 insertions(+), 1 deletions(-)
--
How do you raise an elephant ... with a crane
^ permalink raw reply
* Re: Moving drivers into staging (was Re: [GIT PULL] SCSI fixes for 2.6.32-rc3)
From: Ingo Molnar @ 2009-10-12 15:42 UTC (permalink / raw)
To: Greg KH
Cc: James Bottomley, Linus Torvalds, Theodore Tso, Andrew Morton,
linux-scsi, linux-kernel, Jing Huang, netdev, linux-wireless
In-Reply-To: <20091012150911.GB1656@suse.de>
* Greg KH <gregkh@suse.de> wrote:
> > Sidenote, in fact i think we should expand on that: drivers/staging/
> > should be used in the _other_ direction as well - to un-upstream
> > stale drivers that are abandoned and unused, in a gradual fashion.
> > 'git mv' is cheap.
>
> Ok, this is about the 3rd or 4th time I've heard this, from totally
> different people lately. [...]
Heh. I guess i had a good crystal ball on that then - i raised that
issue in my very first comments on drivers/staging/, 2.5 years ago - see
the "Linux Kernel developer statement about closed source code" thread,
where i wrote:
| - We must accept open-source drivers (which are license-compatible
| with the kernel) for new hardware the moment they are offered. No
| ifs and when. No whining about quality, style, security, re-use,
| non-reuse, obsolete APIs, overlapping functionality, the already
| busy merge schedule of a maintainer or whatever other thing can come
| up on lkml.
|
| We can create arbitrary quarantine mechanisms we wish to use:
| CONFIG_REALLY_BROKEN. We could even create drivers/staging/ as a
| temporary staging area for drivers.
|
| What we cannot do is to _deny_ the distribution channel and exclude
| users. The moment we do that (and we still do that in way too many
| areas of the kernel) we have lost the availability race.
[...]
| If it's not maintained actively(sc) (i.e. it's a fire-and-forget
| driver) then it can get marked BROKEN with time, and can get removed
| as well.
Hm, i think i even gave drivers/staging/ its name?
> [...] It seems that I'm the only one that has the ability to drop
> drivers out of the kernel tree, which is a funny situation :)
You are the only one who has the ability to send a warning shot towards
drivers _without hurting users_, and by moving it into the focus of a
team of cleanup oriented developers.
I think that's an important distinction ;-)
> In thinking about this a lot more, I don't really mind it. If people
> want to push stuff out of "real" places in the kernel, into
> drivers/staging/ and give the original authors and maintainers notice
> about what is going on, _and_ provide a TODO file for what needs to
> happen to get the code back into the main portion of the kernel tree,
> then I'll be happy to help out with this and manage it.
>
> I think a 6-9 month window (basically 3 kernel releases) should be
> sufficient time to have a driver that has been in drivers/staging/ be
> cleaned up enough to move back into the main kernel tree. If not, it
> could be easily dropped.
>
> Any objections to this?
Sounds excellent to me!
> > Basically, drivers/staging/ gives us an excellent opportunity to
> > _increase_ the quality of drivers by applying stronger upstream
> > inclusion filters, without having to hurt users/developers in the
> > process. We just have to start using it that way as well.
>
> I totally agree. And so far, it does seem to be working well for
> this. A number of companies have used it to successfully get their
> code into the main kernel, as well as driving them to clean up their
> code better to keep it from having to go into the staging tree.
Yeah. I think we were hurting from an under-estimated trust problem:
driver authors couldnt trust _us maintainers_ to follow through with
upstreaming. drivers/staging/ improved that IMHO.
I.e. the old process of upstreaming drivers was too arbitrary, incurred
big latencies and was dependent on the whims of maintainers. I.e. new
developers got exposed to some of the worst social aspects of a
distributed development process.
Now there's basically a single (and friendly! ;-) upstreaming channel
that people (yet-)unfamilar with Linux practices can standardize on.
This reduces the pressure on maintainers and also creates a reference
point for upstreaming honesty - which is almost unconditionally good i
think.
Ingo
^ permalink raw reply
* Re: Moving drivers into staging (was Re: [GIT PULL] SCSI fixes for 2.6.32-rc3)
From: James Bottomley @ 2009-10-12 15:43 UTC (permalink / raw)
To: Greg KH
Cc: Ingo Molnar, Linus Torvalds, Theodore Tso, Andrew Morton,
linux-scsi, linux-kernel, Jing Huang,
netdev-u79uwXL29TY76Z2rM5mHXA,
linux-wireless-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20091012150911.GB1656-l3A5Bk7waGM@public.gmane.org>
On Mon, 2009-10-12 at 08:09 -0700, Greg KH wrote:
> adding David Miller and the wireless developers who had this idea as
> well...
>
> On Mon, Oct 12, 2009 at 04:54:53PM +0200, Ingo Molnar wrote:
> > I think your interpretation is arbitrary - where did you get that ABI
> > rule from? I'm sure it cannot be from any of the drivers/staging/
> > discussions on lkml, i've followed them quite closely. If 'has a messy
> > ABI' was the only requirement for drivers/staging/ then we could move
> > 90% of drivers/staging/ into drivers/ straight away - and that would be
> > counter-productive IMHO.
>
> I agree with this, and the other points you raised that I snipped out.
>
> > Sidenote, in fact i think we should expand on that: drivers/staging/
> > should be used in the _other_ direction as well - to un-upstream stale
> > drivers that are abandoned and unused, in a gradual fashion. 'git mv' is
> > cheap.
>
> Ok, this is about the 3rd or 4th time I've heard this, from totally
> different people lately. It seems that I'm the only one that has the
> ability to drop drivers out of the kernel tree, which is a funny
> situation :)
>
> In thinking about this a lot more, I don't really mind it. If people
> want to push stuff out of "real" places in the kernel, into
> drivers/staging/ and give the original authors and maintainers notice
> about what is going on, _and_ provide a TODO file for what needs to
> happen to get the code back into the main portion of the kernel tree,
> then I'll be happy to help out with this and manage it.
>
> I think a 6-9 month window (basically 3 kernel releases) should be
> sufficient time to have a driver that has been in drivers/staging/ be
> cleaned up enough to move back into the main kernel tree. If not, it
> could be easily dropped.
>
> Any objections to this?
Not as an optional tool to use when necessary.
If you want to make this a mandatory path for old drivers, then, I think
it's far too rigid, yes. There's a huge amount of danger to changing
working drivers simply on grounds of code cleanup and that danger
increases exponentially as they get older and the hardware gets rarer.
Look at what happened to the initio driver in 2008 for instance. That
was cleaned up by Alan Cox, no mean expert in the field, with the
assistance of a tester with the actual card, so basically a textbook
operation. However, a bug crept in during this process that wasn't
spotted by the tester. When it was spotted (bug report ~6 months later)
the original tester wasn't available and code inspection across the
cleanup was very hard. Fortunately, the reporter was motivated to track
down and patch the driver, so it worked out all right in the end, but a
lot of bug reporters aren't so capable (or so motivated). Plus most
clean up patches for old hardware tend only to be compile tested, so the
potential for bugs is far greater.
James
> > Basically, drivers/staging/ gives us an excellent opportunity to
> > _increase_ the quality of drivers by applying stronger upstream
> > inclusion filters, without having to hurt users/developers in the
> > process. We just have to start using it that way as well.
>
> I totally agree. And so far, it does seem to be working well for this.
> A number of companies have used it to successfully get their code into
> the main kernel, as well as driving them to clean up their code better
> to keep it from having to go into the staging tree.
>
> thanks,
>
> greg k-h
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH 0/8] gianfar: Add support for hibernation
From: Anton Vorontsov @ 2009-10-12 16:00 UTC (permalink / raw)
To: David Miller; +Cc: Scott Wood, linuxppc-dev, netdev, Andy Fleming
Hi all,
Here are few patches that add support for hibernation for gianfar
driver.
Technically, we could just do gfar_close() and then gfar_enet_open()
sequence to restore gianfar functionality after hibernation, but
close/open does so many unneeded things (e.g. BDs buffers freeing and
allocation, IRQ freeing and requesting), that I felt it would be much
better to cleanup and refactor some code to make the hibernation [and
not only hibernation] code a little bit prettier.
Patches on the way...
Thanks,
--
Anton Vorontsov
email: cbouatmailru@gmail.com
irc://irc.freenode.net/bd2
^ permalink raw reply
* [PATCH 1/8] gianfar: Some cleanups for startup_gfar()
From: Anton Vorontsov @ 2009-10-12 16:00 UTC (permalink / raw)
To: David Miller; +Cc: Scott Wood, linuxppc-dev, netdev, Andy Fleming
In-Reply-To: <20091012160000.GA32406@oksana.dev.rtsoft.ru>
We're going to split the startup_gfar() into 3 separate functions,
so let's cleanup the code a little bit so that cosmetic changes
won't distract attention from logical ones.
- Remove needless casts (e.g. (struct sk_buff **)kmalloc());
- Turn 'unsigned long vaddr;' into 'void *vaddr', to avoid casting;
- Add new 'struct device *dev' variable as a shorthand for
'&priv->ofdev->dev' that is used all over the place, also rename
'struct net_device *dev' to 'struct net_device *ndev';
- Turn printk(KERN_ERR ...) to pr_err(...), which is shorter;
- Don't return bogus -1 (i.e. -EPERM) when request_irq() fails;
- Turn '&priv->regs->' to just '®s->'.
Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
---
drivers/net/gianfar.c | 143 ++++++++++++++++++++++---------------------------
1 files changed, 64 insertions(+), 79 deletions(-)
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 5bf31f1..8c7322f 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -925,16 +925,17 @@ void gfar_start(struct net_device *dev)
}
/* Bring the controller up and running */
-int startup_gfar(struct net_device *dev)
+int startup_gfar(struct net_device *ndev)
{
struct txbd8 *txbdp;
struct rxbd8 *rxbdp;
dma_addr_t addr = 0;
- unsigned long vaddr;
+ void *vaddr;
int i;
- struct gfar_private *priv = netdev_priv(dev);
+ struct gfar_private *priv = netdev_priv(ndev);
+ struct device *dev = &priv->ofdev->dev;
struct gfar __iomem *regs = priv->regs;
- int err = 0;
+ int err;
u32 rctrl = 0;
u32 tctrl = 0;
u32 attrs = 0;
@@ -942,38 +943,34 @@ int startup_gfar(struct net_device *dev)
gfar_write(®s->imask, IMASK_INIT_CLEAR);
/* Allocate memory for the buffer descriptors */
- vaddr = (unsigned long) dma_alloc_coherent(&priv->ofdev->dev,
- sizeof (struct txbd8) * priv->tx_ring_size +
- sizeof (struct rxbd8) * priv->rx_ring_size,
- &addr, GFP_KERNEL);
-
- if (vaddr == 0) {
+ vaddr = dma_alloc_coherent(dev, sizeof(*txbdp) * priv->tx_ring_size +
+ sizeof(*rxbdp) * priv->rx_ring_size,
+ &addr, GFP_KERNEL);
+ if (!vaddr) {
if (netif_msg_ifup(priv))
- printk(KERN_ERR "%s: Could not allocate buffer descriptors!\n",
- dev->name);
+ pr_err("%s: Could not allocate buffer descriptors!\n",
+ ndev->name);
return -ENOMEM;
}
- priv->tx_bd_base = (struct txbd8 *) vaddr;
+ priv->tx_bd_base = vaddr;
/* enet DMA only understands physical addresses */
gfar_write(®s->tbase0, addr);
/* Start the rx descriptor ring where the tx ring leaves off */
- addr = addr + sizeof (struct txbd8) * priv->tx_ring_size;
- vaddr = vaddr + sizeof (struct txbd8) * priv->tx_ring_size;
- priv->rx_bd_base = (struct rxbd8 *) vaddr;
+ addr = addr + sizeof(*txbdp) * priv->tx_ring_size;
+ vaddr = vaddr + sizeof(*txbdp) * priv->tx_ring_size;
+ priv->rx_bd_base = vaddr;
gfar_write(®s->rbase0, addr);
/* Setup the skbuff rings */
- priv->tx_skbuff =
- (struct sk_buff **) kmalloc(sizeof (struct sk_buff *) *
- priv->tx_ring_size, GFP_KERNEL);
-
- if (NULL == priv->tx_skbuff) {
+ priv->tx_skbuff = kmalloc(sizeof(*priv->tx_skbuff) *
+ priv->tx_ring_size, GFP_KERNEL);
+ if (!priv->tx_skbuff) {
if (netif_msg_ifup(priv))
- printk(KERN_ERR "%s: Could not allocate tx_skbuff\n",
- dev->name);
+ pr_err("%s: Could not allocate tx_skbuff\n",
+ ndev->name);
err = -ENOMEM;
goto tx_skb_fail;
}
@@ -981,14 +978,12 @@ int startup_gfar(struct net_device *dev)
for (i = 0; i < priv->tx_ring_size; i++)
priv->tx_skbuff[i] = NULL;
- priv->rx_skbuff =
- (struct sk_buff **) kmalloc(sizeof (struct sk_buff *) *
- priv->rx_ring_size, GFP_KERNEL);
-
- if (NULL == priv->rx_skbuff) {
+ priv->rx_skbuff = kmalloc(sizeof(*priv->rx_skbuff) *
+ priv->rx_ring_size, GFP_KERNEL);
+ if (!priv->rx_skbuff) {
if (netif_msg_ifup(priv))
- printk(KERN_ERR "%s: Could not allocate rx_skbuff\n",
- dev->name);
+ pr_err("%s: Could not allocate rx_skbuff\n",
+ ndev->name);
err = -ENOMEM;
goto rx_skb_fail;
}
@@ -1019,18 +1014,16 @@ int startup_gfar(struct net_device *dev)
for (i = 0; i < priv->rx_ring_size; i++) {
struct sk_buff *skb;
- skb = gfar_new_skb(dev);
-
+ skb = gfar_new_skb(ndev);
if (!skb) {
- printk(KERN_ERR "%s: Can't allocate RX buffers\n",
- dev->name);
-
+ pr_err("%s: Can't allocate RX buffers\n", ndev->name);
+ err = -ENOMEM;
goto err_rxalloc_fail;
}
priv->rx_skbuff[i] = skb;
- gfar_new_rxbdp(dev, rxbdp, skb);
+ gfar_new_rxbdp(ndev, rxbdp, skb);
rxbdp++;
}
@@ -1044,44 +1037,39 @@ int startup_gfar(struct net_device *dev)
if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) {
/* Install our interrupt handlers for Error,
* Transmit, and Receive */
- if (request_irq(priv->interruptError, gfar_error,
- 0, priv->int_name_er, dev) < 0) {
+ err = request_irq(priv->interruptError, gfar_error, 0,
+ priv->int_name_er, ndev);
+ if (err) {
if (netif_msg_intr(priv))
- printk(KERN_ERR "%s: Can't get IRQ %d\n",
- dev->name, priv->interruptError);
-
- err = -1;
+ pr_err("%s: Can't get IRQ %d\n", ndev->name,
+ priv->interruptError);
goto err_irq_fail;
}
- if (request_irq(priv->interruptTransmit, gfar_transmit,
- 0, priv->int_name_tx, dev) < 0) {
+ err = request_irq(priv->interruptTransmit, gfar_transmit, 0,
+ priv->int_name_tx, ndev);
+ if (err) {
if (netif_msg_intr(priv))
- printk(KERN_ERR "%s: Can't get IRQ %d\n",
- dev->name, priv->interruptTransmit);
-
- err = -1;
-
+ pr_err("%s: Can't get IRQ %d\n", ndev->name,
+ priv->interruptTransmit);
goto tx_irq_fail;
}
- if (request_irq(priv->interruptReceive, gfar_receive,
- 0, priv->int_name_rx, dev) < 0) {
+ err = request_irq(priv->interruptReceive, gfar_receive, 0,
+ priv->int_name_rx, ndev);
+ if (err) {
if (netif_msg_intr(priv))
- printk(KERN_ERR "%s: Can't get IRQ %d (receive0)\n",
- dev->name, priv->interruptReceive);
-
- err = -1;
+ pr_err("%s: Can't get IRQ %d (receive0)\n",
+ ndev->name, priv->interruptReceive);
goto rx_irq_fail;
}
} else {
- if (request_irq(priv->interruptTransmit, gfar_interrupt,
- 0, priv->int_name_tx, dev) < 0) {
+ err = request_irq(priv->interruptTransmit, gfar_interrupt,
+ 0, priv->int_name_tx, ndev);
+ if (err) {
if (netif_msg_intr(priv))
- printk(KERN_ERR "%s: Can't get IRQ %d\n",
- dev->name, priv->interruptTransmit);
-
- err = -1;
+ pr_err("%s: Can't get IRQ %d\n", ndev->name,
+ priv->interruptTransmit);
goto err_irq_fail;
}
}
@@ -1103,7 +1091,7 @@ int startup_gfar(struct net_device *dev)
if (priv->extended_hash) {
rctrl |= RCTRL_EXTHASH;
- gfar_clear_exact_match(dev);
+ gfar_clear_exact_match(ndev);
rctrl |= RCTRL_EMEN;
}
@@ -1119,18 +1107,18 @@ int startup_gfar(struct net_device *dev)
}
/* Init rctrl based on our settings */
- gfar_write(&priv->regs->rctrl, rctrl);
+ gfar_write(®s->rctrl, rctrl);
- if (dev->features & NETIF_F_IP_CSUM)
+ if (ndev->features & NETIF_F_IP_CSUM)
tctrl |= TCTRL_INIT_CSUM;
- gfar_write(&priv->regs->tctrl, tctrl);
+ gfar_write(®s->tctrl, tctrl);
/* Set the extraction length and index */
attrs = ATTRELI_EL(priv->rx_stash_size) |
ATTRELI_EI(priv->rx_stash_index);
- gfar_write(&priv->regs->attreli, attrs);
+ gfar_write(®s->attreli, attrs);
/* Start with defaults, and add stashing or locking
* depending on the approprate variables */
@@ -1142,32 +1130,29 @@ int startup_gfar(struct net_device *dev)
if (priv->rx_stash_size != 0)
attrs |= ATTR_BUFSTASH;
- gfar_write(&priv->regs->attr, attrs);
+ gfar_write(®s->attr, attrs);
- gfar_write(&priv->regs->fifo_tx_thr, priv->fifo_threshold);
- gfar_write(&priv->regs->fifo_tx_starve, priv->fifo_starve);
- gfar_write(&priv->regs->fifo_tx_starve_shutoff, priv->fifo_starve_off);
+ gfar_write(®s->fifo_tx_thr, priv->fifo_threshold);
+ gfar_write(®s->fifo_tx_starve, priv->fifo_starve);
+ gfar_write(®s->fifo_tx_starve_shutoff, priv->fifo_starve_off);
/* Start the controller */
- gfar_start(dev);
+ gfar_start(ndev);
return 0;
rx_irq_fail:
- free_irq(priv->interruptTransmit, dev);
+ free_irq(priv->interruptTransmit, ndev);
tx_irq_fail:
- free_irq(priv->interruptError, dev);
+ free_irq(priv->interruptError, ndev);
err_irq_fail:
err_rxalloc_fail:
rx_skb_fail:
free_skb_resources(priv);
tx_skb_fail:
- dma_free_coherent(&priv->ofdev->dev,
- sizeof(struct txbd8)*priv->tx_ring_size
- + sizeof(struct rxbd8)*priv->rx_ring_size,
- priv->tx_bd_base,
- gfar_read(®s->tbase0));
-
+ dma_free_coherent(dev, sizeof(*txbdp) * priv->tx_ring_size +
+ sizeof(*rxbdp) * priv->rx_ring_size,
+ priv->tx_bd_base, gfar_read(®s->tbase0));
return err;
}
--
1.6.3.3
^ permalink raw reply related
* [PATCH 2/8] gianfar: Simplify skb resources freeing code
From: Anton Vorontsov @ 2009-10-12 16:00 UTC (permalink / raw)
To: David Miller; +Cc: Scott Wood, linuxppc-dev, netdev, Andy Fleming
In-Reply-To: <20091012160000.GA32406@oksana.dev.rtsoft.ru>
Remove dma_free_coherent() from stop_gfar() and gfar_start() calls,
place it into free_skb_resources(). That makes SKB resources management
more understandable, plus free_skb_resources() will be used as a cleanup
routine for gfar_alloc_skb_resources() that will be implemented soon.
Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
---
drivers/net/gianfar.c | 53 +++++++++++++++++++++++-------------------------
1 files changed, 25 insertions(+), 28 deletions(-)
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 8c7322f..b7881e6 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -806,7 +806,6 @@ void gfar_halt(struct net_device *dev)
void stop_gfar(struct net_device *dev)
{
struct gfar_private *priv = netdev_priv(dev);
- struct gfar __iomem *regs = priv->regs;
unsigned long flags;
phy_stop(priv->phydev);
@@ -830,18 +829,13 @@ void stop_gfar(struct net_device *dev)
}
free_skb_resources(priv);
-
- dma_free_coherent(&priv->ofdev->dev,
- sizeof(struct txbd8)*priv->tx_ring_size
- + sizeof(struct rxbd8)*priv->rx_ring_size,
- priv->tx_bd_base,
- gfar_read(®s->tbase0));
}
/* If there are any tx skbs or rx skbs still around, free them.
* Then free tx_skbuff and rx_skbuff */
static void free_skb_resources(struct gfar_private *priv)
{
+ struct device *dev = &priv->ofdev->dev;
struct rxbd8 *rxbdp;
struct txbd8 *txbdp;
int i, j;
@@ -849,6 +843,9 @@ static void free_skb_resources(struct gfar_private *priv)
/* Go through all the buffer descriptors and free their data buffers */
txbdp = priv->tx_bd_base;
+ if (!priv->tx_skbuff)
+ goto skip_tx_skbuff;
+
for (i = 0; i < priv->tx_ring_size; i++) {
if (!priv->tx_skbuff[i])
continue;
@@ -867,30 +864,33 @@ static void free_skb_resources(struct gfar_private *priv)
}
kfree(priv->tx_skbuff);
+skip_tx_skbuff:
rxbdp = priv->rx_bd_base;
- /* rx_skbuff is not guaranteed to be allocated, so only
- * free it and its contents if it is allocated */
- if(priv->rx_skbuff != NULL) {
- for (i = 0; i < priv->rx_ring_size; i++) {
- if (priv->rx_skbuff[i]) {
- dma_unmap_single(&priv->ofdev->dev, rxbdp->bufPtr,
- priv->rx_buffer_size,
- DMA_FROM_DEVICE);
-
- dev_kfree_skb_any(priv->rx_skbuff[i]);
- priv->rx_skbuff[i] = NULL;
- }
-
- rxbdp->lstatus = 0;
- rxbdp->bufPtr = 0;
+ if (!priv->rx_skbuff)
+ goto skip_rx_skbuff;
- rxbdp++;
+ for (i = 0; i < priv->rx_ring_size; i++) {
+ if (priv->rx_skbuff[i]) {
+ dma_unmap_single(&priv->ofdev->dev, rxbdp->bufPtr,
+ priv->rx_buffer_size,
+ DMA_FROM_DEVICE);
+ dev_kfree_skb_any(priv->rx_skbuff[i]);
+ priv->rx_skbuff[i] = NULL;
}
- kfree(priv->rx_skbuff);
+ rxbdp->lstatus = 0;
+ rxbdp->bufPtr = 0;
+ rxbdp++;
}
+
+ kfree(priv->rx_skbuff);
+skip_rx_skbuff:
+
+ dma_free_coherent(dev, sizeof(*txbdp) * priv->tx_ring_size +
+ sizeof(*rxbdp) * priv->rx_ring_size,
+ priv->tx_bd_base, gfar_read(&priv->regs->tbase0));
}
void gfar_start(struct net_device *dev)
@@ -1148,11 +1148,8 @@ tx_irq_fail:
err_irq_fail:
err_rxalloc_fail:
rx_skb_fail:
- free_skb_resources(priv);
tx_skb_fail:
- dma_free_coherent(dev, sizeof(*txbdp) * priv->tx_ring_size +
- sizeof(*rxbdp) * priv->rx_ring_size,
- priv->tx_bd_base, gfar_read(®s->tbase0));
+ free_skb_resources(priv);
return err;
}
--
1.6.3.3
^ permalink raw reply related
* [PATCH 3/8] gianfar: Don't needlessly set the wrap bit for the last RX BD
From: Anton Vorontsov @ 2009-10-12 16:00 UTC (permalink / raw)
To: David Miller; +Cc: Scott Wood, linuxppc-dev, netdev, Andy Fleming
In-Reply-To: <20091012160000.GA32406@oksana.dev.rtsoft.ru>
startup_gfar() sets the wrap bit for the last rxbd just after
gfar_new_rxbdp() call, which is issued for all rxbds. And
gfar_new_rxbdp() has the following check already:
if (bdp == priv->rx_bd_base + priv->rx_ring_size - 1)
lstatus |= BD_LFLAG(RXBD_WRAP);
So we don't need to set the bit again.
Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
---
drivers/net/gianfar.c | 4 ----
1 files changed, 0 insertions(+), 4 deletions(-)
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index b7881e6..ee23431 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -1028,10 +1028,6 @@ int startup_gfar(struct net_device *ndev)
rxbdp++;
}
- /* Set the last descriptor in the ring to wrap */
- rxbdp--;
- rxbdp->status |= RXBD_WRAP;
-
/* If the device has multiple interrupts, register for
* them. Otherwise, only register for the one */
if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) {
--
1.6.3.3
^ permalink raw reply related
* [PATCH 4/8] gianfar: Split allocation and initialization steps out of startup_gfar()
From: Anton Vorontsov @ 2009-10-12 16:00 UTC (permalink / raw)
To: David Miller; +Cc: Scott Wood, linuxppc-dev, netdev, Andy Fleming
In-Reply-To: <20091012160000.GA32406@oksana.dev.rtsoft.ru>
Two new functions implemented: gfar_alloc_skb_resources() and
gfar_init_mac(). We'll use gfar_init_mac() for restoring after
hibernation.
The patch just moves the code around, there should be no functional
changes.
Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
---
drivers/net/gianfar.c | 334 ++++++++++++++++++++++++++-----------------------
1 files changed, 176 insertions(+), 158 deletions(-)
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index ee23431..4dcaaa7 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -147,6 +147,176 @@ MODULE_AUTHOR("Freescale Semiconductor, Inc");
MODULE_DESCRIPTION("Gianfar Ethernet Driver");
MODULE_LICENSE("GPL");
+static int gfar_alloc_skb_resources(struct net_device *ndev)
+{
+ struct txbd8 *txbdp;
+ struct rxbd8 *rxbdp;
+ dma_addr_t addr = 0;
+ void *vaddr;
+ int i;
+ struct gfar_private *priv = netdev_priv(ndev);
+ struct device *dev = &priv->ofdev->dev;
+ struct gfar __iomem *regs = priv->regs;
+
+ /* Allocate memory for the buffer descriptors */
+ vaddr = dma_alloc_coherent(dev, sizeof(*txbdp) * priv->tx_ring_size +
+ sizeof(*rxbdp) * priv->rx_ring_size,
+ &addr, GFP_KERNEL);
+ if (!vaddr) {
+ if (netif_msg_ifup(priv))
+ pr_err("%s: Could not allocate buffer descriptors!\n",
+ ndev->name);
+ return -ENOMEM;
+ }
+
+ priv->tx_bd_base = vaddr;
+
+ /* enet DMA only understands physical addresses */
+ gfar_write(®s->tbase0, addr);
+
+ /* Start the rx descriptor ring where the tx ring leaves off */
+ addr = addr + sizeof(*txbdp) * priv->tx_ring_size;
+ vaddr = vaddr + sizeof(*txbdp) * priv->tx_ring_size;
+ priv->rx_bd_base = vaddr;
+ gfar_write(®s->rbase0, addr);
+
+ /* Setup the skbuff rings */
+ priv->tx_skbuff = kmalloc(sizeof(*priv->tx_skbuff) *
+ priv->tx_ring_size, GFP_KERNEL);
+ if (!priv->tx_skbuff) {
+ if (netif_msg_ifup(priv))
+ pr_err("%s: Could not allocate tx_skbuff\n",
+ ndev->name);
+ goto cleanup;
+ }
+
+ for (i = 0; i < priv->tx_ring_size; i++)
+ priv->tx_skbuff[i] = NULL;
+
+ priv->rx_skbuff = kmalloc(sizeof(*priv->rx_skbuff) *
+ priv->rx_ring_size, GFP_KERNEL);
+ if (!priv->rx_skbuff) {
+ if (netif_msg_ifup(priv))
+ pr_err("%s: Could not allocate rx_skbuff\n",
+ ndev->name);
+ goto cleanup;
+ }
+
+ for (i = 0; i < priv->rx_ring_size; i++)
+ priv->rx_skbuff[i] = NULL;
+
+ /* Initialize some variables in our dev structure */
+ priv->num_txbdfree = priv->tx_ring_size;
+ priv->dirty_tx = priv->cur_tx = priv->tx_bd_base;
+ priv->cur_rx = priv->rx_bd_base;
+ priv->skb_curtx = priv->skb_dirtytx = 0;
+ priv->skb_currx = 0;
+
+ /* Initialize Transmit Descriptor Ring */
+ txbdp = priv->tx_bd_base;
+ for (i = 0; i < priv->tx_ring_size; i++) {
+ txbdp->lstatus = 0;
+ txbdp->bufPtr = 0;
+ txbdp++;
+ }
+
+ /* Set the last descriptor in the ring to indicate wrap */
+ txbdp--;
+ txbdp->status |= TXBD_WRAP;
+
+ rxbdp = priv->rx_bd_base;
+ for (i = 0; i < priv->rx_ring_size; i++) {
+ struct sk_buff *skb;
+
+ skb = gfar_new_skb(ndev);
+ if (!skb) {
+ pr_err("%s: Can't allocate RX buffers\n", ndev->name);
+ goto cleanup;
+ }
+
+ priv->rx_skbuff[i] = skb;
+
+ gfar_new_rxbdp(ndev, rxbdp, skb);
+
+ rxbdp++;
+ }
+
+ return 0;
+
+cleanup:
+ free_skb_resources(priv);
+ return -ENOMEM;
+}
+
+static void gfar_init_mac(struct net_device *ndev)
+{
+ struct gfar_private *priv = netdev_priv(ndev);
+ struct gfar __iomem *regs = priv->regs;
+ u32 rctrl = 0;
+ u32 tctrl = 0;
+ u32 attrs = 0;
+
+ /* Configure the coalescing support */
+ gfar_write(®s->txic, 0);
+ if (priv->txcoalescing)
+ gfar_write(®s->txic, priv->txic);
+
+ gfar_write(®s->rxic, 0);
+ if (priv->rxcoalescing)
+ gfar_write(®s->rxic, priv->rxic);
+
+ if (priv->rx_csum_enable)
+ rctrl |= RCTRL_CHECKSUMMING;
+
+ if (priv->extended_hash) {
+ rctrl |= RCTRL_EXTHASH;
+
+ gfar_clear_exact_match(ndev);
+ rctrl |= RCTRL_EMEN;
+ }
+
+ if (priv->padding) {
+ rctrl &= ~RCTRL_PAL_MASK;
+ rctrl |= RCTRL_PADDING(priv->padding);
+ }
+
+ /* keep vlan related bits if it's enabled */
+ if (priv->vlgrp) {
+ rctrl |= RCTRL_VLEX | RCTRL_PRSDEP_INIT;
+ tctrl |= TCTRL_VLINS;
+ }
+
+ /* Init rctrl based on our settings */
+ gfar_write(®s->rctrl, rctrl);
+
+ if (ndev->features & NETIF_F_IP_CSUM)
+ tctrl |= TCTRL_INIT_CSUM;
+
+ gfar_write(®s->tctrl, tctrl);
+
+ /* Set the extraction length and index */
+ attrs = ATTRELI_EL(priv->rx_stash_size) |
+ ATTRELI_EI(priv->rx_stash_index);
+
+ gfar_write(®s->attreli, attrs);
+
+ /* Start with defaults, and add stashing or locking
+ * depending on the approprate variables */
+ attrs = ATTR_INIT_SETTINGS;
+
+ if (priv->bd_stash_en)
+ attrs |= ATTR_BDSTASH;
+
+ if (priv->rx_stash_size != 0)
+ attrs |= ATTR_BUFSTASH;
+
+ gfar_write(®s->attr, attrs);
+
+ gfar_write(®s->fifo_tx_thr, priv->fifo_threshold);
+ gfar_write(®s->fifo_tx_starve, priv->fifo_starve);
+ gfar_write(®s->fifo_tx_starve_shutoff, priv->fifo_starve_off);
+}
+
static const struct net_device_ops gfar_netdev_ops = {
.ndo_open = gfar_enet_open,
.ndo_start_xmit = gfar_start_xmit,
@@ -927,106 +1097,17 @@ void gfar_start(struct net_device *dev)
/* Bring the controller up and running */
int startup_gfar(struct net_device *ndev)
{
- struct txbd8 *txbdp;
- struct rxbd8 *rxbdp;
- dma_addr_t addr = 0;
- void *vaddr;
- int i;
struct gfar_private *priv = netdev_priv(ndev);
- struct device *dev = &priv->ofdev->dev;
struct gfar __iomem *regs = priv->regs;
int err;
- u32 rctrl = 0;
- u32 tctrl = 0;
- u32 attrs = 0;
gfar_write(®s->imask, IMASK_INIT_CLEAR);
- /* Allocate memory for the buffer descriptors */
- vaddr = dma_alloc_coherent(dev, sizeof(*txbdp) * priv->tx_ring_size +
- sizeof(*rxbdp) * priv->rx_ring_size,
- &addr, GFP_KERNEL);
- if (!vaddr) {
- if (netif_msg_ifup(priv))
- pr_err("%s: Could not allocate buffer descriptors!\n",
- ndev->name);
- return -ENOMEM;
- }
-
- priv->tx_bd_base = vaddr;
-
- /* enet DMA only understands physical addresses */
- gfar_write(®s->tbase0, addr);
-
- /* Start the rx descriptor ring where the tx ring leaves off */
- addr = addr + sizeof(*txbdp) * priv->tx_ring_size;
- vaddr = vaddr + sizeof(*txbdp) * priv->tx_ring_size;
- priv->rx_bd_base = vaddr;
- gfar_write(®s->rbase0, addr);
-
- /* Setup the skbuff rings */
- priv->tx_skbuff = kmalloc(sizeof(*priv->tx_skbuff) *
- priv->tx_ring_size, GFP_KERNEL);
- if (!priv->tx_skbuff) {
- if (netif_msg_ifup(priv))
- pr_err("%s: Could not allocate tx_skbuff\n",
- ndev->name);
- err = -ENOMEM;
- goto tx_skb_fail;
- }
-
- for (i = 0; i < priv->tx_ring_size; i++)
- priv->tx_skbuff[i] = NULL;
-
- priv->rx_skbuff = kmalloc(sizeof(*priv->rx_skbuff) *
- priv->rx_ring_size, GFP_KERNEL);
- if (!priv->rx_skbuff) {
- if (netif_msg_ifup(priv))
- pr_err("%s: Could not allocate rx_skbuff\n",
- ndev->name);
- err = -ENOMEM;
- goto rx_skb_fail;
- }
-
- for (i = 0; i < priv->rx_ring_size; i++)
- priv->rx_skbuff[i] = NULL;
-
- /* Initialize some variables in our dev structure */
- priv->num_txbdfree = priv->tx_ring_size;
- priv->dirty_tx = priv->cur_tx = priv->tx_bd_base;
- priv->cur_rx = priv->rx_bd_base;
- priv->skb_curtx = priv->skb_dirtytx = 0;
- priv->skb_currx = 0;
-
- /* Initialize Transmit Descriptor Ring */
- txbdp = priv->tx_bd_base;
- for (i = 0; i < priv->tx_ring_size; i++) {
- txbdp->lstatus = 0;
- txbdp->bufPtr = 0;
- txbdp++;
- }
-
- /* Set the last descriptor in the ring to indicate wrap */
- txbdp--;
- txbdp->status |= TXBD_WRAP;
-
- rxbdp = priv->rx_bd_base;
- for (i = 0; i < priv->rx_ring_size; i++) {
- struct sk_buff *skb;
-
- skb = gfar_new_skb(ndev);
- if (!skb) {
- pr_err("%s: Can't allocate RX buffers\n", ndev->name);
- err = -ENOMEM;
- goto err_rxalloc_fail;
- }
-
- priv->rx_skbuff[i] = skb;
-
- gfar_new_rxbdp(ndev, rxbdp, skb);
+ err = gfar_alloc_skb_resources(ndev);
+ if (err)
+ return err;
- rxbdp++;
- }
+ gfar_init_mac(ndev);
/* If the device has multiple interrupts, register for
* them. Otherwise, only register for the one */
@@ -1070,71 +1151,11 @@ int startup_gfar(struct net_device *ndev)
}
}
- phy_start(priv->phydev);
-
- /* Configure the coalescing support */
- gfar_write(®s->txic, 0);
- if (priv->txcoalescing)
- gfar_write(®s->txic, priv->txic);
-
- gfar_write(®s->rxic, 0);
- if (priv->rxcoalescing)
- gfar_write(®s->rxic, priv->rxic);
-
- if (priv->rx_csum_enable)
- rctrl |= RCTRL_CHECKSUMMING;
-
- if (priv->extended_hash) {
- rctrl |= RCTRL_EXTHASH;
-
- gfar_clear_exact_match(ndev);
- rctrl |= RCTRL_EMEN;
- }
-
- if (priv->padding) {
- rctrl &= ~RCTRL_PAL_MASK;
- rctrl |= RCTRL_PADDING(priv->padding);
- }
-
- /* keep vlan related bits if it's enabled */
- if (priv->vlgrp) {
- rctrl |= RCTRL_VLEX | RCTRL_PRSDEP_INIT;
- tctrl |= TCTRL_VLINS;
- }
-
- /* Init rctrl based on our settings */
- gfar_write(®s->rctrl, rctrl);
-
- if (ndev->features & NETIF_F_IP_CSUM)
- tctrl |= TCTRL_INIT_CSUM;
-
- gfar_write(®s->tctrl, tctrl);
-
- /* Set the extraction length and index */
- attrs = ATTRELI_EL(priv->rx_stash_size) |
- ATTRELI_EI(priv->rx_stash_index);
-
- gfar_write(®s->attreli, attrs);
-
- /* Start with defaults, and add stashing or locking
- * depending on the approprate variables */
- attrs = ATTR_INIT_SETTINGS;
-
- if (priv->bd_stash_en)
- attrs |= ATTR_BDSTASH;
-
- if (priv->rx_stash_size != 0)
- attrs |= ATTR_BUFSTASH;
-
- gfar_write(®s->attr, attrs);
-
- gfar_write(®s->fifo_tx_thr, priv->fifo_threshold);
- gfar_write(®s->fifo_tx_starve, priv->fifo_starve);
- gfar_write(®s->fifo_tx_starve_shutoff, priv->fifo_starve_off);
-
/* Start the controller */
gfar_start(ndev);
+ phy_start(priv->phydev);
+
return 0;
rx_irq_fail:
@@ -1142,9 +1163,6 @@ rx_irq_fail:
tx_irq_fail:
free_irq(priv->interruptError, ndev);
err_irq_fail:
-err_rxalloc_fail:
-rx_skb_fail:
-tx_skb_fail:
free_skb_resources(priv);
return err;
}
--
1.6.3.3
^ permalink raw reply related
* [PATCH 5/8] gianfar: Move tbase/rbase initialization to gfar_init_mac()
From: Anton Vorontsov @ 2009-10-12 16:00 UTC (permalink / raw)
To: David Miller; +Cc: Scott Wood, linuxppc-dev, netdev, Andy Fleming
In-Reply-To: <20091012160000.GA32406@oksana.dev.rtsoft.ru>
For hibernation we want to call gfar_init_mac() without need to
free/allocate_skb_resources sequence, so save the DMA address into a
private struct, and move tbase/rbase initialization to gfar_init_mac().
Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
---
drivers/net/gianfar.c | 17 ++++++++---------
drivers/net/gianfar.h | 1 +
2 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 4dcaaa7..46b0b37 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -151,17 +151,15 @@ static int gfar_alloc_skb_resources(struct net_device *ndev)
{
struct txbd8 *txbdp;
struct rxbd8 *rxbdp;
- dma_addr_t addr = 0;
void *vaddr;
int i;
struct gfar_private *priv = netdev_priv(ndev);
struct device *dev = &priv->ofdev->dev;
- struct gfar __iomem *regs = priv->regs;
/* Allocate memory for the buffer descriptors */
vaddr = dma_alloc_coherent(dev, sizeof(*txbdp) * priv->tx_ring_size +
sizeof(*rxbdp) * priv->rx_ring_size,
- &addr, GFP_KERNEL);
+ &priv->tx_bd_dma_base, GFP_KERNEL);
if (!vaddr) {
if (netif_msg_ifup(priv))
pr_err("%s: Could not allocate buffer descriptors!\n",
@@ -171,14 +169,9 @@ static int gfar_alloc_skb_resources(struct net_device *ndev)
priv->tx_bd_base = vaddr;
- /* enet DMA only understands physical addresses */
- gfar_write(®s->tbase0, addr);
-
/* Start the rx descriptor ring where the tx ring leaves off */
- addr = addr + sizeof(*txbdp) * priv->tx_ring_size;
vaddr = vaddr + sizeof(*txbdp) * priv->tx_ring_size;
priv->rx_bd_base = vaddr;
- gfar_write(®s->rbase0, addr);
/* Setup the skbuff rings */
priv->tx_skbuff = kmalloc(sizeof(*priv->tx_skbuff) *
@@ -256,6 +249,12 @@ static void gfar_init_mac(struct net_device *ndev)
u32 tctrl = 0;
u32 attrs = 0;
+ /* enet DMA only understands physical addresses */
+ gfar_write(®s->tbase0, priv->tx_bd_dma_base);
+ gfar_write(®s->rbase0, priv->tx_bd_dma_base +
+ sizeof(*priv->tx_bd_base) *
+ priv->tx_ring_size);
+
/* Configure the coalescing support */
gfar_write(®s->txic, 0);
if (priv->txcoalescing)
@@ -1060,7 +1059,7 @@ skip_rx_skbuff:
dma_free_coherent(dev, sizeof(*txbdp) * priv->tx_ring_size +
sizeof(*rxbdp) * priv->rx_ring_size,
- priv->tx_bd_base, gfar_read(&priv->regs->tbase0));
+ priv->tx_bd_base, priv->tx_bd_dma_base);
}
void gfar_start(struct net_device *dev)
diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h
index 2cd9433..05732fa 100644
--- a/drivers/net/gianfar.h
+++ b/drivers/net/gianfar.h
@@ -726,6 +726,7 @@ struct gfar_private {
unsigned long txic;
/* Buffer descriptor pointers */
+ dma_addr_t tx_bd_dma_base;
struct txbd8 *tx_bd_base; /* First tx buffer descriptor */
struct txbd8 *cur_tx; /* Next free ring entry */
struct txbd8 *dirty_tx; /* First buffer in line
--
1.6.3.3
^ permalink raw reply related
* [PATCH 6/8] gianfar: Factor out RX BDs initialization from gfar_new_rxbdp()
From: Anton Vorontsov @ 2009-10-12 16:00 UTC (permalink / raw)
To: David Miller; +Cc: Scott Wood, linuxppc-dev, netdev, Andy Fleming
In-Reply-To: <20091012160000.GA32406@oksana.dev.rtsoft.ru>
We want to just reinitialize RX BDs after hibernation, no need to
map the skb->data again. So let's factor gfar_init_rxbdp() out of
gfar_new_rxbdp().
Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
---
drivers/net/gianfar.c | 33 +++++++++++++++++++++------------
1 files changed, 21 insertions(+), 12 deletions(-)
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 46b0b37..1b32274 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -147,6 +147,23 @@ MODULE_AUTHOR("Freescale Semiconductor, Inc");
MODULE_DESCRIPTION("Gianfar Ethernet Driver");
MODULE_LICENSE("GPL");
+static void gfar_init_rxbdp(struct net_device *dev, struct rxbd8 *bdp,
+ dma_addr_t buf)
+{
+ struct gfar_private *priv = netdev_priv(dev);
+ u32 lstatus;
+
+ bdp->bufPtr = buf;
+
+ lstatus = BD_LFLAG(RXBD_EMPTY | RXBD_INTERRUPT);
+ if (bdp == priv->rx_bd_base + priv->rx_ring_size - 1)
+ lstatus |= BD_LFLAG(RXBD_WRAP);
+
+ eieio();
+
+ bdp->lstatus = lstatus;
+}
+
static int gfar_alloc_skb_resources(struct net_device *ndev)
{
struct txbd8 *txbdp;
@@ -1676,19 +1693,11 @@ static void gfar_new_rxbdp(struct net_device *dev, struct rxbd8 *bdp,
struct sk_buff *skb)
{
struct gfar_private *priv = netdev_priv(dev);
- u32 lstatus;
-
- bdp->bufPtr = dma_map_single(&priv->ofdev->dev, skb->data,
- priv->rx_buffer_size, DMA_FROM_DEVICE);
-
- lstatus = BD_LFLAG(RXBD_EMPTY | RXBD_INTERRUPT);
+ dma_addr_t buf;
- if (bdp == priv->rx_bd_base + priv->rx_ring_size - 1)
- lstatus |= BD_LFLAG(RXBD_WRAP);
-
- eieio();
-
- bdp->lstatus = lstatus;
+ buf = dma_map_single(&priv->ofdev->dev, skb->data,
+ priv->rx_buffer_size, DMA_FROM_DEVICE);
+ gfar_init_rxbdp(dev, bdp, buf);
}
--
1.6.3.3
^ permalink raw reply related
* [PATCH 7/8] gianfar: Factor out gfar_init_bds() from gfar_alloc_skb_resources()
From: Anton Vorontsov @ 2009-10-12 16:00 UTC (permalink / raw)
To: David Miller; +Cc: Scott Wood, linuxppc-dev, netdev, Andy Fleming
In-Reply-To: <20091012160000.GA32406@oksana.dev.rtsoft.ru>
After hibernation we want to just reinitialize BDs, no need to allocate
anything. So, factor out BDs initialization code from
gfar_alloc_skb_resourses().
Also, teach gfar_init_bds() to reuse already allocated RX SKBs, i.e.
just call gfar_init_rxbdp() if a SKB was already allocated and mapped.
Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
---
drivers/net/gianfar.c | 96 ++++++++++++++++++++++++++++--------------------
1 files changed, 56 insertions(+), 40 deletions(-)
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 1b32274..634a15b 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -164,19 +164,68 @@ static void gfar_init_rxbdp(struct net_device *dev, struct rxbd8 *bdp,
bdp->lstatus = lstatus;
}
-static int gfar_alloc_skb_resources(struct net_device *ndev)
+static int gfar_init_bds(struct net_device *ndev)
{
+ struct gfar_private *priv = netdev_priv(ndev);
struct txbd8 *txbdp;
struct rxbd8 *rxbdp;
+ int i;
+
+ /* Initialize some variables in our dev structure */
+ priv->num_txbdfree = priv->tx_ring_size;
+ priv->dirty_tx = priv->cur_tx = priv->tx_bd_base;
+ priv->cur_rx = priv->rx_bd_base;
+ priv->skb_curtx = priv->skb_dirtytx = 0;
+ priv->skb_currx = 0;
+
+ /* Initialize Transmit Descriptor Ring */
+ txbdp = priv->tx_bd_base;
+ for (i = 0; i < priv->tx_ring_size; i++) {
+ txbdp->lstatus = 0;
+ txbdp->bufPtr = 0;
+ txbdp++;
+ }
+
+ /* Set the last descriptor in the ring to indicate wrap */
+ txbdp--;
+ txbdp->status |= TXBD_WRAP;
+
+ rxbdp = priv->rx_bd_base;
+ for (i = 0; i < priv->rx_ring_size; i++) {
+ struct sk_buff *skb = priv->rx_skbuff[i];
+
+ if (skb) {
+ gfar_init_rxbdp(ndev, rxbdp, rxbdp->bufPtr);
+ } else {
+ skb = gfar_new_skb(ndev);
+ if (!skb) {
+ pr_err("%s: Can't allocate RX buffers\n",
+ ndev->name);
+ return -ENOMEM;
+ }
+ priv->rx_skbuff[i] = skb;
+
+ gfar_new_rxbdp(ndev, rxbdp, skb);
+ }
+
+ rxbdp++;
+ }
+
+ return 0;
+}
+
+static int gfar_alloc_skb_resources(struct net_device *ndev)
+{
void *vaddr;
int i;
struct gfar_private *priv = netdev_priv(ndev);
struct device *dev = &priv->ofdev->dev;
/* Allocate memory for the buffer descriptors */
- vaddr = dma_alloc_coherent(dev, sizeof(*txbdp) * priv->tx_ring_size +
- sizeof(*rxbdp) * priv->rx_ring_size,
- &priv->tx_bd_dma_base, GFP_KERNEL);
+ vaddr = dma_alloc_coherent(dev,
+ sizeof(*priv->tx_bd_base) * priv->tx_ring_size +
+ sizeof(*priv->rx_bd_base) * priv->rx_ring_size,
+ &priv->tx_bd_dma_base, GFP_KERNEL);
if (!vaddr) {
if (netif_msg_ifup(priv))
pr_err("%s: Could not allocate buffer descriptors!\n",
@@ -187,7 +236,7 @@ static int gfar_alloc_skb_resources(struct net_device *ndev)
priv->tx_bd_base = vaddr;
/* Start the rx descriptor ring where the tx ring leaves off */
- vaddr = vaddr + sizeof(*txbdp) * priv->tx_ring_size;
+ vaddr = vaddr + sizeof(*priv->tx_bd_base) * priv->tx_ring_size;
priv->rx_bd_base = vaddr;
/* Setup the skbuff rings */
@@ -215,41 +264,8 @@ static int gfar_alloc_skb_resources(struct net_device *ndev)
for (i = 0; i < priv->rx_ring_size; i++)
priv->rx_skbuff[i] = NULL;
- /* Initialize some variables in our dev structure */
- priv->num_txbdfree = priv->tx_ring_size;
- priv->dirty_tx = priv->cur_tx = priv->tx_bd_base;
- priv->cur_rx = priv->rx_bd_base;
- priv->skb_curtx = priv->skb_dirtytx = 0;
- priv->skb_currx = 0;
-
- /* Initialize Transmit Descriptor Ring */
- txbdp = priv->tx_bd_base;
- for (i = 0; i < priv->tx_ring_size; i++) {
- txbdp->lstatus = 0;
- txbdp->bufPtr = 0;
- txbdp++;
- }
-
- /* Set the last descriptor in the ring to indicate wrap */
- txbdp--;
- txbdp->status |= TXBD_WRAP;
-
- rxbdp = priv->rx_bd_base;
- for (i = 0; i < priv->rx_ring_size; i++) {
- struct sk_buff *skb;
-
- skb = gfar_new_skb(ndev);
- if (!skb) {
- pr_err("%s: Can't allocate RX buffers\n", ndev->name);
- goto cleanup;
- }
-
- priv->rx_skbuff[i] = skb;
-
- gfar_new_rxbdp(ndev, rxbdp, skb);
-
- rxbdp++;
- }
+ if (gfar_init_bds(ndev))
+ goto cleanup;
return 0;
--
1.6.3.3
^ permalink raw reply related
* [PATCH 8/8] gianfar: Add support for hibernation
From: Anton Vorontsov @ 2009-10-12 16:00 UTC (permalink / raw)
To: David Miller; +Cc: Scott Wood, linuxppc-dev, netdev, Andy Fleming
In-Reply-To: <20091012160000.GA32406@oksana.dev.rtsoft.ru>
Thanks to various cleanups and refactorings this is now straightforward:
convert the gianfar driver to dev_pm_ops, plus add ->restore() callback
that will fully reinitialize MAC internal registers and BDs.
Note that I kept legacy suspend/resume callbacks so that this patch
doesn't depend on PowerPC changes (i.e. dev_pm_ops support for OF
platform drivers).
Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
---
drivers/net/gianfar.c | 87 +++++++++++++++++++++++++++++++++++++++---------
1 files changed, 70 insertions(+), 17 deletions(-)
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 634a15b..f714186 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -700,23 +700,24 @@ static int gfar_remove(struct of_device *ofdev)
}
#ifdef CONFIG_PM
-static int gfar_suspend(struct of_device *ofdev, pm_message_t state)
+
+static int gfar_suspend(struct device *dev)
{
- struct gfar_private *priv = dev_get_drvdata(&ofdev->dev);
- struct net_device *dev = priv->ndev;
+ struct gfar_private *priv = dev_get_drvdata(dev);
+ struct net_device *ndev = priv->ndev;
unsigned long flags;
u32 tempval;
int magic_packet = priv->wol_en &&
(priv->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET);
- netif_device_detach(dev);
+ netif_device_detach(ndev);
- if (netif_running(dev)) {
+ if (netif_running(ndev)) {
spin_lock_irqsave(&priv->txlock, flags);
spin_lock(&priv->rxlock);
- gfar_halt_nodisable(dev);
+ gfar_halt_nodisable(ndev);
/* Disable Tx, and Rx if wake-on-LAN is disabled. */
tempval = gfar_read(&priv->regs->maccfg1);
@@ -749,17 +750,17 @@ static int gfar_suspend(struct of_device *ofdev, pm_message_t state)
return 0;
}
-static int gfar_resume(struct of_device *ofdev)
+static int gfar_resume(struct device *dev)
{
- struct gfar_private *priv = dev_get_drvdata(&ofdev->dev);
- struct net_device *dev = priv->ndev;
+ struct gfar_private *priv = dev_get_drvdata(dev);
+ struct net_device *ndev = priv->ndev;
unsigned long flags;
u32 tempval;
int magic_packet = priv->wol_en &&
(priv->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET);
- if (!netif_running(dev)) {
- netif_device_attach(dev);
+ if (!netif_running(ndev)) {
+ netif_device_attach(ndev);
return 0;
}
@@ -777,20 +778,71 @@ static int gfar_resume(struct of_device *ofdev)
tempval &= ~MACCFG2_MPEN;
gfar_write(&priv->regs->maccfg2, tempval);
- gfar_start(dev);
+ gfar_start(ndev);
spin_unlock(&priv->rxlock);
spin_unlock_irqrestore(&priv->txlock, flags);
- netif_device_attach(dev);
+ netif_device_attach(ndev);
+
+ napi_enable(&priv->napi);
+
+ return 0;
+}
+
+static int gfar_restore(struct device *dev)
+{
+ struct gfar_private *priv = dev_get_drvdata(dev);
+ struct net_device *ndev = priv->ndev;
+
+ if (!netif_running(ndev))
+ return 0;
+
+ gfar_init_bds(ndev);
+ init_registers(ndev);
+ gfar_set_mac_address(ndev);
+ gfar_init_mac(ndev);
+ gfar_start(ndev);
+
+ priv->oldlink = 0;
+ priv->oldspeed = 0;
+ priv->oldduplex = -1;
+
+ if (priv->phydev)
+ phy_start(priv->phydev);
+ netif_device_attach(ndev);
napi_enable(&priv->napi);
return 0;
}
+
+static struct dev_pm_ops gfar_pm_ops = {
+ .suspend = gfar_suspend,
+ .resume = gfar_resume,
+ .freeze = gfar_suspend,
+ .thaw = gfar_resume,
+ .restore = gfar_restore,
+};
+
+#define GFAR_PM_OPS (&gfar_pm_ops)
+
+static int gfar_legacy_suspend(struct of_device *ofdev, pm_message_t state)
+{
+ return gfar_suspend(&ofdev->dev);
+}
+
+static int gfar_legacy_resume(struct of_device *ofdev)
+{
+ return gfar_resume(&ofdev->dev);
+}
+
#else
-#define gfar_suspend NULL
-#define gfar_resume NULL
+
+#define GFAR_PM_OPS NULL
+#define gfar_legacy_suspend NULL
+#define gfar_legacy_resume NULL
+
#endif
/* Reads the controller's registers to determine what interface
@@ -2362,8 +2414,9 @@ static struct of_platform_driver gfar_driver = {
.probe = gfar_probe,
.remove = gfar_remove,
- .suspend = gfar_suspend,
- .resume = gfar_resume,
+ .suspend = gfar_legacy_suspend,
+ .resume = gfar_legacy_resume,
+ .driver.pm = GFAR_PM_OPS,
};
static int __init gfar_init(void)
--
1.6.3.3
^ permalink raw reply related
* Re: Occasional crashes with sky2
From: Stephen Hemminger @ 2009-10-12 16:11 UTC (permalink / raw)
To: Bernd Schmidt; +Cc: netdev
In-Reply-To: <4AD1F1F2.4060001@t-online.de>
On Sun, 11 Oct 2009 15:55:46 +0100
Bernd Schmidt <bernds_cb1@t-online.de> wrote:
> For a few months now, I've been seeing occasional kernel panics that
> would happen every few weeks. I'm not exactly sure when they started,
> but I definitely see them in 2.6.29 and 2.6.30, and never saw them in
> 2.6.25 and earlier. They happen with 32 bit and 64 bit kernels.
>
> Today I managed to capture an oops with netconsole; it's attached. This
> seems to point towards the sky2 driver.
>
Since you are using tained(nvidia) driver, I really hate to go do indepth
fixing it. And like Mike said 2.6.26 is over a year old by now.
--
^ permalink raw reply
* Re: [PATCH 2/3] sky2: Reading registers in reset causes a hang
From: Stephen Hemminger @ 2009-10-12 16:14 UTC (permalink / raw)
To: Mike McCormack; +Cc: netdev
In-Reply-To: <4AD337ED.4090409@ring3k.org>
On Mon, 12 Oct 2009 23:06:37 +0900
Mike McCormack <mikem@ring3k.org> wrote:
> When sky2 hardware is in reset, reading registers with ethtool -d
> causes a hard system hang. eg.
>
> ifconfig eth1 down
> ethtool -d eth1
>
> Avoid reading FIFOs, descriptor and status unit, etc. after we've
> bought the interface down, as these seem to cause the issue.
>
> Assume the same is true for the second port, as my port only has
> one card.
I don't see this on my cards. Let me investigate further before
committing this. Also, the debugfs interface would also be screwed
if the registers were unavailable.
^ permalink raw reply
* Re: PATCH: Network Device Naming mechanism and policy
From: Bryan Kadzban @ 2009-10-12 16:19 UTC (permalink / raw)
To: Greg KH
Cc: Matt Domsch, Stephen Hemminger, netdev, linux-hotplug, Narendra_K,
jordan_hargrave
In-Reply-To: <4AD2CAD8.2040903@kadzban.is-a-geek.net>
[-- Attachment #1: Type: text/plain, Size: 788 bytes --]
Bryan Kadzban wrote:
> (Now, if open() would return effectively a netlink socket bound to
> that ifindex already, such that the program didn't need to fill in
> the various ifindex fields for e.g. rtnetlink... but it's probably
> really hard to do that, so this isn't a serious suggestion.)
Wait, scratch that. It's not "really hard", it's "almost impossible".
At open() time, you have no idea which netlink family the program wants
to communicate with. bind() is also hard. (In theory, you could
support bind() on this new FD -- but then why is userspace using a file
in the first place, and not a socket?)
So this is even less of a serious suggestion now.
I'd still like to be able to refer to NICs by multiple names though, if
we can find a way that works...
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 260 bytes --]
^ permalink raw reply
* [PATCH 1/1] net: Introduce recvmmsg socket syscall
From: Arnaldo Carvalho de Melo @ 2009-10-12 16:20 UTC (permalink / raw)
To: David Miller
Cc: netdev, Arnaldo Carvalho de Melo, Caitlin Bestler, Chris Van Hoof,
Clark Williams, Neil Horman, Nir Tzachar, Nivedita Singhvi,
Paul Moore, Rémi Denis-Courmont, Steven Whitehouse
Meaning receive multiple messages, reducing the number of syscalls and
net stack entry/exit operations.
Next patches will introduce mechanisms where protocols that want to
optimize this operation will provide an unlocked_recvmsg operation.
This takes into account comments made by:
. Paul Moore: sock_recvmsg is called only for the first datagram,
sock_recvmsg_nosec is used for the rest.
. Caitlin Bestler: recvmmsg now has a struct timespec timeout, that
works in the same fashion as the ppoll one.
If the underlying protocol returns a datagram with MSG_OOB set, this
will make recvmmsg return right away with as many datagrams (+ the OOB
one) it has received so far.
. Rémi Denis-Courmont & Steven Whitehouse: If we receive N < vlen
datagrams and then recvmsg returns an error, recvmmsg will return
the successfully received datagrams, store the error and return it
in the next call.
This paves the way for a subsequent optimization, sk_prot->unlocked_recvmsg,
where we will be able to acquire the lock only at batch start and end, not at
every underlying recvmsg call.
Cc: Caitlin Bestler <caitlin.bestler@gmail.com>
Cc: Chris Van Hoof <vanhoof@redhat.com>
Cc: Clark Williams <williams@redhat.com>
Cc: Neil Horman <nhorman@tuxdriver.com>
Cc: Nir Tzachar <nir.tzachar@gmail.com>
Cc: Nivedita Singhvi <niv@us.ibm.com>
Cc: Paul Moore <paul.moore@hp.com>
Cc: Rémi Denis-Courmont <remi.denis-courmont@nokia.com>
Cc: Steven Whitehouse <steve@chygwyn.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
arch/alpha/kernel/systbls.S | 1 +
arch/arm/kernel/calls.S | 1 +
arch/avr32/kernel/syscall_table.S | 1 +
arch/blackfin/mach-common/entry.S | 1 +
arch/ia64/kernel/entry.S | 1 +
arch/microblaze/kernel/syscall_table.S | 1 +
arch/mips/kernel/scall32-o32.S | 1 +
arch/mips/kernel/scall64-64.S | 1 +
arch/mips/kernel/scall64-n32.S | 1 +
arch/mips/kernel/scall64-o32.S | 1 +
arch/sh/kernel/syscalls_64.S | 1 +
arch/sparc/kernel/systbls_64.S | 4 +-
arch/x86/ia32/ia32entry.S | 1 +
arch/x86/include/asm/unistd_32.h | 3 +-
arch/x86/include/asm/unistd_64.h | 2 +
arch/x86/kernel/syscall_table_32.S | 1 +
arch/xtensa/include/asm/unistd.h | 4 +-
include/linux/net.h | 1 +
include/linux/socket.h | 10 ++
include/linux/syscalls.h | 4 +
include/net/compat.h | 8 +
kernel/sys_ni.c | 2 +
net/compat.c | 33 +++++-
net/socket.c | 225 ++++++++++++++++++++++++++------
24 files changed, 260 insertions(+), 49 deletions(-)
diff --git a/arch/alpha/kernel/systbls.S b/arch/alpha/kernel/systbls.S
index 95c9aef..cda6b8b 100644
--- a/arch/alpha/kernel/systbls.S
+++ b/arch/alpha/kernel/systbls.S
@@ -497,6 +497,7 @@ sys_call_table:
.quad sys_signalfd
.quad sys_ni_syscall
.quad sys_eventfd
+ .quad sys_recvmmsg
.size sys_call_table, . - sys_call_table
.type sys_call_table, @object
diff --git a/arch/arm/kernel/calls.S b/arch/arm/kernel/calls.S
index fafce1b..f58c115 100644
--- a/arch/arm/kernel/calls.S
+++ b/arch/arm/kernel/calls.S
@@ -374,6 +374,7 @@
CALL(sys_pwritev)
CALL(sys_rt_tgsigqueueinfo)
CALL(sys_perf_event_open)
+/* 365 */ CALL(sys_recvmmsg)
#ifndef syscalls_counted
.equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls
#define syscalls_counted
diff --git a/arch/avr32/kernel/syscall_table.S b/arch/avr32/kernel/syscall_table.S
index 7ee0057..e76bad1 100644
--- a/arch/avr32/kernel/syscall_table.S
+++ b/arch/avr32/kernel/syscall_table.S
@@ -295,4 +295,5 @@ sys_call_table:
.long sys_signalfd
.long sys_ni_syscall /* 280, was sys_timerfd */
.long sys_eventfd
+ .long sys_recvmmsg
.long sys_ni_syscall /* r8 is saturated at nr_syscalls */
diff --git a/arch/blackfin/mach-common/entry.S b/arch/blackfin/mach-common/entry.S
index 1e7cac2..4869272 100644
--- a/arch/blackfin/mach-common/entry.S
+++ b/arch/blackfin/mach-common/entry.S
@@ -1621,6 +1621,7 @@ ENTRY(_sys_call_table)
.long _sys_pwritev
.long _sys_rt_tgsigqueueinfo
.long _sys_perf_event_open
+ .long _sys_recvmmsg /* 370 */
.rept NR_syscalls-(.-_sys_call_table)/4
.long _sys_ni_syscall
diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S
index d0e7d37..d75b872 100644
--- a/arch/ia64/kernel/entry.S
+++ b/arch/ia64/kernel/entry.S
@@ -1806,6 +1806,7 @@ sys_call_table:
data8 sys_preadv
data8 sys_pwritev // 1320
data8 sys_rt_tgsigqueueinfo
+ data8 sys_recvmmsg
.org sys_call_table + 8*NR_syscalls // guard against failures to increase NR_syscalls
#endif /* __IA64_ASM_PARAVIRTUALIZED_NATIVE */
diff --git a/arch/microblaze/kernel/syscall_table.S b/arch/microblaze/kernel/syscall_table.S
index ecec191..c1ab1dc 100644
--- a/arch/microblaze/kernel/syscall_table.S
+++ b/arch/microblaze/kernel/syscall_table.S
@@ -371,3 +371,4 @@ ENTRY(sys_call_table)
.long sys_ni_syscall
.long sys_rt_tgsigqueueinfo /* 365 */
.long sys_perf_event_open
+ .long sys_recvmmsg
diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S
index fd2a9bb..17202bb 100644
--- a/arch/mips/kernel/scall32-o32.S
+++ b/arch/mips/kernel/scall32-o32.S
@@ -583,6 +583,7 @@ einval: li v0, -ENOSYS
sys sys_rt_tgsigqueueinfo 4
sys sys_perf_event_open 5
sys sys_accept4 4
+ sys sys_recvmmsg 5
.endm
/* We pre-compute the number of _instruction_ bytes needed to
diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S
index 18bf7f3..a8a6c59 100644
--- a/arch/mips/kernel/scall64-64.S
+++ b/arch/mips/kernel/scall64-64.S
@@ -420,4 +420,5 @@ sys_call_table:
PTR sys_rt_tgsigqueueinfo
PTR sys_perf_event_open
PTR sys_accept4
+ PTR sys_recvmmsg
.size sys_call_table,.-sys_call_table
diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S
index 6ebc079..5154e64 100644
--- a/arch/mips/kernel/scall64-n32.S
+++ b/arch/mips/kernel/scall64-n32.S
@@ -418,4 +418,5 @@ EXPORT(sysn32_call_table)
PTR compat_sys_rt_tgsigqueueinfo /* 5295 */
PTR sys_perf_event_open
PTR sys_accept4
+ PTR compat_sys_recvmmsg
.size sysn32_call_table,.-sysn32_call_table
diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S
index 9bbf977..d0eff53 100644
--- a/arch/mips/kernel/scall64-o32.S
+++ b/arch/mips/kernel/scall64-o32.S
@@ -538,4 +538,5 @@ sys_call_table:
PTR compat_sys_rt_tgsigqueueinfo
PTR sys_perf_event_open
PTR sys_accept4
+ PTR compat_sys_recvmmsg
.size sys_call_table,.-sys_call_table
diff --git a/arch/sh/kernel/syscalls_64.S b/arch/sh/kernel/syscalls_64.S
index 5bfde6c..07d2aae 100644
--- a/arch/sh/kernel/syscalls_64.S
+++ b/arch/sh/kernel/syscalls_64.S
@@ -391,3 +391,4 @@ sys_call_table:
.long sys_pwritev
.long sys_rt_tgsigqueueinfo
.long sys_perf_event_open
+ .long sys_recvmmsg /* 365 */
diff --git a/arch/sparc/kernel/systbls_64.S b/arch/sparc/kernel/systbls_64.S
index 009825f..f37bef7 100644
--- a/arch/sparc/kernel/systbls_64.S
+++ b/arch/sparc/kernel/systbls_64.S
@@ -83,7 +83,7 @@ sys_call_table32:
/*310*/ .word compat_sys_utimensat, compat_sys_signalfd, sys_timerfd_create, sys_eventfd, compat_sys_fallocate
.word compat_sys_timerfd_settime, compat_sys_timerfd_gettime, compat_sys_signalfd4, sys_eventfd2, sys_epoll_create1
/*320*/ .word sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, compat_sys_preadv
- .word compat_sys_pwritev, compat_sys_rt_tgsigqueueinfo, sys_perf_event_open
+ .word compat_sys_pwritev, compat_sys_rt_tgsigqueueinfo, sys_perf_event_open, compat_sys_recvmmsg
#endif /* CONFIG_COMPAT */
@@ -158,4 +158,4 @@ sys_call_table:
/*310*/ .word sys_utimensat, sys_signalfd, sys_timerfd_create, sys_eventfd, sys_fallocate
.word sys_timerfd_settime, sys_timerfd_gettime, sys_signalfd4, sys_eventfd2, sys_epoll_create1
/*320*/ .word sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, sys_preadv
- .word sys_pwritev, sys_rt_tgsigqueueinfo, sys_perf_event_open
+ .word sys_pwritev, sys_rt_tgsigqueueinfo, sys_perf_event_open, sys_recvmmsg
diff --git a/arch/x86/ia32/ia32entry.S b/arch/x86/ia32/ia32entry.S
index 74619c4..11a6c79 100644
--- a/arch/x86/ia32/ia32entry.S
+++ b/arch/x86/ia32/ia32entry.S
@@ -832,4 +832,5 @@ ia32_sys_call_table:
.quad compat_sys_pwritev
.quad compat_sys_rt_tgsigqueueinfo /* 335 */
.quad sys_perf_event_open
+ .quad compat_sys_recvmmsg
ia32_syscall_end:
diff --git a/arch/x86/include/asm/unistd_32.h b/arch/x86/include/asm/unistd_32.h
index 6fb3c20..3baf379 100644
--- a/arch/x86/include/asm/unistd_32.h
+++ b/arch/x86/include/asm/unistd_32.h
@@ -342,10 +342,11 @@
#define __NR_pwritev 334
#define __NR_rt_tgsigqueueinfo 335
#define __NR_perf_event_open 336
+#define __NR_recvmmsg 337
#ifdef __KERNEL__
-#define NR_syscalls 337
+#define NR_syscalls 338
#define __ARCH_WANT_IPC_PARSE_VERSION
#define __ARCH_WANT_OLD_READDIR
diff --git a/arch/x86/include/asm/unistd_64.h b/arch/x86/include/asm/unistd_64.h
index 8d3ad0a..4843f7b 100644
--- a/arch/x86/include/asm/unistd_64.h
+++ b/arch/x86/include/asm/unistd_64.h
@@ -661,6 +661,8 @@ __SYSCALL(__NR_pwritev, sys_pwritev)
__SYSCALL(__NR_rt_tgsigqueueinfo, sys_rt_tgsigqueueinfo)
#define __NR_perf_event_open 298
__SYSCALL(__NR_perf_event_open, sys_perf_event_open)
+#define __NR_recvmmsg 299
+__SYSCALL(__NR_recvmmsg, sys_recvmmsg)
#ifndef __NO_STUBS
#define __ARCH_WANT_OLD_READDIR
diff --git a/arch/x86/kernel/syscall_table_32.S b/arch/x86/kernel/syscall_table_32.S
index 0157cd2..70c2125 100644
--- a/arch/x86/kernel/syscall_table_32.S
+++ b/arch/x86/kernel/syscall_table_32.S
@@ -336,3 +336,4 @@ ENTRY(sys_call_table)
.long sys_pwritev
.long sys_rt_tgsigqueueinfo /* 335 */
.long sys_perf_event_open
+ .long sys_recvmmsg
diff --git a/arch/xtensa/include/asm/unistd.h b/arch/xtensa/include/asm/unistd.h
index c092c8f..4e55dc7 100644
--- a/arch/xtensa/include/asm/unistd.h
+++ b/arch/xtensa/include/asm/unistd.h
@@ -681,8 +681,10 @@ __SYSCALL(304, sys_signalfd, 3)
__SYSCALL(305, sys_ni_syscall, 0)
#define __NR_eventfd 306
__SYSCALL(306, sys_eventfd, 1)
+#define __NR_recvmmsg 307
+__SYSCALL(307, sys_recvmmsg, 5)
-#define __NR_syscall_count 307
+#define __NR_syscall_count 308
/*
* sysxtensa syscall handler
diff --git a/include/linux/net.h b/include/linux/net.h
index 529a093..b42bb60 100644
--- a/include/linux/net.h
+++ b/include/linux/net.h
@@ -41,6 +41,7 @@
#define SYS_SENDMSG 16 /* sys_sendmsg(2) */
#define SYS_RECVMSG 17 /* sys_recvmsg(2) */
#define SYS_ACCEPT4 18 /* sys_accept4(2) */
+#define SYS_RECVMMSG 19 /* sys_recvmmsg(2) */
typedef enum {
SS_FREE = 0, /* not allocated */
diff --git a/include/linux/socket.h b/include/linux/socket.h
index 3273a0c..59966f1 100644
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -65,6 +65,12 @@ struct msghdr {
unsigned msg_flags;
};
+/* For recvmmsg/sendmmsg */
+struct mmsghdr {
+ struct msghdr msg_hdr;
+ unsigned msg_len;
+};
+
/*
* POSIX 1003.1g - ancillary data object information
* Ancillary data consits of a sequence of pairs of
@@ -312,6 +318,10 @@ extern int move_addr_to_user(struct sockaddr *kaddr, int klen, void __user *uadd
extern int move_addr_to_kernel(void __user *uaddr, int ulen, struct sockaddr *kaddr);
extern int put_cmsg(struct msghdr*, int level, int type, int len, void *data);
+struct timespec;
+
+extern int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
+ unsigned int flags, struct timespec *timeout);
#endif
#endif /* not kernel and not glibc */
#endif /* _LINUX_SOCKET_H */
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index a990ace..714f063 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -25,6 +25,7 @@ struct linux_dirent64;
struct list_head;
struct msgbuf;
struct msghdr;
+struct mmsghdr;
struct msqid_ds;
struct new_utsname;
struct nfsctl_arg;
@@ -677,6 +678,9 @@ asmlinkage long sys_recv(int, void __user *, size_t, unsigned);
asmlinkage long sys_recvfrom(int, void __user *, size_t, unsigned,
struct sockaddr __user *, int __user *);
asmlinkage long sys_recvmsg(int fd, struct msghdr __user *msg, unsigned flags);
+asmlinkage long sys_recvmmsg(int fd, struct mmsghdr __user *msg,
+ unsigned int vlen, unsigned flags,
+ struct timespec __user *timeout);
asmlinkage long sys_socket(int, int, int);
asmlinkage long sys_socketpair(int, int, int, int __user *);
asmlinkage long sys_socketcall(int call, unsigned long __user *args);
diff --git a/include/net/compat.h b/include/net/compat.h
index 7c30028..9679f05 100644
--- a/include/net/compat.h
+++ b/include/net/compat.h
@@ -18,6 +18,11 @@ struct compat_msghdr {
compat_uint_t msg_flags;
};
+struct compat_mmsghdr {
+ struct compat_msghdr msg_hdr;
+ compat_uint_t msg_len;
+};
+
struct compat_cmsghdr {
compat_size_t cmsg_len;
compat_int_t cmsg_level;
@@ -35,6 +40,9 @@ extern int get_compat_msghdr(struct msghdr *, struct compat_msghdr __user *);
extern int verify_compat_iovec(struct msghdr *, struct iovec *, struct sockaddr *, int);
extern asmlinkage long compat_sys_sendmsg(int,struct compat_msghdr __user *,unsigned);
extern asmlinkage long compat_sys_recvmsg(int,struct compat_msghdr __user *,unsigned);
+extern asmlinkage long compat_sys_recvmmsg(int, struct compat_mmsghdr __user *,
+ unsigned, unsigned,
+ struct timespec __user *);
extern asmlinkage long compat_sys_getsockopt(int, int, int, char __user *, int __user *);
extern int put_cmsg_compat(struct msghdr*, int, int, int, void *);
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c
index e06d0b8..f050ba8 100644
--- a/kernel/sys_ni.c
+++ b/kernel/sys_ni.c
@@ -48,8 +48,10 @@ cond_syscall(sys_shutdown);
cond_syscall(sys_sendmsg);
cond_syscall(compat_sys_sendmsg);
cond_syscall(sys_recvmsg);
+cond_syscall(sys_recvmmsg);
cond_syscall(compat_sys_recvmsg);
cond_syscall(compat_sys_recvfrom);
+cond_syscall(compat_sys_recvmmsg);
cond_syscall(sys_socketcall);
cond_syscall(sys_futex);
cond_syscall(compat_sys_futex);
diff --git a/net/compat.c b/net/compat.c
index a407c3a..e13f525 100644
--- a/net/compat.c
+++ b/net/compat.c
@@ -727,10 +727,10 @@ EXPORT_SYMBOL(compat_mc_getsockopt);
/* Argument list sizes for compat_sys_socketcall */
#define AL(x) ((x) * sizeof(u32))
-static unsigned char nas[19]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3),
+static unsigned char nas[20]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3),
AL(3),AL(3),AL(4),AL(4),AL(4),AL(6),
AL(6),AL(2),AL(5),AL(5),AL(3),AL(3),
- AL(4)};
+ AL(4),AL(5)};
#undef AL
asmlinkage long compat_sys_sendmsg(int fd, struct compat_msghdr __user *msg, unsigned flags)
@@ -755,13 +755,36 @@ asmlinkage long compat_sys_recvfrom(int fd, void __user *buf, size_t len,
return sys_recvfrom(fd, buf, len, flags | MSG_CMSG_COMPAT, addr, addrlen);
}
+asmlinkage long compat_sys_recvmmsg(int fd, struct compat_mmsghdr __user *mmsg,
+ unsigned vlen, unsigned int flags,
+ struct timespec __user *timeout)
+{
+ int datagrams;
+ struct timespec ktspec;
+ struct compat_timespec __user *utspec =
+ (struct compat_timespec __user *)timeout;
+
+ if (get_user(ktspec.tv_sec, &utspec->tv_sec) ||
+ get_user(ktspec.tv_nsec, &utspec->tv_nsec))
+ return -EFAULT;
+
+ datagrams = __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
+ flags | MSG_CMSG_COMPAT, &ktspec);
+ if (datagrams > 0 &&
+ (put_user(ktspec.tv_sec, &utspec->tv_sec) ||
+ put_user(ktspec.tv_nsec, &utspec->tv_nsec)))
+ datagrams = -EFAULT;
+
+ return datagrams;
+}
+
asmlinkage long compat_sys_socketcall(int call, u32 __user *args)
{
int ret;
u32 a[6];
u32 a0, a1;
- if (call < SYS_SOCKET || call > SYS_ACCEPT4)
+ if (call < SYS_SOCKET || call > SYS_RECVMMSG)
return -EINVAL;
if (copy_from_user(a, args, nas[call]))
return -EFAULT;
@@ -823,6 +846,10 @@ asmlinkage long compat_sys_socketcall(int call, u32 __user *args)
case SYS_RECVMSG:
ret = compat_sys_recvmsg(a0, compat_ptr(a1), a[2]);
break;
+ case SYS_RECVMMSG:
+ ret = compat_sys_recvmmsg(a0, compat_ptr(a1), a[2], a[3],
+ compat_ptr(a[4]));
+ break;
case SYS_ACCEPT4:
ret = sys_accept4(a0, compat_ptr(a1), compat_ptr(a[2]), a[3]);
break;
diff --git a/net/socket.c b/net/socket.c
index 954f338..3dd03df 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -668,10 +668,9 @@ void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk,
EXPORT_SYMBOL_GPL(__sock_recv_timestamp);
-static inline int __sock_recvmsg(struct kiocb *iocb, struct socket *sock,
- struct msghdr *msg, size_t size, int flags)
+static inline int __sock_recvmsg_nosec(struct kiocb *iocb, struct socket *sock,
+ struct msghdr *msg, size_t size, int flags)
{
- int err;
struct sock_iocb *si = kiocb_to_siocb(iocb);
si->sock = sock;
@@ -680,13 +679,17 @@ static inline int __sock_recvmsg(struct kiocb *iocb, struct socket *sock,
si->size = size;
si->flags = flags;
- err = security_socket_recvmsg(sock, msg, size, flags);
- if (err)
- return err;
-
return sock->ops->recvmsg(iocb, sock, msg, size, flags);
}
+static inline int __sock_recvmsg(struct kiocb *iocb, struct socket *sock,
+ struct msghdr *msg, size_t size, int flags)
+{
+ int err = security_socket_recvmsg(sock, msg, size, flags);
+
+ return err ?: __sock_recvmsg_nosec(iocb, sock, msg, size, flags);
+}
+
int sock_recvmsg(struct socket *sock, struct msghdr *msg,
size_t size, int flags)
{
@@ -702,6 +705,21 @@ int sock_recvmsg(struct socket *sock, struct msghdr *msg,
return ret;
}
+static int sock_recvmsg_nosec(struct socket *sock, struct msghdr *msg,
+ size_t size, int flags)
+{
+ struct kiocb iocb;
+ struct sock_iocb siocb;
+ int ret;
+
+ init_sync_kiocb(&iocb, NULL);
+ iocb.private = &siocb;
+ ret = __sock_recvmsg_nosec(&iocb, sock, msg, size, flags);
+ if (-EIOCBQUEUED == ret)
+ ret = wait_on_sync_kiocb(&iocb);
+ return ret;
+}
+
int kernel_recvmsg(struct socket *sock, struct msghdr *msg,
struct kvec *vec, size_t num, size_t size, int flags)
{
@@ -1968,22 +1986,15 @@ out:
return err;
}
-/*
- * BSD recvmsg interface
- */
-
-SYSCALL_DEFINE3(recvmsg, int, fd, struct msghdr __user *, msg,
- unsigned int, flags)
+static int __sys_recvmsg(struct socket *sock, struct msghdr __user *msg,
+ struct msghdr *msg_sys, unsigned flags, int nosec)
{
struct compat_msghdr __user *msg_compat =
(struct compat_msghdr __user *)msg;
- struct socket *sock;
struct iovec iovstack[UIO_FASTIOV];
struct iovec *iov = iovstack;
- struct msghdr msg_sys;
unsigned long cmsg_ptr;
int err, iov_size, total_len, len;
- int fput_needed;
/* kernel mode address */
struct sockaddr_storage addr;
@@ -1993,27 +2004,23 @@ SYSCALL_DEFINE3(recvmsg, int, fd, struct msghdr __user *, msg,
int __user *uaddr_len;
if (MSG_CMSG_COMPAT & flags) {
- if (get_compat_msghdr(&msg_sys, msg_compat))
+ if (get_compat_msghdr(msg_sys, msg_compat))
return -EFAULT;
}
- else if (copy_from_user(&msg_sys, msg, sizeof(struct msghdr)))
+ else if (copy_from_user(msg_sys, msg, sizeof(struct msghdr)))
return -EFAULT;
- sock = sockfd_lookup_light(fd, &err, &fput_needed);
- if (!sock)
- goto out;
-
err = -EMSGSIZE;
- if (msg_sys.msg_iovlen > UIO_MAXIOV)
- goto out_put;
+ if (msg_sys->msg_iovlen > UIO_MAXIOV)
+ goto out;
/* Check whether to allocate the iovec area */
err = -ENOMEM;
- iov_size = msg_sys.msg_iovlen * sizeof(struct iovec);
- if (msg_sys.msg_iovlen > UIO_FASTIOV) {
+ iov_size = msg_sys->msg_iovlen * sizeof(struct iovec);
+ if (msg_sys->msg_iovlen > UIO_FASTIOV) {
iov = sock_kmalloc(sock->sk, iov_size, GFP_KERNEL);
if (!iov)
- goto out_put;
+ goto out;
}
/*
@@ -2021,46 +2028,47 @@ SYSCALL_DEFINE3(recvmsg, int, fd, struct msghdr __user *, msg,
* kernel msghdr to use the kernel address space)
*/
- uaddr = (__force void __user *)msg_sys.msg_name;
+ uaddr = (__force void __user *)msg_sys->msg_name;
uaddr_len = COMPAT_NAMELEN(msg);
if (MSG_CMSG_COMPAT & flags) {
- err = verify_compat_iovec(&msg_sys, iov,
+ err = verify_compat_iovec(msg_sys, iov,
(struct sockaddr *)&addr,
VERIFY_WRITE);
} else
- err = verify_iovec(&msg_sys, iov,
+ err = verify_iovec(msg_sys, iov,
(struct sockaddr *)&addr,
VERIFY_WRITE);
if (err < 0)
goto out_freeiov;
total_len = err;
- cmsg_ptr = (unsigned long)msg_sys.msg_control;
- msg_sys.msg_flags = flags & (MSG_CMSG_CLOEXEC|MSG_CMSG_COMPAT);
+ cmsg_ptr = (unsigned long)msg_sys->msg_control;
+ msg_sys->msg_flags = flags & (MSG_CMSG_CLOEXEC|MSG_CMSG_COMPAT);
if (sock->file->f_flags & O_NONBLOCK)
flags |= MSG_DONTWAIT;
- err = sock_recvmsg(sock, &msg_sys, total_len, flags);
+ err = (nosec ? sock_recvmsg_nosec : sock_recvmsg)(sock, msg_sys,
+ total_len, flags);
if (err < 0)
goto out_freeiov;
len = err;
if (uaddr != NULL) {
err = move_addr_to_user((struct sockaddr *)&addr,
- msg_sys.msg_namelen, uaddr,
+ msg_sys->msg_namelen, uaddr,
uaddr_len);
if (err < 0)
goto out_freeiov;
}
- err = __put_user((msg_sys.msg_flags & ~MSG_CMSG_COMPAT),
+ err = __put_user((msg_sys->msg_flags & ~MSG_CMSG_COMPAT),
COMPAT_FLAGS(msg));
if (err)
goto out_freeiov;
if (MSG_CMSG_COMPAT & flags)
- err = __put_user((unsigned long)msg_sys.msg_control - cmsg_ptr,
+ err = __put_user((unsigned long)msg_sys->msg_control - cmsg_ptr,
&msg_compat->msg_controllen);
else
- err = __put_user((unsigned long)msg_sys.msg_control - cmsg_ptr,
+ err = __put_user((unsigned long)msg_sys->msg_control - cmsg_ptr,
&msg->msg_controllen);
if (err)
goto out_freeiov;
@@ -2069,21 +2077,150 @@ SYSCALL_DEFINE3(recvmsg, int, fd, struct msghdr __user *, msg,
out_freeiov:
if (iov != iovstack)
sock_kfree_s(sock->sk, iov, iov_size);
-out_put:
+out:
+ return err;
+}
+
+/*
+ * BSD recvmsg interface
+ */
+
+SYSCALL_DEFINE3(recvmsg, int, fd, struct msghdr __user *, msg,
+ unsigned int, flags)
+{
+ int fput_needed, err;
+ struct msghdr msg_sys;
+ struct socket *sock = sockfd_lookup_light(fd, &err, &fput_needed);
+
+ if (!sock)
+ goto out;
+
+ err = __sys_recvmsg(sock, msg, &msg_sys, flags, 0);
+
fput_light(sock->file, fput_needed);
out:
return err;
}
-#ifdef __ARCH_WANT_SYS_SOCKETCALL
+/*
+ * Linux recvmmsg interface
+ */
+
+int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
+ unsigned int flags, struct timespec *timeout)
+{
+ int fput_needed, err, datagrams;
+ struct socket *sock;
+ struct mmsghdr __user *entry;
+ struct msghdr msg_sys;
+ struct timespec end_time;
+
+ if (timeout &&
+ poll_select_set_timeout(&end_time, timeout->tv_sec,
+ timeout->tv_nsec))
+ return -EINVAL;
+
+ datagrams = 0;
+
+ sock = sockfd_lookup_light(fd, &err, &fput_needed);
+ if (!sock)
+ return err;
+
+ err = sock_error(sock->sk);
+ if (err)
+ goto out_put;
+
+ entry = mmsg;
+
+ while (datagrams < vlen) {
+ /*
+ * No need to ask LSM for more than the first datagram.
+ */
+ err = __sys_recvmsg(sock, (struct msghdr __user *)entry,
+ &msg_sys, flags, datagrams);
+ if (err < 0)
+ break;
+ err = put_user(err, &entry->msg_len);
+ if (err)
+ break;
+ ++entry;
+ ++datagrams;
+
+ if (timeout) {
+ ktime_get_ts(timeout);
+ *timeout = timespec_sub(end_time, *timeout);
+ if (timeout->tv_sec < 0) {
+ timeout->tv_sec = timeout->tv_nsec = 0;
+ break;
+ }
+
+ /* Timeout, return less than vlen datagrams */
+ if (timeout->tv_nsec == 0 && timeout->tv_sec == 0)
+ break;
+ }
+
+ /* Out of band data, return right away */
+ if (msg_sys.msg_flags & MSG_OOB)
+ break;
+ }
+
+out_put:
+ fput_light(sock->file, fput_needed);
+ if (err == 0)
+ return datagrams;
+
+ if (datagrams != 0) {
+ /*
+ * We may return less entries than requested (vlen) if the
+ * sock is non block and there aren't enough datagrams...
+ */
+ if (err != -EAGAIN) {
+ /*
+ * ... or if recvmsg returns an error after we
+ * received some datagrams, where we record the
+ * error to return on the next call or if the
+ * app asks about it using getsockopt(SO_ERROR).
+ */
+ sock->sk->sk_err = -err;
+ }
+
+ return datagrams;
+ }
+
+ return err;
+}
+
+SYSCALL_DEFINE5(recvmmsg, int, fd, struct mmsghdr __user *, mmsg,
+ unsigned int, vlen, unsigned int, flags,
+ struct timespec __user *, timeout)
+{
+ int datagrams;
+ struct timespec timeout_sys;
+
+ if (!timeout)
+ return __sys_recvmmsg(fd, mmsg, vlen, flags, NULL);
+
+ if (copy_from_user(&timeout_sys, timeout, sizeof(timeout_sys)))
+ return -EFAULT;
+
+ datagrams = __sys_recvmmsg(fd, mmsg, vlen, flags, &timeout_sys);
+
+ if (datagrams > 0 &&
+ copy_to_user(timeout, &timeout_sys, sizeof(timeout_sys)))
+ datagrams = -EFAULT;
+
+ return datagrams;
+}
+
+#ifdef __ARCH_WANT_SYS_SOCKETCALL
/* Argument list sizes for sys_socketcall */
#define AL(x) ((x) * sizeof(unsigned long))
-static const unsigned char nargs[19]={
+static const unsigned char nargs[20] = {
AL(0),AL(3),AL(3),AL(3),AL(2),AL(3),
AL(3),AL(3),AL(4),AL(4),AL(4),AL(6),
AL(6),AL(2),AL(5),AL(5),AL(3),AL(3),
- AL(4)
+ AL(4),AL(5)
};
#undef AL
@@ -2103,7 +2240,7 @@ SYSCALL_DEFINE2(socketcall, int, call, unsigned long __user *, args)
int err;
unsigned int len;
- if (call < 1 || call > SYS_ACCEPT4)
+ if (call < 1 || call > SYS_RECVMMSG)
return -EINVAL;
len = nargs[call];
@@ -2181,6 +2318,10 @@ SYSCALL_DEFINE2(socketcall, int, call, unsigned long __user *, args)
case SYS_RECVMSG:
err = sys_recvmsg(a0, (struct msghdr __user *)a1, a[2]);
break;
+ case SYS_RECVMMSG:
+ err = sys_recvmmsg(a0, (struct mmsghdr __user *)a1, a[2], a[3],
+ (struct timespec __user *)a[4]);
+ break;
case SYS_ACCEPT4:
err = sys_accept4(a0, (struct sockaddr __user *)a1,
(int __user *)a[2], a[3]);
--
1.5.5.1
^ permalink raw reply related
* Re: PATCH: Network Device Naming mechanism and policy
From: Bill Nottingham @ 2009-10-12 17:37 UTC (permalink / raw)
To: Scott James Remnant
Cc: Matt Domsch, Narendra K, netdev, linux-hotplug, jordan_hargrave
In-Reply-To: <1255344075.2143.1.camel@warcraft>
Scott James Remnant (scott@ubuntu.com) said:
> On the other hand, they *tend* to be unique for a wide range of systems.
> This makes them pretty comparable to LABELs on disks, and we have
> a /dev/disk/by-label
>
> Remember that udev already supports symlink stacking, and priorities and
> such.
>
> I don't think there's any danger of supporting a /dev/netdev/by-mac by
> default, it'll be a benefit to most and those who don't have unique MACs
> will just ignore it.
At the moment, we do not appear to get the proper change uevents from things
like 'ip link set dev <foo> address <bar>', so we can't currently maintain
these symlinks.
Bill
^ 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