* [patch 2.6.35 17/25] wimax/i2400m: fix incorrect handling of type 2 and 3 RX messages
From: Inaky Perez-Gonzalez @ 2010-05-14 21:45 UTC (permalink / raw)
To: netdev, wimax; +Cc: Prasanna S. Panchamukhi
In-Reply-To: <cover.1273708027.git.inaky.perez-gonzalez@intel.com>
From: Prasanna S. Panchamukhi <prasannax.s.panchamukhi@intel.com>
According to Intel Wimax i3200, i5x50 and i6x60 device specification documents,
the host driver must not reset the device if the normalized sequence numbers
are greater than 1023 for type 2 and type 3 RX messages.
This patch removes the code that incorrectly used to reset the device.
Signed-off-by: Prasanna S. Panchamukhi <prasannax.s.panchamukhi@intel.com>
---
drivers/net/wimax/i2400m/rx.c | 51 +++++++++++++++++++++--------------------
1 files changed, 26 insertions(+), 25 deletions(-)
diff --git a/drivers/net/wimax/i2400m/rx.c b/drivers/net/wimax/i2400m/rx.c
index 71b697f..66f968a 100644
--- a/drivers/net/wimax/i2400m/rx.c
+++ b/drivers/net/wimax/i2400m/rx.c
@@ -743,12 +743,12 @@ unsigned __i2400m_roq_update_ws(struct i2400m *i2400m, struct i2400m_roq *roq,
unsigned new_nws, nsn_itr;
new_nws = __i2400m_roq_nsn(roq, sn);
- if (unlikely(new_nws >= 1024) && d_test(1)) {
- dev_err(dev, "SW BUG? __update_ws new_nws %u (sn %u ws %u)\n",
- new_nws, sn, roq->ws);
- WARN_ON(1);
- i2400m_roq_log_dump(i2400m, roq);
- }
+ /*
+ * For type 2(update_window_start) rx messages, there is no
+ * need to check if the normalized sequence number is greater 1023.
+ * Simply insert and deliver all packets to the host up to the
+ * window start.
+ */
skb_queue_walk_safe(&roq->queue, skb_itr, tmp_itr) {
roq_data_itr = (struct i2400m_roq_data *) &skb_itr->cb;
nsn_itr = __i2400m_roq_nsn(roq, roq_data_itr->sn);
@@ -890,26 +890,27 @@ void i2400m_roq_queue_update_ws(struct i2400m *i2400m, struct i2400m_roq *roq,
i2400m, roq, skb, sn);
len = skb_queue_len(&roq->queue);
nsn = __i2400m_roq_nsn(roq, sn);
+ /*
+ * For type 3(queue_update_window_start) rx messages, there is no
+ * need to check if the normalized sequence number is greater 1023.
+ * Simply insert and deliver all packets to the host up to the
+ * window start.
+ */
old_ws = roq->ws;
- if (unlikely(nsn >= 1024)) {
- dev_err(dev, "SW BUG? queue_update_ws nsn %u (sn %u ws %u)\n",
- nsn, sn, roq->ws);
- i2400m_roq_log_dump(i2400m, roq);
- i2400m_reset(i2400m, I2400M_RT_WARM);
- } else {
- /* if the queue is empty, don't bother as we'd queue
- * it and inmediately unqueue it -- just deliver it */
- if (len == 0) {
- struct i2400m_roq_data *roq_data;
- roq_data = (struct i2400m_roq_data *) &skb->cb;
- i2400m_net_erx(i2400m, skb, roq_data->cs);
- }
- else
- __i2400m_roq_queue(i2400m, roq, skb, sn, nsn);
- __i2400m_roq_update_ws(i2400m, roq, sn + 1);
- i2400m_roq_log_add(i2400m, roq, I2400M_RO_TYPE_PACKET_WS,
- old_ws, len, sn, nsn, roq->ws);
- }
+ /* If the queue is empty, don't bother as we'd queue
+ * it and immediately unqueue it -- just deliver it.
+ */
+ if (len == 0) {
+ struct i2400m_roq_data *roq_data;
+ roq_data = (struct i2400m_roq_data *) &skb->cb;
+ i2400m_net_erx(i2400m, skb, roq_data->cs);
+ } else
+ __i2400m_roq_queue(i2400m, roq, skb, sn, nsn);
+
+ __i2400m_roq_update_ws(i2400m, roq, sn + 1);
+ i2400m_roq_log_add(i2400m, roq, I2400M_RO_TYPE_PACKET_WS,
+ old_ws, len, sn, nsn, roq->ws);
+
d_fnend(2, dev, "(i2400m %p roq %p skb %p sn %u) = void\n",
i2400m, roq, skb, sn);
return;
--
1.6.6.1
^ permalink raw reply related
* [patch 2.6.35 16/25] wimax i2400m: fix race condition while accessing rx_roq by using kref count
From: Inaky Perez-Gonzalez @ 2010-05-14 21:45 UTC (permalink / raw)
To: netdev, wimax; +Cc: Prasanna S. Panchamukhi
In-Reply-To: <cover.1273708027.git.inaky.perez-gonzalez@intel.com>
From: Prasanna S. Panchamukhi <prasannax.s.panchamukhi@intel.com>
This patch fixes the race condition when one thread tries to destroy
the memory allocated for rx_roq, while another thread still happen
to access rx_roq.
Such a race condition occurs when i2400m-sdio kernel module gets
unloaded, destroying the memory allocated for rx_roq while rx_roq
is accessed by i2400m_rx_edata(), as explained below:
$thread1 $thread2
$ void i2400m_rx_edata() $
$Access rx_roq[] $
$roq = &i2400m->rx_roq[ro_cin] $
$ i2400m_roq_[reset/queue/update_ws] $
$ $ void i2400m_rx_release();
$ $kfree(rx->roq);
$ $rx->roq = NULL;
$Oops! rx_roq is NULL
This patch fixes the race condition using refcount approach.
Signed-off-by: Prasanna S. Panchamukhi <prasannax.s.panchamukhi@intel.com>
---
drivers/net/wimax/i2400m/i2400m.h | 12 +++++++--
drivers/net/wimax/i2400m/rx.c | 44 ++++++++++++++++++++++++++++++++----
2 files changed, 48 insertions(+), 8 deletions(-)
diff --git a/drivers/net/wimax/i2400m/i2400m.h b/drivers/net/wimax/i2400m/i2400m.h
index 7a9c2c5..b8c7dbf 100644
--- a/drivers/net/wimax/i2400m/i2400m.h
+++ b/drivers/net/wimax/i2400m/i2400m.h
@@ -412,7 +412,7 @@ struct i2400m_barker_db;
*
* @tx_size_max: biggest TX message sent.
*
- * @rx_lock: spinlock to protect RX members
+ * @rx_lock: spinlock to protect RX members and rx_roq_refcount.
*
* @rx_pl_num: total number of payloads received
*
@@ -436,6 +436,10 @@ struct i2400m_barker_db;
* delivered. Then the driver can release them to the host. See
* drivers/net/i2400m/rx.c for details.
*
+ * @rx_roq_refcount: refcount rx_roq. This refcounts any access to
+ * rx_roq thus preventing rx_roq being destroyed when rx_roq
+ * is being accessed. rx_roq_refcount is protected by rx_lock.
+ *
* @rx_reports: reports received from the device that couldn't be
* processed because the driver wasn't still ready; when ready,
* they are pulled from here and chewed.
@@ -597,10 +601,12 @@ struct i2400m {
tx_num, tx_size_acc, tx_size_min, tx_size_max;
/* RX stuff */
- spinlock_t rx_lock; /* protect RX state */
+ /* protect RX state and rx_roq_refcount */
+ spinlock_t rx_lock;
unsigned rx_pl_num, rx_pl_max, rx_pl_min,
rx_num, rx_size_acc, rx_size_min, rx_size_max;
- struct i2400m_roq *rx_roq; /* not under rx_lock! */
+ struct i2400m_roq *rx_roq; /* access is refcounted */
+ struct kref rx_roq_refcount; /* refcount access to rx_roq */
u8 src_mac_addr[ETH_HLEN];
struct list_head rx_reports; /* under rx_lock! */
struct work_struct rx_report_ws;
diff --git a/drivers/net/wimax/i2400m/rx.c b/drivers/net/wimax/i2400m/rx.c
index fa2e11e..71b697f 100644
--- a/drivers/net/wimax/i2400m/rx.c
+++ b/drivers/net/wimax/i2400m/rx.c
@@ -917,6 +917,25 @@ void i2400m_roq_queue_update_ws(struct i2400m *i2400m, struct i2400m_roq *roq,
/*
+ * This routine destroys the memory allocated for rx_roq, when no
+ * other thread is accessing it. Access to rx_roq is refcounted by
+ * rx_roq_refcount, hence memory allocated must be destroyed when
+ * rx_roq_refcount becomes zero. This routine gets executed when
+ * rx_roq_refcount becomes zero.
+ */
+void i2400m_rx_roq_destroy(struct kref *ref)
+{
+ unsigned itr;
+ struct i2400m *i2400m
+ = container_of(ref, struct i2400m, rx_roq_refcount);
+ for (itr = 0; itr < I2400M_RO_CIN + 1; itr++)
+ __skb_queue_purge(&i2400m->rx_roq[itr].queue);
+ kfree(i2400m->rx_roq[0].log);
+ kfree(i2400m->rx_roq);
+ i2400m->rx_roq = NULL;
+}
+
+/*
* Receive and send up an extended data packet
*
* @i2400m: device descriptor
@@ -969,6 +988,7 @@ void i2400m_rx_edata(struct i2400m *i2400m, struct sk_buff *skb_rx,
unsigned ro_needed, ro_type, ro_cin, ro_sn;
struct i2400m_roq *roq;
struct i2400m_roq_data *roq_data;
+ unsigned long flags;
BUILD_BUG_ON(ETH_HLEN > sizeof(*hdr));
@@ -1007,7 +1027,16 @@ void i2400m_rx_edata(struct i2400m *i2400m, struct sk_buff *skb_rx,
ro_cin = (reorder >> I2400M_RO_CIN_SHIFT) & I2400M_RO_CIN;
ro_sn = (reorder >> I2400M_RO_SN_SHIFT) & I2400M_RO_SN;
+ spin_lock_irqsave(&i2400m->rx_lock, flags);
roq = &i2400m->rx_roq[ro_cin];
+ if (roq == NULL) {
+ kfree_skb(skb); /* rx_roq is already destroyed */
+ spin_unlock_irqrestore(&i2400m->rx_lock, flags);
+ goto error;
+ }
+ kref_get(&i2400m->rx_roq_refcount);
+ spin_unlock_irqrestore(&i2400m->rx_lock, flags);
+
roq_data = (struct i2400m_roq_data *) &skb->cb;
roq_data->sn = ro_sn;
roq_data->cs = cs;
@@ -1034,6 +1063,10 @@ void i2400m_rx_edata(struct i2400m *i2400m, struct sk_buff *skb_rx,
default:
dev_err(dev, "HW BUG? unknown reorder type %u\n", ro_type);
}
+
+ spin_lock_irqsave(&i2400m->rx_lock, flags);
+ kref_put(&i2400m->rx_roq_refcount, i2400m_rx_roq_destroy);
+ spin_unlock_irqrestore(&i2400m->rx_lock, flags);
}
else
i2400m_net_erx(i2400m, skb, cs);
@@ -1344,6 +1377,7 @@ int i2400m_rx_setup(struct i2400m *i2400m)
__i2400m_roq_init(&i2400m->rx_roq[itr]);
i2400m->rx_roq[itr].log = &rd[itr];
}
+ kref_init(&i2400m->rx_roq_refcount);
}
return 0;
@@ -1357,12 +1391,12 @@ error_roq_alloc:
/* Tear down the RX queue and infrastructure */
void i2400m_rx_release(struct i2400m *i2400m)
{
+ unsigned long flags;
+
if (i2400m->rx_reorder) {
- unsigned itr;
- for(itr = 0; itr < I2400M_RO_CIN + 1; itr++)
- __skb_queue_purge(&i2400m->rx_roq[itr].queue);
- kfree(i2400m->rx_roq[0].log);
- kfree(i2400m->rx_roq);
+ spin_lock_irqsave(&i2400m->rx_lock, flags);
+ kref_put(&i2400m->rx_roq_refcount, i2400m_rx_roq_destroy);
+ spin_unlock_irqrestore(&i2400m->rx_lock, flags);
}
/* at this point, nothing can be received... */
i2400m_report_hook_flush(i2400m);
--
1.6.6.1
^ permalink raw reply related
* [patch 2.6.35 19/25] wimax/i2400m: SDIO specific TX queue's minimum buffer room for new message
From: Inaky Perez-Gonzalez @ 2010-05-14 21:45 UTC (permalink / raw)
To: netdev, wimax; +Cc: Prasanna S. Panchamukhi
In-Reply-To: <cover.1273708027.git.inaky.perez-gonzalez@intel.com>
From: Prasanna S. Panchamukhi <prasannax.s.panchamukhi@intel.com>
This patch specifies the TX queue's minimum buffer room required to
accommodate one smallest SDIO payload.
Please refer the documentation in the code.
Signed-off-by: Prasanna S. Panchamukhi <prasannax.s.panchamukhi@intel.com>
---
drivers/net/wimax/i2400m/sdio.c | 7 +++++++
1 files changed, 7 insertions(+), 0 deletions(-)
diff --git a/drivers/net/wimax/i2400m/sdio.c b/drivers/net/wimax/i2400m/sdio.c
index 7632f80..9bfc26e 100644
--- a/drivers/net/wimax/i2400m/sdio.c
+++ b/drivers/net/wimax/i2400m/sdio.c
@@ -483,6 +483,13 @@ int i2400ms_probe(struct sdio_func *func,
sdio_set_drvdata(func, i2400ms);
i2400m->bus_tx_block_size = I2400MS_BLK_SIZE;
+ /*
+ * Room required in the TX queue for SDIO message to accommodate
+ * a smallest payload while allocating header space is 224 bytes,
+ * which is the smallest message size(the block size 256 bytes)
+ * minus the smallest message header size(32 bytes).
+ */
+ i2400m->bus_tx_room_min = I2400MS_BLK_SIZE - I2400M_PL_ALIGN * 2;
i2400m->bus_pl_size_max = I2400MS_PL_SIZE_MAX;
i2400m->bus_setup = i2400ms_bus_setup;
i2400m->bus_dev_start = i2400ms_bus_dev_start;
--
1.6.6.1
^ permalink raw reply related
* [patch 2.6.35 18/25] wimax/i2400m: reserve additional space in the TX queue's buffer while allocating space for a new message header
From: Inaky Perez-Gonzalez @ 2010-05-14 21:45 UTC (permalink / raw)
To: netdev, wimax; +Cc: Prasanna S. Panchamukhi
In-Reply-To: <cover.1273708027.git.inaky.perez-gonzalez@intel.com>
From: Prasanna S. Panchamukhi <prasannax.s.panchamukhi@intel.com>
Increase the possibilities of including at least one payload by reserving
some additional space in the TX queue while allocating TX queue's space
for new message header. Please refer the documentation in the code for details.
Signed-off-by: Prasanna S. Panchamukhi <prasannax.s.panchamukhi@intel.com>
---
drivers/net/wimax/i2400m/i2400m.h | 6 ++++++
drivers/net/wimax/i2400m/tx.c | 11 ++++++++++-
2 files changed, 16 insertions(+), 1 deletions(-)
diff --git a/drivers/net/wimax/i2400m/i2400m.h b/drivers/net/wimax/i2400m/i2400m.h
index b8c7dbf..1babc55 100644
--- a/drivers/net/wimax/i2400m/i2400m.h
+++ b/drivers/net/wimax/i2400m/i2400m.h
@@ -242,6 +242,11 @@ struct i2400m_barker_db;
* so we have a tx_blk_size variable that the bus layer sets to
* tell the engine how much of that we need.
*
+ * @bus_tx_room_min: [fill] Minimum room required while allocating
+ * TX queue's buffer space for message header. SDIO requires
+ * 224 bytes and USB 16 bytes. Refer bus specific driver code
+ * for details.
+ *
* @bus_pl_size_max: [fill] Maximum payload size.
*
* @bus_setup: [optional fill] Function called by the bus-generic code
@@ -573,6 +578,7 @@ struct i2400m {
wait_queue_head_t state_wq; /* Woken up when on state updates */
size_t bus_tx_block_size;
+ size_t bus_tx_room_min;
size_t bus_pl_size_max;
unsigned bus_bm_retries;
diff --git a/drivers/net/wimax/i2400m/tx.c b/drivers/net/wimax/i2400m/tx.c
index 609f1ca..3f819ef 100644
--- a/drivers/net/wimax/i2400m/tx.c
+++ b/drivers/net/wimax/i2400m/tx.c
@@ -563,8 +563,17 @@ void i2400m_tx_new(struct i2400m *i2400m)
struct i2400m_msg_hdr *tx_msg;
bool try_head = 0;
BUG_ON(i2400m->tx_msg != NULL);
+ /*
+ * In certain situations, TX queue might have enough space to
+ * accommodate the new message header I2400M_TX_PLD_SIZE, but
+ * might not have enough space to accommodate the payloads.
+ * Adding bus_tx_room_min padding while allocating a new TX message
+ * increases the possibilities of including at least one payload of the
+ * size <= bus_tx_room_min.
+ */
try_head:
- tx_msg = i2400m_tx_fifo_push(i2400m, I2400M_TX_PLD_SIZE, 0, try_head);
+ tx_msg = i2400m_tx_fifo_push(i2400m, I2400M_TX_PLD_SIZE,
+ i2400m->bus_tx_room_min, try_head);
if (tx_msg == NULL)
goto out;
else if (tx_msg == TAIL_FULL) {
--
1.6.6.1
^ permalink raw reply related
* [patch 2.6.35 20/25] wimax/i2400m: USB specific TX queue's minimum buffer room required for new message
From: Inaky Perez-Gonzalez @ 2010-05-14 21:45 UTC (permalink / raw)
To: netdev, wimax; +Cc: Prasanna S. Panchamukhi
In-Reply-To: <cover.1273708027.git.inaky.perez-gonzalez@intel.com>
From: Prasanna S. Panchamukhi <prasannax.s.panchamukhi@intel.com>
This patch specifies the TX queue's buffer room required by the
USB bus driver while allocating header space for a new message.
Please refer the documentation in the code.
Signed-off-by: Prasanna S. Panchamukhi <prasannax.s.panchamukhi@intel.com>
---
drivers/net/wimax/i2400m/usb.c | 7 +++++++
1 files changed, 7 insertions(+), 0 deletions(-)
diff --git a/drivers/net/wimax/i2400m/usb.c b/drivers/net/wimax/i2400m/usb.c
index d8c4d64..6fd8cf5 100644
--- a/drivers/net/wimax/i2400m/usb.c
+++ b/drivers/net/wimax/i2400m/usb.c
@@ -467,6 +467,13 @@ int i2400mu_probe(struct usb_interface *iface,
usb_set_intfdata(iface, i2400mu);
i2400m->bus_tx_block_size = I2400MU_BLK_SIZE;
+ /*
+ * Room required in the Tx queue for USB message to accommodate
+ * a smallest payload while allocating header space is 16 bytes.
+ * Adding this room for the new tx message increases the
+ * possibilities of including any payload with size <= 16 bytes.
+ */
+ i2400m->bus_tx_room_min = I2400MU_BLK_SIZE;
i2400m->bus_pl_size_max = I2400MU_PL_SIZE_MAX;
i2400m->bus_setup = NULL;
i2400m->bus_dev_start = i2400mu_bus_dev_start;
--
1.6.6.1
^ permalink raw reply related
* [patch 2.6.35 21/25] wimax: checking ERR_PTR vs null
From: Inaky Perez-Gonzalez @ 2010-05-14 21:45 UTC (permalink / raw)
To: netdev, wimax; +Cc: Dan Carpenter
In-Reply-To: <cover.1273708027.git.inaky.perez-gonzalez@intel.com>
From: Dan Carpenter <error27@gmail.com>
stch_skb is allocated with wimax_gnl_re_state_change_alloc(). That
function returns ERR_PTRs on failure and doesn't return NULL.
Signed-off-by: Dan Carpenter <error27@gmail.com>
---
net/wimax/stack.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/net/wimax/stack.c b/net/wimax/stack.c
index 1ed65db..62b1a66 100644
--- a/net/wimax/stack.c
+++ b/net/wimax/stack.c
@@ -315,7 +315,7 @@ void __wimax_state_change(struct wimax_dev *wimax_dev, enum wimax_st new_state)
BUG();
}
__wimax_state_set(wimax_dev, new_state);
- if (stch_skb)
+ if (!IS_ERR(stch_skb))
wimax_gnl_re_state_change_send(wimax_dev, stch_skb, header);
out:
d_fnend(3, dev, "(wimax_dev %p new_state %u [old %u]) = void\n",
--
1.6.6.1
^ permalink raw reply related
* [patch 2.6.35 23/25] wimax/i2400m: Move module params to other file so they can be static
From: Inaky Perez-Gonzalez @ 2010-05-14 21:45 UTC (permalink / raw)
To: netdev, wimax; +Cc: Prasanna S Panchamukhi
In-Reply-To: <cover.1273708027.git.inaky.perez-gonzalez@intel.com>
From: Prasanna S Panchamukhi <prasannax.s.panchamukhi@intel.com>
This patch moves the module parameters to the file where they
can be avoided to be global and allow them to be static.
The module param : idle_mode_disabled and power_save_disabled
are moved from driver.c to control.c. Also these module parameters
are declared to be static as they are not required to be global anymore.
The module param : rx_reorder_disabled is moved from driver.c file to
rx.c file. Also this parameter is declated as static as it is not
required to be global anymore.
Signed-off-by: Prasanna S Panchamukhi<prasannax.s.panchamukhi@intel.com>
---
drivers/net/wimax/i2400m/control.c | 15 +++++++++++++++
drivers/net/wimax/i2400m/driver.c | 19 -------------------
drivers/net/wimax/i2400m/i2400m.h | 6 ------
drivers/net/wimax/i2400m/rx.c | 5 +++++
4 files changed, 20 insertions(+), 25 deletions(-)
diff --git a/drivers/net/wimax/i2400m/control.c b/drivers/net/wimax/i2400m/control.c
index 6180772..0c1aa88 100644
--- a/drivers/net/wimax/i2400m/control.c
+++ b/drivers/net/wimax/i2400m/control.c
@@ -83,6 +83,21 @@
#define D_SUBMODULE control
#include "debug-levels.h"
+static int i2400m_idle_mode_disabled;/* 0 (idle mode enabled) by default */
+module_param_named(idle_mode_disabled, i2400m_idle_mode_disabled, int, 0644);
+MODULE_PARM_DESC(idle_mode_disabled,
+ "If true, the device will not enable idle mode negotiation "
+ "with the base station (when connected) to save power.");
+
+/* 0 (power saving enabled) by default */
+static int i2400m_power_save_disabled;
+module_param_named(power_save_disabled, i2400m_power_save_disabled, int, 0644);
+MODULE_PARM_DESC(power_save_disabled,
+ "If true, the driver will not tell the device to enter "
+ "power saving mode when it reports it is ready for it. "
+ "False by default (so the device is told to do power "
+ "saving).");
+
int i2400m_passive_mode; /* 0 (passive mode disabled) by default */
module_param_named(passive_mode, i2400m_passive_mode, int, 0644);
MODULE_PARM_DESC(passive_mode,
diff --git a/drivers/net/wimax/i2400m/driver.c b/drivers/net/wimax/i2400m/driver.c
index 39cf96a..66bdb5d 100644
--- a/drivers/net/wimax/i2400m/driver.c
+++ b/drivers/net/wimax/i2400m/driver.c
@@ -75,25 +75,6 @@
#include "debug-levels.h"
-int i2400m_idle_mode_disabled; /* 0 (idle mode enabled) by default */
-module_param_named(idle_mode_disabled, i2400m_idle_mode_disabled, int, 0644);
-MODULE_PARM_DESC(idle_mode_disabled,
- "If true, the device will not enable idle mode negotiation "
- "with the base station (when connected) to save power.");
-
-int i2400m_rx_reorder_disabled; /* 0 (rx reorder enabled) by default */
-module_param_named(rx_reorder_disabled, i2400m_rx_reorder_disabled, int, 0644);
-MODULE_PARM_DESC(rx_reorder_disabled,
- "If true, RX reordering will be disabled.");
-
-int i2400m_power_save_disabled; /* 0 (power saving enabled) by default */
-module_param_named(power_save_disabled, i2400m_power_save_disabled, int, 0644);
-MODULE_PARM_DESC(power_save_disabled,
- "If true, the driver will not tell the device to enter "
- "power saving mode when it reports it is ready for it. "
- "False by default (so the device is told to do power "
- "saving).");
-
static char i2400m_debug_params[128];
module_param_string(debug, i2400m_debug_params, sizeof(i2400m_debug_params),
0644);
diff --git a/drivers/net/wimax/i2400m/i2400m.h b/drivers/net/wimax/i2400m/i2400m.h
index 1babc55..fa74777 100644
--- a/drivers/net/wimax/i2400m/i2400m.h
+++ b/drivers/net/wimax/i2400m/i2400m.h
@@ -885,7 +885,6 @@ extern int i2400m_rx(struct i2400m *, struct sk_buff *);
extern struct i2400m_msg_hdr *i2400m_tx_msg_get(struct i2400m *, size_t *);
extern void i2400m_tx_msg_sent(struct i2400m *);
-extern int i2400m_power_save_disabled;
/*
* Utility functions
@@ -992,10 +991,5 @@ extern int i2400m_barker_db_init(const char *);
extern void i2400m_barker_db_exit(void);
-/* Module parameters */
-
-extern int i2400m_idle_mode_disabled;
-extern int i2400m_rx_reorder_disabled;
-
#endif /* #ifndef __I2400M_H__ */
diff --git a/drivers/net/wimax/i2400m/rx.c b/drivers/net/wimax/i2400m/rx.c
index 0004c68..c835ae8 100644
--- a/drivers/net/wimax/i2400m/rx.c
+++ b/drivers/net/wimax/i2400m/rx.c
@@ -155,6 +155,11 @@
#define D_SUBMODULE rx
#include "debug-levels.h"
+static int i2400m_rx_reorder_disabled; /* 0 (rx reorder enabled) by default */
+module_param_named(rx_reorder_disabled, i2400m_rx_reorder_disabled, int, 0644);
+MODULE_PARM_DESC(rx_reorder_disabled,
+ "If true, RX reordering will be disabled.");
+
struct i2400m_report_hook_args {
struct sk_buff *skb_rx;
const struct i2400m_l3l4_hdr *l3l4_hdr;
--
1.6.6.1
^ permalink raw reply related
* [patch 2.6.35 22/25] wimax: wimax_msg_alloc() returns ERR_PTR not null
From: Inaky Perez-Gonzalez @ 2010-05-14 21:45 UTC (permalink / raw)
To: netdev, wimax; +Cc: Dan Carpenter
In-Reply-To: <cover.1273708027.git.inaky.perez-gonzalez@intel.com>
From: Dan Carpenter <error27@gmail.com>
wimax_msg_alloc() returns an ERR_PTR and not null. I changed it to test
for ERR_PTR instead of null. I also added a check in front of the
kfree() because kfree() can handle null but not ERR_PTR.
Signed-off-by: Dan Carpenter <error27@gmail.com>
---
drivers/net/wimax/i2400m/rx.c | 9 ++++-----
1 files changed, 4 insertions(+), 5 deletions(-)
diff --git a/drivers/net/wimax/i2400m/rx.c b/drivers/net/wimax/i2400m/rx.c
index 66f968a..0004c68 100644
--- a/drivers/net/wimax/i2400m/rx.c
+++ b/drivers/net/wimax/i2400m/rx.c
@@ -300,17 +300,16 @@ void i2400m_rx_ctl_ack(struct i2400m *i2400m,
d_printf(1, dev, "Huh? waiter for command reply cancelled\n");
goto error_waiter_cancelled;
}
- if (ack_skb == NULL) {
+ if (IS_ERR(ack_skb))
dev_err(dev, "CMD/GET/SET ack: cannot allocate SKB\n");
- i2400m->ack_skb = ERR_PTR(-ENOMEM);
- } else
- i2400m->ack_skb = ack_skb;
+ i2400m->ack_skb = ack_skb;
spin_unlock_irqrestore(&i2400m->rx_lock, flags);
complete(&i2400m->msg_completion);
return;
error_waiter_cancelled:
- kfree_skb(ack_skb);
+ if (!IS_ERR(ack_skb))
+ kfree_skb(ack_skb);
error_no_waiter:
spin_unlock_irqrestore(&i2400m->rx_lock, flags);
return;
--
1.6.6.1
^ permalink raw reply related
* [patch 2.6.35 24/25] wimax/i2400m: driver defaults to firmware v1.5 for i5x50 devices
From: Inaky Perez-Gonzalez @ 2010-05-14 21:45 UTC (permalink / raw)
To: netdev, wimax
In-Reply-To: <cover.1273708027.git.inaky.perez-gonzalez@intel.com>
Updates the i2400m driver to default to firmware versions v1.5 for the
Intel Wireless WiMAX Connection 5150 and 5350 devices.
Firmware available in linux-firmware.
Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
drivers/net/wimax/i2400m/usb.c | 4 +++-
1 files changed, 3 insertions(+), 1 deletions(-)
diff --git a/drivers/net/wimax/i2400m/usb.c b/drivers/net/wimax/i2400m/usb.c
index 6fd8cf5..f456807 100644
--- a/drivers/net/wimax/i2400m/usb.c
+++ b/drivers/net/wimax/i2400m/usb.c
@@ -82,6 +82,8 @@ MODULE_PARM_DESC(debug,
/* Our firmware file name */
static const char *i2400mu_bus_fw_names_5x50[] = {
+#define I2400MU_FW_FILE_NAME_v1_5 "i2400m-fw-usb-1.5.sbcf"
+ I2400MU_FW_FILE_NAME_v1_5,
#define I2400MU_FW_FILE_NAME_v1_4 "i2400m-fw-usb-1.4.sbcf"
I2400MU_FW_FILE_NAME_v1_4,
NULL,
@@ -785,4 +787,4 @@ MODULE_AUTHOR("Intel Corporation <linux-wimax@intel.com>");
MODULE_DESCRIPTION("Driver for USB based Intel Wireless WiMAX Connection 2400M "
"(5x50 & 6050)");
MODULE_LICENSE("GPL");
-MODULE_FIRMWARE(I2400MU_FW_FILE_NAME_v1_4);
+MODULE_FIRMWARE(I2400MU_FW_FILE_NAME_v1_5);
--
1.6.6.1
^ permalink raw reply related
* [patch 2.6.35 25/25] wimax/i2400m: driver defaults to firmware v1.5 for i6x60 devices
From: Inaky Perez-Gonzalez @ 2010-05-14 21:45 UTC (permalink / raw)
To: netdev, wimax
In-Reply-To: <cover.1273708027.git.inaky.perez-gonzalez@intel.com>
Firmware is available in the linux-firmware package.
Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
drivers/net/wimax/i2400m/usb.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/drivers/net/wimax/i2400m/usb.c b/drivers/net/wimax/i2400m/usb.c
index f456807..16341ff 100644
--- a/drivers/net/wimax/i2400m/usb.c
+++ b/drivers/net/wimax/i2400m/usb.c
@@ -788,3 +788,4 @@ MODULE_DESCRIPTION("Driver for USB based Intel Wireless WiMAX Connection 2400M "
"(5x50 & 6050)");
MODULE_LICENSE("GPL");
MODULE_FIRMWARE(I2400MU_FW_FILE_NAME_v1_5);
+MODULE_FIRMWARE(I6050U_FW_FILE_NAME_v1_5);
--
1.6.6.1
^ permalink raw reply related
* Re: loosing IPMI-card by loading netconsole
From: Tejun Heo @ 2010-05-14 22:11 UTC (permalink / raw)
To: Matt Mackall
Cc: Ronciak, John, Henning Fehrmann, Kirsher, Jeffrey T,
Brandeburg, Jesse, Allan, Bruce W, Waskiewicz Jr, Peter P,
netdev@vger.kernel.org, Carsten Aulbert
In-Reply-To: <1273858653.15067.1335.camel@calx>
Hello,
On 05/14/2010 07:37 PM, Matt Mackall wrote:
>> On 2.6.27.39, netconsole + IPMI works fine. On 2.6.32.7, as soon as
>> netconsole is loaded, IPMI stops working. Unloading netconsole
>> doesn't revive IPMI but detaching the driver from the controller does.
>> In both cases, usual networking works fine.
>
> Looks like a job for bisect.
Yeap, sure, it would be effective but I kind of want to leave
bisection as the last resort. Bisection is a somewhat painful process
especially when the machine isn't right next to you and someone who
has overall knowledge can often identify the problem much easier with
appropriate debugging info.
Thanks.
--
tejun
^ permalink raw reply
* Re: loosing IPMI-card by loading netconsole
From: Matt Mackall @ 2010-05-14 22:16 UTC (permalink / raw)
To: Tejun Heo
Cc: Ronciak, John, Henning Fehrmann, Kirsher, Jeffrey T,
Brandeburg, Jesse, Allan, Bruce W, Waskiewicz Jr, Peter P,
netdev@vger.kernel.org, Carsten Aulbert
In-Reply-To: <4BEDCA89.7000707@kernel.org>
On Sat, 2010-05-15 at 00:11 +0200, Tejun Heo wrote:
> Hello,
>
> On 05/14/2010 07:37 PM, Matt Mackall wrote:
> >> On 2.6.27.39, netconsole + IPMI works fine. On 2.6.32.7, as soon as
> >> netconsole is loaded, IPMI stops working. Unloading netconsole
> >> doesn't revive IPMI but detaching the driver from the controller does.
> >> In both cases, usual networking works fine.
> >
> > Looks like a job for bisect.
>
> Yeap, sure, it would be effective but I kind of want to leave
> bisection as the last resort. Bisection is a somewhat painful process
> especially when the machine isn't right next to you and someone who
> has overall knowledge can often identify the problem much easier with
> appropriate debugging info.
Well nothing jumps to mind in the netpoll/netconsole code and I haven't
heard any similar reports. My guess is it's something obscure, so I
think the sooner you start bisecting... Even one or two tests will get
us a lot closer to figuring out what changed in the last 1.5 years.
--
Mathematics is the supreme nostalgia of our time.
^ permalink raw reply
* Re: loosing IPMI-card by loading netconsole
From: Tejun Heo @ 2010-05-14 22:18 UTC (permalink / raw)
To: Brandeburg, Jesse
Cc: e1000-devel, netdev@vger.kernel.org, Allan, Bruce W,
Henning Fehrmann, Ronciak, John, Kirsher, Jeffrey T, Matt Mackall,
Carsten Aulbert
In-Reply-To: <1273857641.3057.20.camel@localhost.localdomain>
Hello,
On 05/14/2010 07:20 PM, "Brandeburg, Jesse" wrote:
> On Fri, 2010-05-14 at 09:27 -0700, Tejun Heo wrote:
> We've actually had quite a few problems like this over the years, so I'm
> not quite so surprised to hear about something like this.
>
> Its easy to break the reception of IPMI packets because there are a
> couple of registers that if not correctly configured during all points
> of driver lifetime (probe only, administratively down, up)
Heh... yeah, haven't heard a lot of kind things about IPMI. IPMI
which shares the usual network connection seems like a good idea on
paper but doesn't really seem to work as expected. It is a pretty
backward idea to have low level debugging / management mechanism
depending on all the highlevel stuff working correctly.
> One thing that would really help us is to see the stats from ethtool -S
> ethX when interface is up, and not receiving IPMI
>
> The other "smoking gun" indicator is the output of the register dump
> tool called ethregs that we have posted at sourceforge. Please gather
> registers for the card in question before and after loading netconsole.
>
> http://prdownloads.sf.net/e1000/ethregs-1.7.2.tar.gz
I think Henning would be able to provide these info early next week.
>> On 2.6.27.39, netconsole + IPMI works fine. On 2.6.32.7, as soon as
>> netconsole is loaded, IPMI stops working. Unloading netconsole
>> doesn't revive IPMI but detaching the driver from the controller does.
>> In both cases, usual networking works fine.
>
> I think that "loading netconsole" means bringing the interface "UP", in
> this case, is this correct?
Nope, modprobing the netconsole module. Usual networking and IPMI
work happily together until netconsole is loaded. The weird thing tho
is that Henning is reporting that IPMI is using different interface
from the netconsole. No idea how they could interfact.
> To ask another way: Is network traffic active on the interface in
> question before netconsole is loaded?
So, yeap.
Thanks.
--
tejun
------------------------------------------------------------------------------
_______________________________________________
E1000-devel mailing list
E1000-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/e1000-devel
To learn more about Intel® Ethernet, visit http://communities.intel.com/community/wired
^ permalink raw reply
* Re: loosing IPMI-card by loading netconsole
From: Tejun Heo @ 2010-05-14 22:24 UTC (permalink / raw)
To: Matt Mackall
Cc: Ronciak, John, Henning Fehrmann, Kirsher, Jeffrey T,
Brandeburg, Jesse, Allan, Bruce W, Waskiewicz Jr, Peter P,
netdev@vger.kernel.org, Carsten Aulbert
In-Reply-To: <1273875413.15067.1348.camel@calx>
Hello,
On 05/15/2010 12:16 AM, Matt Mackall wrote:
>> Yeap, sure, it would be effective but I kind of want to leave
>> bisection as the last resort. Bisection is a somewhat painful process
>> especially when the machine isn't right next to you and someone who
>> has overall knowledge can often identify the problem much easier with
>> appropriate debugging info.
>
> Well nothing jumps to mind in the netpoll/netconsole code and I haven't
> heard any similar reports. My guess is it's something obscure, so I
> think the sooner you start bisecting... Even one or two tests will get
> us a lot closer to figuring out what changed in the last 1.5 years.
I see. I was hoping it would ring a bell to someone. We'll probably
try to provide the info Jesse asked and if that doesn't lead anywhere
start bisecting.
Thank you.
--
tejun
^ permalink raw reply
* Re: TSC unstable due to TSC halts in idle?
From: john stultz @ 2010-05-14 22:28 UTC (permalink / raw)
To: Jesper Dangaard Brouer
Cc: Thomas Gleixner, linux-kernel, netdev, Len Brown, Shaohua Li,
hawk
In-Reply-To: <Pine.LNX.4.64.1005142208290.6220@ask.diku.dk>
On Fri, May 14, 2010 at 1:13 PM, Jesper Dangaard Brouer <hawk@diku.dk> wrote:
> I want to know, if its safe to enable the TSC clocksource, when the
> kernel reports:
> "Marking TSC unstable due to TSC halts in idle"
>
> The system selects HPET (in current_clocksource), but I can still see
> TSC as an available clocksource (in
> /sys/devices/system/clocksource/clocksource0/available_clocksource).
>
> Is it safe to enable TSC manually (by changing current_clocksource)?
> (my workload is 10Git/s routing, cannot survive with a slow clock)
>
>
> Any trick to avoid this? (e.g. kernel config setting, or a /sys/ setting
> which changes the minimum P-state?)
Might try booting with the max-cstate=1 option.
thanks
-john
^ permalink raw reply
* Weird TCP retransmit behaviour in recent kernels
From: Michael Smith @ 2010-05-14 23:01 UTC (permalink / raw)
To: netdev
Hi,
I'm struggling with TCP sessions stalling when Windows XP SP2 clients
connect to a SUSE Linux Enterprise 11 server (kernel 2.6.27.x). The
problem doesn't occur with kernel 2.6.18.8 on the server, and I'm
wondering if something's changed since then in the retransmit logic.
It seems like when consecutive packets are lost, the SLES11
server retransmits the first packet when the timeout fires. The client
ACKs, but the server doesn't retransmit the next lost packet; instead,
it sends a couple more new packets, which don't get ACKed. The new
packets don't show up in Wireshark - either something in the network is
dropping them, or maybe Windows doesn't forward them to WinPcap because
there's a hole in the sequence. The timeout fires again after double
the time, and the second packet is retransmitted and ACKed, then
more brand new packets are sent out. The transfer quickly grinds to a
halt.
There's a WAN and VPN between the clients and the server. HTTP downloads
from the server stall at various points depending on the client. The
point at which the connection stalls seems to be dependent on latency.
For example, if the RTT to the client is 12 ms, the connection might
usually stall after 120 KB; if it's 20 ms, it might stall at 1200 KB.
The problem doesn't occur when a Windows client talks to a Windows
server. When a Linux client talks to the SLES11 server, the connection
doesn't stall completely but slows to a crawl (~3 KB/sec, as opposed to
typical 50-200 KB/sec).
I was able to work around the problem for most clients by locking the
TCP congestion window to a maximum of 6 on the SLES11 server. Some sites
are pathologically bad and the connection stalls unless I lock the
congestion window to 1 (!!).
I've put up a couple of sample traces from a pathological site where
the problem shows up with cwnd locked to 3:
http://www.hurts.ca/sles11.router.pcap.gz - view from the server's firewall
http://www.hurts.ca/sles11.windows.pcap.gz - view from a client PC
On the firewall, you can see the problem around packets 93-104. The server
sends sequence 66781, 68041, 69301; retransmits 66781, gets an ACK, then
sends 70561, 71821; retransmits 68041, gets an ACK, then sends 73081,
74341, and so on. On the client, the "future" sequence packets after
the ACK never show up in Wireshark.
I've tried all of the obvious things:
- disabling TCP segment/checksum offloading functions on client and server;
- disabling SACK;
- trying all available congestion control algorithms on SLES11
(cubic, reno, veno, illinois);
- turning off anti-virus on the client.
The only 100% reliable workaround seems to be to proxy the connections
through a kernel 2.6.18.8 machine on the same subnet. It seems like
the problem exists with a vanilla 2.6.31 kernel, too.
Has anyone seen something like this before? Any ideas where to go next?
I'm pretty sure there's nothing strange in the network - just plain old
Cisco routers and site-to-site VPNs.
Thanks,
Mike
PS: the frame with the HTTP request will show as having a bad checksum
because I hand edited the IP in the Host: header, poorly. Also, the
transfer recovered briefly about 231 seconds in - I couldn't figure out
why, but the SLES11 server finally filled in the sequence hole for a
bit.
^ permalink raw reply
* Re: TSC unstable due to TSC halts in idle?
From: Suresh Siddha @ 2010-05-14 23:15 UTC (permalink / raw)
To: john stultz
Cc: Jesper Dangaard Brouer, Thomas Gleixner,
linux-kernel@vger.kernel.org, netdev, Brown, Len, Li, Shaohua,
hawk@comx.dk
In-Reply-To: <AANLkTimeXEaUnzSBuilbQLHj_oho3ia9EgyPGpB7vJRI@mail.gmail.com>
On Fri, 2010-05-14 at 15:28 -0700, john stultz wrote:
> On Fri, May 14, 2010 at 1:13 PM, Jesper Dangaard Brouer <hawk@diku.dk> wrote:
> > I want to know, if its safe to enable the TSC clocksource, when the
> > kernel reports:
> > "Marking TSC unstable due to TSC halts in idle"
> >
> > The system selects HPET (in current_clocksource), but I can still see
> > TSC as an available clocksource (in
> > /sys/devices/system/clocksource/clocksource0/available_clocksource).
> >
> > Is it safe to enable TSC manually (by changing current_clocksource)?
> > (my workload is 10Git/s routing, cannot survive with a slow clock)
> >
> >
> > Any trick to avoid this? (e.g. kernel config setting, or a /sys/ setting
> > which changes the minimum P-state?)
>
> Might try booting with the max-cstate=1 option.
Jesper mentioned that it is xeon 5550. TSC's for that processor doesn't
stop in idle. Perhaps he is using an older kernel which doesn't detect
this fact. Jesper, more recent kernels should be able to use TSC as the
clocksource.
thanks,
suresh
^ permalink raw reply
* Re: [PATCH 2.6.34-rc6] net: Improve ks8851 snl transmit performance
From: Bill Fink @ 2010-05-14 23:22 UTC (permalink / raw)
To: Ha, Tristram
Cc: Arce, Abraham, Ben Dooks, David Miller, netdev, linux-kernel,
Jan, Sebastien
In-Reply-To: <14385191E87B904DBD836449AA30269D021A66@MORGANITE.micrel.com>
On Wed, 12 May 2010, Ha, Tristram wrote:
> I use a web browser to send patches through my company's e-mail system. The message is composed by cut and paste, so it may not conform to Linux standard.
>
> The latest nuttcp default size for UDP is 1500 bytes, rather than 8192 bytes. In my case, the transmit performance improves from 10 Mbps to 11. Have you tried TCP?
Just a nuttcp correction. The default unicast UDP buflen in any
recent nuttcp is the largest power of 2 less than the MSS of the
control connection. This means that the default UDP buflen for a
1500 byte MTU link is 1024, while for 9000 byte jumbo capable
networks it would be 8192. This was done to avoid IP fragmentation
by default in most common scenarios (can be overridden by explicitly
setting the buflen with the "-l" nuttcp option).
-Bill
> -----Original Message-----
> From: Arce, Abraham [mailto:x0066660@ti.com]
> Sent: Thu 5/6/2010 10:02 PM
> To: Ha, Tristram; Ben Dooks
> Cc: David Miller; netdev@vger.kernel.org; linux-kernel@vger.kernel.org; Jan, Sebastien
> Subject: RE: [PATCH 2.6.34-rc6] net: Improve ks8851 snl transmit performance
>
> Hi,
>
> [snip]
>
> > There is a driver option no_tx_opt so that the driver can revert to original
> > implementation. This allows user to verify if the transmit performance
> > actually improves.
>
> Should we limit patch description to 80 characters also?
>
> > Signed-off-by: Tristram Ha <Tristram.Ha@micrel.com>
> > ---
> > This replaces the [patch 01/13] patch I submitted and was objected by David.
> >
> > Other users with Micrel KSZ8851 SNL chip please verify the transmit
> > performance does improve or not.
>
> Tested-by: Abraham Arce <x0066660@ti.com>
>
> Executing some nuttcp scenarios:
>
> - Without Patch -
>
> # /testsuites/ethernet/bin/nuttcp -u -i -Ri50m <serverip>
> 1.2676 MB / 1.00 sec = 10.6330 Mbps 0 / 1298 ~drop/pkt 0.00 ~%loss
> 1.2705 MB / 1.00 sec = 10.6579 Mbps 0 / 1301 ~drop/pkt 0.00 ~%loss
> 1.2686 MB / 1.00 sec = 10.6414 Mbps 0 / 1299 ~drop/pkt 0.00 ~%loss
> 1.2695 MB / 1.00 sec = 10.6496 Mbps 0 / 1300 ~drop/pkt 0.00 ~%loss
> 1.2695 MB / 1.00 sec = 10.6496 Mbps 0 / 1300 ~drop/pkt 0.00 ~%loss
> 1.2686 MB / 1.00 sec = 10.6414 Mbps 0 / 1299 ~drop/pkt 0.00 ~%loss
> 1.2686 MB / 1.00 sec = 10.6414 Mbps 0 / 1299 ~drop/pkt 0.00 ~%loss
> 1.2646 MB / 1.00 sec = 10.6086 Mbps 0 / 1295 ~drop/pkt 0.00 ~%loss
> 1.2686 MB / 1.00 sec = 10.6412 Mbps 0 / 1299 ~drop/pkt 0.00 ~%loss
> 1.2695 MB / 1.00 sec = 10.6498 Mbps 0 / 1300 ~drop/pkt 0.00 ~%loss
>
> 12.7314 MB / 10.02 sec = 10.6637 Mbps 4 %TX 0 %RX 0 / 13037 drop/pkt 0.00 %loss
>
> - With Patch -
>
> # /testsuites/ethernet/bin/nuttcp -u -i -Ri50m 10.87.231.229
> 1.2891 MB / 1.00 sec = 10.8133 Mbps 0 / 1320 ~drop/pkt 0.00 ~%loss
> 1.2900 MB / 1.00 sec = 10.8217 Mbps 0 / 1321 ~drop/pkt 0.00 ~%loss
> 1.2900 MB / 1.00 sec = 10.8217 Mbps 0 / 1321 ~drop/pkt 0.00 ~%loss
> 1.2910 MB / 1.00 sec = 10.8298 Mbps 0 / 1322 ~drop/pkt 0.00 ~%loss
> 1.2910 MB / 1.00 sec = 10.8299 Mbps 0 / 1322 ~drop/pkt 0.00 ~%loss
> 1.2900 MB / 1.00 sec = 10.8216 Mbps 0 / 1321 ~drop/pkt 0.00 ~%loss
> 1.2900 MB / 1.00 sec = 10.8216 Mbps 0 / 1321 ~drop/pkt 0.00 ~%loss
> 1.2891 MB / 1.00 sec = 10.8135 Mbps 0 / 1320 ~drop/pkt 0.00 ~%loss
> 1.2900 MB / 1.00 sec = 10.8216 Mbps 0 / 1321 ~drop/pkt 0.00 ~%loss
> 1.2910 MB / 1.00 sec = 10.8298 Mbps 0 / 1322 ~drop/pkt 0.00 ~%loss
>
> 12.9492 MB / 10.02 sec = 10.8461 Mbps 4 %TX 0 %RX 0 / 13260 drop/pkt 0.00
> %loss
>
> Also simulated heavy transmission consisting of 40 processes executed in parallel:
>
> - 20 ping instances using packet size of 32768
> - 20 dd instances creating a 50MB file each under the nfs rootfs
>
> If any specific test scenario/application is required please do let me know...
>
> Best Regards
> Abraham
^ permalink raw reply
* Re: [net-next-2.6 V7 PATCH 1/2] Add netlink support for virtual port management (was iovnl)
From: Chris Wright @ 2010-05-14 23:43 UTC (permalink / raw)
To: Williams, Mitch A
Cc: Patrick McHardy, Chris Wright, Scott Feldman, Arnd Bergmann,
davem@davemloft.net, shemminger@vyatta.com,
netdev@vger.kernel.org
In-Reply-To: <EA929A9653AAE14F841771FB1DE5A1365FF39989D4@rrsmsx501.amr.corp.intel.com>
Hi Mitch,
* Williams, Mitch A (mitch.a.williams@intel.com) wrote:
> I'd really like to find a way to fix this, instead of having the functionality disabled.
I've got some patches that are close to complete. I'll post them
shortly. I'm able to query link from ip at this point.
thanks,
-chris
^ permalink raw reply
* Re: mmotm 2010-05-11 - dies in pm_qos_update_request()
From: mark gross @ 2010-05-14 23:43 UTC (permalink / raw)
To: Rafael J. Wysocki
Cc: Valdis.Kletnieks, Andrew Morton, David S. Miller, linux-kernel,
e1000-devel, netdev
In-Reply-To: <201005140024.50279.rjw@sisk.pl>
On Fri, May 14, 2010 at 12:24:50AM +0200, Rafael J. Wysocki wrote:
> On Thursday 13 May 2010, Valdis.Kletnieks@vt.edu wrote:
> > On Wed, 12 May 2010 23:07:20 +0200, "Rafael J. Wysocki" said:
> > > On Wednesday 12 May 2010, Valdis.Kletnieks@vt.edu wrote:
> > > > On Tue, 11 May 2010 18:21:22 PDT, akpm@linux-foundation.org said:
> > > > > The mm-of-the-moment snapshot 2010-05-11-18-20 has been uploaded to
> > > > >
> > > > > http://userweb.kernel.org/~akpm/mmotm/
> > > >
> > > > Dell Latitude E6500, x86_64 kernel.
> > > >
> > > > Died a horrid death at boot in the e1000e driver. Seems to be
> > > > something in linux-next.patch. Didn't get a netconsole trace for obvious
> > > > reasons...
> > > >
> > > > Copied-by-hand traceback:
> > > > pm_qos_update_request()+0x22
> > > > e1000_configure+0x478
> > > > e1000_open_device+0xee
> > > > ? _raw_notifier_call_chain+0xf
> > > > __dev_open+0xec
> > > > dev_open+0x1b
> > > > netpoll_setup+0x28b
> > > > init_netconsole+0xbc
> > > >
> > > > I suspect this commit:
> > > >
> > > > commit 23606cf5d1192c2b17912cb2ef6e62f9b11de133
> > > > Author: Rafael J. Wysocki <rjw@sisk.pl>
> > > > Date: Sun Mar 14 14:35:17 2010 +0000
> > > >
> > > > e1000e / PCI / PM: Add basic runtime PM support (rev. 4)
> > >
> > > No, I don't think so. I'm running -rc6 with this patch applied on a box with
> > > e1000e and it works just fine.
> > >
> > > Please try to revert this one instead:
> > >
> > > http://git.kernel.org/?p=linux/kernel/git/rafael/suspend-2.6.git;a=patch;h=ed77134bfccf5e75b6cbadab268e559dbe6a4ebb
> >
> > Confirming - reverting that patch and doing the build fixup results in a
> > kernel that doesn't blow up in the e1000e driver...
>
> Then I guess there's an initializations problem somewhere.
>
> Mark, any chance to look into that any time soon? If we don't resolve this
> before the merge window opens, I'm afraid I'll have to revert that commit
> from my tree.
>
I'll look at it right away.
I think I have an e1000e in my home box.
--mgross
^ permalink raw reply
* [PATCH] tbf: stop wanton destruction of children (v2)
From: Stephen Hemminger @ 2010-05-15 0:38 UTC (permalink / raw)
To: Patrick McHardy; +Cc: David Miller, netdev
In-Reply-To: <4BEC2936.2060800@trash.net>
Several netem users use TBF for rate control. But every time the parameters
of TBF are changed it destroys the child qdisc, requiring reconfigation.
Better to just keep child qdisc and just notify it of changed limit.
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
--- a/net/sched/sch_tbf.c 2010-05-14 15:04:56.297095729 -0700
+++ b/net/sched/sch_tbf.c 2010-05-14 15:09:57.296733332 -0700
@@ -273,7 +273,11 @@ static int tbf_change(struct Qdisc* sch,
if (max_size < 0)
goto done;
- if (qopt->limit > 0) {
+ if (q->qdisc != &noop_qdisc) {
+ err = fifo_set_limit(q->qdisc, qopt->limit);
+ if (err)
+ goto done;
+ } else if (qopt->limit > 0) {
child = fifo_create_dflt(sch, &bfifo_qdisc_ops, qopt->limit);
if (IS_ERR(child)) {
err = PTR_ERR(child);
^ permalink raw reply
* [net-next-2.6 V8 PATCH 0/2] Add virtual port netlink support
From: Scott Feldman @ 2010-05-15 1:04 UTC (permalink / raw)
To: davem; +Cc: netdev, chrisw, arnd, kaber
[Add symmetrical set/get layout per Patrick McHardy suggestions]
The following series adds virtual port netlink support and adds an
implementation to Cisco's enic netdev driver:
1/2: Adds virtual netlink RTM_SETLINK/RTM_GETLINK support, and
adds matching netdev ops net_{set|get}_vf_port.
2/2: Adds enic support for net_{set|get}_vf_port for enic
dynamic devices.
Signed-off-by: Scott Feldman <scofeldm@cisco.com>
Signed-off-by: Roopa Prabhu<roprabhu@cisco.com>
^ permalink raw reply
* [net-next-2.6 V8 PATCH 1/2] Add netlink support for virtual port management (was iovnl)
From: Scott Feldman @ 2010-05-15 1:04 UTC (permalink / raw)
To: davem; +Cc: netdev, chrisw, arnd, kaber
In-Reply-To: <20100515010415.21260.35219.stgit@savbu-pc100.cisco.com>
From: Scott Feldman <scofeldm@cisco.com>
Add new netdev ops ndo_{set|get}_vf_port to allow setting of
port-profile on a netdev interface. Extends netlink socket RTM_SETLINK/
RTM_GETLINK with two new sub msgs called IFLA_VF_PORTS and IFLA_PORT_SELF
(added to end of IFLA_cmd list). These are both nested atrtibutes
using this layout:
[IFLA_NUM_VF]
[IFLA_VF_PORTS]
[IFLA_VF_PORT]
[IFLA_PORT_*], ...
[IFLA_VF_PORT]
[IFLA_PORT_*], ...
...
[IFLA_PORT_SELF]
[IFLA_PORT_*], ...
These attributes are design to be set and get symmetrically. VF_PORTS
is a list of VF_PORTs, one for each VF, when dealing with an SR-IOV
device. PORT_SELF is for the PF of the SR-IOV device, in case it wants
to also have a port-profile, or for the case where the VF==PF, like in
enic patch 2/2 of this patch set.
A port-profile is used to configure/enable the external switch virtual port
backing the netdev interface, not to configure the host-facing side of the
netdev. A port-profile is an identifier known to the switch. How port-
profiles are installed on the switch or how available port-profiles are
made know to the host is outside the scope of this patch.
There are two types of port-profiles specs in the netlink msg. The first spec
is for 802.1Qbg (pre-)standard, VDP protocol. The second spec is for devices
that run a similar protocol as VDP but in firmware, thus hiding the protocol
details. In either case, the specs have much in common and makes sense to
define the netlink msg as the union of the two specs. For example, both specs
have a notition of associating/deassociating a port-profile. And both specs
require some information from the hypervisor manager, such as client port
instance ID.
The general flow is the port-profile is applied to a host netdev interface
using RTM_SETLINK, the receiver of the RTM_SETLINK msg communicates with the
switch, and the switch virtual port backing the host netdev interface is
configured/enabled based on the settings defined by the port-profile. What
those settings comprise, and how those settings are managed is again
outside the scope of this patch, since this patch only deals with the
first step in the flow.
Signed-off-by: Scott Feldman <scofeldm@cisco.com>
Signed-off-by: Roopa Prabhu<roprabhu@cisco.com>
---
include/linux/if_link.h | 75 ++++++++++++++++++++
include/linux/netdevice.h | 8 ++
net/core/rtnetlink.c | 169 +++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 251 insertions(+), 1 deletions(-)
diff --git a/include/linux/if_link.h b/include/linux/if_link.h
index cfd420b..c4e80da 100644
--- a/include/linux/if_link.h
+++ b/include/linux/if_link.h
@@ -116,6 +116,8 @@ enum {
IFLA_VF_TX_RATE, /* TX Bandwidth Allocation */
IFLA_VFINFO,
IFLA_STATS64,
+ IFLA_VF_PORTS,
+ IFLA_PORT_SELF,
__IFLA_MAX
};
@@ -259,4 +261,77 @@ struct ifla_vf_info {
__u32 qos;
__u32 tx_rate;
};
+
+/* VF ports management section
+ *
+ * Nested layout of set/get msg is:
+ *
+ * [IFLA_NUM_VF]
+ * [IFLA_VF_PORTS]
+ * [IFLA_VF_PORT]
+ * [IFLA_PORT_*], ...
+ * [IFLA_VF_PORT]
+ * [IFLA_PORT_*], ...
+ * ...
+ * [IFLA_PORT_SELF]
+ * [IFLA_PORT_*], ...
+ */
+
+enum {
+ IFLA_VF_PORT_UNSPEC,
+ IFLA_VF_PORT, /* nest */
+ __IFLA_VF_PORT_MAX,
+};
+
+#define IFLA_VF_PORT_MAX (__IFLA_VF_PORT_MAX - 1)
+
+enum {
+ IFLA_PORT_UNSPEC,
+ IFLA_PORT_VF, /* __u32 */
+ IFLA_PORT_PROFILE, /* string */
+ IFLA_PORT_VSI_TYPE, /* 802.1Qbg (pre-)standard VDP */
+ IFLA_PORT_INSTANCE_UUID, /* binary UUID */
+ IFLA_PORT_HOST_UUID, /* binary UUID */
+ IFLA_PORT_REQUEST, /* __u8 */
+ IFLA_PORT_RESPONSE, /* __u16, output only */
+ __IFLA_PORT_MAX,
+};
+
+#define IFLA_PORT_MAX (__IFLA_PORT_MAX - 1)
+
+#define PORT_PROFILE_MAX 40
+#define PORT_UUID_MAX 16
+#define PORT_SELF_VF -1
+
+enum {
+ PORT_REQUEST_PREASSOCIATE = 0,
+ PORT_REQUEST_PREASSOCIATE_RR,
+ PORT_REQUEST_ASSOCIATE,
+ PORT_REQUEST_DISASSOCIATE,
+};
+
+enum {
+ PORT_VDP_RESPONSE_SUCCESS = 0,
+ PORT_VDP_RESPONSE_INVALID_FORMAT,
+ PORT_VDP_RESPONSE_INSUFFICIENT_RESOURCES,
+ PORT_VDP_RESPONSE_UNUSED_VTID,
+ PORT_VDP_RESPONSE_VTID_VIOLATION,
+ PORT_VDP_RESPONSE_VTID_VERSION_VIOALTION,
+ PORT_VDP_RESPONSE_OUT_OF_SYNC,
+ /* 0x08-0xFF reserved for future VDP use */
+ PORT_PROFILE_RESPONSE_SUCCESS = 0x100,
+ PORT_PROFILE_RESPONSE_INPROGRESS,
+ PORT_PROFILE_RESPONSE_INVALID,
+ PORT_PROFILE_RESPONSE_BADSTATE,
+ PORT_PROFILE_RESPONSE_INSUFFICIENT_RESOURCES,
+ PORT_PROFILE_RESPONSE_ERROR,
+};
+
+struct ifla_port_vsi {
+ __u8 vsi_mgr_id;
+ __u8 vsi_type_id[3];
+ __u8 vsi_type_version;
+ __u8 pad[3];
+};
+
#endif /* _LINUX_IF_LINK_H */
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 69022d4..324f6b8 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -686,6 +686,9 @@ struct netdev_rx_queue {
* int (*ndo_set_vf_tx_rate)(struct net_device *dev, int vf, int rate);
* int (*ndo_get_vf_config)(struct net_device *dev,
* int vf, struct ifla_vf_info *ivf);
+ * int (*ndo_set_vf_port)(struct net_device *dev, int vf,
+ * struct nlattr *port[]);
+ * int (*ndo_get_vf_port)(struct net_device *dev, int vf, struct sk_buff *skb);
*/
#define HAVE_NET_DEVICE_OPS
struct net_device_ops {
@@ -735,6 +738,11 @@ struct net_device_ops {
int (*ndo_get_vf_config)(struct net_device *dev,
int vf,
struct ifla_vf_info *ivf);
+ int (*ndo_set_vf_port)(struct net_device *dev,
+ int vf,
+ struct nlattr *port[]);
+ int (*ndo_get_vf_port)(struct net_device *dev,
+ int vf, struct sk_buff *skb);
#if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE)
int (*ndo_fcoe_enable)(struct net_device *dev);
int (*ndo_fcoe_disable)(struct net_device *dev);
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 23a71cb..eb18f2a 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -653,6 +653,31 @@ static inline int rtnl_vfinfo_size(const struct net_device *dev)
return 0;
}
+static size_t rtnl_port_size(const struct net_device *dev)
+{
+ size_t port_size = nla_total_size(4) /* PORT_VF */
+ + nla_total_size(PORT_PROFILE_MAX) /* PORT_PROFILE */
+ + nla_total_size(sizeof(struct ifla_port_vsi))
+ /* PORT_VSI_TYPE */
+ + nla_total_size(PORT_UUID_MAX) /* PORT_INSTANCE_UUID */
+ + nla_total_size(PORT_UUID_MAX) /* PORT_HOST_UUID */
+ + nla_total_size(1) /* PROT_VDP_REQUEST */
+ + nla_total_size(2); /* PORT_VDP_RESPONSE */
+ size_t vf_ports_size = nla_total_size(sizeof(struct nlattr));
+ size_t vf_port_size = nla_total_size(sizeof(struct nlattr))
+ + port_size;
+ size_t port_self_size = nla_total_size(sizeof(struct nlattr))
+ + port_size;
+
+ if (!dev->netdev_ops->ndo_get_vf_port || !dev->dev.parent)
+ return 0;
+ if (dev_num_vf(dev->dev.parent))
+ return port_self_size + vf_ports_size +
+ vf_port_size * dev_num_vf(dev->dev.parent);
+ else
+ return port_self_size;
+}
+
static inline size_t if_nlmsg_size(const struct net_device *dev)
{
return NLMSG_ALIGN(sizeof(struct ifinfomsg))
@@ -673,9 +698,82 @@ static inline size_t if_nlmsg_size(const struct net_device *dev)
+ nla_total_size(1) /* IFLA_LINKMODE */
+ nla_total_size(4) /* IFLA_NUM_VF */
+ nla_total_size(rtnl_vfinfo_size(dev)) /* IFLA_VFINFO */
+ + rtnl_port_size(dev) /* IFLA_VF_PORTS + IFLA_PORT_SELF */
+ rtnl_link_get_size(dev); /* IFLA_LINKINFO */
}
+static int rtnl_vf_ports_fill(struct sk_buff *skb, struct net_device *dev)
+{
+ struct nlattr *vf_ports;
+ struct nlattr *vf_port;
+ int vf;
+ int err;
+
+ vf_ports = nla_nest_start(skb, IFLA_VF_PORTS);
+ if (!vf_ports)
+ return -EMSGSIZE;
+
+ for (vf = 0; vf < dev_num_vf(dev->dev.parent); vf++) {
+ vf_port = nla_nest_start(skb, IFLA_VF_PORT);
+ if (!vf_port) {
+ nla_nest_cancel(skb, vf_ports);
+ return -EMSGSIZE;
+ }
+ NLA_PUT_U32(skb, IFLA_PORT_VF, vf);
+ err = dev->netdev_ops->ndo_get_vf_port(dev, vf, skb);
+ if (err) {
+nla_put_failure:
+ nla_nest_cancel(skb, vf_port);
+ continue;
+ }
+ nla_nest_end(skb, vf_port);
+ }
+
+ nla_nest_end(skb, vf_ports);
+
+ return 0;
+}
+
+static int rtnl_port_self_fill(struct sk_buff *skb, struct net_device *dev)
+{
+ struct nlattr *port_self;
+ int err;
+
+ port_self = nla_nest_start(skb, IFLA_PORT_SELF);
+ if (!port_self)
+ return -EMSGSIZE;
+
+ err = dev->netdev_ops->ndo_get_vf_port(dev, PORT_SELF_VF, skb);
+ if (err) {
+ nla_nest_cancel(skb, port_self);
+ return err;
+ }
+
+ nla_nest_end(skb, port_self);
+
+ return 0;
+}
+
+static int rtnl_port_fill(struct sk_buff *skb, struct net_device *dev)
+{
+ int err;
+
+ if (!dev->netdev_ops->ndo_get_vf_port || !dev->dev.parent)
+ return 0;
+
+ err = rtnl_port_self_fill(skb, dev);
+ if (err)
+ return err;
+
+ if (dev_num_vf(dev->dev.parent)) {
+ err = rtnl_vf_ports_fill(skb, dev);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
int type, u32 pid, u32 seq, u32 change,
unsigned int flags)
@@ -747,17 +845,23 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
goto nla_put_failure;
copy_rtnl_link_stats64(nla_data(attr), stats);
+ if (dev->dev.parent)
+ NLA_PUT_U32(skb, IFLA_NUM_VF, dev_num_vf(dev->dev.parent));
+
if (dev->netdev_ops->ndo_get_vf_config && dev->dev.parent) {
int i;
struct ifla_vf_info ivi;
- NLA_PUT_U32(skb, IFLA_NUM_VF, dev_num_vf(dev->dev.parent));
for (i = 0; i < dev_num_vf(dev->dev.parent); i++) {
if (dev->netdev_ops->ndo_get_vf_config(dev, i, &ivi))
break;
NLA_PUT(skb, IFLA_VFINFO, sizeof(ivi), &ivi);
}
}
+
+ if (rtnl_port_fill(skb, dev))
+ goto nla_put_failure;
+
if (dev->rtnl_link_ops) {
if (rtnl_link_fill(skb, dev) < 0)
goto nla_put_failure;
@@ -824,6 +928,8 @@ const struct nla_policy ifla_policy[IFLA_MAX+1] = {
.len = sizeof(struct ifla_vf_vlan) },
[IFLA_VF_TX_RATE] = { .type = NLA_BINARY,
.len = sizeof(struct ifla_vf_tx_rate) },
+ [IFLA_VF_PORTS] = { .type = NLA_NESTED },
+ [IFLA_PORT_SELF] = { .type = NLA_NESTED },
};
EXPORT_SYMBOL(ifla_policy);
@@ -832,6 +938,20 @@ static const struct nla_policy ifla_info_policy[IFLA_INFO_MAX+1] = {
[IFLA_INFO_DATA] = { .type = NLA_NESTED },
};
+static const struct nla_policy ifla_port_policy[IFLA_PORT_MAX+1] = {
+ [IFLA_PORT_VF] = { .type = NLA_U32 },
+ [IFLA_PORT_PROFILE] = { .type = NLA_STRING,
+ .len = PORT_PROFILE_MAX },
+ [IFLA_PORT_VSI_TYPE] = { .type = NLA_BINARY,
+ .len = sizeof(struct ifla_port_vsi)},
+ [IFLA_PORT_INSTANCE_UUID] = { .type = NLA_BINARY,
+ .len = PORT_UUID_MAX },
+ [IFLA_PORT_HOST_UUID] = { .type = NLA_STRING,
+ .len = PORT_UUID_MAX },
+ [IFLA_PORT_REQUEST] = { .type = NLA_U8, },
+ [IFLA_PORT_RESPONSE] = { .type = NLA_U16, },
+};
+
struct net *rtnl_link_get_net(struct net *src_net, struct nlattr *tb[])
{
struct net *net;
@@ -1028,6 +1148,53 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
}
err = 0;
+ if (tb[IFLA_VF_PORTS]) {
+ struct nlattr *port[IFLA_PORT_MAX+1];
+ struct nlattr *attr;
+ int vf;
+ int rem;
+
+ err = -EOPNOTSUPP;
+ if (!ops->ndo_set_vf_port)
+ goto errout;
+
+ nla_for_each_nested(attr, tb[IFLA_VF_PORTS], rem) {
+ if (nla_type(attr) != IFLA_VF_PORT)
+ continue;
+ err = nla_parse_nested(port, IFLA_PORT_MAX,
+ attr, ifla_port_policy);
+ if (err < 0)
+ goto errout;
+ if (!port[IFLA_PORT_VF]) {
+ err = -EOPNOTSUPP;
+ goto errout;
+ }
+ vf = nla_get_u32(port[IFLA_PORT_VF]);
+ err = ops->ndo_set_vf_port(dev, vf, port);
+ if (err < 0)
+ goto errout;
+ modified = 1;
+ }
+ }
+ err = 0;
+
+ if (tb[IFLA_PORT_SELF]) {
+ struct nlattr *port[IFLA_PORT_MAX+1];
+
+ err = nla_parse_nested(port, IFLA_PORT_MAX,
+ tb[IFLA_PORT_SELF], ifla_port_policy);
+ if (err < 0)
+ goto errout;
+
+ err = -EOPNOTSUPP;
+ if (ops->ndo_set_vf_port)
+ err = ops->ndo_set_vf_port(dev, PORT_SELF_VF, port);
+ if (err < 0)
+ goto errout;
+ modified = 1;
+ }
+ err = 0;
+
errout:
if (err < 0 && modified && net_ratelimit())
printk(KERN_WARNING "A link change request failed with "
^ permalink raw reply related
* [net-next-2.6 V8 PATCH 2/2] Add ndo_{set|get}_vf_port support for enic dynamic vnics
From: Scott Feldman @ 2010-05-15 1:04 UTC (permalink / raw)
To: davem; +Cc: netdev, chrisw, arnd, kaber
In-Reply-To: <20100515010415.21260.35219.stgit@savbu-pc100.cisco.com>
From: Scott Feldman <scofeldm@cisco.com>
Add enic ndo_{set|get}_vf_port ops to support setting/getting
port-profile for enic dynamic devices. Enic dynamic devices are just like
normal enic eth devices except dynamic enics require an extra configuration
step to assign a port-profile identifier to the interface before the
interface is useable. Once a port-profile is assigned, link comes up on the
interface and is ready for I/O. The port-profile is used to configure the
network port assigned to the interface. The network port configuration
includes VLAN membership, QoS policies, and port security settings typical
of a data center network.
A dynamic enic initially has a zero-mac address. Before a port-profile is
assigned, a valid non-zero unicast mac address should be assign to the
dynamic enic interface.
Signed-off-by: Scott Feldman <scofeldm@cisco.com>
Signed-off-by: Roopa Prabhu<roprabhu@cisco.com>
---
drivers/net/enic/Makefile | 2
drivers/net/enic/enic.h | 10 +
drivers/net/enic/enic_main.c | 330 ++++++++++++++++++++++++++++++++++++++++--
drivers/net/enic/enic_res.c | 5 -
drivers/net/enic/enic_res.h | 1
drivers/net/enic/vnic_dev.c | 58 +++++++
drivers/net/enic/vnic_dev.h | 7 +
drivers/net/enic/vnic_vic.c | 73 +++++++++
drivers/net/enic/vnic_vic.h | 59 ++++++++
9 files changed, 521 insertions(+), 24 deletions(-)
diff --git a/drivers/net/enic/Makefile b/drivers/net/enic/Makefile
index 391c3bc..e7b6c31 100644
--- a/drivers/net/enic/Makefile
+++ b/drivers/net/enic/Makefile
@@ -1,5 +1,5 @@
obj-$(CONFIG_ENIC) := enic.o
enic-y := enic_main.o vnic_cq.o vnic_intr.o vnic_wq.o \
- enic_res.o vnic_dev.o vnic_rq.o
+ enic_res.o vnic_dev.o vnic_rq.o vnic_vic.o
diff --git a/drivers/net/enic/enic.h b/drivers/net/enic/enic.h
index 5fa56f1..85f2a2e 100644
--- a/drivers/net/enic/enic.h
+++ b/drivers/net/enic/enic.h
@@ -34,7 +34,7 @@
#define DRV_NAME "enic"
#define DRV_DESCRIPTION "Cisco VIC Ethernet NIC Driver"
-#define DRV_VERSION "1.3.1.1"
+#define DRV_VERSION "1.3.1.1-pp"
#define DRV_COPYRIGHT "Copyright 2008-2009 Cisco Systems, Inc"
#define PFX DRV_NAME ": "
@@ -74,6 +74,13 @@ struct enic_msix_entry {
void *devid;
};
+struct enic_port_profile {
+ u8 request;
+ char name[PORT_PROFILE_MAX];
+ u8 instance_uuid[PORT_UUID_MAX];
+ u8 host_uuid[PORT_UUID_MAX];
+};
+
/* Per-instance private data structure */
struct enic {
struct net_device *netdev;
@@ -95,6 +102,7 @@ struct enic {
u32 port_mtu;
u32 rx_coalesce_usecs;
u32 tx_coalesce_usecs;
+ struct enic_port_profile pp;
/* work queue cache line section */
____cacheline_aligned struct vnic_wq wq[ENIC_WQ_MAX];
diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c
index 1232887..e125113 100644
--- a/drivers/net/enic/enic_main.c
+++ b/drivers/net/enic/enic_main.c
@@ -29,6 +29,7 @@
#include <linux/etherdevice.h>
#include <linux/if_ether.h>
#include <linux/if_vlan.h>
+#include <linux/if_link.h>
#include <linux/ethtool.h>
#include <linux/in.h>
#include <linux/ip.h>
@@ -40,6 +41,7 @@
#include "vnic_dev.h"
#include "vnic_intr.h"
#include "vnic_stats.h"
+#include "vnic_vic.h"
#include "enic_res.h"
#include "enic.h"
@@ -49,10 +51,12 @@
#define ENIC_DESC_MAX_SPLITS (MAX_TSO / WQ_ENET_MAX_DESC_LEN + 1)
#define PCI_DEVICE_ID_CISCO_VIC_ENET 0x0043 /* ethernet vnic */
+#define PCI_DEVICE_ID_CISCO_VIC_ENET_DYN 0x0044 /* enet dynamic vnic */
/* Supported devices */
static DEFINE_PCI_DEVICE_TABLE(enic_id_table) = {
{ PCI_VDEVICE(CISCO, PCI_DEVICE_ID_CISCO_VIC_ENET) },
+ { PCI_VDEVICE(CISCO, PCI_DEVICE_ID_CISCO_VIC_ENET_DYN) },
{ 0, } /* end of table */
};
@@ -113,6 +117,11 @@ static const struct enic_stat enic_rx_stats[] = {
static const unsigned int enic_n_tx_stats = ARRAY_SIZE(enic_tx_stats);
static const unsigned int enic_n_rx_stats = ARRAY_SIZE(enic_rx_stats);
+static int enic_is_dynamic(struct enic *enic)
+{
+ return enic->pdev->device == PCI_DEVICE_ID_CISCO_VIC_ENET_DYN;
+}
+
static int enic_get_settings(struct net_device *netdev,
struct ethtool_cmd *ecmd)
{
@@ -810,14 +819,78 @@ static void enic_reset_mcaddrs(struct enic *enic)
static int enic_set_mac_addr(struct net_device *netdev, char *addr)
{
- if (!is_valid_ether_addr(addr))
- return -EADDRNOTAVAIL;
+ struct enic *enic = netdev_priv(netdev);
+
+ if (enic_is_dynamic(enic)) {
+ if (!is_valid_ether_addr(addr) && !is_zero_ether_addr(addr))
+ return -EADDRNOTAVAIL;
+ } else {
+ if (!is_valid_ether_addr(addr))
+ return -EADDRNOTAVAIL;
+ }
memcpy(netdev->dev_addr, addr, netdev->addr_len);
return 0;
}
+static int enic_dev_add_station_addr(struct enic *enic)
+{
+ int err = 0;
+
+ if (is_valid_ether_addr(enic->netdev->dev_addr)) {
+ spin_lock(&enic->devcmd_lock);
+ err = vnic_dev_add_addr(enic->vdev, enic->netdev->dev_addr);
+ spin_unlock(&enic->devcmd_lock);
+ }
+
+ return err;
+}
+
+static int enic_dev_del_station_addr(struct enic *enic)
+{
+ int err = 0;
+
+ if (is_valid_ether_addr(enic->netdev->dev_addr)) {
+ spin_lock(&enic->devcmd_lock);
+ err = vnic_dev_del_addr(enic->vdev, enic->netdev->dev_addr);
+ spin_unlock(&enic->devcmd_lock);
+ }
+
+ return err;
+}
+
+static int enic_set_mac_address_dynamic(struct net_device *netdev, void *p)
+{
+ struct enic *enic = netdev_priv(netdev);
+ struct sockaddr *saddr = p;
+ char *addr = saddr->sa_data;
+ int err;
+
+ if (netif_running(enic->netdev)) {
+ err = enic_dev_del_station_addr(enic);
+ if (err)
+ return err;
+ }
+
+ err = enic_set_mac_addr(netdev, addr);
+ if (err)
+ return err;
+
+ if (netif_running(enic->netdev)) {
+ err = enic_dev_add_station_addr(enic);
+ if (err)
+ return err;
+ }
+
+ return err;
+}
+
+static int enic_set_mac_address(struct net_device *netdev, void *p)
+{
+ return -EOPNOTSUPP;
+}
+
/* netif_tx_lock held, BHs disabled */
static void enic_set_multicast_list(struct net_device *netdev)
{
@@ -922,6 +995,213 @@ static void enic_tx_timeout(struct net_device *netdev)
schedule_work(&enic->reset);
}
+static int enic_vnic_dev_deinit(struct enic *enic)
+{
+ int err;
+
+ spin_lock(&enic->devcmd_lock);
+ err = vnic_dev_deinit(enic->vdev);
+ spin_unlock(&enic->devcmd_lock);
+
+ return err;
+}
+
+static int enic_dev_init_prov(struct enic *enic, struct vic_provinfo *vp)
+{
+ int err;
+
+ spin_lock(&enic->devcmd_lock);
+ err = vnic_dev_init_prov(enic->vdev,
+ (u8 *)vp, vic_provinfo_size(vp));
+ spin_unlock(&enic->devcmd_lock);
+
+ return err;
+}
+
+static int enic_dev_init_done(struct enic *enic, int *done, int *error)
+{
+ int err;
+
+ spin_lock(&enic->devcmd_lock);
+ err = vnic_dev_init_done(enic->vdev, done, error);
+ spin_unlock(&enic->devcmd_lock);
+
+ return err;
+}
+
+static int enic_set_port_profile(struct enic *enic, u8 request, u8 *mac,
+ char *name, u8 *instance_uuid, u8 *host_uuid)
+{
+ struct vic_provinfo *vp;
+ u8 oui[3] = VIC_PROVINFO_CISCO_OUI;
+ unsigned short *uuid;
+ char uuid_str[38];
+ static char *uuid_fmt = "%04X%04X-%04X-%04X-%04X-%04X%04X%04X";
+ int err;
+
+ if (!name)
+ return -EINVAL;
+
+ if (!is_valid_ether_addr(mac))
+ return -EADDRNOTAVAIL;
+
+ vp = vic_provinfo_alloc(GFP_KERNEL, oui, VIC_PROVINFO_LINUX_TYPE);
+ if (!vp)
+ return -ENOMEM;
+
+ vic_provinfo_add_tlv(vp,
+ VIC_LINUX_PROV_TLV_PORT_PROFILE_NAME_STR,
+ strlen(name) + 1, name);
+
+ vic_provinfo_add_tlv(vp,
+ VIC_LINUX_PROV_TLV_CLIENT_MAC_ADDR,
+ ETH_ALEN, mac);
+
+ if (instance_uuid) {
+ uuid = (unsigned short *)instance_uuid;
+ sprintf(uuid_str, uuid_fmt,
+ uuid[0], uuid[1], uuid[2], uuid[3],
+ uuid[4], uuid[5], uuid[6], uuid[7]);
+ vic_provinfo_add_tlv(vp,
+ VIC_LINUX_PROV_TLV_CLIENT_UUID_STR,
+ sizeof(uuid_str), uuid_str);
+ }
+
+ if (host_uuid) {
+ uuid = (unsigned short *)host_uuid;
+ sprintf(uuid_str, uuid_fmt,
+ uuid[0], uuid[1], uuid[2], uuid[3],
+ uuid[4], uuid[5], uuid[6], uuid[7]);
+ vic_provinfo_add_tlv(vp,
+ VIC_LINUX_PROV_TLV_HOST_UUID_STR,
+ sizeof(uuid_str), uuid_str);
+ }
+
+ err = enic_vnic_dev_deinit(enic);
+ if (err)
+ goto err_out;
+
+ memset(&enic->pp, 0, sizeof(enic->pp));
+
+ err = enic_dev_init_prov(enic, vp);
+ if (err)
+ goto err_out;
+
+ enic->pp.request = request;
+ memcpy(enic->pp.name, name, PORT_PROFILE_MAX);
+ if (instance_uuid)
+ memcpy(enic->pp.instance_uuid,
+ instance_uuid, PORT_UUID_MAX);
+ if (host_uuid)
+ memcpy(enic->pp.host_uuid,
+ host_uuid, PORT_UUID_MAX);
+
+err_out:
+ vic_provinfo_free(vp);
+
+ return err;
+}
+
+static int enic_unset_port_profile(struct enic *enic)
+{
+ memset(&enic->pp, 0, sizeof(enic->pp));
+ return enic_vnic_dev_deinit(enic);
+}
+
+static int enic_set_vf_port(struct net_device *netdev, int vf,
+ struct nlattr *port[])
+{
+ struct enic *enic = netdev_priv(netdev);
+ char *name = NULL;
+ u8 *instance_uuid = NULL;
+ u8 *host_uuid = NULL;
+ u8 request = PORT_REQUEST_DISASSOCIATE;
+
+ /* don't support VFs, yet */
+ if (vf != PORT_SELF_VF)
+ return -EOPNOTSUPP;
+
+ if (port[IFLA_PORT_REQUEST])
+ request = nla_get_u8(port[IFLA_PORT_REQUEST]);
+
+ switch (request) {
+ case PORT_REQUEST_ASSOCIATE:
+
+ if (port[IFLA_PORT_PROFILE])
+ name = nla_data(port[IFLA_PORT_PROFILE]);
+
+ if (port[IFLA_PORT_INSTANCE_UUID])
+ instance_uuid =
+ nla_data(port[IFLA_PORT_INSTANCE_UUID]);
+
+ if (port[IFLA_PORT_HOST_UUID])
+ host_uuid = nla_data(port[IFLA_PORT_HOST_UUID]);
+
+ return enic_set_port_profile(enic, request,
+ netdev->dev_addr, name,
+ instance_uuid, host_uuid);
+
+ case PORT_REQUEST_DISASSOCIATE:
+
+ return enic_unset_port_profile(enic);
+
+ default:
+ break;
+ }
+
+ return -EOPNOTSUPP;
+}
+
+static int enic_get_vf_port(struct net_device *netdev, int vf,
+ struct sk_buff *skb)
+{
+ struct enic *enic = netdev_priv(netdev);
+ int err, error, done;
+ u16 response = PORT_PROFILE_RESPONSE_SUCCESS;
+
+ /* don't support VFs, yet */
+ if (vf != PORT_SELF_VF)
+ return -EOPNOTSUPP;
+
+ err = enic_dev_init_done(enic, &done, &error);
+
+ if (err)
+ return err;
+
+ switch (error) {
+ case ERR_SUCCESS:
+ if (!done)
+ response = PORT_PROFILE_RESPONSE_INPROGRESS;
+ break;
+ case ERR_EINVAL:
+ response = PORT_PROFILE_RESPONSE_INVALID;
+ break;
+ case ERR_EBADSTATE:
+ response = PORT_PROFILE_RESPONSE_BADSTATE;
+ break;
+ case ERR_ENOMEM:
+ response = PORT_PROFILE_RESPONSE_INSUFFICIENT_RESOURCES;
+ break;
+ default:
+ response = PORT_PROFILE_RESPONSE_ERROR;
+ break;
+ }
+
+ NLA_PUT_U16(skb, IFLA_PORT_REQUEST, enic->pp.request);
+ NLA_PUT_U16(skb, IFLA_PORT_RESPONSE, response);
+ NLA_PUT(skb, IFLA_PORT_PROFILE, PORT_PROFILE_MAX,
+ enic->pp.name);
+ NLA_PUT(skb, IFLA_PORT_INSTANCE_UUID, PORT_UUID_MAX,
+ enic->pp.instance_uuid);
+ NLA_PUT(skb, IFLA_PORT_HOST_UUID, PORT_UUID_MAX,
+ enic->pp.host_uuid);
+
+ return 0;
+
+nla_put_failure:
+ return -EMSGSIZE;
+}
+
static void enic_free_rq_buf(struct vnic_rq *rq, struct vnic_rq_buf *buf)
{
struct enic *enic = vnic_dev_priv(rq->vdev);
@@ -1440,9 +1720,7 @@ static int enic_open(struct net_device *netdev)
for (i = 0; i < enic->rq_count; i++)
vnic_rq_enable(&enic->rq[i]);
- spin_lock(&enic->devcmd_lock);
- enic_add_station_addr(enic);
- spin_unlock(&enic->devcmd_lock);
+ enic_dev_add_station_addr(enic);
enic_set_multicast_list(netdev);
netif_wake_queue(netdev);
@@ -1489,6 +1767,8 @@ static int enic_stop(struct net_device *netdev)
netif_carrier_off(netdev);
netif_tx_disable(netdev);
+ enic_dev_del_station_addr(enic);
+
for (i = 0; i < enic->wq_count; i++) {
err = vnic_wq_disable(&enic->wq[i]);
if (err)
@@ -1774,14 +2054,34 @@ static void enic_clear_intr_mode(struct enic *enic)
vnic_dev_set_intr_mode(enic->vdev, VNIC_DEV_INTR_MODE_UNKNOWN);
}
+static const struct net_device_ops enic_netdev_dynamic_ops = {
+ .ndo_open = enic_open,
+ .ndo_stop = enic_stop,
+ .ndo_start_xmit = enic_hard_start_xmit,
+ .ndo_get_stats = enic_get_stats,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_set_multicast_list = enic_set_multicast_list,
+ .ndo_set_mac_address = enic_set_mac_address_dynamic,
+ .ndo_change_mtu = enic_change_mtu,
+ .ndo_vlan_rx_register = enic_vlan_rx_register,
+ .ndo_vlan_rx_add_vid = enic_vlan_rx_add_vid,
+ .ndo_vlan_rx_kill_vid = enic_vlan_rx_kill_vid,
+ .ndo_tx_timeout = enic_tx_timeout,
+ .ndo_set_vf_port = enic_set_vf_port,
+ .ndo_get_vf_port = enic_get_vf_port,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ .ndo_poll_controller = enic_poll_controller,
+#endif
+};
+
static const struct net_device_ops enic_netdev_ops = {
.ndo_open = enic_open,
.ndo_stop = enic_stop,
.ndo_start_xmit = enic_hard_start_xmit,
.ndo_get_stats = enic_get_stats,
.ndo_validate_addr = eth_validate_addr,
- .ndo_set_mac_address = eth_mac_addr,
.ndo_set_multicast_list = enic_set_multicast_list,
+ .ndo_set_mac_address = enic_set_mac_address,
.ndo_change_mtu = enic_change_mtu,
.ndo_vlan_rx_register = enic_vlan_rx_register,
.ndo_vlan_rx_add_vid = enic_vlan_rx_add_vid,
@@ -2010,11 +2310,13 @@ static int __devinit enic_probe(struct pci_dev *pdev,
netif_carrier_off(netdev);
- err = vnic_dev_init(enic->vdev, 0);
- if (err) {
- printk(KERN_ERR PFX
- "vNIC dev init failed, aborting.\n");
- goto err_out_dev_close;
+ if (!enic_is_dynamic(enic)) {
+ err = vnic_dev_init(enic->vdev, 0);
+ if (err) {
+ printk(KERN_ERR PFX
+ "vNIC dev init failed, aborting.\n");
+ goto err_out_dev_close;
+ }
}
err = enic_dev_init(enic);
@@ -2054,7 +2356,11 @@ static int __devinit enic_probe(struct pci_dev *pdev,
enic->tx_coalesce_usecs = enic->config.intr_timer_usec;
enic->rx_coalesce_usecs = enic->tx_coalesce_usecs;
- netdev->netdev_ops = &enic_netdev_ops;
+ if (enic_is_dynamic(enic))
+ netdev->netdev_ops = &enic_netdev_dynamic_ops;
+ else
+ netdev->netdev_ops = &enic_netdev_ops;
+
netdev->watchdog_timeo = 2 * HZ;
netdev->ethtool_ops = &enic_ethtool_ops;
diff --git a/drivers/net/enic/enic_res.c b/drivers/net/enic/enic_res.c
index 02839bf..9b18840 100644
--- a/drivers/net/enic/enic_res.c
+++ b/drivers/net/enic/enic_res.c
@@ -103,11 +103,6 @@ int enic_get_vnic_config(struct enic *enic)
return 0;
}
-void enic_add_station_addr(struct enic *enic)
-{
- vnic_dev_add_addr(enic->vdev, enic->mac_addr);
-}
-
void enic_add_multicast_addr(struct enic *enic, u8 *addr)
{
vnic_dev_add_addr(enic->vdev, addr);
diff --git a/drivers/net/enic/enic_res.h b/drivers/net/enic/enic_res.h
index abc1974..494664f 100644
--- a/drivers/net/enic/enic_res.h
+++ b/drivers/net/enic/enic_res.h
@@ -131,7 +131,6 @@ static inline void enic_queue_rq_desc(struct vnic_rq *rq,
struct enic;
int enic_get_vnic_config(struct enic *);
-void enic_add_station_addr(struct enic *enic);
void enic_add_multicast_addr(struct enic *enic, u8 *addr);
void enic_del_multicast_addr(struct enic *enic, u8 *addr);
void enic_add_vlan(struct enic *enic, u16 vlanid);
diff --git a/drivers/net/enic/vnic_dev.c b/drivers/net/enic/vnic_dev.c
index d43a9d4..2b3e16d 100644
--- a/drivers/net/enic/vnic_dev.c
+++ b/drivers/net/enic/vnic_dev.c
@@ -530,7 +530,7 @@ void vnic_dev_packet_filter(struct vnic_dev *vdev, int directed, int multicast,
printk(KERN_ERR "Can't set packet filter\n");
}
-void vnic_dev_add_addr(struct vnic_dev *vdev, u8 *addr)
+int vnic_dev_add_addr(struct vnic_dev *vdev, u8 *addr)
{
u64 a0 = 0, a1 = 0;
int wait = 1000;
@@ -543,9 +543,11 @@ void vnic_dev_add_addr(struct vnic_dev *vdev, u8 *addr)
err = vnic_dev_cmd(vdev, CMD_ADDR_ADD, &a0, &a1, wait);
if (err)
printk(KERN_ERR "Can't add addr [%pM], %d\n", addr, err);
+
+ return err;
}
-void vnic_dev_del_addr(struct vnic_dev *vdev, u8 *addr)
+int vnic_dev_del_addr(struct vnic_dev *vdev, u8 *addr)
{
u64 a0 = 0, a1 = 0;
int wait = 1000;
@@ -558,6 +560,8 @@ void vnic_dev_del_addr(struct vnic_dev *vdev, u8 *addr)
err = vnic_dev_cmd(vdev, CMD_ADDR_DEL, &a0, &a1, wait);
if (err)
printk(KERN_ERR "Can't del addr [%pM], %d\n", addr, err);
+
+ return err;
}
int vnic_dev_raise_intr(struct vnic_dev *vdev, u16 intr)
@@ -682,6 +686,56 @@ int vnic_dev_init(struct vnic_dev *vdev, int arg)
return r;
}
+int vnic_dev_init_done(struct vnic_dev *vdev, int *done, int *err)
+{
+ u64 a0 = 0, a1 = 0;
+ int wait = 1000;
+ int ret;
+
+ *done = 0;
+
+ ret = vnic_dev_cmd(vdev, CMD_INIT_STATUS, &a0, &a1, wait);
+ if (ret)
+ return ret;
+
+ *done = (a0 == 0);
+
+ *err = (a0 == 0) ? a1 : 0;
+
+ return 0;
+}
+
+int vnic_dev_init_prov(struct vnic_dev *vdev, u8 *buf, u32 len)
+{
+ u64 a0, a1 = len;
+ int wait = 1000;
+ u64 prov_pa;
+ void *prov_buf;
+ int ret;
+
+ prov_buf = pci_alloc_consistent(vdev->pdev, len, &prov_pa);
+ if (!prov_buf)
+ return -ENOMEM;
+
+ memcpy(prov_buf, buf, len);
+
+ a0 = prov_pa;
+
+ ret = vnic_dev_cmd(vdev, CMD_INIT_PROV_INFO, &a0, &a1, wait);
+
+ pci_free_consistent(vdev->pdev, len, prov_buf, prov_pa);
+
+ return ret;
+}
+
+int vnic_dev_deinit(struct vnic_dev *vdev)
+{
+ u64 a0 = 0, a1 = 0;
+ int wait = 1000;
+
+ return vnic_dev_cmd(vdev, CMD_DEINIT, &a0, &a1, wait);
+}
+
int vnic_dev_link_status(struct vnic_dev *vdev)
{
if (vdev->linkstatus)
diff --git a/drivers/net/enic/vnic_dev.h b/drivers/net/enic/vnic_dev.h
index f5be640..caccce3 100644
--- a/drivers/net/enic/vnic_dev.h
+++ b/drivers/net/enic/vnic_dev.h
@@ -103,8 +103,8 @@ int vnic_dev_stats_dump(struct vnic_dev *vdev, struct vnic_stats **stats);
int vnic_dev_hang_notify(struct vnic_dev *vdev);
void vnic_dev_packet_filter(struct vnic_dev *vdev, int directed, int multicast,
int broadcast, int promisc, int allmulti);
-void vnic_dev_add_addr(struct vnic_dev *vdev, u8 *addr);
-void vnic_dev_del_addr(struct vnic_dev *vdev, u8 *addr);
+int vnic_dev_add_addr(struct vnic_dev *vdev, u8 *addr);
+int vnic_dev_del_addr(struct vnic_dev *vdev, u8 *addr);
int vnic_dev_mac_addr(struct vnic_dev *vdev, u8 *mac_addr);
int vnic_dev_raise_intr(struct vnic_dev *vdev, u16 intr);
int vnic_dev_notify_setcmd(struct vnic_dev *vdev,
@@ -124,6 +124,9 @@ int vnic_dev_disable(struct vnic_dev *vdev);
int vnic_dev_open(struct vnic_dev *vdev, int arg);
int vnic_dev_open_done(struct vnic_dev *vdev, int *done);
int vnic_dev_init(struct vnic_dev *vdev, int arg);
+int vnic_dev_init_done(struct vnic_dev *vdev, int *done, int *err);
+int vnic_dev_init_prov(struct vnic_dev *vdev, u8 *buf, u32 len);
+int vnic_dev_deinit(struct vnic_dev *vdev);
int vnic_dev_soft_reset(struct vnic_dev *vdev, int arg);
int vnic_dev_soft_reset_done(struct vnic_dev *vdev, int *done);
void vnic_dev_set_intr_mode(struct vnic_dev *vdev,
diff --git a/drivers/net/enic/vnic_vic.c b/drivers/net/enic/vnic_vic.c
new file mode 100644
index 0000000..d769772
--- /dev/null
+++ b/drivers/net/enic/vnic_vic.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2010 Cisco Systems, Inc. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+
+#include "vnic_vic.h"
+
+struct vic_provinfo *vic_provinfo_alloc(gfp_t flags, u8 *oui, u8 type)
+{
+ struct vic_provinfo *vp = kzalloc(VIC_PROVINFO_MAX_DATA, flags);
+
+ if (!vp || !oui)
+ return NULL;
+
+ memcpy(vp->oui, oui, sizeof(vp->oui));
+ vp->type = type;
+ vp->length = htonl(sizeof(vp->num_tlvs));
+
+ return vp;
+}
+
+void vic_provinfo_free(struct vic_provinfo *vp)
+{
+ kfree(vp);
+}
+
+int vic_provinfo_add_tlv(struct vic_provinfo *vp, u16 type, u16 length,
+ void *value)
+{
+ struct vic_provinfo_tlv *tlv;
+
+ if (!vp || !value)
+ return -EINVAL;
+
+ if (ntohl(vp->length) + sizeof(*tlv) + length >
+ VIC_PROVINFO_MAX_TLV_DATA)
+ return -ENOMEM;
+
+ tlv = (struct vic_provinfo_tlv *)((u8 *)vp->tlv +
+ ntohl(vp->length) - sizeof(vp->num_tlvs));
+
+ tlv->type = htons(type);
+ tlv->length = htons(length);
+ memcpy(tlv->value, value, length);
+
+ vp->num_tlvs = htonl(ntohl(vp->num_tlvs) + 1);
+ vp->length = htonl(ntohl(vp->length) + sizeof(*tlv) + length);
+
+ return 0;
+}
+
+size_t vic_provinfo_size(struct vic_provinfo *vp)
+{
+ return vp ? ntohl(vp->length) + sizeof(*vp) - sizeof(vp->num_tlvs) : 0;
+}
diff --git a/drivers/net/enic/vnic_vic.h b/drivers/net/enic/vnic_vic.h
new file mode 100644
index 0000000..085c2a2
--- /dev/null
+++ b/drivers/net/enic/vnic_vic.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2010 Cisco Systems, Inc. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifndef _VNIC_VIC_H_
+#define _VNIC_VIC_H_
+
+/* Note: All integer fields in NETWORK byte order */
+
+/* Note: String field lengths include null char */
+
+#define VIC_PROVINFO_CISCO_OUI { 0x00, 0x00, 0x0c }
+#define VIC_PROVINFO_LINUX_TYPE 0x2
+
+enum vic_linux_prov_tlv_type {
+ VIC_LINUX_PROV_TLV_PORT_PROFILE_NAME_STR = 0,
+ VIC_LINUX_PROV_TLV_CLIENT_MAC_ADDR = 1, /* u8[6] */
+ VIC_LINUX_PROV_TLV_CLIENT_NAME_STR = 2,
+ VIC_LINUX_PROV_TLV_HOST_UUID_STR = 8,
+ VIC_LINUX_PROV_TLV_CLIENT_UUID_STR = 9,
+};
+
+struct vic_provinfo {
+ u8 oui[3]; /* OUI of data provider */
+ u8 type; /* provider-specific type */
+ u32 length; /* length of data below */
+ u32 num_tlvs; /* number of tlvs */
+ struct vic_provinfo_tlv {
+ u16 type;
+ u16 length;
+ u8 value[0];
+ } tlv[0];
+} __attribute__ ((packed));
+
+#define VIC_PROVINFO_MAX_DATA 1385
+#define VIC_PROVINFO_MAX_TLV_DATA (VIC_PROVINFO_MAX_DATA - \
+ sizeof(struct vic_provinfo))
+
+struct vic_provinfo *vic_provinfo_alloc(gfp_t flags, u8 *oui, u8 type);
+void vic_provinfo_free(struct vic_provinfo *vp);
+int vic_provinfo_add_tlv(struct vic_provinfo *vp, u16 type, u16 length,
+ void *value);
+size_t vic_provinfo_size(struct vic_provinfo *vp);
+
+#endif /* _VNIC_VIC_H_ */
^ permalink raw reply related
* Re: [net-next-2.6 V8 PATCH 0/2] Add virtual port netlink support
From: Stephen Hemminger @ 2010-05-15 1:29 UTC (permalink / raw)
To: Scott Feldman; +Cc: davem, netdev, chrisw, arnd, kaber
In-Reply-To: <20100515010415.21260.35219.stgit@savbu-pc100.cisco.com>
On Fri, 14 May 2010 18:04:23 -0700
Scott Feldman <scofeldm@cisco.com> wrote:
> [Add symmetrical set/get layout per Patrick McHardy suggestions]
>
> The following series adds virtual port netlink support and adds an
> implementation to Cisco's enic netdev driver:
>
> 1/2: Adds virtual netlink RTM_SETLINK/RTM_GETLINK support, and
> adds matching netdev ops net_{set|get}_vf_port.
>
> 2/2: Adds enic support for net_{set|get}_vf_port for enic
> dynamic devices.
>
> Signed-off-by: Scott Feldman <scofeldm@cisco.com>
> Signed-off-by: Roopa Prabhu<roprabhu@cisco.com>
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
I assume there will be some documentation for this when the patch
to iproute for supporting this comes out.
^ 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