* Re: [patch net-next-2.6] de2104x: use speed defines instead of number
From: Jiri Pirko @ 2011-06-01 16:19 UTC (permalink / raw)
To: Ben Hutchings; +Cc: netdev, davem
In-Reply-To: <1306943206.22348.10.camel@localhost>
Wed, Jun 01, 2011 at 05:46:46PM CEST, bhutchings@solarflare.com wrote:
>The speed/speed_hi fields are defined to hold speed in Mbit/s, not only
>specific values. I don't see any reason to use the names any more.
Do you mean to remove SPEED_X defines in whole code?
>
>Ben.
>
>On Wed, 2011-06-01 at 16:14 +0200, Jiri Pirko wrote:
>> Signed-off-by: Jiri Pirko <jpirko@redhat.com>
>> ---
>> drivers/net/tulip/de2104x.c | 4 ++--
>> 1 files changed, 2 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c
>> index e2f6923..1cc426d 100644
>> --- a/drivers/net/tulip/de2104x.c
>> +++ b/drivers/net/tulip/de2104x.c
>> @@ -1507,7 +1507,7 @@ static int __de_get_settings(struct de_private *de, struct ethtool_cmd *ecmd)
>> break;
>> }
>>
>> - ethtool_cmd_speed_set(ecmd, 10);
>> + ethtool_cmd_speed_set(ecmd, SPEED_10);
>>
>> if (dr32(MacMode) & FullDuplex)
>> ecmd->duplex = DUPLEX_FULL;
>> @@ -1529,7 +1529,7 @@ static int __de_set_settings(struct de_private *de, struct ethtool_cmd *ecmd)
>> u32 new_media;
>> unsigned int media_lock;
>>
>> - if (ethtool_cmd_speed(ecmd) != 10)
>> + if (ethtool_cmd_speed(ecmd) != SPEED_10)
>> return -EINVAL;
>> if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL)
>> return -EINVAL;
>
>--
>Ben Hutchings, Senior Software Engineer, Solarflare
>Not speaking for my employer; that's the marketing department's job.
>They asked us to note that Solarflare product names are trademarked.
>
^ permalink raw reply
* Re: inet_diag insufficient validation?
From: Dan Rosenberg @ 2011-06-01 15:50 UTC (permalink / raw)
To: davem; +Cc: kuznet, netdev, security
In-Reply-To: <1306942849.3150.10.camel@dan>
On Wed, 2011-06-01 at 11:40 -0400, Dan Rosenberg wrote:
> Once the bytecode is actually run in inet_diag_bc_run(), it looks like
> more infinite loops are possible, if appropriate "yes" or "no" values
> are set to zero and weren't validated by the audit.
On second glance, there don't appear to be any infinite loops at runtime
(but the audit loop seems real). Thanks to Nelson Elhage for setting me
straight.
-Dan
^ permalink raw reply
* Re: [patch net-next-2.6] de2104x: use speed defines instead of number
From: Ben Hutchings @ 2011-06-01 15:46 UTC (permalink / raw)
To: Jiri Pirko; +Cc: netdev, davem
In-Reply-To: <1306937677-11101-1-git-send-email-jpirko@redhat.com>
The speed/speed_hi fields are defined to hold speed in Mbit/s, not only
specific values. I don't see any reason to use the names any more.
Ben.
On Wed, 2011-06-01 at 16:14 +0200, Jiri Pirko wrote:
> Signed-off-by: Jiri Pirko <jpirko@redhat.com>
> ---
> drivers/net/tulip/de2104x.c | 4 ++--
> 1 files changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c
> index e2f6923..1cc426d 100644
> --- a/drivers/net/tulip/de2104x.c
> +++ b/drivers/net/tulip/de2104x.c
> @@ -1507,7 +1507,7 @@ static int __de_get_settings(struct de_private *de, struct ethtool_cmd *ecmd)
> break;
> }
>
> - ethtool_cmd_speed_set(ecmd, 10);
> + ethtool_cmd_speed_set(ecmd, SPEED_10);
>
> if (dr32(MacMode) & FullDuplex)
> ecmd->duplex = DUPLEX_FULL;
> @@ -1529,7 +1529,7 @@ static int __de_set_settings(struct de_private *de, struct ethtool_cmd *ecmd)
> u32 new_media;
> unsigned int media_lock;
>
> - if (ethtool_cmd_speed(ecmd) != 10)
> + if (ethtool_cmd_speed(ecmd) != SPEED_10)
> return -EINVAL;
> if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL)
> return -EINVAL;
--
Ben Hutchings, Senior Software Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply
* inet_diag insufficient validation?
From: Dan Rosenberg @ 2011-06-01 15:40 UTC (permalink / raw)
To: davem, kuznet; +Cc: netdev, security
It seems to me that the auditing performed by inet_diag_bc_audit() is
insufficient to prevent pathological INET_DIAG bytecode from doing bad
things.
Firstly, it's possible to cause an infinite loop in inet_diag_bc_audit()
with a INET_DIAG_BC_JMP opcode with a "yes" value of 0. The valid_cc()
function, also called from here, seems suspicious as well.
Once the bytecode is actually run in inet_diag_bc_run(), it looks like
more infinite loops are possible, if appropriate "yes" or "no" values
are set to zero and weren't validated by the audit.
Finally, I can't seem to find any validation that the reported length of
the netlink message header doesn't exceed the skb length, as checked in
some other netlink receive functions, which could result in reading
beyond the bounds of the socket data. I could just be missing something
here though.
Regards,
Dan
^ permalink raw reply
* Re: [PATCH] vlan: fix typo in vlan_dev_hard_start_xmit()
From: Eric Dumazet @ 2011-06-01 15:07 UTC (permalink / raw)
To: Wei Yongjun; +Cc: David Miller, netdev@vger.kernel.org
In-Reply-To: <4DE5FDFF.4000208@cn.fujitsu.com>
Le mercredi 01 juin 2011 à 16:53 +0800, Wei Yongjun a écrit :
> commit 4af429d29b341bb1735f04c2fb960178ed5d52e7 (vlan: lockless
> transmit path) have a typo in vlan_dev_hard_start_xmit(), using
> u64_stats_update_begin() to end the stat update, it should be
> u64_stats_update_end().
>
> Signed-off-by: Wei Yongjun <yjwei@cn.fujitsu.com>
Good catch, Thanks !
Acked-by: Eric Dumazet <eric.dumazet@gmail.com>
^ permalink raw reply
* (unknown),
From: Greg Moore Financial Home @ 2011-06-01 14:16 UTC (permalink / raw)
I Am Greg Moore.We give out loan of all kinds in a very fast and easy way,
get back to us if interested
^ permalink raw reply
* [patch net-next-2.6] de2104x: use speed defines instead of number
From: Jiri Pirko @ 2011-06-01 14:14 UTC (permalink / raw)
To: netdev; +Cc: davem
Signed-off-by: Jiri Pirko <jpirko@redhat.com>
---
drivers/net/tulip/de2104x.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c
index e2f6923..1cc426d 100644
--- a/drivers/net/tulip/de2104x.c
+++ b/drivers/net/tulip/de2104x.c
@@ -1507,7 +1507,7 @@ static int __de_get_settings(struct de_private *de, struct ethtool_cmd *ecmd)
break;
}
- ethtool_cmd_speed_set(ecmd, 10);
+ ethtool_cmd_speed_set(ecmd, SPEED_10);
if (dr32(MacMode) & FullDuplex)
ecmd->duplex = DUPLEX_FULL;
@@ -1529,7 +1529,7 @@ static int __de_set_settings(struct de_private *de, struct ethtool_cmd *ecmd)
u32 new_media;
unsigned int media_lock;
- if (ethtool_cmd_speed(ecmd) != 10)
+ if (ethtool_cmd_speed(ecmd) != SPEED_10)
return -EINVAL;
if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL)
return -EINVAL;
--
1.7.4.4
^ permalink raw reply related
* Re: [PATCH] vlan: fix typo in vlan_dev_hard_start_xmit()
From: WANG Cong @ 2011-06-01 13:54 UTC (permalink / raw)
To: netdev
In-Reply-To: <4DE5FDFF.4000208@cn.fujitsu.com>
On Wed, 01 Jun 2011 16:53:19 +0800, Wei Yongjun wrote:
> commit 4af429d29b341bb1735f04c2fb960178ed5d52e7 (vlan: lockless transmit
> path) have a typo in vlan_dev_hard_start_xmit(), using
> u64_stats_update_begin() to end the stat update, it should be
> u64_stats_update_end().
>
> Signed-off-by: Wei Yongjun <yjwei@cn.fujitsu.com>
Yup, good catch!
Reviewed-by: WANG Cong <xiyou.wangcong@gmail.com>
^ permalink raw reply
* Re: [patch net-next-2.6] bonding: allow resetting slave failure counters
From: Jiri Pirko @ 2011-06-01 13:53 UTC (permalink / raw)
To: Flavio Leitner; +Cc: netdev, davem, fubar, andy
In-Reply-To: <4DE63E85.7020508@redhat.com>
Wed, Jun 01, 2011 at 03:28:37PM CEST, fbl@redhat.com wrote:
>On 06/01/2011 06:40 AM, Jiri Pirko wrote:
>> This patch allows to reset failure counters for all enslaved devices.
>>
>> Signed-off-by: Jiri Pirko <jpirko@redhat.com>
>> ---
>> Documentation/networking/bonding.txt | 7 +++++++
>> drivers/net/bonding/bond_sysfs.c | 27 +++++++++++++++++++++++++++
>> 2 files changed, 34 insertions(+), 0 deletions(-)
>>
>> diff --git a/Documentation/networking/bonding.txt b/Documentation/networking/bonding.txt
>> index 675612f..2f51d73 100644
>> --- a/Documentation/networking/bonding.txt
>> +++ b/Documentation/networking/bonding.txt
>> @@ -782,6 +782,13 @@ resend_igmp
>>
>> This option was added for bonding version 3.7.0.
>>
>> +reset_failure_counters
>> +
>> + This write-only control file will zero failure counters for
>> + all slaves. Note there is no appropriate module parameter for this
>> + since it would not make much sense.
>> + Write any value to perform reset.
>
>nit: many options mention when they were added.
>i.e. This option was added for bonding version 3.7.1
hmm, is that necessary Jay, Andy?
/me thinks this versioning should be removed at all in the first place...
>
>fbl
>
>> 3. Configuring Bonding Devices
>> ==============================
>>
>> diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
>> index 88fcb25..9b45164 100644
>> --- a/drivers/net/bonding/bond_sysfs.c
>> +++ b/drivers/net/bonding/bond_sysfs.c
>> @@ -1572,6 +1572,32 @@ out:
>> static DEVICE_ATTR(resend_igmp, S_IRUGO | S_IWUSR,
>> bonding_show_resend_igmp, bonding_store_resend_igmp);
>>
>> +static ssize_t
>> +bonding_store_reset_failure_counters(struct device *d,
>> + struct device_attribute *attr,
>> + const char *buf, size_t count)
>> +{
>> + struct slave *slave;
>> + int i;
>> + struct bonding *bond = to_bond(d);
>> +
>> + if (!rtnl_trylock())
>> + return restart_syscall();
>> +
>> + read_lock(&bond->lock);
>> + pr_info("%s: Resetting counters.\n", bond->dev->name);
>> + bond_for_each_slave(bond, slave, i)
>> + slave->link_failure_count = 0;
>> + read_unlock(&bond->lock);
>> +
>> + rtnl_unlock();
>> +
>> + return count;
>> +}
>> +
>> +static DEVICE_ATTR(reset_failure_counters, S_IWUSR, NULL,
>> + bonding_store_reset_failure_counters);
>> +
>> static struct attribute *per_bond_attrs[] = {
>> &dev_attr_slaves.attr,
>> &dev_attr_mode.attr,
>> @@ -1600,6 +1626,7 @@ static struct attribute *per_bond_attrs[] = {
>> &dev_attr_queue_id.attr,
>> &dev_attr_all_slaves_active.attr,
>> &dev_attr_resend_igmp.attr,
>> + &dev_attr_reset_failure_counters.attr,
>> NULL,
>> };
>>
>
^ permalink raw reply
* Re: [patch net-next-2.6] bonding: allow resetting slave failure counters
From: WANG Cong @ 2011-06-01 13:51 UTC (permalink / raw)
To: netdev
In-Reply-To: <1306921249-3623-1-git-send-email-jpirko@redhat.com>
On Wed, 01 Jun 2011 11:40:49 +0200, Jiri Pirko wrote:
> This patch allows to reset failure counters for all enslaved devices.
>
> Signed-off-by: Jiri Pirko <jpirko@redhat.com>
> ---
> Documentation/networking/bonding.txt | 7 +++++++
> drivers/net/bonding/bond_sysfs.c | 27 +++++++++++++++++++++++++++
> 2 files changed, 34 insertions(+), 0 deletions(-)
>
> diff --git a/Documentation/networking/bonding.txt
> b/Documentation/networking/bonding.txt index 675612f..2f51d73 100644
> --- a/Documentation/networking/bonding.txt +++
> b/Documentation/networking/bonding.txt @@ -782,6 +782,13 @@ resend_igmp
>
> This option was added for bonding version 3.7.0.
>
> +reset_failure_counters
> +
> + This write-only control file will zero failure counters for + all
> slaves. Note there is no appropriate module parameter for this
> + since
> it would not make much sense. + Write any value to perform reset.
> +
Writing any value includes zero will work? I think only non-zero
number makes sense, if we write zero, nothing should happen.
Thanks.
^ permalink raw reply
* [PATCHv3] caif: Add CAIF HSI Link layer driver
From: Sjur Brændeland @ 2011-06-01 13:29 UTC (permalink / raw)
To: David S. Miller, netdev; +Cc: Dmitry.Tarnyagin, Sjur Brændeland
From: Dmitry.Tarnyagin <Dmitry.Tarnyagin@stericsson.com>
This patch introduces the CAIF HSI Protocol Driver for the
CAIF Link Layer.
This driver implements a platform driver to accommodate for a
platform specific HSI devices. A general platform driver is not
possible as there are no HSI side Kernel API defined.
Signed-off-by: Sjur Brændeland <sjur.brandeland@stericsson.com>
---
Hi Dave,
Do you still allow drivers to go into Linux 3.0 at this point?
If not I can resend this patch later.
Changes from v2 time:
- Adding support for handshaking for power management
- Changed lock handling for skb lists.
Regards,
Sjur
drivers/net/caif/Kconfig | 9 +
drivers/net/caif/Makefile | 3 +
drivers/net/caif/caif_hsi.c | 1220 +++++++++++++++++++++++++++++++++++++++++++
include/net/caif/caif_hsi.h | 145 +++++
4 files changed, 1377 insertions(+), 0 deletions(-)
create mode 100644 drivers/net/caif/caif_hsi.c
create mode 100644 include/net/caif/caif_hsi.h
diff --git a/drivers/net/caif/Kconfig b/drivers/net/caif/Kconfig
index 09ed3f4..abf4d7a 100644
--- a/drivers/net/caif/Kconfig
+++ b/drivers/net/caif/Kconfig
@@ -38,3 +38,12 @@ config CAIF_SHM
default n
---help---
The CAIF shared memory protocol driver for the STE UX5500 platform.
+
+config CAIF_HSI
+ tristate "CAIF HSI transport driver"
+ depends on CAIF
+ default n
+ ---help---
+ The caif low level driver for CAIF over HSI.
+ Be aware that if you enable this then you also need to
+ enable a low-level HSI driver.
diff --git a/drivers/net/caif/Makefile b/drivers/net/caif/Makefile
index 9560b9d..91dff86 100644
--- a/drivers/net/caif/Makefile
+++ b/drivers/net/caif/Makefile
@@ -10,3 +10,6 @@ obj-$(CONFIG_CAIF_SPI_SLAVE) += cfspi_slave.o
# Shared memory
caif_shm-objs := caif_shmcore.o caif_shm_u5500.o
obj-$(CONFIG_CAIF_SHM) += caif_shm.o
+
+# HSI interface
+obj-$(CONFIG_CAIF_HSI) += caif_hsi.o
diff --git a/drivers/net/caif/caif_hsi.c b/drivers/net/caif/caif_hsi.c
new file mode 100644
index 0000000..7a8ce61
--- /dev/null
+++ b/drivers/net/caif/caif_hsi.c
@@ -0,0 +1,1220 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ * Contact: Sjur Brendeland / sjur.brandeland@stericsson.com
+ * Author: Daniel Martensson / daniel.martensson@stericsson.com
+ * Dmitry.Tarnyagin / dmitry.tarnyagin@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2.
+ */
+
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/netdevice.h>
+#include <linux/string.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/if_arp.h>
+#include <linux/timer.h>
+#include <net/caif/caif_layer.h>
+#include <net/caif/caif_hsi.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Daniel Martensson<daniel.martensson@stericsson.com>");
+MODULE_DESCRIPTION("CAIF HSI driver");
+
+/* Returns the number of padding bytes for alignment. */
+#define PAD_POW2(x, pow) ((((x)&((pow)-1)) == 0) ? 0 :\
+ (((pow)-((x)&((pow)-1)))))
+
+/*
+ * HSI padding options.
+ * Warning: must be a base of 2 (& operation used) and can not be zero !
+ */
+static int hsi_head_align = 4;
+module_param(hsi_head_align, int, S_IRUGO);
+MODULE_PARM_DESC(hsi_head_align, "HSI head alignment.");
+
+static int hsi_tail_align = 4;
+module_param(hsi_tail_align, int, S_IRUGO);
+MODULE_PARM_DESC(hsi_tail_align, "HSI tail alignment.");
+
+/*
+ * HSI link layer flowcontrol thresholds.
+ * Warning: A high threshold value migth increase throughput but it will at
+ * the same time prevent channel prioritization and increase the risk of
+ * flooding the modem. The high threshold should be above the low.
+ */
+static int hsi_high_threshold = 100;
+module_param(hsi_high_threshold, int, S_IRUGO);
+MODULE_PARM_DESC(hsi_high_threshold, "HSI high threshold (FLOW OFF).");
+
+static int hsi_low_threshold = 50;
+module_param(hsi_low_threshold, int, S_IRUGO);
+MODULE_PARM_DESC(hsi_low_threshold, "HSI high threshold (FLOW ON).");
+
+#define ON 1
+#define OFF 0
+
+/*
+ * Threshold values for the HSI packet queue. Flowcontrol will be asserted
+ * when the number of packets exceeds HIGH_WATER_MARK. It will not be
+ * de-asserted before the number of packets drops below LOW_WATER_MARK.
+ */
+#define LOW_WATER_MARK hsi_low_threshold
+#define HIGH_WATER_MARK hsi_high_threshold
+
+static LIST_HEAD(cfhsi_list);
+static spinlock_t cfhsi_list_lock;
+
+static void cfhsi_inactivity_tout(unsigned long arg)
+{
+ struct cfhsi *cfhsi = (struct cfhsi *)arg;
+
+ dev_dbg(&cfhsi->ndev->dev, "%s.\n",
+ __func__);
+
+ /* Schedule power down work queue. */
+ if (!test_bit(CFHSI_SHUTDOWN, &cfhsi->bits))
+ queue_work(cfhsi->wq, &cfhsi->wake_down_work);
+}
+
+static void cfhsi_abort_tx(struct cfhsi *cfhsi)
+{
+ struct sk_buff *skb;
+
+ for (;;) {
+ spin_lock_bh(&cfhsi->lock);
+ skb = skb_dequeue(&cfhsi->qhead);
+ if (!skb)
+ break;
+
+ cfhsi->ndev->stats.tx_errors++;
+ cfhsi->ndev->stats.tx_dropped++;
+ spin_unlock_bh(&cfhsi->lock);
+ kfree_skb(skb);
+ }
+ cfhsi->tx_state = CFHSI_TX_STATE_IDLE;
+ if (!test_bit(CFHSI_SHUTDOWN, &cfhsi->bits))
+ mod_timer(&cfhsi->timer, jiffies + CFHSI_INACTIVITY_TOUT);
+ spin_unlock_bh(&cfhsi->lock);
+}
+
+static int cfhsi_flush_fifo(struct cfhsi *cfhsi)
+{
+ char buffer[32]; /* Any reasonable value */
+ size_t fifo_occupancy;
+ int ret;
+
+ dev_dbg(&cfhsi->ndev->dev, "%s.\n",
+ __func__);
+
+
+ ret = cfhsi->dev->cfhsi_wake_up(cfhsi->dev);
+ if (ret) {
+ dev_warn(&cfhsi->ndev->dev,
+ "%s: can't wake up HSI interface: %d.\n",
+ __func__, ret);
+ return ret;
+ }
+
+ do {
+ ret = cfhsi->dev->cfhsi_fifo_occupancy(cfhsi->dev,
+ &fifo_occupancy);
+ if (ret) {
+ dev_warn(&cfhsi->ndev->dev,
+ "%s: can't get FIFO occupancy: %d.\n",
+ __func__, ret);
+ break;
+ } else if (!fifo_occupancy)
+ /* No more data, exitting normally */
+ break;
+
+ fifo_occupancy = min(sizeof(buffer), fifo_occupancy);
+ set_bit(CFHSI_FLUSH_FIFO, &cfhsi->bits);
+ ret = cfhsi->dev->cfhsi_rx(buffer, fifo_occupancy,
+ cfhsi->dev);
+ if (ret) {
+ clear_bit(CFHSI_FLUSH_FIFO, &cfhsi->bits);
+ dev_warn(&cfhsi->ndev->dev,
+ "%s: can't read data: %d.\n",
+ __func__, ret);
+ break;
+ }
+
+ ret = 5 * HZ;
+ wait_event_interruptible_timeout(cfhsi->flush_fifo_wait,
+ !test_bit(CFHSI_FLUSH_FIFO, &cfhsi->bits), ret);
+
+ if (ret < 0) {
+ dev_warn(&cfhsi->ndev->dev,
+ "%s: can't wait for flush complete: %d.\n",
+ __func__, ret);
+ break;
+ } else if (!ret) {
+ ret = -ETIMEDOUT;
+ dev_warn(&cfhsi->ndev->dev,
+ "%s: timeout waiting for flush complete.\n",
+ __func__);
+ break;
+ }
+ } while (1);
+
+ cfhsi->dev->cfhsi_wake_down(cfhsi->dev);
+
+ return ret;
+}
+
+static int cfhsi_tx_frm(struct cfhsi_desc *desc, struct cfhsi *cfhsi)
+{
+ int nfrms = 0;
+ int pld_len = 0;
+ struct sk_buff *skb;
+ u8 *pfrm = desc->emb_frm + CFHSI_MAX_EMB_FRM_SZ;
+
+ skb = skb_dequeue(&cfhsi->qhead);
+ if (!skb)
+ return 0;
+
+ /* Check if we can embed a CAIF frame. */
+ if (skb->len < CFHSI_MAX_EMB_FRM_SZ) {
+ struct caif_payload_info *info;
+ int hpad = 0;
+ int tpad = 0;
+
+ /* Calculate needed head alignment and tail alignment. */
+ info = (struct caif_payload_info *)&skb->cb;
+
+ hpad = 1 + PAD_POW2((info->hdr_len + 1), hsi_head_align);
+ tpad = PAD_POW2((skb->len + hpad), hsi_tail_align);
+
+ /* Check if frame still fits with added alignment. */
+ if ((skb->len + hpad + tpad) <= CFHSI_MAX_EMB_FRM_SZ) {
+ u8 *pemb = desc->emb_frm;
+ desc->offset = CFHSI_DESC_SHORT_SZ;
+ *pemb = (u8)(hpad - 1);
+ pemb += hpad;
+
+ /* Update network statistics. */
+ cfhsi->ndev->stats.tx_packets++;
+ cfhsi->ndev->stats.tx_bytes += skb->len;
+
+ /* Copy in embedded CAIF frame. */
+ skb_copy_bits(skb, 0, pemb, skb->len);
+ consume_skb(skb);
+ skb = NULL;
+ }
+ } else
+ /* Clear offset. */
+ desc->offset = 0;
+
+ /* Create payload CAIF frames. */
+ pfrm = desc->emb_frm + CFHSI_MAX_EMB_FRM_SZ;
+ while (nfrms < CFHSI_MAX_PKTS) {
+ struct caif_payload_info *info;
+ int hpad = 0;
+ int tpad = 0;
+
+ if (!skb)
+ skb = skb_dequeue(&cfhsi->qhead);
+
+ if (!skb)
+ break;
+
+ /* Calculate needed head alignment and tail alignment. */
+ info = (struct caif_payload_info *)&skb->cb;
+
+ hpad = 1 + PAD_POW2((info->hdr_len + 1), hsi_head_align);
+ tpad = PAD_POW2((skb->len + hpad), hsi_tail_align);
+
+ /* Fill in CAIF frame length in descriptor. */
+ desc->cffrm_len[nfrms] = hpad + skb->len + tpad;
+
+ /* Fill head padding information. */
+ *pfrm = (u8)(hpad - 1);
+ pfrm += hpad;
+
+ /* Update network statistics. */
+ cfhsi->ndev->stats.tx_packets++;
+ cfhsi->ndev->stats.tx_bytes += skb->len;
+
+ /* Copy in CAIF frame. */
+ skb_copy_bits(skb, 0, pfrm, skb->len);
+
+ /* Update payload length. */
+ pld_len += desc->cffrm_len[nfrms];
+
+ /* Update frame pointer. */
+ pfrm += skb->len + tpad;
+ consume_skb(skb);
+ skb = NULL;
+
+ /* Update number of frames. */
+ nfrms++;
+ }
+
+ /* Unused length fields should be zero-filled (according to SPEC). */
+ while (nfrms < CFHSI_MAX_PKTS) {
+ desc->cffrm_len[nfrms] = 0x0000;
+ nfrms++;
+ }
+
+ /* Check if we can piggy-back another descriptor. */
+ skb = skb_peek(&cfhsi->qhead);
+ if (skb)
+ desc->header |= CFHSI_PIGGY_DESC;
+ else
+ desc->header &= ~CFHSI_PIGGY_DESC;
+
+ return CFHSI_DESC_SZ + pld_len;
+}
+
+static void cfhsi_tx_done_work(struct work_struct *work)
+{
+ struct cfhsi *cfhsi = NULL;
+ struct cfhsi_desc *desc = NULL;
+ int len = 0;
+ int res;
+
+ cfhsi = container_of(work, struct cfhsi, tx_done_work);
+ dev_dbg(&cfhsi->ndev->dev, "%s.\n",
+ __func__);
+
+ if (test_bit(CFHSI_SHUTDOWN, &cfhsi->bits))
+ return;
+
+ desc = (struct cfhsi_desc *)cfhsi->tx_buf;
+
+ do {
+ /*
+ * Send flow on if flow off has been previously signalled
+ * and number of packets is below low water mark.
+ */
+ spin_lock_bh(&cfhsi->lock);
+ if (cfhsi->flow_off_sent &&
+ cfhsi->qhead.qlen <= cfhsi->q_low_mark &&
+ cfhsi->cfdev.flowctrl) {
+
+ cfhsi->flow_off_sent = 0;
+ cfhsi->cfdev.flowctrl(cfhsi->ndev, ON);
+ }
+ spin_unlock_bh(&cfhsi->lock);
+
+ /* Create HSI frame. */
+ len = cfhsi_tx_frm(desc, cfhsi);
+ if (!len) {
+ cfhsi->tx_state = CFHSI_TX_STATE_IDLE;
+ /* Start inactivity timer. */
+ mod_timer(&cfhsi->timer,
+ jiffies + CFHSI_INACTIVITY_TOUT);
+ break;
+ }
+
+ /* Set up new transfer. */
+ res = cfhsi->dev->cfhsi_tx(cfhsi->tx_buf, len, cfhsi->dev);
+ if (WARN_ON(res < 0)) {
+ dev_err(&cfhsi->ndev->dev, "%s: TX error %d.\n",
+ __func__, res);
+ }
+ } while (res < 0);
+}
+
+static void cfhsi_tx_done_cb(struct cfhsi_drv *drv)
+{
+ struct cfhsi *cfhsi;
+
+ cfhsi = container_of(drv, struct cfhsi, drv);
+ dev_dbg(&cfhsi->ndev->dev, "%s.\n",
+ __func__);
+
+ if (test_bit(CFHSI_SHUTDOWN, &cfhsi->bits))
+ return;
+
+ queue_work(cfhsi->wq, &cfhsi->tx_done_work);
+}
+
+static int cfhsi_rx_desc(struct cfhsi_desc *desc, struct cfhsi *cfhsi)
+{
+ int xfer_sz = 0;
+ int nfrms = 0;
+ u16 *plen = NULL;
+ u8 *pfrm = NULL;
+
+ if ((desc->header & ~CFHSI_PIGGY_DESC) ||
+ (desc->offset > CFHSI_MAX_EMB_FRM_SZ)) {
+ dev_err(&cfhsi->ndev->dev, "%s: Invalid descriptor.\n",
+ __func__);
+ return 0;
+ }
+
+ /* Check for embedded CAIF frame. */
+ if (desc->offset) {
+ struct sk_buff *skb;
+ u8 *dst = NULL;
+ int len = 0, retries = 0;
+ pfrm = ((u8 *)desc) + desc->offset;
+
+ /* Remove offset padding. */
+ pfrm += *pfrm + 1;
+
+ /* Read length of CAIF frame (little endian). */
+ len = *pfrm;
+ len |= ((*(pfrm+1)) << 8) & 0xFF00;
+ len += 2; /* Add FCS fields. */
+
+
+ /* Allocate SKB (OK even in IRQ context). */
+ skb = alloc_skb(len + 1, GFP_KERNEL);
+ while (!skb) {
+ retries++;
+ schedule_timeout(1);
+ skb = alloc_skb(len + 1, GFP_KERNEL);
+ if (skb) {
+ printk(KERN_WARNING "%s: slept for %u "
+ "before getting memory\n",
+ __func__, retries);
+ break;
+ }
+ if (retries > HZ) {
+ printk(KERN_ERR "%s: slept for 1HZ and "
+ "did not get memory\n",
+ __func__);
+ cfhsi->ndev->stats.rx_dropped++;
+ goto drop_frame;
+ }
+ }
+ caif_assert(skb != NULL);
+
+ dst = skb_put(skb, len);
+ memcpy(dst, pfrm, len);
+
+ skb->protocol = htons(ETH_P_CAIF);
+ skb_reset_mac_header(skb);
+ skb->dev = cfhsi->ndev;
+
+ /*
+ * We are called from a arch specific platform device.
+ * Unfortunately we don't know what context we're
+ * running in.
+ */
+ if (in_interrupt())
+ netif_rx(skb);
+ else
+ netif_rx_ni(skb);
+
+ /* Update network statistics. */
+ cfhsi->ndev->stats.rx_packets++;
+ cfhsi->ndev->stats.rx_bytes += len;
+ }
+
+drop_frame:
+ /* Calculate transfer length. */
+ plen = desc->cffrm_len;
+ while (nfrms < CFHSI_MAX_PKTS && *plen) {
+ xfer_sz += *plen;
+ plen++;
+ nfrms++;
+ }
+
+ /* Check for piggy-backed descriptor. */
+ if (desc->header & CFHSI_PIGGY_DESC)
+ xfer_sz += CFHSI_DESC_SZ;
+
+ if (xfer_sz % 4) {
+ dev_err(&cfhsi->ndev->dev,
+ "%s: Invalid payload len: %d, ignored.\n",
+ __func__, xfer_sz);
+ xfer_sz = 0;
+ }
+
+ return xfer_sz;
+}
+
+static int cfhsi_rx_pld(struct cfhsi_desc *desc, struct cfhsi *cfhsi)
+{
+ int rx_sz = 0;
+ int nfrms = 0;
+ u16 *plen = NULL;
+ u8 *pfrm = NULL;
+
+ /* Sanity check header and offset. */
+ if (WARN_ON((desc->header & ~CFHSI_PIGGY_DESC) ||
+ (desc->offset > CFHSI_MAX_EMB_FRM_SZ))) {
+ dev_err(&cfhsi->ndev->dev, "%s: Invalid descriptor.\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ /* Set frame pointer to start of payload. */
+ pfrm = desc->emb_frm + CFHSI_MAX_EMB_FRM_SZ;
+ plen = desc->cffrm_len;
+ while (nfrms < CFHSI_MAX_PKTS && *plen) {
+ struct sk_buff *skb;
+ u8 *dst = NULL;
+ u8 *pcffrm = NULL;
+ int len = 0, retries = 0;
+
+ if (WARN_ON(desc->cffrm_len[nfrms] > CFHSI_MAX_PAYLOAD_SZ)) {
+ dev_err(&cfhsi->ndev->dev, "%s: Invalid payload.\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ /* CAIF frame starts after head padding. */
+ pcffrm = pfrm + *pfrm + 1;
+
+ /* Read length of CAIF frame (little endian). */
+ len = *pcffrm;
+ len |= ((*(pcffrm + 1)) << 8) & 0xFF00;
+ len += 2; /* Add FCS fields. */
+
+ /* Allocate SKB (OK even in IRQ context). */
+ skb = alloc_skb(len + 1, GFP_KERNEL);
+ while (!skb) {
+ retries++;
+ schedule_timeout(1);
+ skb = alloc_skb(len + 1, GFP_KERNEL);
+ if (skb) {
+ printk(KERN_WARNING "%s: slept for %u "
+ "before getting memory\n",
+ __func__, retries);
+ break;
+ }
+ if (retries > HZ) {
+ printk(KERN_ERR "%s: slept for 1HZ "
+ "and did not get memory\n",
+ __func__);
+ cfhsi->ndev->stats.rx_dropped++;
+ goto drop_frame;
+ }
+ }
+ caif_assert(skb != NULL);
+
+ dst = skb_put(skb, len);
+ memcpy(dst, pcffrm, len);
+
+ skb->protocol = htons(ETH_P_CAIF);
+ skb_reset_mac_header(skb);
+ skb->dev = cfhsi->ndev;
+
+ /*
+ * We're called from a platform device,
+ * and don't know the context we're running in.
+ */
+ if (in_interrupt())
+ netif_rx(skb);
+ else
+ netif_rx_ni(skb);
+
+ /* Update network statistics. */
+ cfhsi->ndev->stats.rx_packets++;
+ cfhsi->ndev->stats.rx_bytes += len;
+
+drop_frame:
+ pfrm += *plen;
+ rx_sz += *plen;
+ plen++;
+ nfrms++;
+ }
+
+ return rx_sz;
+}
+
+static void cfhsi_rx_done_work(struct work_struct *work)
+{
+ int res;
+ int desc_pld_len = 0;
+ struct cfhsi *cfhsi = NULL;
+ struct cfhsi_desc *desc = NULL;
+
+ cfhsi = container_of(work, struct cfhsi, rx_done_work);
+ desc = (struct cfhsi_desc *)cfhsi->rx_buf;
+
+ dev_dbg(&cfhsi->ndev->dev, "%s: Kick timer if pending.\n",
+ __func__);
+
+ if (test_bit(CFHSI_SHUTDOWN, &cfhsi->bits))
+ return;
+
+ /* Update inactivity timer if pending. */
+ mod_timer_pending(&cfhsi->timer, jiffies + CFHSI_INACTIVITY_TOUT);
+
+ if (cfhsi->rx_state == CFHSI_RX_STATE_DESC) {
+ desc_pld_len = cfhsi_rx_desc(desc, cfhsi);
+ } else {
+ int pld_len;
+
+ pld_len = cfhsi_rx_pld(desc, cfhsi);
+
+ if ((pld_len > 0) && (desc->header & CFHSI_PIGGY_DESC)) {
+ struct cfhsi_desc *piggy_desc;
+ piggy_desc = (struct cfhsi_desc *)
+ (desc->emb_frm + CFHSI_MAX_EMB_FRM_SZ +
+ pld_len);
+
+ /* Extract piggy-backed descriptor. */
+ desc_pld_len = cfhsi_rx_desc(piggy_desc, cfhsi);
+
+ /*
+ * Copy needed information from the piggy-backed
+ * descriptor to the descriptor in the start.
+ */
+ memcpy((u8 *)desc, (u8 *)piggy_desc,
+ CFHSI_DESC_SHORT_SZ);
+ }
+ }
+
+ if (desc_pld_len) {
+ cfhsi->rx_state = CFHSI_RX_STATE_PAYLOAD;
+ cfhsi->rx_ptr = cfhsi->rx_buf + CFHSI_DESC_SZ;
+ cfhsi->rx_len = desc_pld_len;
+ } else {
+ cfhsi->rx_state = CFHSI_RX_STATE_DESC;
+ cfhsi->rx_ptr = cfhsi->rx_buf;
+ cfhsi->rx_len = CFHSI_DESC_SZ;
+ }
+ clear_bit(CFHSI_PENDING_RX, &cfhsi->bits);
+
+ if (test_bit(CFHSI_AWAKE, &cfhsi->bits)) {
+ /* Set up new transfer. */
+ dev_dbg(&cfhsi->ndev->dev, "%s: Start RX.\n",
+ __func__);
+ res = cfhsi->dev->cfhsi_rx(cfhsi->rx_ptr, cfhsi->rx_len,
+ cfhsi->dev);
+ if (WARN_ON(res < 0)) {
+ dev_err(&cfhsi->ndev->dev, "%s: RX error %d.\n",
+ __func__, res);
+ cfhsi->ndev->stats.rx_errors++;
+ cfhsi->ndev->stats.rx_dropped++;
+ }
+ }
+}
+
+static void cfhsi_rx_done_cb(struct cfhsi_drv *drv)
+{
+ struct cfhsi *cfhsi;
+
+ cfhsi = container_of(drv, struct cfhsi, drv);
+ dev_dbg(&cfhsi->ndev->dev, "%s.\n",
+ __func__);
+
+ if (test_bit(CFHSI_SHUTDOWN, &cfhsi->bits))
+ return;
+
+ set_bit(CFHSI_PENDING_RX, &cfhsi->bits);
+
+ if (test_and_clear_bit(CFHSI_FLUSH_FIFO, &cfhsi->bits))
+ wake_up_interruptible(&cfhsi->flush_fifo_wait);
+ else
+ queue_work(cfhsi->wq, &cfhsi->rx_done_work);
+}
+
+static void cfhsi_wake_up(struct work_struct *work)
+{
+ struct cfhsi *cfhsi = NULL;
+ int res;
+ int len;
+ long ret;
+
+ cfhsi = container_of(work, struct cfhsi, wake_up_work);
+
+ if (test_bit(CFHSI_SHUTDOWN, &cfhsi->bits))
+ return;
+
+ if (unlikely(test_bit(CFHSI_AWAKE, &cfhsi->bits))) {
+ /* It happenes when wakeup is requested by
+ * both ends at the same time. */
+ clear_bit(CFHSI_WAKE_UP, &cfhsi->bits);
+ return;
+ }
+
+ /* Activate wake line. */
+ cfhsi->dev->cfhsi_wake_up(cfhsi->dev);
+
+ dev_dbg(&cfhsi->ndev->dev, "%s: Start waiting.\n",
+ __func__);
+
+ /* Wait for acknowledge. */
+ ret = CFHSI_WAKEUP_TOUT;
+ wait_event_interruptible_timeout(cfhsi->wake_up_wait,
+ test_bit(CFHSI_WAKE_UP_ACK,
+ &cfhsi->bits), ret);
+ if (unlikely(ret < 0)) {
+ /* Interrupted by signal. */
+ dev_info(&cfhsi->ndev->dev, "%s: Signalled: %ld.\n",
+ __func__, ret);
+ clear_bit(CFHSI_WAKE_UP, &cfhsi->bits);
+ cfhsi->dev->cfhsi_wake_down(cfhsi->dev);
+ return;
+ } else if (!ret) {
+ /* Wakeup timeout */
+ dev_err(&cfhsi->ndev->dev, "%s: Timeout.\n",
+ __func__);
+ clear_bit(CFHSI_WAKE_UP, &cfhsi->bits);
+ cfhsi->dev->cfhsi_wake_down(cfhsi->dev);
+ return;
+ }
+ dev_dbg(&cfhsi->ndev->dev, "%s: Woken.\n",
+ __func__);
+
+ /* Clear power up bit. */
+ set_bit(CFHSI_AWAKE, &cfhsi->bits);
+ clear_bit(CFHSI_WAKE_UP, &cfhsi->bits);
+
+ /* Resume read operation. */
+ if (!test_bit(CFHSI_PENDING_RX, &cfhsi->bits)) {
+ dev_dbg(&cfhsi->ndev->dev, "%s: Start RX.\n",
+ __func__);
+ res = cfhsi->dev->cfhsi_rx(cfhsi->rx_ptr,
+ cfhsi->rx_len, cfhsi->dev);
+ if (WARN_ON(res < 0)) {
+ dev_err(&cfhsi->ndev->dev, "%s: RX error %d.\n",
+ __func__, res);
+ }
+ }
+
+ /* Clear power up acknowledment. */
+ clear_bit(CFHSI_WAKE_UP_ACK, &cfhsi->bits);
+
+ spin_lock_bh(&cfhsi->lock);
+
+ /* Resume transmit if queue is not empty. */
+ if (!skb_peek(&cfhsi->qhead)) {
+ dev_dbg(&cfhsi->ndev->dev, "%s: Peer wake, start timer.\n",
+ __func__);
+ /* Start inactivity timer. */
+ mod_timer(&cfhsi->timer,
+ jiffies + CFHSI_INACTIVITY_TOUT);
+ spin_unlock_bh(&cfhsi->lock);
+ return;
+ }
+
+ dev_dbg(&cfhsi->ndev->dev, "%s: Host wake.\n",
+ __func__);
+
+ spin_unlock_bh(&cfhsi->lock);
+
+ /* Create HSI frame. */
+ len = cfhsi_tx_frm((struct cfhsi_desc *)cfhsi->tx_buf, cfhsi);
+
+ if (likely(len > 0)) {
+ /* Set up new transfer. */
+ res = cfhsi->dev->cfhsi_tx(cfhsi->tx_buf, len, cfhsi->dev);
+ if (WARN_ON(res < 0)) {
+ dev_err(&cfhsi->ndev->dev, "%s: TX error %d.\n",
+ __func__, res);
+ cfhsi_abort_tx(cfhsi);
+ }
+ } else {
+ dev_err(&cfhsi->ndev->dev,
+ "%s: Failed to create HSI frame: %d.\n",
+ __func__, len);
+ }
+
+}
+
+static void cfhsi_wake_down(struct work_struct *work)
+{
+ long ret;
+ struct cfhsi *cfhsi = NULL;
+ size_t fifo_occupancy;
+
+ cfhsi = container_of(work, struct cfhsi, wake_down_work);
+ dev_dbg(&cfhsi->ndev->dev, "%s.\n",
+ __func__);
+
+ if (test_bit(CFHSI_SHUTDOWN, &cfhsi->bits))
+ return;
+
+ /* Check if there is something in FIFO. */
+ if (WARN_ON(cfhsi->dev->cfhsi_fifo_occupancy(cfhsi->dev,
+ &fifo_occupancy)))
+ fifo_occupancy = 0;
+
+ if (fifo_occupancy) {
+ dev_dbg(&cfhsi->ndev->dev,
+ "%s: %u words in RX FIFO, restart timer.\n",
+ __func__, (unsigned) fifo_occupancy);
+ spin_lock_bh(&cfhsi->lock);
+ mod_timer(&cfhsi->timer,
+ jiffies + CFHSI_INACTIVITY_TOUT);
+ spin_unlock_bh(&cfhsi->lock);
+ return;
+ }
+
+ /* Cancel pending RX requests */
+ cfhsi->dev->cfhsi_rx_cancel(cfhsi->dev);
+
+ /* Deactivate wake line. */
+ cfhsi->dev->cfhsi_wake_down(cfhsi->dev);
+
+ /* Wait for acknowledge. */
+ ret = CFHSI_WAKEUP_TOUT;
+ ret = wait_event_interruptible_timeout(cfhsi->wake_down_wait,
+ test_bit(CFHSI_WAKE_DOWN_ACK,
+ &cfhsi->bits),
+ ret);
+ if (ret < 0) {
+ /* Interrupted by signal. */
+ dev_info(&cfhsi->ndev->dev, "%s: Signalled: %ld.\n",
+ __func__, ret);
+ return;
+ } else if (!ret) {
+ /* Timeout */
+ dev_err(&cfhsi->ndev->dev, "%s: Timeout.\n",
+ __func__);
+ }
+
+ /* Clear power down acknowledment. */
+ clear_bit(CFHSI_WAKE_DOWN_ACK, &cfhsi->bits);
+ clear_bit(CFHSI_AWAKE, &cfhsi->bits);
+
+ /* Check if there is something in FIFO. */
+ if (WARN_ON(cfhsi->dev->cfhsi_fifo_occupancy(cfhsi->dev,
+ &fifo_occupancy)))
+ fifo_occupancy = 0;
+
+ if (fifo_occupancy) {
+ dev_dbg(&cfhsi->ndev->dev,
+ "%s: %u words in RX FIFO, wakeup forced.\n",
+ __func__, (unsigned) fifo_occupancy);
+ if (!test_and_set_bit(CFHSI_WAKE_UP, &cfhsi->bits))
+ queue_work(cfhsi->wq, &cfhsi->wake_up_work);
+ } else
+ dev_dbg(&cfhsi->ndev->dev, "%s: Done.\n",
+ __func__);
+}
+
+static void cfhsi_wake_up_cb(struct cfhsi_drv *drv)
+{
+ struct cfhsi *cfhsi = NULL;
+
+ cfhsi = container_of(drv, struct cfhsi, drv);
+ dev_dbg(&cfhsi->ndev->dev, "%s.\n",
+ __func__);
+
+ set_bit(CFHSI_WAKE_UP_ACK, &cfhsi->bits);
+ wake_up_interruptible(&cfhsi->wake_up_wait);
+
+ if (test_bit(CFHSI_SHUTDOWN, &cfhsi->bits))
+ return;
+
+ /* Schedule wake up work queue if the peer initiates. */
+ if (!test_and_set_bit(CFHSI_WAKE_UP, &cfhsi->bits))
+ queue_work(cfhsi->wq, &cfhsi->wake_up_work);
+}
+
+static void cfhsi_wake_down_cb(struct cfhsi_drv *drv)
+{
+ struct cfhsi *cfhsi = NULL;
+
+ cfhsi = container_of(drv, struct cfhsi, drv);
+ dev_dbg(&cfhsi->ndev->dev, "%s.\n",
+ __func__);
+
+ /* Initiating low power is only permitted by the host (us). */
+ set_bit(CFHSI_WAKE_DOWN_ACK, &cfhsi->bits);
+ wake_up_interruptible(&cfhsi->wake_down_wait);
+}
+
+static int cfhsi_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct cfhsi *cfhsi = NULL;
+ int start_xfer = 0;
+ int timer_active;
+
+ if (!dev)
+ return -EINVAL;
+
+ cfhsi = netdev_priv(dev);
+
+ spin_lock_bh(&cfhsi->lock);
+
+ skb_queue_tail(&cfhsi->qhead, skb);
+
+ /* Sanity check; xmit should not be called after unregister_netdev */
+ if (WARN_ON(test_bit(CFHSI_SHUTDOWN, &cfhsi->bits))) {
+ spin_unlock_bh(&cfhsi->lock);
+ cfhsi_abort_tx(cfhsi);
+ return -EINVAL;
+ }
+
+ /* Send flow off if number of packets is above high water mark. */
+ if (!cfhsi->flow_off_sent &&
+ cfhsi->qhead.qlen > cfhsi->q_high_mark &&
+ cfhsi->cfdev.flowctrl) {
+ cfhsi->flow_off_sent = 1;
+ cfhsi->cfdev.flowctrl(cfhsi->ndev, OFF);
+ }
+
+ if (cfhsi->tx_state == CFHSI_TX_STATE_IDLE) {
+ cfhsi->tx_state = CFHSI_TX_STATE_XFER;
+ start_xfer = 1;
+ }
+
+ spin_unlock_bh(&cfhsi->lock);
+
+ if (!start_xfer)
+ return 0;
+
+ /* Delete inactivity timer if started. */
+#ifdef CONFIG_SMP
+ timer_active = del_timer_sync(&cfhsi->timer);
+#else
+ timer_active = del_timer(&cfhsi->timer);
+#endif /* CONFIG_SMP */
+
+ if (timer_active) {
+ struct cfhsi_desc *desc = (struct cfhsi_desc *)cfhsi->tx_buf;
+ int len;
+ int res;
+
+ /* Create HSI frame. */
+ len = cfhsi_tx_frm(desc, cfhsi);
+ BUG_ON(!len);
+
+ /* Set up new transfer. */
+ res = cfhsi->dev->cfhsi_tx(cfhsi->tx_buf, len, cfhsi->dev);
+ if (WARN_ON(res < 0)) {
+ dev_err(&cfhsi->ndev->dev, "%s: TX error %d.\n",
+ __func__, res);
+ cfhsi_abort_tx(cfhsi);
+ }
+ } else {
+ /* Schedule wake up work queue if the we initiate. */
+ if (!test_and_set_bit(CFHSI_WAKE_UP, &cfhsi->bits))
+ queue_work(cfhsi->wq, &cfhsi->wake_up_work);
+ }
+
+ return 0;
+}
+
+static int cfhsi_open(struct net_device *dev)
+{
+ netif_wake_queue(dev);
+
+ return 0;
+}
+
+static int cfhsi_close(struct net_device *dev)
+{
+ netif_stop_queue(dev);
+
+ return 0;
+}
+
+static const struct net_device_ops cfhsi_ops = {
+ .ndo_open = cfhsi_open,
+ .ndo_stop = cfhsi_close,
+ .ndo_start_xmit = cfhsi_xmit
+};
+
+static void cfhsi_setup(struct net_device *dev)
+{
+ struct cfhsi *cfhsi = netdev_priv(dev);
+ dev->features = 0;
+ dev->netdev_ops = &cfhsi_ops;
+ dev->type = ARPHRD_CAIF;
+ dev->flags = IFF_POINTOPOINT | IFF_NOARP;
+ dev->mtu = CFHSI_MAX_PAYLOAD_SZ;
+ dev->tx_queue_len = 0;
+ dev->destructor = free_netdev;
+ skb_queue_head_init(&cfhsi->qhead);
+ cfhsi->cfdev.link_select = CAIF_LINK_HIGH_BANDW;
+ cfhsi->cfdev.use_frag = false;
+ cfhsi->cfdev.use_stx = false;
+ cfhsi->cfdev.use_fcs = false;
+ cfhsi->ndev = dev;
+}
+
+int cfhsi_probe(struct platform_device *pdev)
+{
+ struct cfhsi *cfhsi = NULL;
+ struct net_device *ndev;
+ struct cfhsi_dev *dev;
+ int res;
+
+ ndev = alloc_netdev(sizeof(struct cfhsi), "cfhsi%d", cfhsi_setup);
+ if (!ndev) {
+ dev_err(&pdev->dev, "%s: alloc_netdev failed.\n",
+ __func__);
+ return -ENODEV;
+ }
+
+ cfhsi = netdev_priv(ndev);
+ cfhsi->ndev = ndev;
+ cfhsi->pdev = pdev;
+
+ /* Initialize state vaiables. */
+ cfhsi->tx_state = CFHSI_TX_STATE_IDLE;
+ cfhsi->rx_state = CFHSI_RX_STATE_DESC;
+
+ /* Set flow info */
+ cfhsi->flow_off_sent = 0;
+ cfhsi->q_low_mark = LOW_WATER_MARK;
+ cfhsi->q_high_mark = HIGH_WATER_MARK;
+
+ /* Assign the HSI device. */
+ dev = (struct cfhsi_dev *)pdev->dev.platform_data;
+ cfhsi->dev = dev;
+
+ /* Assign the driver to this HSI device. */
+ dev->drv = &cfhsi->drv;
+
+ /*
+ * Allocate a TX buffer with the size of a HSI packet descriptors
+ * and the necessary room for CAIF payload frames.
+ */
+ cfhsi->tx_buf = kzalloc(CFHSI_BUF_SZ_TX, GFP_KERNEL);
+ if (!cfhsi->tx_buf) {
+ dev_err(&ndev->dev, "%s: Failed to allocate TX buffer.\n",
+ __func__);
+ res = -ENODEV;
+ goto err_alloc_tx;
+ }
+
+ /*
+ * Allocate a RX buffer with the size of two HSI packet descriptors and
+ * the necessary room for CAIF payload frames.
+ */
+ cfhsi->rx_buf = kzalloc(CFHSI_BUF_SZ_RX, GFP_KERNEL);
+ if (!cfhsi->rx_buf) {
+ dev_err(&ndev->dev, "%s: Failed to allocate RX buffer.\n",
+ __func__);
+ res = -ENODEV;
+ goto err_alloc_rx;
+ }
+
+ /* Initialize recieve vaiables. */
+ cfhsi->rx_ptr = cfhsi->rx_buf;
+ cfhsi->rx_len = CFHSI_DESC_SZ;
+
+ /* Initialize spin locks. */
+ spin_lock_init(&cfhsi->lock);
+
+ /* Set up the driver. */
+ cfhsi->drv.tx_done_cb = cfhsi_tx_done_cb;
+ cfhsi->drv.rx_done_cb = cfhsi_rx_done_cb;
+
+ /* Initialize the work queues. */
+ INIT_WORK(&cfhsi->wake_up_work, cfhsi_wake_up);
+ INIT_WORK(&cfhsi->wake_down_work, cfhsi_wake_down);
+ INIT_WORK(&cfhsi->rx_done_work, cfhsi_rx_done_work);
+ INIT_WORK(&cfhsi->tx_done_work, cfhsi_tx_done_work);
+
+ /* Clear all bit fields. */
+ clear_bit(CFHSI_WAKE_UP_ACK, &cfhsi->bits);
+ clear_bit(CFHSI_WAKE_DOWN_ACK, &cfhsi->bits);
+ clear_bit(CFHSI_WAKE_UP, &cfhsi->bits);
+ clear_bit(CFHSI_AWAKE, &cfhsi->bits);
+ clear_bit(CFHSI_PENDING_RX, &cfhsi->bits);
+
+ /* Create work thread. */
+ cfhsi->wq = create_singlethread_workqueue(pdev->name);
+ if (!cfhsi->wq) {
+ dev_err(&ndev->dev, "%s: Failed to create work queue.\n",
+ __func__);
+ res = -ENODEV;
+ goto err_create_wq;
+ }
+
+ /* Initialize wait queues. */
+ init_waitqueue_head(&cfhsi->wake_up_wait);
+ init_waitqueue_head(&cfhsi->wake_down_wait);
+ init_waitqueue_head(&cfhsi->flush_fifo_wait);
+
+ /* Setup the inactivity timer. */
+ init_timer(&cfhsi->timer);
+ cfhsi->timer.data = (unsigned long)cfhsi;
+ cfhsi->timer.function = cfhsi_inactivity_tout;
+
+ /* Add CAIF HSI device to list. */
+ spin_lock(&cfhsi_list_lock);
+ list_add_tail(&cfhsi->list, &cfhsi_list);
+ spin_unlock(&cfhsi_list_lock);
+
+ /* Activate HSI interface. */
+ res = cfhsi->dev->cfhsi_up(cfhsi->dev);
+ if (res) {
+ dev_err(&cfhsi->ndev->dev,
+ "%s: can't activate HSI interface: %d.\n",
+ __func__, res);
+ goto err_activate;
+ }
+
+ /* Flush FIFO */
+ res = cfhsi_flush_fifo(cfhsi);
+ if (res) {
+ dev_err(&ndev->dev, "%s: Can't flush FIFO: %d.\n",
+ __func__, res);
+ goto err_net_reg;
+ }
+
+ cfhsi->drv.wake_up_cb = cfhsi_wake_up_cb;
+ cfhsi->drv.wake_down_cb = cfhsi_wake_down_cb;
+
+ /* Register network device. */
+ res = register_netdev(ndev);
+ if (res) {
+ dev_err(&ndev->dev, "%s: Registration error: %d.\n",
+ __func__, res);
+ goto err_net_reg;
+ }
+
+ netif_stop_queue(ndev);
+
+ return res;
+
+ err_net_reg:
+ cfhsi->dev->cfhsi_down(cfhsi->dev);
+ err_activate:
+ destroy_workqueue(cfhsi->wq);
+ err_create_wq:
+ kfree(cfhsi->rx_buf);
+ err_alloc_rx:
+ kfree(cfhsi->tx_buf);
+ err_alloc_tx:
+ free_netdev(ndev);
+
+ return res;
+}
+
+static void cfhsi_shutdown(struct cfhsi *cfhsi, bool remove_platform_dev)
+{
+ u8 *tx_buf, *rx_buf;
+
+ /* Stop TXing */
+ netif_tx_stop_all_queues(cfhsi->ndev);
+
+ /* going to shutdown driver */
+ set_bit(CFHSI_SHUTDOWN, &cfhsi->bits);
+
+ if (remove_platform_dev) {
+ /* Flush workqueue */
+ flush_workqueue(cfhsi->wq);
+
+ /* Notify device. */
+ platform_device_unregister(cfhsi->pdev);
+ }
+
+ /* Flush workqueue */
+ flush_workqueue(cfhsi->wq);
+
+ /* Delete timer if pending */
+#ifdef CONFIG_SMP
+ del_timer_sync(&cfhsi->timer);
+#else
+ del_timer(&cfhsi->timer);
+#endif /* CONFIG_SMP */
+
+ /* Cancel pending RX request (if any) */
+ cfhsi->dev->cfhsi_rx_cancel(cfhsi->dev);
+
+ /* Flush again and destroy workqueue */
+ destroy_workqueue(cfhsi->wq);
+
+ /* Store bufferes: will be freed later. */
+ tx_buf = cfhsi->tx_buf;
+ rx_buf = cfhsi->rx_buf;
+
+ /* Flush transmit queues. */
+ cfhsi_abort_tx(cfhsi);
+
+ /* Deactivate interface */
+ cfhsi->dev->cfhsi_down(cfhsi->dev);
+
+ /* Finally unregister the network device. */
+ unregister_netdev(cfhsi->ndev);
+
+ /* Free buffers. */
+ kfree(tx_buf);
+ kfree(rx_buf);
+}
+
+int cfhsi_remove(struct platform_device *pdev)
+{
+ struct list_head *list_node;
+ struct list_head *n;
+ struct cfhsi *cfhsi = NULL;
+ struct cfhsi_dev *dev;
+
+ dev = (struct cfhsi_dev *)pdev->dev.platform_data;
+ spin_lock(&cfhsi_list_lock);
+ list_for_each_safe(list_node, n, &cfhsi_list) {
+ cfhsi = list_entry(list_node, struct cfhsi, list);
+ /* Find the corresponding device. */
+ if (cfhsi->dev == dev) {
+ /* Remove from list. */
+ list_del(list_node);
+ spin_unlock(&cfhsi_list_lock);
+
+ /* Shutdown driver. */
+ cfhsi_shutdown(cfhsi, false);
+
+ return 0;
+ }
+ }
+ spin_unlock(&cfhsi_list_lock);
+ return -ENODEV;
+}
+
+struct platform_driver cfhsi_plat_drv = {
+ .probe = cfhsi_probe,
+ .remove = cfhsi_remove,
+ .driver = {
+ .name = "cfhsi",
+ .owner = THIS_MODULE,
+ },
+};
+
+static void __exit cfhsi_exit_module(void)
+{
+ struct list_head *list_node;
+ struct list_head *n;
+ struct cfhsi *cfhsi = NULL;
+
+ spin_lock(&cfhsi_list_lock);
+ list_for_each_safe(list_node, n, &cfhsi_list) {
+ cfhsi = list_entry(list_node, struct cfhsi, list);
+
+ /* Remove from list. */
+ list_del(list_node);
+ spin_unlock(&cfhsi_list_lock);
+
+ /* Shutdown driver. */
+ cfhsi_shutdown(cfhsi, true);
+
+ spin_lock(&cfhsi_list_lock);
+ }
+ spin_unlock(&cfhsi_list_lock);
+
+ /* Unregister platform driver. */
+ platform_driver_unregister(&cfhsi_plat_drv);
+}
+
+static int __init cfhsi_init_module(void)
+{
+ int result;
+
+ /* Initialize spin lock. */
+ spin_lock_init(&cfhsi_list_lock);
+
+ /* Register platform driver. */
+ result = platform_driver_register(&cfhsi_plat_drv);
+ if (result) {
+ printk(KERN_ERR "Could not register platform HSI driver: %d.\n",
+ result);
+ goto err_dev_register;
+ }
+
+ return result;
+
+ err_dev_register:
+ return result;
+}
+
+module_init(cfhsi_init_module);
+module_exit(cfhsi_exit_module);
diff --git a/include/net/caif/caif_hsi.h b/include/net/caif/caif_hsi.h
new file mode 100644
index 0000000..c5dedd8
--- /dev/null
+++ b/include/net/caif/caif_hsi.h
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ * Contact: Sjur Brendeland / sjur.brandeland@stericsson.com
+ * Author: Daniel Martensson / daniel.martensson@stericsson.com
+ * Dmitry.Tarnyagin / dmitry.tarnyagin@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef CAIF_HSI_H_
+#define CAIF_HSI_H_
+
+#include <net/caif/caif_layer.h>
+#include <net/caif/caif_device.h>
+#include <linux/atomic.h>
+
+/*
+ * Maximum number of CAIF frames that can reside in the same HSI frame.
+ */
+#define CFHSI_MAX_PKTS 15
+
+/*
+ * Maximum number of bytes used for the frame that can be embedded in the
+ * HSI descriptor.
+ */
+#define CFHSI_MAX_EMB_FRM_SZ 96
+
+/*
+ * Decides if HSI buffers should be prefilled with 0xFF pattern for easier
+ * debugging. Both TX and RX buffers will be filled before the transfer.
+ */
+#define CFHSI_DBG_PREFILL 0
+
+/* Structure describing a HSI packet descriptor. */
+#pragma pack(1) /* Byte alignment. */
+struct cfhsi_desc {
+ u8 header;
+ u8 offset;
+ u16 cffrm_len[CFHSI_MAX_PKTS];
+ u8 emb_frm[CFHSI_MAX_EMB_FRM_SZ];
+};
+#pragma pack() /* Default alignment. */
+
+/* Size of the complete HSI packet descriptor. */
+#define CFHSI_DESC_SZ (sizeof(struct cfhsi_desc))
+
+/*
+ * Size of the complete HSI packet descriptor excluding the optional embedded
+ * CAIF frame.
+ */
+#define CFHSI_DESC_SHORT_SZ (CFHSI_DESC_SZ - CFHSI_MAX_EMB_FRM_SZ)
+
+/*
+ * Maximum bytes transferred in one transfer.
+ */
+/* TODO: 4096 is temporary... */
+#define CFHSI_MAX_PAYLOAD_SZ (CFHSI_MAX_PKTS * 4096)
+
+/* Size of the complete HSI TX buffer. */
+#define CFHSI_BUF_SZ_TX (CFHSI_DESC_SZ + CFHSI_MAX_PAYLOAD_SZ)
+
+/* Size of the complete HSI RX buffer. */
+#define CFHSI_BUF_SZ_RX ((2 * CFHSI_DESC_SZ) + CFHSI_MAX_PAYLOAD_SZ)
+
+/* Bitmasks for the HSI descriptor. */
+#define CFHSI_PIGGY_DESC (0x01 << 7)
+
+#define CFHSI_TX_STATE_IDLE 0
+#define CFHSI_TX_STATE_XFER 1
+
+#define CFHSI_RX_STATE_DESC 0
+#define CFHSI_RX_STATE_PAYLOAD 1
+
+/* Bitmasks for power management. */
+#define CFHSI_WAKE_UP 0
+#define CFHSI_WAKE_UP_ACK 1
+#define CFHSI_WAKE_DOWN_ACK 2
+#define CFHSI_AWAKE 3
+#define CFHSI_PENDING_RX 4
+#define CFHSI_SHUTDOWN 6
+#define CFHSI_FLUSH_FIFO 7
+
+#ifndef CFHSI_INACTIVITY_TOUT
+#define CFHSI_INACTIVITY_TOUT (1 * HZ)
+#endif /* CFHSI_INACTIVITY_TOUT */
+
+#ifndef CFHSI_WAKEUP_TOUT
+#define CFHSI_WAKEUP_TOUT (3 * HZ)
+#endif /* CFHSI_WAKEUP_TOUT */
+
+
+/* Structure implemented by the CAIF HSI driver. */
+struct cfhsi_drv {
+ void (*tx_done_cb) (struct cfhsi_drv *drv);
+ void (*rx_done_cb) (struct cfhsi_drv *drv);
+ void (*wake_up_cb) (struct cfhsi_drv *drv);
+ void (*wake_down_cb) (struct cfhsi_drv *drv);
+};
+
+/* Structure implemented by HSI device. */
+struct cfhsi_dev {
+ int (*cfhsi_up) (struct cfhsi_dev *dev);
+ int (*cfhsi_down) (struct cfhsi_dev *dev);
+ int (*cfhsi_tx) (u8 *ptr, int len, struct cfhsi_dev *dev);
+ int (*cfhsi_rx) (u8 *ptr, int len, struct cfhsi_dev *dev);
+ int (*cfhsi_wake_up) (struct cfhsi_dev *dev);
+ int (*cfhsi_wake_down) (struct cfhsi_dev *dev);
+ int (*cfhsi_fifo_occupancy)(struct cfhsi_dev *dev, size_t *occupancy);
+ int (*cfhsi_rx_cancel)(struct cfhsi_dev *dev);
+ struct cfhsi_drv *drv;
+};
+
+/* Structure implemented by CAIF HSI drivers. */
+struct cfhsi {
+ struct caif_dev_common cfdev;
+ struct net_device *ndev;
+ struct platform_device *pdev;
+ struct sk_buff_head qhead;
+ struct cfhsi_drv drv;
+ struct cfhsi_dev *dev;
+ int tx_state;
+ int rx_state;
+ int rx_len;
+ u8 *rx_ptr;
+ u8 *tx_buf;
+ u8 *rx_buf;
+ spinlock_t lock;
+ int flow_off_sent;
+ u32 q_low_mark;
+ u32 q_high_mark;
+ struct list_head list;
+ struct work_struct wake_up_work;
+ struct work_struct wake_down_work;
+ struct work_struct rx_done_work;
+ struct work_struct tx_done_work;
+ struct workqueue_struct *wq;
+ wait_queue_head_t wake_up_wait;
+ wait_queue_head_t wake_down_wait;
+ wait_queue_head_t flush_fifo_wait;
+ struct timer_list timer;
+ unsigned long bits;
+};
+
+extern struct platform_driver cfhsi_driver;
+
+#endif /* CAIF_HSI_H_ */
--
1.7.0.4
^ permalink raw reply related
* Re: [patch net-next-2.6] bonding: allow resetting slave failure counters
From: Flavio Leitner @ 2011-06-01 13:28 UTC (permalink / raw)
To: Jiri Pirko; +Cc: netdev, davem, fubar, andy
In-Reply-To: <1306921249-3623-1-git-send-email-jpirko@redhat.com>
On 06/01/2011 06:40 AM, Jiri Pirko wrote:
> This patch allows to reset failure counters for all enslaved devices.
>
> Signed-off-by: Jiri Pirko <jpirko@redhat.com>
> ---
> Documentation/networking/bonding.txt | 7 +++++++
> drivers/net/bonding/bond_sysfs.c | 27 +++++++++++++++++++++++++++
> 2 files changed, 34 insertions(+), 0 deletions(-)
>
> diff --git a/Documentation/networking/bonding.txt b/Documentation/networking/bonding.txt
> index 675612f..2f51d73 100644
> --- a/Documentation/networking/bonding.txt
> +++ b/Documentation/networking/bonding.txt
> @@ -782,6 +782,13 @@ resend_igmp
>
> This option was added for bonding version 3.7.0.
>
> +reset_failure_counters
> +
> + This write-only control file will zero failure counters for
> + all slaves. Note there is no appropriate module parameter for this
> + since it would not make much sense.
> + Write any value to perform reset.
nit: many options mention when they were added.
i.e. This option was added for bonding version 3.7.1
fbl
> 3. Configuring Bonding Devices
> ==============================
>
> diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
> index 88fcb25..9b45164 100644
> --- a/drivers/net/bonding/bond_sysfs.c
> +++ b/drivers/net/bonding/bond_sysfs.c
> @@ -1572,6 +1572,32 @@ out:
> static DEVICE_ATTR(resend_igmp, S_IRUGO | S_IWUSR,
> bonding_show_resend_igmp, bonding_store_resend_igmp);
>
> +static ssize_t
> +bonding_store_reset_failure_counters(struct device *d,
> + struct device_attribute *attr,
> + const char *buf, size_t count)
> +{
> + struct slave *slave;
> + int i;
> + struct bonding *bond = to_bond(d);
> +
> + if (!rtnl_trylock())
> + return restart_syscall();
> +
> + read_lock(&bond->lock);
> + pr_info("%s: Resetting counters.\n", bond->dev->name);
> + bond_for_each_slave(bond, slave, i)
> + slave->link_failure_count = 0;
> + read_unlock(&bond->lock);
> +
> + rtnl_unlock();
> +
> + return count;
> +}
> +
> +static DEVICE_ATTR(reset_failure_counters, S_IWUSR, NULL,
> + bonding_store_reset_failure_counters);
> +
> static struct attribute *per_bond_attrs[] = {
> &dev_attr_slaves.attr,
> &dev_attr_mode.attr,
> @@ -1600,6 +1626,7 @@ static struct attribute *per_bond_attrs[] = {
> &dev_attr_queue_id.attr,
> &dev_attr_all_slaves_active.attr,
> &dev_attr_resend_igmp.attr,
> + &dev_attr_reset_failure_counters.attr,
> NULL,
> };
>
^ permalink raw reply
* [PATCH 1/1] Fix 802.3az compatible issue
From: Aries Lee @ 2011-06-01 12:50 UTC (permalink / raw)
To: 'David Rehner'; +Cc: 'Guo-Fu Tseng', netdev, devinchiu
The older JMicron NIC chip -- Jme251A, can NOT connect with a linking
partner with "802.3az" feature in 1000M speed.
More specifically speaking, it's HW design has a problem in
auto-negotiation if the linking partner is running 802.3az function.
This "Auto speed down" patch is a software workaround to avoid the user
of older jme chip unable to connect with the linking partner with
802.3az function.
If the NIC is down speed to 100M, everything is fine. But if the NIC is
running by 1000M speed, this problem makes it unable to link up.
The algorithm of this workaround is as following:
Setup a timer to polling when the PHY link status is down, If the
ethernet cable was attached but auto-negotiation has not been
accomplished for a long time (default 11 second), that mean the linking
partner maybe running 802.3az function, driver will try to
connect by 100M speed.
If the link is up, then stop the timer.
Signed-off-by: arieslee <arieslee@jmicron.com>
---
drivers/net/jme.c | 193
++++++++++++++++++++++++++++++++++++++++++++++++++++-
drivers/net/jme.h | 14 ++++
2 files changed, 206 insertions(+), 1 deletions(-)
diff --git a/drivers/net/jme.c b/drivers/net/jme.c
index b5b174a..b76d213 100644
--- a/drivers/net/jme.c
+++ b/drivers/net/jme.c
@@ -47,6 +47,7 @@
static int force_pseudohp = -1;
static int no_pseudohp = -1;
static int no_extplug = -1;
+static int delay_time = 11;
module_param(force_pseudohp, int, 0);
MODULE_PARM_DESC(force_pseudohp,
"Enable pseudo hot-plug feature manually by driver instead of
BIOS.");
@@ -55,6 +56,9 @@ MODULE_PARM_DESC(no_pseudohp, "Disable pseudo hot-plug
feature.");
module_param(no_extplug, int, 0);
MODULE_PARM_DESC(no_extplug,
"Do not use external plug signal for pseudo hot-plug.");
+module_param(delay_time, uint, 0);
+MODULE_PARM_DESC(delay_time,
+ "Seconds to delay before switching lower speed; default = 11
seconds");
static int
jme_mdio_read(struct net_device *netdev, int phy, int reg)
@@ -1289,6 +1293,151 @@ jme_stop_shutdown_timer(struct jme_adapter *jme)
}
static void
+jme_set_physpeed_capability(struct jme_adapter *jme, u16 speed)
+{
+ u32 advert, advert2;
+
+ spin_lock_bh(&jme->phy_lock);
+ if (speed == SPEED_1000) {
+ advert2 = jme_mdio_read(jme->dev,
+ jme->mii_if.phy_id,
+ MII_CTRL1000);
+ advert2 = (advert2|ADVERTISE_1000HALF|ADVERTISE_1000FULL);
+ jme_mdio_write(jme->dev,
+ jme->mii_if.phy_id,
+ MII_CTRL1000,
+ advert2);
+ advert = jme_mdio_read(jme->dev,
+ jme->mii_if.phy_id,
+ MII_ADVERTISE);
+ advert = (advert|ADVERTISE_100HALF|ADVERTISE_100FULL);
+ jme_mdio_write(jme->dev,
+ jme->mii_if.phy_id,
+ MII_ADVERTISE,
+ advert);
+ } else if (speed == SPEED_100) {
+ advert2 = jme_mdio_read(jme->dev,
+ jme->mii_if.phy_id,
+ MII_CTRL1000);
+ advert2 = advert2 &
~(ADVERTISE_1000HALF|ADVERTISE_1000FULL);
+ jme_mdio_write(jme->dev,
+ jme->mii_if.phy_id,
+ MII_CTRL1000,
+ advert2);
+ advert = jme_mdio_read(jme->dev,
+ jme->mii_if.phy_id,
+ MII_ADVERTISE);
+ advert = (advert|ADVERTISE_100HALF|ADVERTISE_100FULL);
+ jme_mdio_write(jme->dev,
+ jme->mii_if.phy_id,
+ MII_ADVERTISE,
+ advert);
+ } else{
+ advert2 = jme_mdio_read(jme->dev,
+ jme->mii_if.phy_id,
+ MII_CTRL1000);
+ advert2 = advert2 &
~(ADVERTISE_1000HALF|ADVERTISE_1000FULL);
+ jme_mdio_write(jme->dev,
+ jme->mii_if.phy_id,
+ MII_CTRL1000,
+ advert2);
+ advert = jme_mdio_read(jme->dev,
+ jme->mii_if.phy_id,
+ MII_ADVERTISE);
+ advert = advert & ~(ADVERTISE_100HALF|ADVERTISE_100FULL);
+ jme_mdio_write(jme->dev,
+ jme->mii_if.phy_id,
+ MII_ADVERTISE,
+ advert);
+ }
+ spin_unlock_bh(&jme->phy_lock);
+ return;
+}
+
+/* PHY reg: MII_FCSCOUNTER is read and clear, we have to continuing
read
+ until RJ45 is attached, then cache this result. */
+static int
+jme_check_ANcomplete(struct jme_adapter *jme)
+{
+ u32 val;
+
+ val = jme_mdio_read(jme->dev, jme->mii_if.phy_id, MII_FCSCOUNTER);
+ return ((val&(PHY_SPEC_STATUS_AN_FAIL|PHY_SPEC_STATUS_AN_COMPLETE))
==
+ PHY_SPEC_STATUS_AN_COMPLETE) ? true : false;
+}
+
+static int
+jme_media_connected(struct jme_adapter *jme)
+{
+ if (jme->flag_media_connected == true)
+ return true;
+
+ jme->flag_media_connected = jme_check_ANcomplete(jme);
+
+ return jme->flag_media_connected;
+}
+
+static void
+asd_polling_func(unsigned long data)
+{
+ struct jme_adapter *jme = (struct jme_adapter *)data;
+
+ /*
+ check condition term by term.
+ 1. link is up()
+ ==> reset all thing, exit the process.
+ 2. there is no RJ45 cable attached.
+ ==> do nothing but polling.
+ 3. RJ45 cable attached. but link is down
+ ==> downspeed if the timeing is over [delay_time]
second.
+ */
+ if (jme->flag_run_asd) {
+ if (jme_media_connected(jme)) {
+ jme->mc_count++;
+ if (jme->mc_count == (delay_time*3 - 5)) {
+ /* RJ45 is attached but unable to link anyway, it CANT
+ be resolved by speed, restore the capability */
+ jme_set_physpeed_capability(jme,
SPEED_1000);
+ jme->flag_media_connected = false;
+ jme->mc_count = 0;
+ } else if (jme->mc_count == (delay_time*2 - 5)) {
+ if (jme_check_ANcomplete(jme))
+ jme_set_physpeed_capability(jme,
SPEED_10);
+ else{
+ jme->flag_media_connected = false;
+ jme->mc_count = 0;
+ }
+ } else if (jme->mc_count == delay_time - 5) {
+ if (jme_check_ANcomplete(jme))
+ jme_set_physpeed_capability(jme,
SPEED_100);
+ else{
+ jme->flag_media_connected = false;
+ jme->mc_count = 0;
+ }
+ }
+ }
+ mod_timer(&jme->asd_timer, jiffies+HZ);
+ return ;
+ }
+
+ jme->flag_media_connected = false;
+ jme->mc_count = 0;
+ return;
+}
+
+static int jme_check_linkup(struct jme_adapter *jme)
+{
+ u32 phylink;
+
+ if (jme->fpgaver)
+ phylink = jme_linkstat_from_phy(jme);
+ else
+ phylink = jread32(jme, JME_PHY_LINK);
+
+ return (phylink & PHY_LINK_UP) ? true : false;
+}
+
+static void
jme_link_change_tasklet(unsigned long arg)
{
struct jme_adapter *jme = (struct jme_adapter *)arg;
@@ -1302,6 +1451,27 @@ jme_link_change_tasklet(unsigned long arg)
netif_info(jme, intr, jme->dev, "Waiting link change
lock\n");
}
+ if (jme_check_linkup(jme)) {
+ if (jme->flag_run_asd) {
+ /* stop asd_polling_timer(); */
+ jme->flag_run_asd = false;
+ del_timer_sync(&jme->asd_timer);
+ }
+ } else {
+ if (!jme->flag_run_asd) {
+ /* start asd_polling_timer() if doesn't linkup in 5 seconds
*/
+ jme_set_physpeed_capability(jme, SPEED_1000);
+ jme_check_ANcomplete(jme);
+ jme->flag_media_connected = false;
+ jme->flag_run_asd = true;
+ jme->mc_count = 0;
+ jme->asd_timer.expires = jiffies + 5*HZ;
+ jme->asd_timer.function = &asd_polling_func;
+ jme->asd_timer.data = (unsigned long)jme;
+ add_timer(&jme->asd_timer);
+ }
+ }
+
if (jme_check_link(netdev, 1) && jme->old_mtu == netdev->mtu)
goto out;
@@ -3086,6 +3256,11 @@ jme_init_one(struct pci_dev *pdev,
goto err_out_unmap;
}
+ init_timer(&(jme->asd_timer));
+ jme->mc_count = 0;
+ jme->flag_run_asd = false;
+ jme->flag_media_connected = false;
+
netif_info(jme, probe, jme->dev, "%s%s chiprev:%x pcirev:%x
macaddr:%pM\n",
(jme->pdev->device == PCI_DEVICE_ID_JMICRON_JMC250) ?
"JMC250 Gigabit Ethernet" :
@@ -3116,6 +3291,9 @@ jme_remove_one(struct pci_dev *pdev)
struct net_device *netdev = pci_get_drvdata(pdev);
struct jme_adapter *jme = netdev_priv(netdev);
+ if (jme->flag_run_asd)
+ del_timer_sync(&jme->asd_timer);
+
unregister_netdev(netdev);
iounmap(jme->regs);
pci_set_drvdata(pdev, NULL);
@@ -3148,6 +3326,9 @@ static int jme_suspend(struct device *dev)
netif_stop_queue(netdev);
jme_stop_irq(jme);
+ if (jme->flag_run_asd)
+ del_timer_sync(&jme->asd_timer);
+
tasklet_disable(&jme->txclean_task);
tasklet_disable(&jme->rxclean_task);
tasklet_disable(&jme->rxempty_task);
@@ -3171,6 +3352,8 @@ static int jme_suspend(struct device *dev)
tasklet_hi_enable(&jme->rxempty_task);
jme_powersave_phy(jme);
+ jme->mc_count = 0;
+ jme->flag_media_connected = false;
return 0;
}
@@ -3196,6 +3379,15 @@ static int jme_resume(struct device *dev)
jme_reset_link(jme);
+ if (jme->flag_run_asd) {
+ jme_set_physpeed_capability(jme, SPEED_1000);
+ jme_check_ANcomplete(jme);
+ jme->asd_timer.expires = jiffies + 5*HZ;
+ jme->asd_timer.function = &asd_polling_func;
+ jme->asd_timer.data = (unsigned long)jme;
+ add_timer(&jme->asd_timer);
+ }
+
return 0;
}
@@ -3243,4 +3435,3 @@ MODULE_DESCRIPTION("JMicron JMC2x0 PCI Express
Ethernet driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);
MODULE_DEVICE_TABLE(pci, jme_pci_tbl);
-
diff --git a/drivers/net/jme.h b/drivers/net/jme.h
index e9aaeca..fee2da2 100644
--- a/drivers/net/jme.h
+++ b/drivers/net/jme.h
@@ -461,6 +461,13 @@ struct jme_adapter {
int (*jme_vlan_rx)(struct sk_buff *skb,
struct vlan_group *grp,
unsigned short vlan_tag);
+ /* Is Auto Speed Down polling function running*/
+ u8 flag_run_asd;
+ /* second counter as RJ45 is attached */
+ u32 mc_count;
+ /* Because PHY 0x13 is read and clear, we need to record it */
+ u8 flag_media_connected;
+ struct timer_list asd_timer;
DECLARE_NAPI_STRUCT
DECLARE_NET_DEVICE_STATS
};
@@ -889,6 +896,13 @@ enum jme_phy_pwr_bit_masks {
* 1: xtl_out = phy_giga.PD_OSC
*/
};
+/*
+ * False carrier Counter
+ */
+enum jme_phy_an_status {
+ PHY_SPEC_STATUS_AN_COMPLETE = 0x00000800,
+ PHY_SPEC_STATUS_AN_FAIL = 0x00008000,
+};
/*
* Giga PHY Status Registers
--
1.7.3.4
^ permalink raw reply related
* RE: [PATCH] TODO FLAG_POINTTOPOINT => FLAG_WWAN? usbnet/cdc_ncm: mark ncm devices as "mobile broadband devices" with FLAG_WWAN
From: Alexey ORISHKO @ 2011-06-01 12:27 UTC (permalink / raw)
To: Stefan (metze) Metzmacher
Cc: Oliver Neukum, Greg Kroah-Hartman, linux-usb@vger.kernel.org,
netdev@vger.kernel.org, linux-kernel@vger.kernel.org
In-Reply-To: <4DE6287D.5080807@samba.org>
> -----Original Message-----
> From: Stefan (metze) Metzmacher [mailto:metze@samba.org]
> Sent: Wednesday, June 01, 2011 1:55 PM
> > If you use udev rules and create an alias for your device, you won't
> > be dependent on generic driver code.
>
> Ok, do you have examples for that?
Please, read udev man pages. Rule might be as follows
KERNEL=="usb*", ATTRS{idVendor}=="04cc", ATTRS{idProduct}=="xxxx", NAME="ste_bridge0"
Regards,
alexey
^ permalink raw reply
* Re: [BUG] net: cpu offline cause napi stall
From: Eric Dumazet @ 2011-06-01 12:13 UTC (permalink / raw)
To: Frank Blaschka; +Cc: davem, netdev, linux-s390, heiko.carstens
In-Reply-To: <20110601103356.GA45482@tuxmaker.boeblingen.de.ibm.com>
Le mercredi 01 juin 2011 à 12:33 +0200, Frank Blaschka a écrit :
> Hi Dave, Eric,
>
> during heavy network load we turn off/on cpus.
> Sometimes this causes a stall on the network device.
> Digging into the dump I found out following:
>
> napi is scheduled but does not run. From the I/O buffers
> and the napi state I see napi/rx_softirq processing has stopped
> because the budget was reached. napi stays in the
> softnet_data poll_list and the rx_softirq was raised again.
>
> I assume at this time the cpu offline comes in.
> the rx softirq is raised/moved to another cpu but napi stays in the poll_list
> of the softnet_data of the now offline cpu.
>
> reviewing dev_cpu_callback (net/core/dev.c) I did not find the poll_list
> is transfered to the new cpu. Do you think this could cause the stall or
> did I miss something?
>
> Thx for your help.
Hi Frank
I believe you are right, I cant see where the poll_list transfert from
dead cpu to online cpu is done.
Do you want to prepare a patch ?
Thanks !
^ permalink raw reply
* [PATCH] usbnet/cdc_ncm: add missing .reset_resume hook
From: Stefan Metzmacher @ 2011-06-01 12:01 UTC (permalink / raw)
To: Oliver Neukum
Cc: Greg Kroah-Hartman, linux-usb, netdev, linux-kernel,
Stefan Metzmacher
In-Reply-To: <1306929701-22861-1-git-send-email-metze@samba.org>
This avoids messages like this after suspend:
cdc_ncm 2-1.4:1.6: no reset_resume for driver cdc_ncm?
cdc_ncm 2-1.4:1.7: no reset_resume for driver cdc_ncm?
cdc_ncm 2-1.4:1.6: usb0: unregister 'cdc_ncm' usb-0000:00:1d.0-1.4, CDC NCM
This is important for the Ericsson F5521gw GSM/UMTS modem.
Otherwise modemmanager looses the fact that the cdc_ncm and cdc_acm devices
belong together.
The cdc_ether module does the same.
Signed-off-by: Stefan Metzmacher <metze@samba.org>
---
drivers/net/usb/cdc_ncm.c | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)
diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c
index cdd3ae4..f33ca6a 100644
--- a/drivers/net/usb/cdc_ncm.c
+++ b/drivers/net/usb/cdc_ncm.c
@@ -54,7 +54,7 @@
#include <linux/usb/usbnet.h>
#include <linux/usb/cdc.h>
-#define DRIVER_VERSION "24-May-2011"
+#define DRIVER_VERSION "01-June-2011"
/* CDC NCM subclass 3.2.1 */
#define USB_CDC_NCM_NDP16_LENGTH_MIN 0x10
@@ -1234,6 +1234,7 @@ static struct usb_driver cdc_ncm_driver = {
.disconnect = cdc_ncm_disconnect,
.suspend = usbnet_suspend,
.resume = usbnet_resume,
+ .reset_resume = usbnet_resume,
.supports_autosuspend = 1,
};
--
1.7.4.1
^ permalink raw reply related
* RE: [PATCH] usbnet/cdc_ncm: add missing .reset_resume hook
From: Stefan Metzmacher @ 2011-06-01 12:01 UTC (permalink / raw)
To: Oliver Neukum; +Cc: Greg Kroah-Hartman, linux-usb, netdev, linux-kernel
In-Reply-To: <2AC7D4AD8BA1C640B4C60C61C8E520153E3C07E568@EXDCVYMBSTM006.EQ1STM.local>
Here comes the patch with the DRIVER_VERSION change.
Are there chances to get this also backported in stable kernel.
I need it for 2.6.38.x (ubuntu 11.04).
metze
^ permalink raw reply
* Re: [PATCH] TODO FLAG_POINTTOPOINT => FLAG_WWAN? usbnet/cdc_ncm: mark ncm devices as "mobile broadband devices" with FLAG_WWAN
From: Stefan (metze) Metzmacher @ 2011-06-01 11:54 UTC (permalink / raw)
To: Alexey ORISHKO
Cc: Oliver Neukum, Greg Kroah-Hartman, linux-usb@vger.kernel.org,
netdev@vger.kernel.org, linux-kernel@vger.kernel.org
In-Reply-To: <2AC7D4AD8BA1C640B4C60C61C8E520153E3C07E64B@EXDCVYMBSTM006.EQ1STM.local>
[-- Attachment #1: Type: text/plain, Size: 472 bytes --]
Am 01.06.2011 13:39, schrieb Alexey ORISHKO:
>> -----Original Message-----
>> From: Stefan (metze) Metzmacher [mailto:metze@samba.org]
>> Sent: Wednesday, June 01, 2011 12:47 PM
>>
>> Would it be possible to add some autodetection for known devices, in a
>> similar way the cdc_ether driver does it.
>
> If you use udev rules and create an alias for your device, you won't
> be dependent on generic driver code.
Ok, do you have examples for that?
metze
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 262 bytes --]
^ permalink raw reply
* Re: KVM induced panic on 2.6.38[2367] & 2.6.39
From: Brad Campbell @ 2011-06-01 11:52 UTC (permalink / raw)
To: CaT
Cc: Avi Kivity, Hugh Dickins, Andrea Arcangeli, Borislav Petkov,
linux-kernel, kvm, linux-mm, netdev
In-Reply-To: <20110601111841.GB3956@zip.com.au>
On 01/06/11 19:18, CaT wrote:
> On Wed, Jun 01, 2011 at 06:53:31PM +0800, Brad Campbell wrote:
>> I rebooted into a netfilter kernel, and did all the steps I'd used
>> on the no-netfilter kernel and it ticked along happily.
>>
>> So the result of the experiment is inconclusive. Having said that,
>> the backtraces certainly smell networky.
>>
>> To get it to crash, I have to start IE in the VM and https to the
>> public address of the machine, which is then redirected by netfilter
>> back into another of the VM's.
>>
>> I can https directly to the other VM's address, but that does not
>> cause it to crash, however without netfilter loaded I can't bounce
>> off the public IP. It's all rather confusing really.
>>
>> What next Sherlock?
>
> I think you're hitting something I've seen. Can you try rewriting
> your firewall rules so that it does not reference any bridge
> interfaces at all. Instead, reference the real interface names
> in their place. I'm betting it wont crash.
>
Unfortunately the only interface that is mentioned by name anywhere in
my firewall is $DMZ (which is ppp0 and not part of any bridge).
All of the nat/dnat and other horrible hacks are based on IP addresses.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply
* RE: [PATCH] TODO FLAG_POINTTOPOINT => FLAG_WWAN? usbnet/cdc_ncm: mark ncm devices as "mobile broadband devices" with FLAG_WWAN
From: Alexey ORISHKO @ 2011-06-01 11:39 UTC (permalink / raw)
To: Stefan (metze) Metzmacher
Cc: Oliver Neukum, Greg Kroah-Hartman, linux-usb@vger.kernel.org,
netdev@vger.kernel.org, linux-kernel@vger.kernel.org
In-Reply-To: <4DE618B7.5070903@samba.org>
> -----Original Message-----
> From: Stefan (metze) Metzmacher [mailto:metze@samba.org]
> Sent: Wednesday, June 01, 2011 12:47 PM
>
> Would it be possible to add some autodetection for known devices, in a
> similar way the cdc_ether driver does it.
If you use udev rules and create an alias for your device, you won't
be dependent on generic driver code.
Regards,
alexey
^ permalink raw reply
* Re: KVM induced panic on 2.6.38[2367] & 2.6.39
From: CaT @ 2011-06-01 11:18 UTC (permalink / raw)
To: Brad Campbell
Cc: Avi Kivity, Hugh Dickins, Andrea Arcangeli, Borislav Petkov,
linux-kernel, kvm, linux-mm, netdev
In-Reply-To: <4DE61A2B.7000008@fnarfbargle.com>
On Wed, Jun 01, 2011 at 06:53:31PM +0800, Brad Campbell wrote:
> I rebooted into a netfilter kernel, and did all the steps I'd used
> on the no-netfilter kernel and it ticked along happily.
>
> So the result of the experiment is inconclusive. Having said that,
> the backtraces certainly smell networky.
>
> To get it to crash, I have to start IE in the VM and https to the
> public address of the machine, which is then redirected by netfilter
> back into another of the VM's.
>
> I can https directly to the other VM's address, but that does not
> cause it to crash, however without netfilter loaded I can't bounce
> off the public IP. It's all rather confusing really.
>
> What next Sherlock?
I think you're hitting something I've seen. Can you try rewriting
your firewall rules so that it does not reference any bridge
interfaces at all. Instead, reference the real interface names
in their place. I'm betting it wont crash.
(netdev added to CC since we're aleady bouncing there)
--
"A search of his car uncovered pornography, a homemade sex aid, women's
stockings and a Jack Russell terrier."
- http://www.dailytelegraph.com.au/news/wacky/indeed/story-e6frev20-1111118083480
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply
* Re: KVM induced panic on 2.6.38[2367] & 2.6.39
From: Avi Kivity @ 2011-06-01 11:09 UTC (permalink / raw)
To: Brad Campbell
Cc: Hugh Dickins, Andrea Arcangeli, Borislav Petkov, linux-kernel,
kvm, linux-mm, netdev
In-Reply-To: <4DE61A2B.7000008@fnarfbargle.com>
On 06/01/2011 01:53 PM, Brad Campbell wrote:
> On 01/06/11 17:41, Avi Kivity wrote:
>> On 06/01/2011 12:40 PM, Avi Kivity wrote:
>>>
>>> bridge and netfilter, IIRC this was also the problem last time.
>>>
>>> Do you have any ebtables loaded?
>
> Never heard of them, but making a cursory check just in case..
>
> brad@srv:/raid10/src/linux-2.6.39$ grep EBTABLE .config
> # CONFIG_BRIDGE_NF_EBTABLES is not set
>
>>> Can you try building a kernel without ebtables? Without netfilter at
>>> all?
>
> Well, without netfilter I can't get it to crash. The problem is
> without netfilter I can't actually use it the way I use it to get it
> to crash.
>
> I rebooted into a netfilter kernel, and did all the steps I'd used on
> the no-netfilter kernel and it ticked along happily.
>
> So the result of the experiment is inconclusive. Having said that, the
> backtraces certainly smell networky.
>
> To get it to crash, I have to start IE in the VM and https to the
> public address of the machine, which is then redirected by netfilter
> back into another of the VM's.
>
> I can https directly to the other VM's address, but that does not
> cause it to crash, however without netfilter loaded I can't bounce off
> the public IP. It's all rather confusing really.
>
> What next Sherlock?
>
Maybe the Sherlocks at netdev@ can tell.
--
error compiling committee.c: too many arguments to function
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply
* [PATCH] caif: Fix race when conditionally taking rtnl lock
From: Sjur Brændeland @ 2011-06-01 10:55 UTC (permalink / raw)
To: David S. Miller, netdev; +Cc: Sjur Brændeland
Take the RTNL lock unconditionally when calling dev_close.
Taking the lock conditionally may cause race conditions.
Signed-off-by: Sjur Brændeland <sjur.brandeland@stericsson.com>
---
net/caif/chnl_net.c | 9 +++------
1 files changed, 3 insertions(+), 6 deletions(-)
diff --git a/net/caif/chnl_net.c b/net/caif/chnl_net.c
index 649ebac..adbb424 100644
--- a/net/caif/chnl_net.c
+++ b/net/caif/chnl_net.c
@@ -139,17 +139,14 @@ static void close_work(struct work_struct *work)
struct chnl_net *dev = NULL;
struct list_head *list_node;
struct list_head *_tmp;
- /* May be called with or without RTNL lock held */
- int islocked = rtnl_is_locked();
- if (!islocked)
- rtnl_lock();
+
+ rtnl_lock();
list_for_each_safe(list_node, _tmp, &chnl_net_list) {
dev = list_entry(list_node, struct chnl_net, list_field);
if (dev->state == CAIF_SHUTDOWN)
dev_close(dev->netdev);
}
- if (!islocked)
- rtnl_unlock();
+ rtnl_unlock();
}
static DECLARE_WORK(close_worker, close_work);
--
1.7.0.4
^ permalink raw reply related
* Re: [PATCH] TODO FLAG_POINTTOPOINT => FLAG_WWAN? usbnet/cdc_ncm: mark ncm devices as "mobile broadband devices" with FLAG_WWAN
From: Stefan (metze) Metzmacher @ 2011-06-01 10:47 UTC (permalink / raw)
To: Alexey ORISHKO
Cc: Oliver Neukum, Greg Kroah-Hartman, linux-usb@vger.kernel.org,
netdev@vger.kernel.org, linux-kernel@vger.kernel.org
In-Reply-To: <2AC7D4AD8BA1C640B4C60C61C8E520153E3C07E583@EXDCVYMBSTM006.EQ1STM.local>
[-- Attachment #1: Type: text/plain, Size: 1338 bytes --]
Am 01.06.2011 12:20, schrieb Alexey ORISHKO:
>> -----Original Message-----
>> From: netdev-owner@vger.kernel.org [mailto:netdev-
>> owner@vger.kernel.org] On Behalf Of Stefan Metzmacher
>> Sent: Wednesday, June 01, 2011 12:09 PM
>
>
>> - .flags = FLAG_POINTTOPOINT | FLAG_NO_SETINT | FLAG_MULTI_PACKET,
>> + .flags = FLAG_WWAN | FLAG_NO_SETINT | FLAG_MULTI_PACKET,
>
> This patch will introduce incompatibility with already existing
> applications, which track usbX devices. As a result, end user
> application will stop working.
The same argument would apply to commits
e1e499eef2200c2a7120c9ebf297d48b195cf887 and
c261344d3ce3edac781f9d3c7eabe2e96d8e8fe8,
while they made it into the upstream kernel.
So I would think that such a change should be ok for a next release,
but without backport to stable branches.
> cdc_ncm driver can also be used for local link terminated in device,
> so wwan would be inappropriate name.
Would it be possible to add some autodetection for known devices,
in a similar way the cdc_ether driver does it.
It's really strange that Ericsson F3507g and Ericsson F5521gw appear as
different kind of devices, while using the same kernel version.
And Ericsson F3507g already changed from usbX to wwanX between 2.6.32
(ubuntu 10.04)
and 2.6.38 (ubuntu 11.04).
metze
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 262 bytes --]
^ permalink raw reply
* [BUG] net: cpu offline cause napi stall
From: Frank Blaschka @ 2011-06-01 10:33 UTC (permalink / raw)
To: davem, eric.dumazet; +Cc: netdev, linux-s390, heiko.carstens
Hi Dave, Eric,
during heavy network load we turn off/on cpus.
Sometimes this causes a stall on the network device.
Digging into the dump I found out following:
napi is scheduled but does not run. From the I/O buffers
and the napi state I see napi/rx_softirq processing has stopped
because the budget was reached. napi stays in the
softnet_data poll_list and the rx_softirq was raised again.
I assume at this time the cpu offline comes in.
the rx softirq is raised/moved to another cpu but napi stays in the poll_list
of the softnet_data of the now offline cpu.
reviewing dev_cpu_callback (net/core/dev.c) I did not find the poll_list
is transfered to the new cpu. Do you think this could cause the stall or
did I miss something?
Thx for your help.
Frank
^ 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