* [PATCH 0/18] Updates & bug fixes for iseries_veth network driver
@ 2005-09-01 1:28 Michael Ellerman
2005-09-01 1:28 ` [PATCH 1/18] iseries_veth: Cleanup error and debug messages Michael Ellerman
` (18 more replies)
0 siblings, 19 replies; 20+ messages in thread
From: Michael Ellerman @ 2005-09-01 1:28 UTC (permalink / raw)
To: jgarzik; +Cc: netdev, linux-kernel, linuxppc64-dev
Hi,
This is a series of patches for the iseries_veth driver. Most of these are
pretty much unchanged since I posted them earlier:
http://www.uwsg.iu.edu/hypermail/linux/kernel/0506.3/1837.html
I've added patches to add sysfs support, and do some further code cleanups.
Please merge if they look ok.
cheers
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 1/18] iseries_veth: Cleanup error and debug messages
2005-09-01 1:28 [PATCH 0/18] Updates & bug fixes for iseries_veth network driver Michael Ellerman
@ 2005-09-01 1:28 ` Michael Ellerman
2005-09-01 1:28 ` [PATCH 2/18] iseries_veth: Remove a FIXME WRT deletion of the ack_timer Michael Ellerman
` (17 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: Michael Ellerman @ 2005-09-01 1:28 UTC (permalink / raw)
To: jgarzik; +Cc: netdev, linux-kernel, linuxppc64-dev
Currently the iseries_veth driver prints the file name and line number in its
error messages. This isn't very useful for most users, so just print
"iseries_veth: message" instead.
- convert uses of veth_printk() to veth_debug()/veth_error()/veth_info()
- make terminology consistent, ie. always refer to LPAR not lpar
- be consistent about printing return codes as %d not %x
- make format strings fit in 80 columns
Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---
drivers/net/iseries_veth.c | 98 +++++++++++++++++++++++----------------------
1 files changed, 51 insertions(+), 47 deletions(-)
Index: veth-dev2/drivers/net/iseries_veth.c
===================================================================
--- veth-dev2.orig/drivers/net/iseries_veth.c
+++ veth-dev2/drivers/net/iseries_veth.c
@@ -79,6 +79,8 @@
#include <asm/iommu.h>
#include <asm/vio.h>
+#undef DEBUG
+
#include "iseries_veth.h"
MODULE_AUTHOR("Kyle Lucke <klucke@us.ibm.com>");
@@ -176,11 +178,18 @@ static void veth_timed_ack(unsigned long
* Utility functions
*/
-#define veth_printk(prio, fmt, args...) \
- printk(prio "%s: " fmt, __FILE__, ## args)
+#define veth_info(fmt, args...) \
+ printk(KERN_INFO "iseries_veth: " fmt, ## args)
#define veth_error(fmt, args...) \
- printk(KERN_ERR "(%s:%3.3d) ERROR: " fmt, __FILE__, __LINE__ , ## args)
+ printk(KERN_ERR "iseries_veth: Error: " fmt, ## args)
+
+#ifdef DEBUG
+#define veth_debug(fmt, args...) \
+ printk(KERN_DEBUG "iseries_veth: " fmt, ## args)
+#else
+#define veth_debug(fmt, args...) do {} while (0)
+#endif
static inline void veth_stack_push(struct veth_lpar_connection *cnx,
struct veth_msg *msg)
@@ -278,7 +287,7 @@ static void veth_take_cap(struct veth_lp
HvLpEvent_Type_VirtualLan);
if (cnx->state & VETH_STATE_GOTCAPS) {
- veth_error("Received a second capabilities from lpar %d\n",
+ veth_error("Received a second capabilities from LPAR %d.\n",
cnx->remote_lp);
event->base_event.xRc = HvLpEvent_Rc_BufferNotAvailable;
HvCallEvent_ackLpEvent((struct HvLpEvent *) event);
@@ -297,7 +306,7 @@ static void veth_take_cap_ack(struct vet
spin_lock_irqsave(&cnx->lock, flags);
if (cnx->state & VETH_STATE_GOTCAPACK) {
- veth_error("Received a second capabilities ack from lpar %d\n",
+ veth_error("Received a second capabilities ack from LPAR %d.\n",
cnx->remote_lp);
} else {
memcpy(&cnx->cap_ack_event, event,
@@ -314,8 +323,7 @@ static void veth_take_monitor_ack(struct
unsigned long flags;
spin_lock_irqsave(&cnx->lock, flags);
- veth_printk(KERN_DEBUG, "Monitor ack returned for lpar %d\n",
- cnx->remote_lp);
+ veth_debug("cnx %d: lost connection.\n", cnx->remote_lp);
cnx->state |= VETH_STATE_RESET;
veth_kick_statemachine(cnx);
spin_unlock_irqrestore(&cnx->lock, flags);
@@ -336,8 +344,8 @@ static void veth_handle_ack(struct VethL
veth_take_monitor_ack(cnx, event);
break;
default:
- veth_error("Unknown ack type %d from lpar %d\n",
- event->base_event.xSubtype, rlp);
+ veth_error("Unknown ack type %d from LPAR %d.\n",
+ event->base_event.xSubtype, rlp);
};
}
@@ -373,8 +381,8 @@ static void veth_handle_int(struct VethL
veth_receive(cnx, event);
break;
default:
- veth_error("Unknown interrupt type %d from lpar %d\n",
- event->base_event.xSubtype, rlp);
+ veth_error("Unknown interrupt type %d from LPAR %d.\n",
+ event->base_event.xSubtype, rlp);
};
}
@@ -400,8 +408,8 @@ static int veth_process_caps(struct veth
|| (remote_caps->ack_threshold > VETH_MAX_ACKS_PER_MSG)
|| (remote_caps->ack_threshold == 0)
|| (cnx->ack_timeout == 0) ) {
- veth_error("Received incompatible capabilities from lpar %d\n",
- cnx->remote_lp);
+ veth_error("Received incompatible capabilities from LPAR %d.\n",
+ cnx->remote_lp);
return HvLpEvent_Rc_InvalidSubtypeData;
}
@@ -418,8 +426,8 @@ static int veth_process_caps(struct veth
cnx->num_ack_events += num;
if (cnx->num_ack_events < num_acks_needed) {
- veth_error("Couldn't allocate enough ack events for lpar %d\n",
- cnx->remote_lp);
+ veth_error("Couldn't allocate enough ack events "
+ "for LPAR %d.\n", cnx->remote_lp);
return HvLpEvent_Rc_BufferNotAvailable;
}
@@ -498,9 +506,8 @@ static void veth_statemachine(void *p)
} else {
if ( (rc != HvLpEvent_Rc_PartitionDead)
&& (rc != HvLpEvent_Rc_PathClosed) )
- veth_error("Error sending monitor to "
- "lpar %d, rc=%x\n",
- rlp, (int) rc);
+ veth_error("Error sending monitor to LPAR %d, "
+ "rc = %d\n", rlp, rc);
/* Oh well, hope we get a cap from the other
* end and do better when that kicks us */
@@ -523,9 +530,9 @@ static void veth_statemachine(void *p)
} else {
if ( (rc != HvLpEvent_Rc_PartitionDead)
&& (rc != HvLpEvent_Rc_PathClosed) )
- veth_error("Error sending caps to "
- "lpar %d, rc=%x\n",
- rlp, (int) rc);
+ veth_error("Error sending caps to LPAR %d, "
+ "rc = %d\n", rlp, rc);
+
/* Oh well, hope we get a cap from the other
* end and do better when that kicks us */
goto out;
@@ -565,10 +572,8 @@ static void veth_statemachine(void *p)
add_timer(&cnx->ack_timer);
cnx->state |= VETH_STATE_READY;
} else {
- veth_printk(KERN_ERR, "Caps rejected (rc=%d) by "
- "lpar %d\n",
- cnx->cap_ack_event.base_event.xRc,
- rlp);
+ veth_error("Caps rejected by LPAR %d, rc = %d\n",
+ rlp, cnx->cap_ack_event.base_event.xRc);
goto cant_cope;
}
}
@@ -581,8 +586,8 @@ static void veth_statemachine(void *p)
/* FIXME: we get here if something happens we really can't
* cope with. The link will never work once we get here, and
* all we can do is not lock the rest of the system up */
- veth_error("Badness on connection to lpar %d (state=%04lx) "
- " - shutting down\n", rlp, cnx->state);
+ veth_error("Unrecoverable error on connection to LPAR %d, shutting down"
+ " (state = 0x%04lx)\n", rlp, cnx->state);
cnx->state |= VETH_STATE_SHUTDOWN;
spin_unlock_irq(&cnx->lock);
}
@@ -614,7 +619,7 @@ static int veth_init_connection(u8 rlp)
msgs = kmalloc(VETH_NUMBUFFERS * sizeof(struct veth_msg), GFP_KERNEL);
if (! msgs) {
- veth_error("Can't allocate buffers for lpar %d\n", rlp);
+ veth_error("Can't allocate buffers for LPAR %d.\n", rlp);
return -ENOMEM;
}
@@ -630,8 +635,7 @@ static int veth_init_connection(u8 rlp)
cnx->num_events = veth_allocate_events(rlp, 2 + VETH_NUMBUFFERS);
if (cnx->num_events < (2 + VETH_NUMBUFFERS)) {
- veth_error("Can't allocate events for lpar %d, only got %d\n",
- rlp, cnx->num_events);
+ veth_error("Can't allocate enough events for LPAR %d.\n", rlp);
return -ENOMEM;
}
@@ -889,15 +893,13 @@ static struct net_device * __init veth_p
rc = register_netdev(dev);
if (rc != 0) {
- veth_printk(KERN_ERR,
- "Failed to register ethernet device for vlan %d\n",
- vlan);
+ veth_error("Failed registering net device for vlan%d.\n", vlan);
free_netdev(dev);
return NULL;
}
- veth_printk(KERN_DEBUG, "%s attached to iSeries vlan %d (lpar_map=0x%04x)\n",
- dev->name, vlan, port->lpar_map);
+ veth_info("%s attached to iSeries vlan %d (LPAR map = 0x%.4X)\n",
+ dev->name, vlan, port->lpar_map);
return dev;
}
@@ -1030,7 +1032,7 @@ static int veth_start_xmit(struct sk_buf
dev_kfree_skb(skb);
} else {
if (port->pending_skb) {
- veth_error("%s: Tx while skb was pending!\n",
+ veth_error("%s: TX while skb was pending!\n",
dev->name);
dev_kfree_skb(skb);
spin_unlock_irqrestore(&port->pending_gate, flags);
@@ -1066,10 +1068,10 @@ static void veth_recycle_msg(struct veth
memset(&msg->data, 0, sizeof(msg->data));
veth_stack_push(cnx, msg);
- } else
- if (cnx->state & VETH_STATE_OPEN)
- veth_error("Bogus frames ack from lpar %d (#%d)\n",
- cnx->remote_lp, msg->token);
+ } else if (cnx->state & VETH_STATE_OPEN) {
+ veth_error("Non-pending frame (# %d) acked by LPAR %d.\n",
+ cnx->remote_lp, msg->token);
+ }
}
static void veth_flush_pending(struct veth_lpar_connection *cnx)
@@ -1179,8 +1181,8 @@ static void veth_flush_acks(struct veth_
0, &cnx->pending_acks);
if (rc != HvLpEvent_Rc_Good)
- veth_error("Error 0x%x acking frames from lpar %d!\n",
- (unsigned)rc, cnx->remote_lp);
+ veth_error("Failed acking frames from LPAR %d, rc = %d\n",
+ cnx->remote_lp, (int)rc);
cnx->num_pending_acks = 0;
memset(&cnx->pending_acks, 0xff, sizeof(cnx->pending_acks));
@@ -1216,9 +1218,10 @@ static void veth_receive(struct veth_lpa
/* make sure that we have at least 1 EOF entry in the
* remaining entries */
if (! (senddata->eofmask >> (startchunk + VETH_EOF_SHIFT))) {
- veth_error("missing EOF frag in event "
- "eofmask=0x%x startchunk=%d\n",
- (unsigned) senddata->eofmask, startchunk);
+ veth_error("Missing EOF fragment in event "
+ "eofmask = 0x%x startchunk = %d\n",
+ (unsigned)senddata->eofmask,
+ startchunk);
break;
}
@@ -1237,8 +1240,9 @@ static void veth_receive(struct veth_lpa
/* nchunks == # of chunks in this frame */
if ((length - ETH_HLEN) > VETH_MAX_MTU) {
- veth_error("Received oversize frame from lpar %d "
- "(length=%d)\n", cnx->remote_lp, length);
+ veth_error("Received oversize frame from LPAR %d "
+ "(length = %d)\n",
+ cnx->remote_lp, length);
continue;
}
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 2/18] iseries_veth: Remove a FIXME WRT deletion of the ack_timer
2005-09-01 1:28 [PATCH 0/18] Updates & bug fixes for iseries_veth network driver Michael Ellerman
2005-09-01 1:28 ` [PATCH 1/18] iseries_veth: Cleanup error and debug messages Michael Ellerman
@ 2005-09-01 1:28 ` Michael Ellerman
2005-09-01 1:29 ` [PATCH 3/18] iseries_veth: Try to avoid pathological reset behaviour Michael Ellerman
` (16 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: Michael Ellerman @ 2005-09-01 1:28 UTC (permalink / raw)
To: jgarzik; +Cc: netdev, linux-kernel, linuxppc64-dev
The iseries_veth driver has a timer which we use to send acks. When the
connection is reset or stopped we need to delete the timer.
Currently we only call del_timer() when resetting a connection, which means
the timer might run again while the connection is being re-setup. As it turns
out that's ok, because the flags the timer consults have been reset.
It's cleaner though to call del_timer_sync() once we've dropped the lock,
although the timer may still run between us dropping the lock and calling
del_timer_sync(), but as above that's ok.
Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---
drivers/net/iseries_veth.c | 21 +++++++++++++--------
1 files changed, 13 insertions(+), 8 deletions(-)
Index: veth-dev2/drivers/net/iseries_veth.c
===================================================================
--- veth-dev2.orig/drivers/net/iseries_veth.c
+++ veth-dev2/drivers/net/iseries_veth.c
@@ -450,13 +450,15 @@ static void veth_statemachine(void *p)
if (cnx->state & VETH_STATE_RESET) {
int i;
- del_timer(&cnx->ack_timer);
-
if (cnx->state & VETH_STATE_OPEN)
HvCallEvent_closeLpEventPath(cnx->remote_lp,
HvLpEvent_Type_VirtualLan);
- /* reset ack data */
+ /*
+ * Reset ack data. This prevents the ack_timer actually
+ * doing anything, even if it runs one more time when
+ * we drop the lock below.
+ */
memset(&cnx->pending_acks, 0xff, sizeof (cnx->pending_acks));
cnx->num_pending_acks = 0;
@@ -469,9 +471,16 @@ static void veth_statemachine(void *p)
if (cnx->msgs)
for (i = 0; i < VETH_NUMBUFFERS; ++i)
veth_recycle_msg(cnx, cnx->msgs + i);
+
+ /* Drop the lock so we can do stuff that might sleep or
+ * take other locks. */
spin_unlock_irq(&cnx->lock);
+
+ del_timer_sync(&cnx->ack_timer);
veth_flush_pending(cnx);
+
spin_lock_irq(&cnx->lock);
+
if (cnx->state & VETH_STATE_RESET)
goto restart;
}
@@ -658,13 +667,9 @@ static void veth_stop_connection(u8 rlp)
veth_kick_statemachine(cnx);
spin_unlock_irq(&cnx->lock);
+ /* Wait for the state machine to run. */
flush_scheduled_work();
- /* FIXME: not sure if this is necessary - will already have
- * been deleted by the state machine, just want to make sure
- * its not running any more */
- del_timer_sync(&cnx->ack_timer);
-
if (cnx->num_events > 0)
mf_deallocate_lp_events(cnx->remote_lp,
HvLpEvent_Type_VirtualLan,
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 3/18] iseries_veth: Try to avoid pathological reset behaviour
2005-09-01 1:28 [PATCH 0/18] Updates & bug fixes for iseries_veth network driver Michael Ellerman
2005-09-01 1:28 ` [PATCH 1/18] iseries_veth: Cleanup error and debug messages Michael Ellerman
2005-09-01 1:28 ` [PATCH 2/18] iseries_veth: Remove a FIXME WRT deletion of the ack_timer Michael Ellerman
@ 2005-09-01 1:29 ` Michael Ellerman
2005-09-01 1:29 ` [PATCH 4/18] iseries_veth: Fix broken promiscuous handling Michael Ellerman
` (15 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: Michael Ellerman @ 2005-09-01 1:29 UTC (permalink / raw)
To: jgarzik; +Cc: netdev, linux-kernel, linuxppc64-dev
The iseries_veth driver contains a state machine which is used to manage
how connections are setup and neogotiated between LPARs.
If one side of a connection resets for some reason, the two LPARs can get
stuck in a race to re-setup the connection. This can lead to the connection
being declared dead by one or both ends. In practice the connection is
declared dead by one or both ends approximately 8/10 times a connection is
reset, although it is rare for connections to be reset.
(an example here: http://michael.ellerman.id.au/files/misc/veth-trace.html)
The core of the problem is that the end that resets the connection doesn't
wait for the other end to become aware of the reset. So the resetting end
starts setting the connection back up, and then receives a reset from the
other end (which is the response to the initial reset). And so on.
We're severely limited in what we can do to fix this. The protocol between
LPARs is essentially fixed, as we have to interoperate with both OS/400
and old Linux drivers. Which also means we need a fix that only changes the
code on one end.
The only fix I've found given that, is to just blindly sleep for a bit when
resetting the connection, in the hope that the other end will get itself
sorted. Needless to say I'd love it if someone has a better idea.
This does work, I've so far been unable to get it to break, whereas without
the fix a reset of one end will lead to a dead connection ~8/10 times.
Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---
drivers/net/iseries_veth.c | 25 +++++++++++++++++++++++--
1 files changed, 23 insertions(+), 2 deletions(-)
Index: veth-dev2/drivers/net/iseries_veth.c
===================================================================
--- veth-dev2.orig/drivers/net/iseries_veth.c
+++ veth-dev2/drivers/net/iseries_veth.c
@@ -324,8 +324,14 @@ static void veth_take_monitor_ack(struct
spin_lock_irqsave(&cnx->lock, flags);
veth_debug("cnx %d: lost connection.\n", cnx->remote_lp);
- cnx->state |= VETH_STATE_RESET;
- veth_kick_statemachine(cnx);
+
+ /* Avoid kicking the statemachine once we're shutdown.
+ * It's unnecessary and it could break veth_stop_connection(). */
+
+ if (! (cnx->state & VETH_STATE_SHUTDOWN)) {
+ cnx->state |= VETH_STATE_RESET;
+ veth_kick_statemachine(cnx);
+ }
spin_unlock_irqrestore(&cnx->lock, flags);
}
@@ -483,6 +489,12 @@ static void veth_statemachine(void *p)
if (cnx->state & VETH_STATE_RESET)
goto restart;
+
+ /* Hack, wait for the other end to reset itself. */
+ if (! (cnx->state & VETH_STATE_SHUTDOWN)) {
+ schedule_delayed_work(&cnx->statemachine_wq, 5 * HZ);
+ goto out;
+ }
}
if (cnx->state & VETH_STATE_SHUTDOWN)
@@ -667,6 +679,15 @@ static void veth_stop_connection(u8 rlp)
veth_kick_statemachine(cnx);
spin_unlock_irq(&cnx->lock);
+ /* There's a slim chance the reset code has just queued the
+ * statemachine to run in five seconds. If so we need to cancel
+ * that and requeue the work to run now. */
+ if (cancel_delayed_work(&cnx->statemachine_wq)) {
+ spin_lock_irq(&cnx->lock);
+ veth_kick_statemachine(cnx);
+ spin_unlock_irq(&cnx->lock);
+ }
+
/* Wait for the state machine to run. */
flush_scheduled_work();
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 4/18] iseries_veth: Fix broken promiscuous handling
2005-09-01 1:28 [PATCH 0/18] Updates & bug fixes for iseries_veth network driver Michael Ellerman
` (2 preceding siblings ...)
2005-09-01 1:29 ` [PATCH 3/18] iseries_veth: Try to avoid pathological reset behaviour Michael Ellerman
@ 2005-09-01 1:29 ` Michael Ellerman
2005-09-01 1:29 ` [PATCH 5/18] iseries_veth: Remove redundant message stack lock Michael Ellerman
` (14 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: Michael Ellerman @ 2005-09-01 1:29 UTC (permalink / raw)
To: jgarzik; +Cc: netdev, linux-kernel, linuxppc64-dev
Due to a logic bug, once promiscuous mode is enabled in the iseries_veth
driver it is never disabled.
The driver keeps two flags, promiscuous and all_mcast which have exactly the
same effect. This is because we only ever receive packets destined for us,
or multicast packets. So consolidate them into one promiscuous flag for
simplicity.
Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---
drivers/net/iseries_veth.c | 16 +++++-----------
1 files changed, 5 insertions(+), 11 deletions(-)
Index: veth-dev2/drivers/net/iseries_veth.c
===================================================================
--- veth-dev2.orig/drivers/net/iseries_veth.c
+++ veth-dev2/drivers/net/iseries_veth.c
@@ -159,7 +159,6 @@ struct veth_port {
rwlock_t mcast_gate;
int promiscuous;
- int all_mcast;
int num_mcast;
u64 mcast_addr[VETH_MAX_MCAST];
};
@@ -756,17 +755,15 @@ static void veth_set_multicast_list(stru
write_lock_irqsave(&port->mcast_gate, flags);
- if (dev->flags & IFF_PROMISC) { /* set promiscuous mode */
- printk(KERN_INFO "%s: Promiscuous mode enabled.\n",
- dev->name);
+ if ((dev->flags & IFF_PROMISC) || (dev->flags & IFF_ALLMULTI) ||
+ (dev->mc_count > VETH_MAX_MCAST)) {
port->promiscuous = 1;
- } else if ( (dev->flags & IFF_ALLMULTI)
- || (dev->mc_count > VETH_MAX_MCAST) ) {
- port->all_mcast = 1;
} else {
struct dev_mc_list *dmi = dev->mc_list;
int i;
+ port->promiscuous = 0;
+
/* Update table */
port->num_mcast = 0;
@@ -1145,12 +1142,9 @@ static inline int veth_frame_wanted(stru
if ( (mac_addr == port->mac_addr) || (mac_addr == 0xffffffffffff0000) )
return 1;
- if (! (((char *) &mac_addr)[0] & 0x01))
- return 0;
-
read_lock_irqsave(&port->mcast_gate, flags);
- if (port->promiscuous || port->all_mcast) {
+ if (port->promiscuous) {
wanted = 1;
goto out;
}
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 5/18] iseries_veth: Remove redundant message stack lock
2005-09-01 1:28 [PATCH 0/18] Updates & bug fixes for iseries_veth network driver Michael Ellerman
` (3 preceding siblings ...)
2005-09-01 1:29 ` [PATCH 4/18] iseries_veth: Fix broken promiscuous handling Michael Ellerman
@ 2005-09-01 1:29 ` Michael Ellerman
2005-09-01 1:29 ` [PATCH 6/18] iseries_veth: Replace lock-protected atomic with an ordinary variable Michael Ellerman
` (13 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: Michael Ellerman @ 2005-09-01 1:29 UTC (permalink / raw)
To: jgarzik; +Cc: netdev, linux-kernel, linuxppc64-dev
The iseries_veth driver keeps a stack of messages for each connection
and a lock to protect the stack. However there is also a per-connection lock
which makes the message stack lock redundant.
Remove the message stack lock and document the fact that callers of the
stack-manipulation functions must hold the connection's lock.
Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---
drivers/net/iseries_veth.c | 12 +++---------
1 files changed, 3 insertions(+), 9 deletions(-)
Index: veth-dev2/drivers/net/iseries_veth.c
===================================================================
--- veth-dev2.orig/drivers/net/iseries_veth.c
+++ veth-dev2/drivers/net/iseries_veth.c
@@ -143,7 +143,6 @@ struct veth_lpar_connection {
struct VethCapData remote_caps;
u32 ack_timeout;
- spinlock_t msg_stack_lock;
struct veth_msg *msg_stack_head;
};
@@ -190,27 +189,23 @@ static void veth_timed_ack(unsigned long
#define veth_debug(fmt, args...) do {} while (0)
#endif
+/* You must hold the connection's lock when you call this function. */
static inline void veth_stack_push(struct veth_lpar_connection *cnx,
struct veth_msg *msg)
{
- unsigned long flags;
-
- spin_lock_irqsave(&cnx->msg_stack_lock, flags);
msg->next = cnx->msg_stack_head;
cnx->msg_stack_head = msg;
- spin_unlock_irqrestore(&cnx->msg_stack_lock, flags);
}
+/* You must hold the connection's lock when you call this function. */
static inline struct veth_msg *veth_stack_pop(struct veth_lpar_connection *cnx)
{
- unsigned long flags;
struct veth_msg *msg;
- spin_lock_irqsave(&cnx->msg_stack_lock, flags);
msg = cnx->msg_stack_head;
if (msg)
cnx->msg_stack_head = cnx->msg_stack_head->next;
- spin_unlock_irqrestore(&cnx->msg_stack_lock, flags);
+
return msg;
}
@@ -645,7 +640,6 @@ static int veth_init_connection(u8 rlp)
cnx->msgs = msgs;
memset(msgs, 0, VETH_NUMBUFFERS * sizeof(struct veth_msg));
- spin_lock_init(&cnx->msg_stack_lock);
for (i = 0; i < VETH_NUMBUFFERS; i++) {
msgs[i].token = i;
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 6/18] iseries_veth: Replace lock-protected atomic with an ordinary variable
2005-09-01 1:28 [PATCH 0/18] Updates & bug fixes for iseries_veth network driver Michael Ellerman
` (4 preceding siblings ...)
2005-09-01 1:29 ` [PATCH 5/18] iseries_veth: Remove redundant message stack lock Michael Ellerman
@ 2005-09-01 1:29 ` Michael Ellerman
2005-09-01 1:29 ` [PATCH 7/18] iseries_veth: Only call dma_unmap_single() if dma_map_single() succeeded Michael Ellerman
` (12 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: Michael Ellerman @ 2005-09-01 1:29 UTC (permalink / raw)
To: jgarzik; +Cc: netdev, linux-kernel, linuxppc64-dev
The iseries_veth driver uses atomic ops to manipulate the in_use field of
one of its per-connection structures. However all references to the
flag occur while the connection's lock is held, so the atomic ops aren't
necessary.
Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---
drivers/net/iseries_veth.c | 13 +++++++------
1 files changed, 7 insertions(+), 6 deletions(-)
Index: veth-dev2/drivers/net/iseries_veth.c
===================================================================
--- veth-dev2.orig/drivers/net/iseries_veth.c
+++ veth-dev2/drivers/net/iseries_veth.c
@@ -117,7 +117,7 @@ struct veth_msg {
struct veth_msg *next;
struct VethFramesData data;
int token;
- unsigned long in_use;
+ int in_use;
struct sk_buff *skb;
struct device *dev;
};
@@ -957,6 +957,8 @@ static int veth_transmit_to_one(struct s
goto drop;
}
+ msg->in_use = 1;
+
dma_length = skb->len;
dma_address = dma_map_single(port->dev, skb->data,
dma_length, DMA_TO_DEVICE);
@@ -971,7 +973,6 @@ static int veth_transmit_to_one(struct s
msg->data.addr[0] = dma_address;
msg->data.len[0] = dma_length;
msg->data.eofmask = 1 << VETH_EOF_SHIFT;
- set_bit(0, &(msg->in_use));
rc = veth_signaldata(cnx, VethEventTypeFrames, msg->token, &msg->data);
if (rc != HvLpEvent_Rc_Good)
@@ -981,10 +982,8 @@ static int veth_transmit_to_one(struct s
return 0;
recycle_and_drop:
+ /* we free the skb below, so tell veth_recycle_msg() not to. */
msg->skb = NULL;
- /* need to set in use to make veth_recycle_msg in case this
- * was a mapping failure */
- set_bit(0, &msg->in_use);
veth_recycle_msg(cnx, msg);
drop:
port->stats.tx_errors++;
@@ -1066,12 +1065,14 @@ static int veth_start_xmit(struct sk_buf
return 0;
}
+/* You must hold the connection's lock when you call this function. */
static void veth_recycle_msg(struct veth_lpar_connection *cnx,
struct veth_msg *msg)
{
u32 dma_address, dma_length;
- if (test_and_clear_bit(0, &msg->in_use)) {
+ if (msg->in_use) {
+ msg->in_use = 0;
dma_address = msg->data.addr[0];
dma_length = msg->data.len[0];
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 7/18] iseries_veth: Only call dma_unmap_single() if dma_map_single() succeeded
2005-09-01 1:28 [PATCH 0/18] Updates & bug fixes for iseries_veth network driver Michael Ellerman
` (5 preceding siblings ...)
2005-09-01 1:29 ` [PATCH 6/18] iseries_veth: Replace lock-protected atomic with an ordinary variable Michael Ellerman
@ 2005-09-01 1:29 ` Michael Ellerman
2005-09-01 1:29 ` [PATCH 8/18] iseries_veth: Make init_connection() & destroy_connection() symmetrical Michael Ellerman
` (11 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: Michael Ellerman @ 2005-09-01 1:29 UTC (permalink / raw)
To: jgarzik; +Cc: netdev, linux-kernel, linuxppc64-dev
The iseries_veth driver unconditionally calls dma_unmap_single() even
when the corresponding dma_map_single() may have failed.
Rework the code a bit to keep the return value from dma_unmap_single()
around, and then check if it's a dma_mapping_error() before we do
the dma_unmap_single().
Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---
drivers/net/iseries_veth.c | 17 ++++++++---------
1 files changed, 8 insertions(+), 9 deletions(-)
Index: veth-dev2/drivers/net/iseries_veth.c
===================================================================
--- veth-dev2.orig/drivers/net/iseries_veth.c
+++ veth-dev2/drivers/net/iseries_veth.c
@@ -931,7 +931,6 @@ static int veth_transmit_to_one(struct s
struct veth_lpar_connection *cnx = veth_cnx[rlp];
struct veth_port *port = (struct veth_port *) dev->priv;
HvLpEvent_Rc rc;
- u32 dma_address, dma_length;
struct veth_msg *msg = NULL;
int err = 0;
unsigned long flags;
@@ -959,20 +958,19 @@ static int veth_transmit_to_one(struct s
msg->in_use = 1;
- dma_length = skb->len;
- dma_address = dma_map_single(port->dev, skb->data,
- dma_length, DMA_TO_DEVICE);
+ msg->data.addr[0] = dma_map_single(port->dev, skb->data,
+ skb->len, DMA_TO_DEVICE);
- if (dma_mapping_error(dma_address))
+ if (dma_mapping_error(msg->data.addr[0]))
goto recycle_and_drop;
/* Is it really necessary to check the length and address
* fields of the first entry here? */
msg->skb = skb;
msg->dev = port->dev;
- msg->data.addr[0] = dma_address;
- msg->data.len[0] = dma_length;
+ msg->data.len[0] = skb->len;
msg->data.eofmask = 1 << VETH_EOF_SHIFT;
+
rc = veth_signaldata(cnx, VethEventTypeFrames, msg->token, &msg->data);
if (rc != HvLpEvent_Rc_Good)
@@ -1076,8 +1074,9 @@ static void veth_recycle_msg(struct veth
dma_address = msg->data.addr[0];
dma_length = msg->data.len[0];
- dma_unmap_single(msg->dev, dma_address, dma_length,
- DMA_TO_DEVICE);
+ if (!dma_mapping_error(dma_address))
+ dma_unmap_single(msg->dev, dma_address, dma_length,
+ DMA_TO_DEVICE);
if (msg->skb) {
dev_kfree_skb_any(msg->skb);
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 8/18] iseries_veth: Make init_connection() & destroy_connection() symmetrical
2005-09-01 1:28 [PATCH 0/18] Updates & bug fixes for iseries_veth network driver Michael Ellerman
` (6 preceding siblings ...)
2005-09-01 1:29 ` [PATCH 7/18] iseries_veth: Only call dma_unmap_single() if dma_map_single() succeeded Michael Ellerman
@ 2005-09-01 1:29 ` Michael Ellerman
2005-09-01 1:29 ` [PATCH 9/18] iseries_veth: Use kobjects to track lifecycle of connection structs Michael Ellerman
` (10 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: Michael Ellerman @ 2005-09-01 1:29 UTC (permalink / raw)
To: jgarzik; +Cc: netdev, linux-kernel, linuxppc64-dev
This patch makes veth_init_connection() and veth_destroy_connection()
symmetrical in that they allocate/deallocate the same data.
Currently if there's an error while initialising connections (ie. ENOMEM)
we call veth_module_cleanup(), however this will oops because we call
driver_unregister() before we've called driver_register(). I've never seen
this actually happen though.
So instead we explicitly call veth_destroy_connection() for each connection,
any that have been set up will be deallocated.
We also fix a potential leak if vio_register_driver() fails.
Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---
drivers/net/iseries_veth.c | 35 ++++++++++++++++++++++-------------
1 files changed, 22 insertions(+), 13 deletions(-)
Index: veth-dev2/drivers/net/iseries_veth.c
===================================================================
--- veth-dev2.orig/drivers/net/iseries_veth.c
+++ veth-dev2/drivers/net/iseries_veth.c
@@ -683,6 +683,14 @@ static void veth_stop_connection(u8 rlp)
/* Wait for the state machine to run. */
flush_scheduled_work();
+}
+
+static void veth_destroy_connection(u8 rlp)
+{
+ struct veth_lpar_connection *cnx = veth_cnx[rlp];
+
+ if (! cnx)
+ return;
if (cnx->num_events > 0)
mf_deallocate_lp_events(cnx->remote_lp,
@@ -694,14 +702,6 @@ static void veth_stop_connection(u8 rlp)
HvLpEvent_Type_VirtualLan,
cnx->num_ack_events,
NULL, NULL);
-}
-
-static void veth_destroy_connection(u8 rlp)
-{
- struct veth_lpar_connection *cnx = veth_cnx[rlp];
-
- if (! cnx)
- return;
kfree(cnx->msgs);
kfree(cnx);
@@ -1441,15 +1441,24 @@ int __init veth_module_init(void)
for (i = 0; i < HVMAXARCHITECTEDLPS; ++i) {
rc = veth_init_connection(i);
- if (rc != 0) {
- veth_module_cleanup();
- return rc;
- }
+ if (rc != 0)
+ goto error;
}
HvLpEvent_registerHandler(HvLpEvent_Type_VirtualLan,
&veth_handle_event);
- return vio_register_driver(&veth_driver);
+ rc = vio_register_driver(&veth_driver);
+ if (rc != 0)
+ goto error;
+
+ return 0;
+
+error:
+ for (i = 0; i < HVMAXARCHITECTEDLPS; ++i) {
+ veth_destroy_connection(i);
+ }
+
+ return rc;
}
module_init(veth_module_init);
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 9/18] iseries_veth: Use kobjects to track lifecycle of connection structs
2005-09-01 1:28 [PATCH 0/18] Updates & bug fixes for iseries_veth network driver Michael Ellerman
` (7 preceding siblings ...)
2005-09-01 1:29 ` [PATCH 8/18] iseries_veth: Make init_connection() & destroy_connection() symmetrical Michael Ellerman
@ 2005-09-01 1:29 ` Michael Ellerman
2005-09-01 1:29 ` [PATCH 10/18] iseries_veth: Remove TX timeout code Michael Ellerman
` (9 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: Michael Ellerman @ 2005-09-01 1:29 UTC (permalink / raw)
To: jgarzik; +Cc: netdev, linux-kernel, linuxppc64-dev
The iseries_veth driver can attach to multiple vlans, which correspond to
multiple net devices. However there is only 1 connection between each LPAR,
so the connection structure may be shared by multiple net devices.
This makes module removal messy, because we can't deallocate the connections
until we know there are no net devices still using them. The solution is to
use ref counts on the connections, so we can delete them (actually stop) as
soon as the ref count hits zero.
This patch fixes (part of) a bug we were seeing with IPv6 sending probes to
a dead LPAR, which would then hang us forever due to leftover skbs.
Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---
drivers/net/iseries_veth.c | 121 ++++++++++++++++++++++++++++++---------------
1 files changed, 83 insertions(+), 38 deletions(-)
Index: veth-dev2/drivers/net/iseries_veth.c
===================================================================
--- veth-dev2.orig/drivers/net/iseries_veth.c
+++ veth-dev2/drivers/net/iseries_veth.c
@@ -129,6 +129,7 @@ struct veth_lpar_connection {
int num_events;
struct VethCapData local_caps;
+ struct kobject kobject;
struct timer_list ack_timer;
spinlock_t lock;
@@ -171,6 +172,11 @@ static void veth_recycle_msg(struct veth
static void veth_flush_pending(struct veth_lpar_connection *cnx);
static void veth_receive(struct veth_lpar_connection *, struct VethLpEvent *);
static void veth_timed_ack(unsigned long connectionPtr);
+static void veth_release_connection(struct kobject *kobject);
+
+static struct kobj_type veth_lpar_connection_ktype = {
+ .release = veth_release_connection
+};
/*
* Utility functions
@@ -611,7 +617,7 @@ static int veth_init_connection(u8 rlp)
{
struct veth_lpar_connection *cnx;
struct veth_msg *msgs;
- int i;
+ int i, rc;
if ( (rlp == this_lp)
|| ! HvLpConfig_doLpsCommunicateOnVirtualLan(this_lp, rlp) )
@@ -632,6 +638,14 @@ static int veth_init_connection(u8 rlp)
veth_cnx[rlp] = cnx;
+ /* This gets us 1 reference, which is held on behalf of the driver
+ * infrastructure. It's released at module unload. */
+ kobject_init(&cnx->kobject);
+ cnx->kobject.ktype = &veth_lpar_connection_ktype;
+ rc = kobject_set_name(&cnx->kobject, "cnx%.2d", rlp);
+ if (rc != 0)
+ return rc;
+
msgs = kmalloc(VETH_NUMBUFFERS * sizeof(struct veth_msg), GFP_KERNEL);
if (! msgs) {
veth_error("Can't allocate buffers for LPAR %d.\n", rlp);
@@ -660,11 +674,9 @@ static int veth_init_connection(u8 rlp)
return 0;
}
-static void veth_stop_connection(u8 rlp)
+static void veth_stop_connection(struct veth_lpar_connection *cnx)
{
- struct veth_lpar_connection *cnx = veth_cnx[rlp];
-
- if (! cnx)
+ if (!cnx)
return;
spin_lock_irq(&cnx->lock);
@@ -685,11 +697,9 @@ static void veth_stop_connection(u8 rlp)
flush_scheduled_work();
}
-static void veth_destroy_connection(u8 rlp)
+static void veth_destroy_connection(struct veth_lpar_connection *cnx)
{
- struct veth_lpar_connection *cnx = veth_cnx[rlp];
-
- if (! cnx)
+ if (!cnx)
return;
if (cnx->num_events > 0)
@@ -704,8 +714,16 @@ static void veth_destroy_connection(u8 r
NULL, NULL);
kfree(cnx->msgs);
+ veth_cnx[cnx->remote_lp] = NULL;
kfree(cnx);
- veth_cnx[rlp] = NULL;
+}
+
+static void veth_release_connection(struct kobject *kobj)
+{
+ struct veth_lpar_connection *cnx;
+ cnx = container_of(kobj, struct veth_lpar_connection, kobject);
+ veth_stop_connection(cnx);
+ veth_destroy_connection(cnx);
}
/*
@@ -1349,15 +1367,31 @@ static void veth_timed_ack(unsigned long
static int veth_remove(struct vio_dev *vdev)
{
- int i = vdev->unit_address;
+ struct veth_lpar_connection *cnx;
struct net_device *dev;
+ struct veth_port *port;
+ int i;
- dev = veth_dev[i];
- if (dev != NULL) {
- veth_dev[i] = NULL;
- unregister_netdev(dev);
- free_netdev(dev);
+ dev = veth_dev[vdev->unit_address];
+
+ if (! dev)
+ return 0;
+
+ port = netdev_priv(dev);
+
+ for (i = 0; i < HVMAXARCHITECTEDLPS; i++) {
+ cnx = veth_cnx[i];
+
+ if (cnx && (port->lpar_map & (1 << i))) {
+ /* Drop our reference to connections on our VLAN */
+ kobject_put(&cnx->kobject);
+ }
}
+
+ veth_dev[vdev->unit_address] = NULL;
+ unregister_netdev(dev);
+ free_netdev(dev);
+
return 0;
}
@@ -1365,6 +1399,7 @@ static int veth_probe(struct vio_dev *vd
{
int i = vdev->unit_address;
struct net_device *dev;
+ struct veth_port *port;
dev = veth_probe_one(i, &vdev->dev);
if (dev == NULL) {
@@ -1373,11 +1408,23 @@ static int veth_probe(struct vio_dev *vd
}
veth_dev[i] = dev;
- /* Start the state machine on each connection, to commence
- * link negotiation */
- for (i = 0; i < HVMAXARCHITECTEDLPS; i++)
- if (veth_cnx[i])
- veth_kick_statemachine(veth_cnx[i]);
+ port = (struct veth_port*)netdev_priv(dev);
+
+ /* Start the state machine on each connection on this vlan. If we're
+ * the first dev to do so this will commence link negotiation */
+ for (i = 0; i < HVMAXARCHITECTEDLPS; i++) {
+ struct veth_lpar_connection *cnx;
+
+ if (! (port->lpar_map & (1 << i)))
+ continue;
+
+ cnx = veth_cnx[i];
+ if (!cnx)
+ continue;
+
+ kobject_get(&cnx->kobject);
+ veth_kick_statemachine(cnx);
+ }
return 0;
}
@@ -1406,29 +1453,27 @@ static struct vio_driver veth_driver = {
void __exit veth_module_cleanup(void)
{
int i;
+ struct veth_lpar_connection *cnx;
- /* Stop the queues first to stop any new packets being sent. */
- for (i = 0; i < HVMAXARCHITECTEDVIRTUALLANS; i++)
- if (veth_dev[i])
- netif_stop_queue(veth_dev[i]);
-
- /* Stop the connections before we unregister the driver. This
- * ensures there's no skbs lying around holding the device open. */
- for (i = 0; i < HVMAXARCHITECTEDLPS; ++i)
- veth_stop_connection(i);
-
+ /* Disconnect our "irq" to stop events coming from the Hypervisor. */
HvLpEvent_unregisterHandler(HvLpEvent_Type_VirtualLan);
- /* Hypervisor callbacks may have scheduled more work while we
- * were stoping connections. Now that we've disconnected from
- * the hypervisor make sure everything's finished. */
+ /* Make sure any work queued from Hypervisor callbacks is finished. */
flush_scheduled_work();
- vio_unregister_driver(&veth_driver);
+ for (i = 0; i < HVMAXARCHITECTEDLPS; ++i) {
+ cnx = veth_cnx[i];
+
+ if (!cnx)
+ continue;
- for (i = 0; i < HVMAXARCHITECTEDLPS; ++i)
- veth_destroy_connection(i);
+ /* Drop the driver's reference to the connection */
+ kobject_put(&cnx->kobject);
+ }
+ /* Unregister the driver, which will close all the netdevs and stop
+ * the connections when they're no longer referenced. */
+ vio_unregister_driver(&veth_driver);
}
module_exit(veth_module_cleanup);
@@ -1456,7 +1501,7 @@ int __init veth_module_init(void)
error:
for (i = 0; i < HVMAXARCHITECTEDLPS; ++i) {
- veth_destroy_connection(i);
+ veth_destroy_connection(veth_cnx[i]);
}
return rc;
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 10/18] iseries_veth: Remove TX timeout code
2005-09-01 1:28 [PATCH 0/18] Updates & bug fixes for iseries_veth network driver Michael Ellerman
` (8 preceding siblings ...)
2005-09-01 1:29 ` [PATCH 9/18] iseries_veth: Use kobjects to track lifecycle of connection structs Michael Ellerman
@ 2005-09-01 1:29 ` Michael Ellerman
2005-09-01 1:29 ` [PATCH 11/18] iseries_veth: Add a per-connection ack timer Michael Ellerman
` (8 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: Michael Ellerman @ 2005-09-01 1:29 UTC (permalink / raw)
To: jgarzik; +Cc: netdev, linux-kernel, linuxppc64-dev
The iseries_veth driver uses the generic TX timeout watchdog, however a better
solution is in the works, so remove this code.
Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---
drivers/net/iseries_veth.c | 48 ---------------------------------------------
1 files changed, 48 deletions(-)
Index: veth-dev2/drivers/net/iseries_veth.c
===================================================================
--- veth-dev2.orig/drivers/net/iseries_veth.c
+++ veth-dev2/drivers/net/iseries_veth.c
@@ -830,49 +830,6 @@ static struct ethtool_ops ops = {
.get_link = veth_get_link,
};
-static void veth_tx_timeout(struct net_device *dev)
-{
- struct veth_port *port = (struct veth_port *)dev->priv;
- struct net_device_stats *stats = &port->stats;
- unsigned long flags;
- int i;
-
- stats->tx_errors++;
-
- spin_lock_irqsave(&port->pending_gate, flags);
-
- if (!port->pending_lpmask) {
- spin_unlock_irqrestore(&port->pending_gate, flags);
- return;
- }
-
- printk(KERN_WARNING "%s: Tx timeout! Resetting lp connections: %08x\n",
- dev->name, port->pending_lpmask);
-
- for (i = 0; i < HVMAXARCHITECTEDLPS; i++) {
- struct veth_lpar_connection *cnx = veth_cnx[i];
-
- if (! (port->pending_lpmask & (1<<i)))
- continue;
-
- /* If we're pending on it, we must be connected to it,
- * so we should certainly have a structure for it. */
- BUG_ON(! cnx);
-
- /* Theoretically we could be kicking a connection
- * which doesn't deserve it, but in practice if we've
- * had a Tx timeout, the pending_lpmask will have
- * exactly one bit set - the connection causing the
- * problem. */
- spin_lock(&cnx->lock);
- cnx->state |= VETH_STATE_RESET;
- veth_kick_statemachine(cnx);
- spin_unlock(&cnx->lock);
- }
-
- spin_unlock_irqrestore(&port->pending_gate, flags);
-}
-
static struct net_device * __init veth_probe_one(int vlan, struct device *vdev)
{
struct net_device *dev;
@@ -921,9 +878,6 @@ static struct net_device * __init veth_p
dev->set_multicast_list = veth_set_multicast_list;
SET_ETHTOOL_OPS(dev, &ops);
- dev->watchdog_timeo = 2 * (VETH_ACKTIMEOUT * HZ / 1000000);
- dev->tx_timeout = veth_tx_timeout;
-
SET_NETDEV_DEV(dev, vdev);
rc = register_netdev(dev);
@@ -1058,8 +1012,6 @@ static int veth_start_xmit(struct sk_buf
lpmask = veth_transmit_to_many(skb, lpmask, dev);
- dev->trans_start = jiffies;
-
if (! lpmask) {
dev_kfree_skb(skb);
} else {
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 11/18] iseries_veth: Add a per-connection ack timer
2005-09-01 1:28 [PATCH 0/18] Updates & bug fixes for iseries_veth network driver Michael Ellerman
` (9 preceding siblings ...)
2005-09-01 1:29 ` [PATCH 10/18] iseries_veth: Remove TX timeout code Michael Ellerman
@ 2005-09-01 1:29 ` Michael Ellerman
2005-09-01 1:29 ` [PATCH 12/18] iseries_veth: Simplify full-queue handling Michael Ellerman
` (7 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: Michael Ellerman @ 2005-09-01 1:29 UTC (permalink / raw)
To: jgarzik; +Cc: netdev, linux-kernel, linuxppc64-dev
Currently the iseries_veth driver contravenes the specification in
Documentation/networking/driver.txt, in that if packets are not acked by
the other LPAR they will sit around forever.
This patch adds a per-connection timer which fires if we've had no acks for
five seconds. This is superior to the generic TX timer because it catches
the case of a small number of packets being sent and never acked.
This fixes a bug we were seeing on real systems, where some IPv6 neighbour
discovery packets would not be acked and then prevent the module from being
removed, due to skbs lying around.
Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---
drivers/net/iseries_veth.c | 75 +++++++++++++++++++++++++++++++++++++++++----
1 files changed, 69 insertions(+), 6 deletions(-)
Index: veth-dev2/drivers/net/iseries_veth.c
===================================================================
--- veth-dev2.orig/drivers/net/iseries_veth.c
+++ veth-dev2/drivers/net/iseries_veth.c
@@ -132,6 +132,11 @@ struct veth_lpar_connection {
struct kobject kobject;
struct timer_list ack_timer;
+ struct timer_list reset_timer;
+ unsigned int reset_timeout;
+ unsigned long last_contact;
+ int outstanding_tx;
+
spinlock_t lock;
unsigned long state;
HvLpInstanceId src_inst;
@@ -171,8 +176,9 @@ static int veth_start_xmit(struct sk_buf
static void veth_recycle_msg(struct veth_lpar_connection *, struct veth_msg *);
static void veth_flush_pending(struct veth_lpar_connection *cnx);
static void veth_receive(struct veth_lpar_connection *, struct VethLpEvent *);
-static void veth_timed_ack(unsigned long connectionPtr);
static void veth_release_connection(struct kobject *kobject);
+static void veth_timed_ack(unsigned long ptr);
+static void veth_timed_reset(unsigned long ptr);
static struct kobj_type veth_lpar_connection_ktype = {
.release = veth_release_connection
@@ -360,7 +366,7 @@ static void veth_handle_int(struct VethL
HvLpIndex rlp = event->base_event.xSourceLp;
struct veth_lpar_connection *cnx = veth_cnx[rlp];
unsigned long flags;
- int i;
+ int i, acked = 0;
BUG_ON(! cnx);
@@ -374,13 +380,22 @@ static void veth_handle_int(struct VethL
break;
case VethEventTypeFramesAck:
spin_lock_irqsave(&cnx->lock, flags);
+
for (i = 0; i < VETH_MAX_ACKS_PER_MSG; ++i) {
u16 msgnum = event->u.frames_ack_data.token[i];
- if (msgnum < VETH_NUMBUFFERS)
+ if (msgnum < VETH_NUMBUFFERS) {
veth_recycle_msg(cnx, cnx->msgs + msgnum);
+ cnx->outstanding_tx--;
+ acked++;
+ }
}
+
+ if (acked > 0)
+ cnx->last_contact = jiffies;
+
spin_unlock_irqrestore(&cnx->lock, flags);
+
veth_flush_pending(cnx);
break;
case VethEventTypeFrames:
@@ -454,8 +469,6 @@ static void veth_statemachine(void *p)
restart:
if (cnx->state & VETH_STATE_RESET) {
- int i;
-
if (cnx->state & VETH_STATE_OPEN)
HvCallEvent_closeLpEventPath(cnx->remote_lp,
HvLpEvent_Type_VirtualLan);
@@ -474,15 +487,20 @@ static void veth_statemachine(void *p)
| VETH_STATE_SENTCAPACK | VETH_STATE_READY);
/* Clean up any leftover messages */
- if (cnx->msgs)
+ if (cnx->msgs) {
+ int i;
for (i = 0; i < VETH_NUMBUFFERS; ++i)
veth_recycle_msg(cnx, cnx->msgs + i);
+ }
+ cnx->outstanding_tx = 0;
/* Drop the lock so we can do stuff that might sleep or
* take other locks. */
spin_unlock_irq(&cnx->lock);
del_timer_sync(&cnx->ack_timer);
+ del_timer_sync(&cnx->reset_timer);
+
veth_flush_pending(cnx);
spin_lock_irq(&cnx->lock);
@@ -631,9 +649,16 @@ static int veth_init_connection(u8 rlp)
cnx->remote_lp = rlp;
spin_lock_init(&cnx->lock);
INIT_WORK(&cnx->statemachine_wq, veth_statemachine, cnx);
+
init_timer(&cnx->ack_timer);
cnx->ack_timer.function = veth_timed_ack;
cnx->ack_timer.data = (unsigned long) cnx;
+
+ init_timer(&cnx->reset_timer);
+ cnx->reset_timer.function = veth_timed_reset;
+ cnx->reset_timer.data = (unsigned long) cnx;
+ cnx->reset_timeout = 5 * HZ * (VETH_ACKTIMEOUT / 1000000);
+
memset(&cnx->pending_acks, 0xff, sizeof (cnx->pending_acks));
veth_cnx[rlp] = cnx;
@@ -948,6 +973,13 @@ static int veth_transmit_to_one(struct s
if (rc != HvLpEvent_Rc_Good)
goto recycle_and_drop;
+ /* If the timer's not already running, start it now. */
+ if (0 == cnx->outstanding_tx)
+ mod_timer(&cnx->reset_timer, jiffies + cnx->reset_timeout);
+
+ cnx->last_contact = jiffies;
+ cnx->outstanding_tx++;
+
spin_unlock_irqrestore(&cnx->lock, flags);
return 0;
@@ -1093,6 +1125,37 @@ static void veth_flush_pending(struct ve
}
}
+static void veth_timed_reset(unsigned long ptr)
+{
+ struct veth_lpar_connection *cnx = (struct veth_lpar_connection *)ptr;
+ unsigned long trigger_time, flags;
+
+ /* FIXME is it possible this fires after veth_stop_connection()?
+ * That would reschedule the statemachine for 5 seconds and probably
+ * execute it after the module's been unloaded. Hmm. */
+
+ spin_lock_irqsave(&cnx->lock, flags);
+
+ if (cnx->outstanding_tx > 0) {
+ trigger_time = cnx->last_contact + cnx->reset_timeout;
+
+ if (trigger_time < jiffies) {
+ cnx->state |= VETH_STATE_RESET;
+ veth_kick_statemachine(cnx);
+ veth_error("%d packets not acked by LPAR %d within %d "
+ "seconds, resetting.\n",
+ cnx->outstanding_tx, cnx->remote_lp,
+ cnx->reset_timeout / HZ);
+ } else {
+ /* Reschedule the timer */
+ trigger_time = jiffies + cnx->reset_timeout;
+ mod_timer(&cnx->reset_timer, trigger_time);
+ }
+ }
+
+ spin_unlock_irqrestore(&cnx->lock, flags);
+}
+
/*
* Rx path
*/
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 12/18] iseries_veth: Simplify full-queue handling
2005-09-01 1:28 [PATCH 0/18] Updates & bug fixes for iseries_veth network driver Michael Ellerman
` (10 preceding siblings ...)
2005-09-01 1:29 ` [PATCH 11/18] iseries_veth: Add a per-connection ack timer Michael Ellerman
@ 2005-09-01 1:29 ` Michael Ellerman
2005-09-01 1:29 ` [PATCH 13/18] iseries_veth: Fix bogus counting of TX errors Michael Ellerman
` (6 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: Michael Ellerman @ 2005-09-01 1:29 UTC (permalink / raw)
To: jgarzik; +Cc: netdev, linux-kernel, linuxppc64-dev
The iseries_veth driver often has multiple netdevices sending packets over
a single connection to another LPAR. If the bandwidth to the other LPAR is
exceeded, all the netdevices must have their queues stopped.
The current code achieves this by queueing one incoming skb on the
per-netdevice port structure. When the connection is able to send more packets
we iterate through the port structs and flush any packet that is queued,
as well as restarting the associated netdevice's queue.
This arrangement makes less sense now that we have per-connection TX timers,
rather than the per-netdevice generic TX timer.
The new code simply detects when one of the connections is full, and stops
the queue of all associated netdevices. Then when a packet is acked on that
connection (ie. there is space again) all the queues are woken up.
Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---
drivers/net/iseries_veth.c | 108 ++++++++++++++++++++++++++-------------------
1 files changed, 64 insertions(+), 44 deletions(-)
Index: veth-dev2/drivers/net/iseries_veth.c
===================================================================
--- veth-dev2.orig/drivers/net/iseries_veth.c
+++ veth-dev2/drivers/net/iseries_veth.c
@@ -158,10 +158,11 @@ struct veth_port {
u64 mac_addr;
HvLpIndexMap lpar_map;
- spinlock_t pending_gate;
- struct sk_buff *pending_skb;
- HvLpIndexMap pending_lpmask;
+ /* queue_lock protects the stopped_map and dev's queue. */
+ spinlock_t queue_lock;
+ HvLpIndexMap stopped_map;
+ /* mcast_gate protects promiscuous, num_mcast & mcast_addr. */
rwlock_t mcast_gate;
int promiscuous;
int num_mcast;
@@ -174,7 +175,8 @@ static struct net_device *veth_dev[HVMAX
static int veth_start_xmit(struct sk_buff *skb, struct net_device *dev);
static void veth_recycle_msg(struct veth_lpar_connection *, struct veth_msg *);
-static void veth_flush_pending(struct veth_lpar_connection *cnx);
+static void veth_wake_queues(struct veth_lpar_connection *cnx);
+static void veth_stop_queues(struct veth_lpar_connection *cnx);
static void veth_receive(struct veth_lpar_connection *, struct VethLpEvent *);
static void veth_release_connection(struct kobject *kobject);
static void veth_timed_ack(unsigned long ptr);
@@ -221,6 +223,12 @@ static inline struct veth_msg *veth_stac
return msg;
}
+/* You must hold the connection's lock when you call this function. */
+static inline int veth_stack_is_empty(struct veth_lpar_connection *cnx)
+{
+ return cnx->msg_stack_head == NULL;
+}
+
static inline HvLpEvent_Rc
veth_signalevent(struct veth_lpar_connection *cnx, u16 subtype,
HvLpEvent_AckInd ackind, HvLpEvent_AckType acktype,
@@ -391,12 +399,12 @@ static void veth_handle_int(struct VethL
}
}
- if (acked > 0)
+ if (acked > 0) {
cnx->last_contact = jiffies;
+ veth_wake_queues(cnx);
+ }
spin_unlock_irqrestore(&cnx->lock, flags);
-
- veth_flush_pending(cnx);
break;
case VethEventTypeFrames:
veth_receive(cnx, event);
@@ -492,7 +500,9 @@ static void veth_statemachine(void *p)
for (i = 0; i < VETH_NUMBUFFERS; ++i)
veth_recycle_msg(cnx, cnx->msgs + i);
}
+
cnx->outstanding_tx = 0;
+ veth_wake_queues(cnx);
/* Drop the lock so we can do stuff that might sleep or
* take other locks. */
@@ -501,8 +511,6 @@ static void veth_statemachine(void *p)
del_timer_sync(&cnx->ack_timer);
del_timer_sync(&cnx->reset_timer);
- veth_flush_pending(cnx);
-
spin_lock_irq(&cnx->lock);
if (cnx->state & VETH_STATE_RESET)
@@ -869,8 +877,9 @@ static struct net_device * __init veth_p
port = (struct veth_port *) dev->priv;
- spin_lock_init(&port->pending_gate);
+ spin_lock_init(&port->queue_lock);
rwlock_init(&port->mcast_gate);
+ port->stopped_map = 0;
for (i = 0; i < HVMAXARCHITECTEDLPS; i++) {
HvLpVirtualLanIndexMap map;
@@ -980,6 +989,9 @@ static int veth_transmit_to_one(struct s
cnx->last_contact = jiffies;
cnx->outstanding_tx++;
+ if (veth_stack_is_empty(cnx))
+ veth_stop_queues(cnx);
+
spin_unlock_irqrestore(&cnx->lock, flags);
return 0;
@@ -1023,7 +1035,6 @@ static int veth_start_xmit(struct sk_buf
{
unsigned char *frame = skb->data;
struct veth_port *port = (struct veth_port *) dev->priv;
- unsigned long flags;
HvLpIndexMap lpmask;
if (! (frame[0] & 0x01)) {
@@ -1040,27 +1051,9 @@ static int veth_start_xmit(struct sk_buf
lpmask = port->lpar_map;
}
- spin_lock_irqsave(&port->pending_gate, flags);
-
- lpmask = veth_transmit_to_many(skb, lpmask, dev);
+ veth_transmit_to_many(skb, lpmask, dev);
- if (! lpmask) {
- dev_kfree_skb(skb);
- } else {
- if (port->pending_skb) {
- veth_error("%s: TX while skb was pending!\n",
- dev->name);
- dev_kfree_skb(skb);
- spin_unlock_irqrestore(&port->pending_gate, flags);
- return 1;
- }
-
- port->pending_skb = skb;
- port->pending_lpmask = lpmask;
- netif_stop_queue(dev);
- }
-
- spin_unlock_irqrestore(&port->pending_gate, flags);
+ dev_kfree_skb(skb);
return 0;
}
@@ -1093,9 +1086,10 @@ static void veth_recycle_msg(struct veth
}
}
-static void veth_flush_pending(struct veth_lpar_connection *cnx)
+static void veth_wake_queues(struct veth_lpar_connection *cnx)
{
int i;
+
for (i = 0; i < HVMAXARCHITECTEDVIRTUALLANS; i++) {
struct net_device *dev = veth_dev[i];
struct veth_port *port;
@@ -1109,19 +1103,45 @@ static void veth_flush_pending(struct ve
if (! (port->lpar_map & (1<<cnx->remote_lp)))
continue;
- spin_lock_irqsave(&port->pending_gate, flags);
- if (port->pending_skb) {
- port->pending_lpmask =
- veth_transmit_to_many(port->pending_skb,
- port->pending_lpmask,
- dev);
- if (! port->pending_lpmask) {
- dev_kfree_skb_any(port->pending_skb);
- port->pending_skb = NULL;
- netif_wake_queue(dev);
- }
+ spin_lock_irqsave(&port->queue_lock, flags);
+
+ port->stopped_map &= ~(1 << cnx->remote_lp);
+
+ if (0 == port->stopped_map && netif_queue_stopped(dev)) {
+ veth_debug("cnx %d: woke queue for %s.\n",
+ cnx->remote_lp, dev->name);
+ netif_wake_queue(dev);
}
- spin_unlock_irqrestore(&port->pending_gate, flags);
+ spin_unlock_irqrestore(&port->queue_lock, flags);
+ }
+}
+
+static void veth_stop_queues(struct veth_lpar_connection *cnx)
+{
+ int i;
+
+ for (i = 0; i < HVMAXARCHITECTEDVIRTUALLANS; i++) {
+ struct net_device *dev = veth_dev[i];
+ struct veth_port *port;
+
+ if (! dev)
+ continue;
+
+ port = (struct veth_port *)dev->priv;
+
+ /* If this cnx is not on the vlan for this port, continue */
+ if (! (port->lpar_map & (1 << cnx->remote_lp)))
+ continue;
+
+ spin_lock(&port->queue_lock);
+
+ netif_stop_queue(dev);
+ port->stopped_map |= (1 << cnx->remote_lp);
+
+ veth_debug("cnx %d: stopped queue for %s, map = 0x%x.\n",
+ cnx->remote_lp, dev->name, port->stopped_map);
+
+ spin_unlock(&port->queue_lock);
}
}
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 13/18] iseries_veth: Fix bogus counting of TX errors
2005-09-01 1:28 [PATCH 0/18] Updates & bug fixes for iseries_veth network driver Michael Ellerman
` (11 preceding siblings ...)
2005-09-01 1:29 ` [PATCH 12/18] iseries_veth: Simplify full-queue handling Michael Ellerman
@ 2005-09-01 1:29 ` Michael Ellerman
2005-09-01 1:29 ` [PATCH 14/18] iseries_veth: Add sysfs support for connection structs Michael Ellerman
` (5 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: Michael Ellerman @ 2005-09-01 1:29 UTC (permalink / raw)
To: jgarzik; +Cc: netdev, linux-kernel, linuxppc64-dev
There's a number of problems with the way iseries_veth counts TX errors.
Firstly it counts conditions which aren't really errors as TX errors. This
includes if we don't have a connection struct for the other LPAR, or if the
other LPAR is currently down (or just doesn't want to talk to us). Neither
of these should count as TX errors.
Secondly, it counts one TX error for each LPAR that fails to accept the packet.
This can lead to TX error counts higher than the total number of packets sent
through the interface. This is confusing for users.
This patch fixes that behaviour. The non-error conditions are no longer
counted, and we introduce a new and I think saner meaning to the TX counts.
If a packet is successfully transmitted to any LPAR then it is transmitted
and tx_packets is incremented by 1.
If there is an error transmitting a packet to any LPAR then that is counted
as one error, ie. tx_errors is incremented by 1.
Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---
drivers/net/iseries_veth.c | 47 ++++++++++++++++++---------------------------
1 files changed, 19 insertions(+), 28 deletions(-)
Index: veth-dev2/drivers/net/iseries_veth.c
===================================================================
--- veth-dev2.orig/drivers/net/iseries_veth.c
+++ veth-dev2/drivers/net/iseries_veth.c
@@ -938,31 +938,25 @@ static int veth_transmit_to_one(struct s
struct veth_port *port = (struct veth_port *) dev->priv;
HvLpEvent_Rc rc;
struct veth_msg *msg = NULL;
- int err = 0;
unsigned long flags;
- if (! cnx) {
- port->stats.tx_errors++;
- dev_kfree_skb(skb);
+ if (! cnx)
return 0;
- }
spin_lock_irqsave(&cnx->lock, flags);
if (! (cnx->state & VETH_STATE_READY))
- goto drop;
+ goto no_error;
- if ((skb->len - 14) > VETH_MAX_MTU)
+ if ((skb->len - ETH_HLEN) > VETH_MAX_MTU)
goto drop;
msg = veth_stack_pop(cnx);
-
- if (! msg) {
- err = 1;
+ if (! msg)
goto drop;
- }
msg->in_use = 1;
+ msg->skb = skb_get(skb);
msg->data.addr[0] = dma_map_single(port->dev, skb->data,
skb->len, DMA_TO_DEVICE);
@@ -970,9 +964,6 @@ static int veth_transmit_to_one(struct s
if (dma_mapping_error(msg->data.addr[0]))
goto recycle_and_drop;
- /* Is it really necessary to check the length and address
- * fields of the first entry here? */
- msg->skb = skb;
msg->dev = port->dev;
msg->data.len[0] = skb->len;
msg->data.eofmask = 1 << VETH_EOF_SHIFT;
@@ -992,43 +983,43 @@ static int veth_transmit_to_one(struct s
if (veth_stack_is_empty(cnx))
veth_stop_queues(cnx);
+ no_error:
spin_unlock_irqrestore(&cnx->lock, flags);
return 0;
recycle_and_drop:
- /* we free the skb below, so tell veth_recycle_msg() not to. */
- msg->skb = NULL;
veth_recycle_msg(cnx, msg);
drop:
- port->stats.tx_errors++;
- dev_kfree_skb(skb);
spin_unlock_irqrestore(&cnx->lock, flags);
- return err;
+ return 1;
}
-static HvLpIndexMap veth_transmit_to_many(struct sk_buff *skb,
+static void veth_transmit_to_many(struct sk_buff *skb,
HvLpIndexMap lpmask,
struct net_device *dev)
{
struct veth_port *port = (struct veth_port *) dev->priv;
- int i;
- int rc;
+ int i, success, error;
+
+ success = error = 0;
for (i = 0; i < HVMAXARCHITECTEDLPS; i++) {
if ((lpmask & (1 << i)) == 0)
continue;
- rc = veth_transmit_to_one(skb_get(skb), i, dev);
- if (! rc)
- lpmask &= ~(1<<i);
+ if (veth_transmit_to_one(skb, i, dev))
+ error = 1;
+ else
+ success = 1;
}
- if (! lpmask) {
+ if (error)
+ port->stats.tx_errors++;
+
+ if (success) {
port->stats.tx_packets++;
port->stats.tx_bytes += skb->len;
}
-
- return lpmask;
}
static int veth_start_xmit(struct sk_buff *skb, struct net_device *dev)
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 14/18] iseries_veth: Add sysfs support for connection structs
2005-09-01 1:28 [PATCH 0/18] Updates & bug fixes for iseries_veth network driver Michael Ellerman
` (12 preceding siblings ...)
2005-09-01 1:29 ` [PATCH 13/18] iseries_veth: Fix bogus counting of TX errors Michael Ellerman
@ 2005-09-01 1:29 ` Michael Ellerman
2005-09-01 1:29 ` [PATCH 15/18] iseries_veth: Add sysfs support for port structs Michael Ellerman
` (4 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: Michael Ellerman @ 2005-09-01 1:29 UTC (permalink / raw)
To: jgarzik; +Cc: netdev, linux-kernel, linuxppc64-dev
To aid in field debugging, add sysfs support for iseries_veth's connection
structures. At the moment this is all read-only, however we could think about
adding write support for some attributes in future.
Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---
drivers/net/iseries_veth.c | 94 +++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 90 insertions(+), 4 deletions(-)
Index: veth-dev2/drivers/net/iseries_veth.c
===================================================================
--- veth-dev2.orig/drivers/net/iseries_veth.c
+++ veth-dev2/drivers/net/iseries_veth.c
@@ -182,10 +182,6 @@ static void veth_release_connection(stru
static void veth_timed_ack(unsigned long ptr);
static void veth_timed_reset(unsigned long ptr);
-static struct kobj_type veth_lpar_connection_ktype = {
- .release = veth_release_connection
-};
-
/*
* Utility functions
*/
@@ -280,6 +276,81 @@ static int veth_allocate_events(HvLpInde
}
/*
+ * sysfs support
+ */
+
+struct veth_cnx_attribute {
+ struct attribute attr;
+ ssize_t (*show)(struct veth_lpar_connection *, char *buf);
+ ssize_t (*store)(struct veth_lpar_connection *, const char *buf);
+};
+
+static ssize_t veth_cnx_attribute_show(struct kobject *kobj,
+ struct attribute *attr, char *buf)
+{
+ struct veth_cnx_attribute *cnx_attr;
+ struct veth_lpar_connection *cnx;
+
+ cnx_attr = container_of(attr, struct veth_cnx_attribute, attr);
+ cnx = container_of(kobj, struct veth_lpar_connection, kobject);
+
+ if (!cnx_attr->show)
+ return -EIO;
+
+ return cnx_attr->show(cnx, buf);
+}
+
+#define CUSTOM_CNX_ATTR(_name, _format, _expression) \
+static ssize_t _name##_show(struct veth_lpar_connection *cnx, char *buf)\
+{ \
+ return sprintf(buf, _format, _expression); \
+} \
+struct veth_cnx_attribute veth_cnx_attr_##_name = __ATTR_RO(_name)
+
+#define SIMPLE_CNX_ATTR(_name) \
+ CUSTOM_CNX_ATTR(_name, "%lu\n", (unsigned long)cnx->_name)
+
+SIMPLE_CNX_ATTR(outstanding_tx);
+SIMPLE_CNX_ATTR(remote_lp);
+SIMPLE_CNX_ATTR(num_events);
+SIMPLE_CNX_ATTR(src_inst);
+SIMPLE_CNX_ATTR(dst_inst);
+SIMPLE_CNX_ATTR(num_pending_acks);
+SIMPLE_CNX_ATTR(num_ack_events);
+CUSTOM_CNX_ATTR(ack_timeout, "%d\n", jiffies_to_msecs(cnx->ack_timeout));
+CUSTOM_CNX_ATTR(reset_timeout, "%d\n", jiffies_to_msecs(cnx->reset_timeout));
+CUSTOM_CNX_ATTR(state, "0x%.4lX\n", cnx->state);
+CUSTOM_CNX_ATTR(last_contact, "%d\n", cnx->last_contact ?
+ jiffies_to_msecs(jiffies - cnx->last_contact) : 0);
+
+#define GET_CNX_ATTR(_name) (&veth_cnx_attr_##_name.attr)
+
+static struct attribute *veth_cnx_default_attrs[] = {
+ GET_CNX_ATTR(outstanding_tx),
+ GET_CNX_ATTR(remote_lp),
+ GET_CNX_ATTR(num_events),
+ GET_CNX_ATTR(reset_timeout),
+ GET_CNX_ATTR(last_contact),
+ GET_CNX_ATTR(state),
+ GET_CNX_ATTR(src_inst),
+ GET_CNX_ATTR(dst_inst),
+ GET_CNX_ATTR(num_pending_acks),
+ GET_CNX_ATTR(num_ack_events),
+ GET_CNX_ATTR(ack_timeout),
+ NULL
+};
+
+static struct sysfs_ops veth_cnx_sysfs_ops = {
+ .show = veth_cnx_attribute_show
+};
+
+static struct kobj_type veth_lpar_connection_ktype = {
+ .release = veth_release_connection,
+ .sysfs_ops = &veth_cnx_sysfs_ops,
+ .default_attrs = veth_cnx_default_attrs
+};
+
+/*
* LPAR connection code
*/
@@ -1493,6 +1564,8 @@ void __exit veth_module_cleanup(void)
if (!cnx)
continue;
+ /* Remove the connection from sysfs */
+ kobject_del(&cnx->kobject);
/* Drop the driver's reference to the connection */
kobject_put(&cnx->kobject);
}
@@ -1523,6 +1596,19 @@ int __init veth_module_init(void)
if (rc != 0)
goto error;
+ for (i = 0; i < HVMAXARCHITECTEDLPS; ++i) {
+ struct kobject *kobj;
+
+ if (!veth_cnx[i])
+ continue;
+
+ kobj = &veth_cnx[i]->kobject;
+ kobj->parent = &veth_driver.driver.kobj;
+ /* If the add failes, complain but otherwise continue */
+ if (0 != kobject_add(kobj))
+ veth_error("cnx %d: Failed adding to sysfs.\n", i);
+ }
+
return 0;
error:
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 15/18] iseries_veth: Add sysfs support for port structs
2005-09-01 1:28 [PATCH 0/18] Updates & bug fixes for iseries_veth network driver Michael Ellerman
` (13 preceding siblings ...)
2005-09-01 1:29 ` [PATCH 14/18] iseries_veth: Add sysfs support for connection structs Michael Ellerman
@ 2005-09-01 1:29 ` Michael Ellerman
2005-09-01 1:29 ` [PATCH 16/18] iseries_veth: Incorporate iseries_veth.h in iseries_veth.c Michael Ellerman
` (3 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: Michael Ellerman @ 2005-09-01 1:29 UTC (permalink / raw)
To: jgarzik; +Cc: netdev, linux-kernel, linuxppc64-dev
Also to aid debugging, add sysfs support for iseries_veth's port structures.
Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---
drivers/net/iseries_veth.c | 67 +++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 67 insertions(+)
Index: veth-dev2/drivers/net/iseries_veth.c
===================================================================
--- veth-dev2.orig/drivers/net/iseries_veth.c
+++ veth-dev2/drivers/net/iseries_veth.c
@@ -167,6 +167,8 @@ struct veth_port {
int promiscuous;
int num_mcast;
u64 mcast_addr[VETH_MAX_MCAST];
+
+ struct kobject kobject;
};
static HvLpIndex this_lp;
@@ -350,6 +352,62 @@ static struct kobj_type veth_lpar_connec
.default_attrs = veth_cnx_default_attrs
};
+struct veth_port_attribute {
+ struct attribute attr;
+ ssize_t (*show)(struct veth_port *, char *buf);
+ ssize_t (*store)(struct veth_port *, const char *buf);
+};
+
+static ssize_t veth_port_attribute_show(struct kobject *kobj,
+ struct attribute *attr, char *buf)
+{
+ struct veth_port_attribute *port_attr;
+ struct veth_port *port;
+
+ port_attr = container_of(attr, struct veth_port_attribute, attr);
+ port = container_of(kobj, struct veth_port, kobject);
+
+ if (!port_attr->show)
+ return -EIO;
+
+ return port_attr->show(port, buf);
+}
+
+#define CUSTOM_PORT_ATTR(_name, _format, _expression) \
+static ssize_t _name##_show(struct veth_port *port, char *buf) \
+{ \
+ return sprintf(buf, _format, _expression); \
+} \
+struct veth_port_attribute veth_port_attr_##_name = __ATTR_RO(_name)
+
+#define SIMPLE_PORT_ATTR(_name) \
+ CUSTOM_PORT_ATTR(_name, "%lu\n", (unsigned long)port->_name)
+
+SIMPLE_PORT_ATTR(promiscuous);
+SIMPLE_PORT_ATTR(num_mcast);
+CUSTOM_PORT_ATTR(lpar_map, "0x%X\n", port->lpar_map);
+CUSTOM_PORT_ATTR(stopped_map, "0x%X\n", port->stopped_map);
+CUSTOM_PORT_ATTR(mac_addr, "0x%lX\n", port->mac_addr);
+
+#define GET_PORT_ATTR(_name) (&veth_port_attr_##_name.attr)
+static struct attribute *veth_port_default_attrs[] = {
+ GET_PORT_ATTR(mac_addr),
+ GET_PORT_ATTR(lpar_map),
+ GET_PORT_ATTR(stopped_map),
+ GET_PORT_ATTR(promiscuous),
+ GET_PORT_ATTR(num_mcast),
+ NULL
+};
+
+static struct sysfs_ops veth_port_sysfs_ops = {
+ .show = veth_port_attribute_show
+};
+
+static struct kobj_type veth_port_ktype = {
+ .sysfs_ops = &veth_port_sysfs_ops,
+ .default_attrs = veth_port_default_attrs
+};
+
/*
* LPAR connection code
*/
@@ -992,6 +1050,13 @@ static struct net_device * __init veth_p
return NULL;
}
+ kobject_init(&port->kobject);
+ port->kobject.parent = &dev->class_dev.kobj;
+ port->kobject.ktype = &veth_port_ktype;
+ kobject_set_name(&port->kobject, "veth_port");
+ if (0 != kobject_add(&port->kobject))
+ veth_error("Failed adding port for %s to sysfs.\n", dev->name);
+
veth_info("%s attached to iSeries vlan %d (LPAR map = 0x%.4X)\n",
dev->name, vlan, port->lpar_map);
@@ -1486,6 +1551,8 @@ static int veth_remove(struct vio_dev *v
}
veth_dev[vdev->unit_address] = NULL;
+ kobject_del(&port->kobject);
+ kobject_put(&port->kobject);
unregister_netdev(dev);
free_netdev(dev);
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 16/18] iseries_veth: Incorporate iseries_veth.h in iseries_veth.c
2005-09-01 1:28 [PATCH 0/18] Updates & bug fixes for iseries_veth network driver Michael Ellerman
` (14 preceding siblings ...)
2005-09-01 1:29 ` [PATCH 15/18] iseries_veth: Add sysfs support for port structs Michael Ellerman
@ 2005-09-01 1:29 ` Michael Ellerman
2005-09-01 1:29 ` [PATCH 17/18] iseries_veth: Remove studly caps from iseries_veth.c Michael Ellerman
` (2 subsequent siblings)
18 siblings, 0 replies; 20+ messages in thread
From: Michael Ellerman @ 2005-09-01 1:29 UTC (permalink / raw)
To: jgarzik; +Cc: netdev, linux-kernel, linuxppc64-dev
iseries_veth.h is only used by iseries_veth.c, so merge the former into
the latter.
Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---
drivers/net/iseries_veth.h | 46 ---------------------------------------------
drivers/net/iseries_veth.c | 42 +++++++++++++++++++++++++++++++++++++++--
2 files changed, 40 insertions(+), 48 deletions(-)
Index: veth-dev2/drivers/net/iseries_veth.c
===================================================================
--- veth-dev2.orig/drivers/net/iseries_veth.c
+++ veth-dev2/drivers/net/iseries_veth.c
@@ -81,12 +81,50 @@
#undef DEBUG
-#include "iseries_veth.h"
-
MODULE_AUTHOR("Kyle Lucke <klucke@us.ibm.com>");
MODULE_DESCRIPTION("iSeries Virtual ethernet driver");
MODULE_LICENSE("GPL");
+#define VethEventTypeCap (0)
+#define VethEventTypeFrames (1)
+#define VethEventTypeMonitor (2)
+#define VethEventTypeFramesAck (3)
+
+#define VETH_MAX_ACKS_PER_MSG (20)
+#define VETH_MAX_FRAMES_PER_MSG (6)
+
+struct VethFramesData {
+ u32 addr[VETH_MAX_FRAMES_PER_MSG];
+ u16 len[VETH_MAX_FRAMES_PER_MSG];
+ u32 eofmask;
+};
+#define VETH_EOF_SHIFT (32-VETH_MAX_FRAMES_PER_MSG)
+
+struct VethFramesAckData {
+ u16 token[VETH_MAX_ACKS_PER_MSG];
+};
+
+struct VethCapData {
+ u8 caps_version;
+ u8 rsvd1;
+ u16 num_buffers;
+ u16 ack_threshold;
+ u16 rsvd2;
+ u32 ack_timeout;
+ u32 rsvd3;
+ u64 rsvd4[3];
+};
+
+struct VethLpEvent {
+ struct HvLpEvent base_event;
+ union {
+ struct VethCapData caps_data;
+ struct VethFramesData frames_data;
+ struct VethFramesAckData frames_ack_data;
+ } u;
+
+};
+
#define VETH_NUMBUFFERS (120)
#define VETH_ACKTIMEOUT (1000000) /* microseconds */
#define VETH_MAX_MCAST (12)
Index: veth-dev2/drivers/net/iseries_veth.h
===================================================================
--- veth-dev2.orig/drivers/net/iseries_veth.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/* File veth.h created by Kyle A. Lucke on Mon Aug 7 2000. */
-
-#ifndef _ISERIES_VETH_H
-#define _ISERIES_VETH_H
-
-#define VethEventTypeCap (0)
-#define VethEventTypeFrames (1)
-#define VethEventTypeMonitor (2)
-#define VethEventTypeFramesAck (3)
-
-#define VETH_MAX_ACKS_PER_MSG (20)
-#define VETH_MAX_FRAMES_PER_MSG (6)
-
-struct VethFramesData {
- u32 addr[VETH_MAX_FRAMES_PER_MSG];
- u16 len[VETH_MAX_FRAMES_PER_MSG];
- u32 eofmask;
-};
-#define VETH_EOF_SHIFT (32-VETH_MAX_FRAMES_PER_MSG)
-
-struct VethFramesAckData {
- u16 token[VETH_MAX_ACKS_PER_MSG];
-};
-
-struct VethCapData {
- u8 caps_version;
- u8 rsvd1;
- u16 num_buffers;
- u16 ack_threshold;
- u16 rsvd2;
- u32 ack_timeout;
- u32 rsvd3;
- u64 rsvd4[3];
-};
-
-struct VethLpEvent {
- struct HvLpEvent base_event;
- union {
- struct VethCapData caps_data;
- struct VethFramesData frames_data;
- struct VethFramesAckData frames_ack_data;
- } u;
-
-};
-
-#endif /* _ISERIES_VETH_H */
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 17/18] iseries_veth: Remove studly caps from iseries_veth.c
2005-09-01 1:28 [PATCH 0/18] Updates & bug fixes for iseries_veth network driver Michael Ellerman
` (15 preceding siblings ...)
2005-09-01 1:29 ` [PATCH 16/18] iseries_veth: Incorporate iseries_veth.h in iseries_veth.c Michael Ellerman
@ 2005-09-01 1:29 ` Michael Ellerman
2005-09-01 1:29 ` [PATCH 18/18] iseries_veth: Be consistent about driver name, increment version Michael Ellerman
2005-09-01 2:43 ` [PATCH 0/18] Updates & bug fixes for iseries_veth network driver Jeff Garzik
18 siblings, 0 replies; 20+ messages in thread
From: Michael Ellerman @ 2005-09-01 1:29 UTC (permalink / raw)
To: jgarzik; +Cc: netdev, linux-kernel, linuxppc64-dev
Having merged iseries_veth.h, let's remove some of the studly caps that came
with it.
Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---
drivers/net/iseries_veth.c | 74 ++++++++++++++++++++++-----------------------
1 files changed, 37 insertions(+), 37 deletions(-)
Index: veth-dev2/drivers/net/iseries_veth.c
===================================================================
--- veth-dev2.orig/drivers/net/iseries_veth.c
+++ veth-dev2/drivers/net/iseries_veth.c
@@ -85,26 +85,26 @@ MODULE_AUTHOR("Kyle Lucke <klucke@us.ibm
MODULE_DESCRIPTION("iSeries Virtual ethernet driver");
MODULE_LICENSE("GPL");
-#define VethEventTypeCap (0)
-#define VethEventTypeFrames (1)
-#define VethEventTypeMonitor (2)
-#define VethEventTypeFramesAck (3)
+#define VETH_EVENT_CAP (0)
+#define VETH_EVENT_FRAMES (1)
+#define VETH_EVENT_MONITOR (2)
+#define VETH_EVENT_FRAMES_ACK (3)
#define VETH_MAX_ACKS_PER_MSG (20)
#define VETH_MAX_FRAMES_PER_MSG (6)
-struct VethFramesData {
+struct veth_frames_data {
u32 addr[VETH_MAX_FRAMES_PER_MSG];
u16 len[VETH_MAX_FRAMES_PER_MSG];
u32 eofmask;
};
#define VETH_EOF_SHIFT (32-VETH_MAX_FRAMES_PER_MSG)
-struct VethFramesAckData {
+struct veth_frames_ack_data {
u16 token[VETH_MAX_ACKS_PER_MSG];
};
-struct VethCapData {
+struct veth_cap_data {
u8 caps_version;
u8 rsvd1;
u16 num_buffers;
@@ -115,12 +115,12 @@ struct VethCapData {
u64 rsvd4[3];
};
-struct VethLpEvent {
+struct veth_lpevent {
struct HvLpEvent base_event;
union {
- struct VethCapData caps_data;
- struct VethFramesData frames_data;
- struct VethFramesAckData frames_ack_data;
+ struct veth_cap_data caps_data;
+ struct veth_frames_data frames_data;
+ struct veth_frames_ack_data frames_ack_data;
} u;
};
@@ -153,7 +153,7 @@ struct VethLpEvent {
struct veth_msg {
struct veth_msg *next;
- struct VethFramesData data;
+ struct veth_frames_data data;
int token;
int in_use;
struct sk_buff *skb;
@@ -165,7 +165,7 @@ struct veth_lpar_connection {
struct work_struct statemachine_wq;
struct veth_msg *msgs;
int num_events;
- struct VethCapData local_caps;
+ struct veth_cap_data local_caps;
struct kobject kobject;
struct timer_list ack_timer;
@@ -179,12 +179,12 @@ struct veth_lpar_connection {
unsigned long state;
HvLpInstanceId src_inst;
HvLpInstanceId dst_inst;
- struct VethLpEvent cap_event, cap_ack_event;
+ struct veth_lpevent cap_event, cap_ack_event;
u16 pending_acks[VETH_MAX_ACKS_PER_MSG];
u32 num_pending_acks;
int num_ack_events;
- struct VethCapData remote_caps;
+ struct veth_cap_data remote_caps;
u32 ack_timeout;
struct veth_msg *msg_stack_head;
@@ -217,7 +217,7 @@ static int veth_start_xmit(struct sk_buf
static void veth_recycle_msg(struct veth_lpar_connection *, struct veth_msg *);
static void veth_wake_queues(struct veth_lpar_connection *cnx);
static void veth_stop_queues(struct veth_lpar_connection *cnx);
-static void veth_receive(struct veth_lpar_connection *, struct VethLpEvent *);
+static void veth_receive(struct veth_lpar_connection *, struct veth_lpevent *);
static void veth_release_connection(struct kobject *kobject);
static void veth_timed_ack(unsigned long ptr);
static void veth_timed_reset(unsigned long ptr);
@@ -308,7 +308,7 @@ static int veth_allocate_events(HvLpInde
struct veth_allocation vc = { COMPLETION_INITIALIZER(vc.c), 0 };
mf_allocate_lp_events(rlp, HvLpEvent_Type_VirtualLan,
- sizeof(struct VethLpEvent), number,
+ sizeof(struct veth_lpevent), number,
&veth_complete_allocation, &vc);
wait_for_completion(&vc.c);
@@ -456,7 +456,7 @@ static inline void veth_kick_statemachin
}
static void veth_take_cap(struct veth_lpar_connection *cnx,
- struct VethLpEvent *event)
+ struct veth_lpevent *event)
{
unsigned long flags;
@@ -481,7 +481,7 @@ static void veth_take_cap(struct veth_lp
}
static void veth_take_cap_ack(struct veth_lpar_connection *cnx,
- struct VethLpEvent *event)
+ struct veth_lpevent *event)
{
unsigned long flags;
@@ -499,7 +499,7 @@ static void veth_take_cap_ack(struct vet
}
static void veth_take_monitor_ack(struct veth_lpar_connection *cnx,
- struct VethLpEvent *event)
+ struct veth_lpevent *event)
{
unsigned long flags;
@@ -516,7 +516,7 @@ static void veth_take_monitor_ack(struct
spin_unlock_irqrestore(&cnx->lock, flags);
}
-static void veth_handle_ack(struct VethLpEvent *event)
+static void veth_handle_ack(struct veth_lpevent *event)
{
HvLpIndex rlp = event->base_event.xTargetLp;
struct veth_lpar_connection *cnx = veth_cnx[rlp];
@@ -524,10 +524,10 @@ static void veth_handle_ack(struct VethL
BUG_ON(! cnx);
switch (event->base_event.xSubtype) {
- case VethEventTypeCap:
+ case VETH_EVENT_CAP:
veth_take_cap_ack(cnx, event);
break;
- case VethEventTypeMonitor:
+ case VETH_EVENT_MONITOR:
veth_take_monitor_ack(cnx, event);
break;
default:
@@ -536,7 +536,7 @@ static void veth_handle_ack(struct VethL
};
}
-static void veth_handle_int(struct VethLpEvent *event)
+static void veth_handle_int(struct veth_lpevent *event)
{
HvLpIndex rlp = event->base_event.xSourceLp;
struct veth_lpar_connection *cnx = veth_cnx[rlp];
@@ -546,14 +546,14 @@ static void veth_handle_int(struct VethL
BUG_ON(! cnx);
switch (event->base_event.xSubtype) {
- case VethEventTypeCap:
+ case VETH_EVENT_CAP:
veth_take_cap(cnx, event);
break;
- case VethEventTypeMonitor:
+ case VETH_EVENT_MONITOR:
/* do nothing... this'll hang out here til we're dead,
* and the hypervisor will return it for us. */
break;
- case VethEventTypeFramesAck:
+ case VETH_EVENT_FRAMES_ACK:
spin_lock_irqsave(&cnx->lock, flags);
for (i = 0; i < VETH_MAX_ACKS_PER_MSG; ++i) {
@@ -573,7 +573,7 @@ static void veth_handle_int(struct VethL
spin_unlock_irqrestore(&cnx->lock, flags);
break;
- case VethEventTypeFrames:
+ case VETH_EVENT_FRAMES:
veth_receive(cnx, event);
break;
default:
@@ -584,7 +584,7 @@ static void veth_handle_int(struct VethL
static void veth_handle_event(struct HvLpEvent *event, struct pt_regs *regs)
{
- struct VethLpEvent *veth_event = (struct VethLpEvent *)event;
+ struct veth_lpevent *veth_event = (struct veth_lpevent *)event;
if (event->xFlags.xFunction == HvLpEvent_Function_Ack)
veth_handle_ack(veth_event);
@@ -594,7 +594,7 @@ static void veth_handle_event(struct HvL
static int veth_process_caps(struct veth_lpar_connection *cnx)
{
- struct VethCapData *remote_caps = &cnx->remote_caps;
+ struct veth_cap_data *remote_caps = &cnx->remote_caps;
int num_acks_needed;
/* Convert timer to jiffies */
@@ -710,7 +710,7 @@ static void veth_statemachine(void *p)
if ( (cnx->state & VETH_STATE_OPEN)
&& !(cnx->state & VETH_STATE_SENTMON) ) {
- rc = veth_signalevent(cnx, VethEventTypeMonitor,
+ rc = veth_signalevent(cnx, VETH_EVENT_MONITOR,
HvLpEvent_AckInd_DoAck,
HvLpEvent_AckType_DeferredAck,
0, 0, 0, 0, 0, 0);
@@ -733,7 +733,7 @@ static void veth_statemachine(void *p)
&& !(cnx->state & VETH_STATE_SENTCAPS)) {
u64 *rawcap = (u64 *)&cnx->local_caps;
- rc = veth_signalevent(cnx, VethEventTypeCap,
+ rc = veth_signalevent(cnx, VETH_EVENT_CAP,
HvLpEvent_AckInd_DoAck,
HvLpEvent_AckType_ImmediateAck,
0, rawcap[0], rawcap[1], rawcap[2],
@@ -755,7 +755,7 @@ static void veth_statemachine(void *p)
if ((cnx->state & VETH_STATE_GOTCAPS)
&& !(cnx->state & VETH_STATE_SENTCAPACK)) {
- struct VethCapData *remote_caps = &cnx->remote_caps;
+ struct veth_cap_data *remote_caps = &cnx->remote_caps;
memcpy(remote_caps, &cnx->cap_event.u.caps_data,
sizeof(*remote_caps));
@@ -1142,7 +1142,7 @@ static int veth_transmit_to_one(struct s
msg->data.len[0] = skb->len;
msg->data.eofmask = 1 << VETH_EOF_SHIFT;
- rc = veth_signaldata(cnx, VethEventTypeFrames, msg->token, &msg->data);
+ rc = veth_signaldata(cnx, VETH_EVENT_FRAMES, msg->token, &msg->data);
if (rc != HvLpEvent_Rc_Good)
goto recycle_and_drop;
@@ -1409,7 +1409,7 @@ static void veth_flush_acks(struct veth_
{
HvLpEvent_Rc rc;
- rc = veth_signaldata(cnx, VethEventTypeFramesAck,
+ rc = veth_signaldata(cnx, VETH_EVENT_FRAMES_ACK,
0, &cnx->pending_acks);
if (rc != HvLpEvent_Rc_Good)
@@ -1421,9 +1421,9 @@ static void veth_flush_acks(struct veth_
}
static void veth_receive(struct veth_lpar_connection *cnx,
- struct VethLpEvent *event)
+ struct veth_lpevent *event)
{
- struct VethFramesData *senddata = &event->u.frames_data;
+ struct veth_frames_data *senddata = &event->u.frames_data;
int startchunk = 0;
int nchunks;
unsigned long flags;
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 18/18] iseries_veth: Be consistent about driver name, increment version
2005-09-01 1:28 [PATCH 0/18] Updates & bug fixes for iseries_veth network driver Michael Ellerman
` (16 preceding siblings ...)
2005-09-01 1:29 ` [PATCH 17/18] iseries_veth: Remove studly caps from iseries_veth.c Michael Ellerman
@ 2005-09-01 1:29 ` Michael Ellerman
2005-09-01 2:43 ` [PATCH 0/18] Updates & bug fixes for iseries_veth network driver Jeff Garzik
18 siblings, 0 replies; 20+ messages in thread
From: Michael Ellerman @ 2005-09-01 1:29 UTC (permalink / raw)
To: jgarzik; +Cc: netdev, linux-kernel, linuxppc64-dev
The iseries_veth driver tells sysfs that it's called 'iseries_veth', but if
you ask it via ethtool it thinks it's called 'veth'. I think this comes from
2.4 when the driver was called 'veth', but it's definitely called
'iseries_veth' now, so fix it.
To make sure we don't do it again define DRV_NAME and use it everywhere.
While we're at it, change the version number to 2.0, to reflect the changes
made in this patch series.
Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---
drivers/net/iseries_veth.c | 16 ++++++++++------
1 files changed, 10 insertions(+), 6 deletions(-)
Index: veth-dev2/drivers/net/iseries_veth.c
===================================================================
--- veth-dev2.orig/drivers/net/iseries_veth.c
+++ veth-dev2/drivers/net/iseries_veth.c
@@ -125,6 +125,9 @@ struct veth_lpevent {
};
+#define DRV_NAME "iseries_veth"
+#define DRV_VERSION "2.0"
+
#define VETH_NUMBUFFERS (120)
#define VETH_ACKTIMEOUT (1000000) /* microseconds */
#define VETH_MAX_MCAST (12)
@@ -227,14 +230,14 @@ static void veth_timed_reset(unsigned lo
*/
#define veth_info(fmt, args...) \
- printk(KERN_INFO "iseries_veth: " fmt, ## args)
+ printk(KERN_INFO DRV_NAME ": " fmt, ## args)
#define veth_error(fmt, args...) \
- printk(KERN_ERR "iseries_veth: Error: " fmt, ## args)
+ printk(KERN_ERR DRV_NAME ": Error: " fmt, ## args)
#ifdef DEBUG
#define veth_debug(fmt, args...) \
- printk(KERN_DEBUG "iseries_veth: " fmt, ## args)
+ printk(KERN_DEBUG DRV_NAME ": " fmt, ## args)
#else
#define veth_debug(fmt, args...) do {} while (0)
#endif
@@ -997,9 +1000,10 @@ static void veth_set_multicast_list(stru
static void veth_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
- strncpy(info->driver, "veth", sizeof(info->driver) - 1);
+ strncpy(info->driver, DRV_NAME, sizeof(info->driver) - 1);
info->driver[sizeof(info->driver) - 1] = '\0';
- strncpy(info->version, "1.0", sizeof(info->version) - 1);
+ strncpy(info->version, DRV_VERSION, sizeof(info->version) - 1);
+ info->version[sizeof(info->version) - 1] = '\0';
}
static int veth_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
@@ -1642,7 +1646,7 @@ static struct vio_device_id veth_device_
MODULE_DEVICE_TABLE(vio, veth_device_table);
static struct vio_driver veth_driver = {
- .name = "iseries_veth",
+ .name = DRV_NAME,
.id_table = veth_device_table,
.probe = veth_probe,
.remove = veth_remove
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 0/18] Updates & bug fixes for iseries_veth network driver
2005-09-01 1:28 [PATCH 0/18] Updates & bug fixes for iseries_veth network driver Michael Ellerman
` (17 preceding siblings ...)
2005-09-01 1:29 ` [PATCH 18/18] iseries_veth: Be consistent about driver name, increment version Michael Ellerman
@ 2005-09-01 2:43 ` Jeff Garzik
18 siblings, 0 replies; 20+ messages in thread
From: Jeff Garzik @ 2005-09-01 2:43 UTC (permalink / raw)
To: Michael Ellerman; +Cc: netdev, linux-kernel, linuxppc64-dev
applied patches 1-18
^ permalink raw reply [flat|nested] 20+ messages in thread
end of thread, other threads:[~2005-09-01 2:43 UTC | newest]
Thread overview: 20+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-09-01 1:28 [PATCH 0/18] Updates & bug fixes for iseries_veth network driver Michael Ellerman
2005-09-01 1:28 ` [PATCH 1/18] iseries_veth: Cleanup error and debug messages Michael Ellerman
2005-09-01 1:28 ` [PATCH 2/18] iseries_veth: Remove a FIXME WRT deletion of the ack_timer Michael Ellerman
2005-09-01 1:29 ` [PATCH 3/18] iseries_veth: Try to avoid pathological reset behaviour Michael Ellerman
2005-09-01 1:29 ` [PATCH 4/18] iseries_veth: Fix broken promiscuous handling Michael Ellerman
2005-09-01 1:29 ` [PATCH 5/18] iseries_veth: Remove redundant message stack lock Michael Ellerman
2005-09-01 1:29 ` [PATCH 6/18] iseries_veth: Replace lock-protected atomic with an ordinary variable Michael Ellerman
2005-09-01 1:29 ` [PATCH 7/18] iseries_veth: Only call dma_unmap_single() if dma_map_single() succeeded Michael Ellerman
2005-09-01 1:29 ` [PATCH 8/18] iseries_veth: Make init_connection() & destroy_connection() symmetrical Michael Ellerman
2005-09-01 1:29 ` [PATCH 9/18] iseries_veth: Use kobjects to track lifecycle of connection structs Michael Ellerman
2005-09-01 1:29 ` [PATCH 10/18] iseries_veth: Remove TX timeout code Michael Ellerman
2005-09-01 1:29 ` [PATCH 11/18] iseries_veth: Add a per-connection ack timer Michael Ellerman
2005-09-01 1:29 ` [PATCH 12/18] iseries_veth: Simplify full-queue handling Michael Ellerman
2005-09-01 1:29 ` [PATCH 13/18] iseries_veth: Fix bogus counting of TX errors Michael Ellerman
2005-09-01 1:29 ` [PATCH 14/18] iseries_veth: Add sysfs support for connection structs Michael Ellerman
2005-09-01 1:29 ` [PATCH 15/18] iseries_veth: Add sysfs support for port structs Michael Ellerman
2005-09-01 1:29 ` [PATCH 16/18] iseries_veth: Incorporate iseries_veth.h in iseries_veth.c Michael Ellerman
2005-09-01 1:29 ` [PATCH 17/18] iseries_veth: Remove studly caps from iseries_veth.c Michael Ellerman
2005-09-01 1:29 ` [PATCH 18/18] iseries_veth: Be consistent about driver name, increment version Michael Ellerman
2005-09-01 2:43 ` [PATCH 0/18] Updates & bug fixes for iseries_veth network driver Jeff Garzik
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).