Commit ea584e0c authored by Martin Schwidefsky's avatar Martin Schwidefsky Committed by Linus Torvalds

[PATCH] s390: network driver

From: Thomas Spatzier <tspat@de.ibm.com>
From: Peter Tiedemann <ptiedem@de.ibm.com>

network driver changes:
 - qeth: return -EINVAL if an skb is too large.
 - qeth: don't call netif_stop_queue after cable pull. Drop the
   packets instead.
 - qeth: fix race between SET_IP and SET_MC kernel thread by removing
   SET_MC thread and let the SET_IP thread do multicast requests as well.
 - qeth: make it compile without CONFIG_VLAN.
 - ctc: avoid compiler warnings.
 - lcs: write package sequence number to skb->cb.
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent c5c1e830
/* /*
* $Id: ctcmain.c,v 1.63 2004/07/28 12:27:54 ptiedem Exp $ * $Id: ctcmain.c,v 1.65 2004/10/27 09:12:48 mschwide Exp $
* *
* CTC / ESCON network driver * CTC / ESCON network driver
* *
...@@ -36,7 +36,7 @@ ...@@ -36,7 +36,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
* *
* RELEASE-TAG: CTC/ESCON network driver $Revision: 1.63 $ * RELEASE-TAG: CTC/ESCON network driver $Revision: 1.65 $
* *
*/ */
...@@ -320,7 +320,7 @@ static void ...@@ -320,7 +320,7 @@ static void
print_banner(void) print_banner(void)
{ {
static int printed = 0; static int printed = 0;
char vbuf[] = "$Revision: 1.63 $"; char vbuf[] = "$Revision: 1.65 $";
char *version = vbuf; char *version = vbuf;
if (printed) if (printed)
...@@ -1224,7 +1224,9 @@ ch_action_setmode(fsm_instance * fi, int event, void *arg) ...@@ -1224,7 +1224,9 @@ ch_action_setmode(fsm_instance * fi, int event, void *arg)
fsm_deltimer(&ch->timer); fsm_deltimer(&ch->timer);
fsm_addtimer(&ch->timer, CTC_TIMEOUT_5SEC, CH_EVENT_TIMER, ch); fsm_addtimer(&ch->timer, CTC_TIMEOUT_5SEC, CH_EVENT_TIMER, ch);
fsm_newstate(fi, CH_STATE_SETUPWAIT); fsm_newstate(fi, CH_STATE_SETUPWAIT);
if (event == CH_EVENT_TIMER) saveflags = 0; /* avoids compiler warning with
spin_unlock_irqrestore */
if (event == CH_EVENT_TIMER) // only for timer not yet locked
spin_lock_irqsave(get_ccwdev_lock(ch->cdev), saveflags); spin_lock_irqsave(get_ccwdev_lock(ch->cdev), saveflags);
rc = ccw_device_start(ch->cdev, &ch->ccw[6], (unsigned long) ch, 0xff, 0); rc = ccw_device_start(ch->cdev, &ch->ccw[6], (unsigned long) ch, 0xff, 0);
if (event == CH_EVENT_TIMER) if (event == CH_EVENT_TIMER)
...@@ -1335,7 +1337,9 @@ ch_action_haltio(fsm_instance * fi, int event, void *arg) ...@@ -1335,7 +1337,9 @@ ch_action_haltio(fsm_instance * fi, int event, void *arg)
DBF_TEXT(trace, 3, __FUNCTION__); DBF_TEXT(trace, 3, __FUNCTION__);
fsm_deltimer(&ch->timer); fsm_deltimer(&ch->timer);
fsm_addtimer(&ch->timer, CTC_TIMEOUT_5SEC, CH_EVENT_TIMER, ch); fsm_addtimer(&ch->timer, CTC_TIMEOUT_5SEC, CH_EVENT_TIMER, ch);
if (event == CH_EVENT_STOP) saveflags = 0; /* avoids comp warning with
spin_unlock_irqrestore */
if (event == CH_EVENT_STOP) // only for STOP not yet locked
spin_lock_irqsave(get_ccwdev_lock(ch->cdev), saveflags); spin_lock_irqsave(get_ccwdev_lock(ch->cdev), saveflags);
oldstate = fsm_getstate(fi); oldstate = fsm_getstate(fi);
fsm_newstate(fi, CH_STATE_TERM); fsm_newstate(fi, CH_STATE_TERM);
...@@ -1508,7 +1512,9 @@ ch_action_restart(fsm_instance * fi, int event, void *arg) ...@@ -1508,7 +1512,9 @@ ch_action_restart(fsm_instance * fi, int event, void *arg)
fsm_addtimer(&ch->timer, CTC_TIMEOUT_5SEC, CH_EVENT_TIMER, ch); fsm_addtimer(&ch->timer, CTC_TIMEOUT_5SEC, CH_EVENT_TIMER, ch);
oldstate = fsm_getstate(fi); oldstate = fsm_getstate(fi);
fsm_newstate(fi, CH_STATE_STARTWAIT); fsm_newstate(fi, CH_STATE_STARTWAIT);
if (event == CH_EVENT_TIMER) saveflags = 0; /* avoids compiler warning with
spin_unlock_irqrestore */
if (event == CH_EVENT_TIMER) // only for timer not yet locked
spin_lock_irqsave(get_ccwdev_lock(ch->cdev), saveflags); spin_lock_irqsave(get_ccwdev_lock(ch->cdev), saveflags);
rc = ccw_device_halt(ch->cdev, (unsigned long) ch); rc = ccw_device_halt(ch->cdev, (unsigned long) ch);
if (event == CH_EVENT_TIMER) if (event == CH_EVENT_TIMER)
...@@ -1674,7 +1680,9 @@ ch_action_txretry(fsm_instance * fi, int event, void *arg) ...@@ -1674,7 +1680,9 @@ ch_action_txretry(fsm_instance * fi, int event, void *arg)
return; return;
} }
fsm_addtimer(&ch->timer, 1000, CH_EVENT_TIMER, ch); fsm_addtimer(&ch->timer, 1000, CH_EVENT_TIMER, ch);
if (event == CH_EVENT_TIMER) saveflags = 0; /* avoids compiler warning with
spin_unlock_irqrestore */
if (event == CH_EVENT_TIMER) // only for TIMER not yet locked
spin_lock_irqsave(get_ccwdev_lock(ch->cdev), spin_lock_irqsave(get_ccwdev_lock(ch->cdev),
saveflags); saveflags);
rc = ccw_device_start(ch->cdev, &ch->ccw[3], rc = ccw_device_start(ch->cdev, &ch->ccw[3],
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* Frank Pavlic (pavlic@de.ibm.com) and * Frank Pavlic (pavlic@de.ibm.com) and
* Martin Schwidefsky <schwidefsky@de.ibm.com> * Martin Schwidefsky <schwidefsky@de.ibm.com>
* *
* $Revision: 1.94 $ $Date: 2004/10/19 09:30:54 $ * $Revision: 1.96 $ $Date: 2004/11/11 13:42:33 $
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
...@@ -59,7 +59,7 @@ ...@@ -59,7 +59,7 @@
/** /**
* initialization string for output * initialization string for output
*/ */
#define VERSION_LCS_C "$Revision: 1.94 $" #define VERSION_LCS_C "$Revision: 1.96 $"
static char version[] __initdata = "LCS driver ("VERSION_LCS_C "/" VERSION_LCS_H ")"; static char version[] __initdata = "LCS driver ("VERSION_LCS_C "/" VERSION_LCS_H ")";
static char debug_buffer[255]; static char debug_buffer[255];
...@@ -191,6 +191,7 @@ lcs_alloc_card(void) ...@@ -191,6 +191,7 @@ lcs_alloc_card(void)
return NULL; return NULL;
memset(card, 0, sizeof(struct lcs_card)); memset(card, 0, sizeof(struct lcs_card));
card->lan_type = LCS_FRAME_TYPE_AUTO; card->lan_type = LCS_FRAME_TYPE_AUTO;
card->pkt_seq = 0;
card->lancmd_timeout = LCS_LANCMD_TIMEOUT_DEFAULT; card->lancmd_timeout = LCS_LANCMD_TIMEOUT_DEFAULT;
/* Allocate io buffers for the read channel. */ /* Allocate io buffers for the read channel. */
rc = lcs_alloc_channel(&card->read); rc = lcs_alloc_channel(&card->read);
...@@ -1874,6 +1875,7 @@ lcs_get_skb(struct lcs_card *card, char *skb_data, unsigned int skb_len) ...@@ -1874,6 +1875,7 @@ lcs_get_skb(struct lcs_card *card, char *skb_data, unsigned int skb_len)
skb->protocol = card->lan_type_trans(skb, card->dev); skb->protocol = card->lan_type_trans(skb, card->dev);
card->stats.rx_bytes += skb_len; card->stats.rx_bytes += skb_len;
card->stats.rx_packets++; card->stats.rx_packets++;
*((__u32 *)skb->cb) = ++card->pkt_seq;
netif_rx(skb); netif_rx(skb);
} }
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <asm/ccwdev.h> #include <asm/ccwdev.h>
#define VERSION_LCS_H "$Revision: 1.18 $" #define VERSION_LCS_H "$Revision: 1.19 $"
#define LCS_DBF_TEXT(level, name, text) \ #define LCS_DBF_TEXT(level, name, text) \
do { \ do { \
...@@ -309,6 +309,7 @@ struct lcs_card { ...@@ -309,6 +309,7 @@ struct lcs_card {
__u16 ip_assists_supported; __u16 ip_assists_supported;
__u16 ip_assists_enabled; __u16 ip_assists_enabled;
__s8 lan_type; __s8 lan_type;
__u32 pkt_seq;
__u16 sequence_no; __u16 sequence_no;
__s16 portno; __s16 portno;
/* Some info copied from probeinfo */ /* Some info copied from probeinfo */
......
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
#include "qeth_mpc.h" #include "qeth_mpc.h"
#define VERSION_QETH_H "$Revision: 1.116 $" #define VERSION_QETH_H "$Revision: 1.123 $"
#ifdef CONFIG_QETH_IPV6 #ifdef CONFIG_QETH_IPV6
#define QETH_VERSION_IPV6 ":IPv6" #define QETH_VERSION_IPV6 ":IPv6"
...@@ -557,6 +557,7 @@ enum qeth_ip_types { ...@@ -557,6 +557,7 @@ enum qeth_ip_types {
QETH_IP_TYPE_NORMAL, QETH_IP_TYPE_NORMAL,
QETH_IP_TYPE_VIPA, QETH_IP_TYPE_VIPA,
QETH_IP_TYPE_RXIP, QETH_IP_TYPE_RXIP,
QETH_IP_TYPE_DEL_ALL_MC,
}; };
enum qeth_cmd_buffer_state { enum qeth_cmd_buffer_state {
...@@ -713,8 +714,7 @@ struct qeth_card_options { ...@@ -713,8 +714,7 @@ struct qeth_card_options {
*/ */
enum qeth_threads { enum qeth_threads {
QETH_SET_IP_THREAD = 1, QETH_SET_IP_THREAD = 1,
QETH_SET_MC_THREAD = 2, QETH_RECOVER_THREAD = 2,
QETH_RECOVER_THREAD = 4,
}; };
struct qeth_card { struct qeth_card {
...@@ -748,7 +748,7 @@ struct qeth_card { ...@@ -748,7 +748,7 @@ struct qeth_card {
volatile unsigned long thread_running_mask; volatile unsigned long thread_running_mask;
spinlock_t ip_lock; spinlock_t ip_lock;
struct list_head ip_list; struct list_head ip_list;
struct list_head ip_tbd_list; struct list_head *ip_tbd_list;
struct qeth_ipato ipato; struct qeth_ipato ipato;
struct list_head cmd_waiter_list; struct list_head cmd_waiter_list;
/* QDIO buffer handling */ /* QDIO buffer handling */
......
/* /*
* *
* linux/drivers/s390/net/qeth_main.c ($Revision: 1.155 $) * linux/drivers/s390/net/qeth_main.c ($Revision: 1.168 $)
* *
* Linux on zSeries OSA Express and HiperSockets support * Linux on zSeries OSA Express and HiperSockets support
* *
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
* Frank Pavlic (pavlic@de.ibm.com) and * Frank Pavlic (pavlic@de.ibm.com) and
* Thomas Spatzier <tspat@de.ibm.com> * Thomas Spatzier <tspat@de.ibm.com>
* *
* $Revision: 1.155 $ $Date: 2004/10/21 13:27:46 $ * $Revision: 1.168 $ $Date: 2004/11/08 15:55:12 $
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
...@@ -78,7 +78,7 @@ qeth_eyecatcher(void) ...@@ -78,7 +78,7 @@ qeth_eyecatcher(void)
#include "qeth_mpc.h" #include "qeth_mpc.h"
#include "qeth_fs.h" #include "qeth_fs.h"
#define VERSION_QETH_C "$Revision: 1.155 $" #define VERSION_QETH_C "$Revision: 1.168 $"
static const char *version = "qeth S/390 OSA-Express driver"; static const char *version = "qeth S/390 OSA-Express driver";
/** /**
...@@ -159,6 +159,9 @@ qeth_set_online(struct ccwgroup_device *); ...@@ -159,6 +159,9 @@ qeth_set_online(struct ccwgroup_device *);
static struct qeth_ipaddr * static struct qeth_ipaddr *
qeth_get_addr_buffer(enum qeth_prot_versions); qeth_get_addr_buffer(enum qeth_prot_versions);
static void
qeth_set_multicast_list(struct net_device *);
static void static void
qeth_notify_processes(void) qeth_notify_processes(void)
{ {
...@@ -249,6 +252,7 @@ qeth_free_card(struct qeth_card *card) ...@@ -249,6 +252,7 @@ qeth_free_card(struct qeth_card *card)
free_netdev(card->dev); free_netdev(card->dev);
qeth_clear_ip_list(card, 0, 0); qeth_clear_ip_list(card, 0, 0);
qeth_clear_ipato_list(card); qeth_clear_ipato_list(card);
kfree(card->ip_tbd_list);
qeth_free_qdio_buffers(card); qeth_free_qdio_buffers(card);
kfree(card); kfree(card);
} }
...@@ -660,7 +664,10 @@ __qeth_insert_ip_todo(struct qeth_card *card, struct qeth_ipaddr *addr, int add) ...@@ -660,7 +664,10 @@ __qeth_insert_ip_todo(struct qeth_card *card, struct qeth_ipaddr *addr, int add)
struct qeth_ipaddr *tmp, *t; struct qeth_ipaddr *tmp, *t;
int found = 0; int found = 0;
list_for_each_entry_safe(tmp, t, &card->ip_tbd_list, entry) { list_for_each_entry_safe(tmp, t, card->ip_tbd_list, entry) {
if ((addr->type == QETH_IP_TYPE_DEL_ALL_MC) &&
(tmp->type == QETH_IP_TYPE_DEL_ALL_MC))
return 0;
if ((tmp->proto == QETH_PROT_IPV4) && if ((tmp->proto == QETH_PROT_IPV4) &&
(addr->proto == QETH_PROT_IPV4) && (addr->proto == QETH_PROT_IPV4) &&
(tmp->type == addr->type) && (tmp->type == addr->type) &&
...@@ -692,6 +699,9 @@ __qeth_insert_ip_todo(struct qeth_card *card, struct qeth_ipaddr *addr, int add) ...@@ -692,6 +699,9 @@ __qeth_insert_ip_todo(struct qeth_card *card, struct qeth_ipaddr *addr, int add)
} }
return 0; return 0;
} else { } else {
if (addr->type == QETH_IP_TYPE_DEL_ALL_MC)
list_add(&addr->entry, card->ip_tbd_list);
else {
if (addr->users == 0) if (addr->users == 0)
addr->users += add? 1:-1; addr->users += add? 1:-1;
if (add && (addr->type == QETH_IP_TYPE_NORMAL) && if (add && (addr->type == QETH_IP_TYPE_NORMAL) &&
...@@ -699,7 +709,8 @@ __qeth_insert_ip_todo(struct qeth_card *card, struct qeth_ipaddr *addr, int add) ...@@ -699,7 +709,8 @@ __qeth_insert_ip_todo(struct qeth_card *card, struct qeth_ipaddr *addr, int add)
QETH_DBF_TEXT(trace, 2, "tkovaddr"); QETH_DBF_TEXT(trace, 2, "tkovaddr");
addr->set_flags |= QETH_IPA_SETIP_TAKEOVER_FLAG; addr->set_flags |= QETH_IPA_SETIP_TAKEOVER_FLAG;
} }
list_add_tail(&addr->entry, &card->ip_tbd_list); list_add_tail(&addr->entry, card->ip_tbd_list);
}
return 1; return 1;
} }
} }
...@@ -717,8 +728,8 @@ qeth_delete_ip(struct qeth_card *card, struct qeth_ipaddr *addr) ...@@ -717,8 +728,8 @@ qeth_delete_ip(struct qeth_card *card, struct qeth_ipaddr *addr)
if (addr->proto == QETH_PROT_IPV4) if (addr->proto == QETH_PROT_IPV4)
QETH_DBF_HEX(trace,4,&addr->u.a4.addr,4); QETH_DBF_HEX(trace,4,&addr->u.a4.addr,4);
else { else {
QETH_DBF_HEX(trace,4,&addr->u.a6.addr,4); QETH_DBF_HEX(trace,4,&addr->u.a6.addr,8);
QETH_DBF_HEX(trace,4,((char *)&addr->u.a6.addr)+4,4); QETH_DBF_HEX(trace,4,((char *)&addr->u.a6.addr)+8,8);
} }
spin_lock_irqsave(&card->ip_lock, flags); spin_lock_irqsave(&card->ip_lock, flags);
rc = __qeth_insert_ip_todo(card, addr, 0); rc = __qeth_insert_ip_todo(card, addr, 0);
...@@ -736,8 +747,8 @@ qeth_add_ip(struct qeth_card *card, struct qeth_ipaddr *addr) ...@@ -736,8 +747,8 @@ qeth_add_ip(struct qeth_card *card, struct qeth_ipaddr *addr)
if (addr->proto == QETH_PROT_IPV4) if (addr->proto == QETH_PROT_IPV4)
QETH_DBF_HEX(trace,4,&addr->u.a4.addr,4); QETH_DBF_HEX(trace,4,&addr->u.a4.addr,4);
else { else {
QETH_DBF_HEX(trace,4,&addr->u.a6.addr,4); QETH_DBF_HEX(trace,4,&addr->u.a6.addr,8);
QETH_DBF_HEX(trace,4,((char *)&addr->u.a6.addr)+4,4); QETH_DBF_HEX(trace,4,((char *)&addr->u.a6.addr)+8,8);
} }
spin_lock_irqsave(&card->ip_lock, flags); spin_lock_irqsave(&card->ip_lock, flags);
rc = __qeth_insert_ip_todo(card, addr, 1); rc = __qeth_insert_ip_todo(card, addr, 1);
...@@ -745,19 +756,21 @@ qeth_add_ip(struct qeth_card *card, struct qeth_ipaddr *addr) ...@@ -745,19 +756,21 @@ qeth_add_ip(struct qeth_card *card, struct qeth_ipaddr *addr)
return rc; return rc;
} }
static void static inline void
qeth_reinsert_todos(struct qeth_card *card, struct list_head *todos) __qeth_delete_all_mc(struct qeth_card *card, unsigned long *flags)
{ {
struct qeth_ipaddr *todo, *tmp; struct qeth_ipaddr *addr, *tmp;
int rc;
list_for_each_entry_safe(todo, tmp, todos, entry){ list_for_each_entry_safe(addr, tmp, &card->ip_list, entry) {
list_del_init(&todo->entry); if (addr->is_multicast) {
if (todo->users < 0) { spin_unlock_irqrestore(&card->ip_lock, *flags);
if (!qeth_delete_ip(card, todo)) rc = qeth_deregister_addr_entry(card, addr);
kfree(todo); spin_lock_irqsave(&card->ip_lock, *flags);
} else { if (!rc) {
if (!qeth_add_ip(card, todo)) list_del(&addr->entry);
kfree(todo); kfree(addr);
}
} }
} }
} }
...@@ -765,7 +778,7 @@ qeth_reinsert_todos(struct qeth_card *card, struct list_head *todos) ...@@ -765,7 +778,7 @@ qeth_reinsert_todos(struct qeth_card *card, struct list_head *todos)
static void static void
qeth_set_ip_addr_list(struct qeth_card *card) qeth_set_ip_addr_list(struct qeth_card *card)
{ {
struct list_head failed_todos; struct list_head *tbd_list;
struct qeth_ipaddr *todo, *addr; struct qeth_ipaddr *todo, *addr;
unsigned long flags; unsigned long flags;
int rc; int rc;
...@@ -773,13 +786,25 @@ qeth_set_ip_addr_list(struct qeth_card *card) ...@@ -773,13 +786,25 @@ qeth_set_ip_addr_list(struct qeth_card *card)
QETH_DBF_TEXT(trace, 2, "sdiplist"); QETH_DBF_TEXT(trace, 2, "sdiplist");
QETH_DBF_HEX(trace, 2, &card, sizeof(void *)); QETH_DBF_HEX(trace, 2, &card, sizeof(void *));
INIT_LIST_HEAD(&failed_todos);
spin_lock_irqsave(&card->ip_lock, flags); spin_lock_irqsave(&card->ip_lock, flags);
while (!list_empty(&card->ip_tbd_list)) { tbd_list = card->ip_tbd_list;
todo = list_entry(card->ip_tbd_list.next, card->ip_tbd_list = kmalloc(sizeof(struct list_head), GFP_ATOMIC);
struct qeth_ipaddr, entry); if (!card->ip_tbd_list) {
list_del_init(&todo->entry); QETH_DBF_TEXT(trace, 0, "silnomem");
card->ip_tbd_list = tbd_list;
spin_unlock_irqrestore(&card->ip_lock, flags);
return;
} else
INIT_LIST_HEAD(card->ip_tbd_list);
while (!list_empty(tbd_list)){
todo = list_entry(tbd_list->next, struct qeth_ipaddr, entry);
list_del(&todo->entry);
if (todo->type == QETH_IP_TYPE_DEL_ALL_MC){
__qeth_delete_all_mc(card, &flags);
kfree(todo);
continue;
}
rc = __qeth_ref_ip_on_card(card, todo, &addr); rc = __qeth_ref_ip_on_card(card, todo, &addr);
if (rc == 0) { if (rc == 0) {
/* nothing to be done; only adjusted refcount */ /* nothing to be done; only adjusted refcount */
...@@ -792,24 +817,22 @@ qeth_set_ip_addr_list(struct qeth_card *card) ...@@ -792,24 +817,22 @@ qeth_set_ip_addr_list(struct qeth_card *card)
if (!rc) if (!rc)
list_add_tail(&todo->entry, &card->ip_list); list_add_tail(&todo->entry, &card->ip_list);
else else
list_add_tail(&todo->entry, &failed_todos); kfree(todo);
} else if (rc == -1) { } else if (rc == -1) {
/* on-card entry to be removed */ /* on-card entry to be removed */
list_del_init(&addr->entry); list_del_init(&addr->entry);
spin_unlock_irqrestore(&card->ip_lock, flags); spin_unlock_irqrestore(&card->ip_lock, flags);
rc = qeth_deregister_addr_entry(card, addr); rc = qeth_deregister_addr_entry(card, addr);
spin_lock_irqsave(&card->ip_lock, flags); spin_lock_irqsave(&card->ip_lock, flags);
if (!rc) { if (!rc)
kfree(addr); kfree(addr);
kfree(todo); else
} else {
list_add_tail(&addr->entry, &card->ip_list); list_add_tail(&addr->entry, &card->ip_list);
list_add_tail(&todo->entry, &failed_todos); kfree(todo);
}
} }
} }
spin_unlock_irqrestore(&card->ip_lock, flags); spin_unlock_irqrestore(&card->ip_lock, flags);
qeth_reinsert_todos(card, &failed_todos); kfree(tbd_list);
} }
static void qeth_delete_mc_addresses(struct qeth_card *); static void qeth_delete_mc_addresses(struct qeth_card *);
...@@ -887,28 +910,7 @@ qeth_do_run_thread(struct qeth_card *card, unsigned long thread) ...@@ -887,28 +910,7 @@ qeth_do_run_thread(struct qeth_card *card, unsigned long thread)
} }
static int static int
qeth_register_mc_addresses(void *ptr) qeth_register_ip_addresses(void *ptr)
{
struct qeth_card *card;
card = (struct qeth_card *) ptr;
daemonize("qeth_reg_mcaddrs");
QETH_DBF_TEXT(trace,4,"regmcth1");
if (!qeth_do_run_thread(card, QETH_SET_MC_THREAD))
return 0;
QETH_DBF_TEXT(trace,4,"regmcth2");
qeth_delete_mc_addresses(card);
qeth_add_multicast_ipv4(card);
#ifdef CONFIG_QETH_IPV6
qeth_add_multicast_ipv6(card);
#endif
qeth_set_ip_addr_list(card);
qeth_clear_thread_running_bit(card, QETH_SET_MC_THREAD);
return 0;
}
static int
qeth_register_ip_address(void *ptr)
{ {
struct qeth_card *card; struct qeth_card *card;
...@@ -988,9 +990,7 @@ qeth_start_kernel_thread(struct qeth_card *card) ...@@ -988,9 +990,7 @@ qeth_start_kernel_thread(struct qeth_card *card)
return; return;
if (qeth_do_start_thread(card, QETH_SET_IP_THREAD)) if (qeth_do_start_thread(card, QETH_SET_IP_THREAD))
kernel_thread(qeth_register_ip_address, (void *) card, SIGCHLD); kernel_thread(qeth_register_ip_addresses, (void *)card,SIGCHLD);
if (qeth_do_start_thread(card, QETH_SET_MC_THREAD))
kernel_thread(qeth_register_mc_addresses, (void *)card,SIGCHLD);
if (qeth_do_start_thread(card, QETH_RECOVER_THREAD)) if (qeth_do_start_thread(card, QETH_RECOVER_THREAD))
kernel_thread(qeth_recover, (void *) card, SIGCHLD); kernel_thread(qeth_recover, (void *) card, SIGCHLD);
} }
...@@ -1041,7 +1041,12 @@ qeth_setup_card(struct qeth_card *card) ...@@ -1041,7 +1041,12 @@ qeth_setup_card(struct qeth_card *card)
INIT_WORK(&card->kernel_thread_starter, INIT_WORK(&card->kernel_thread_starter,
(void *)qeth_start_kernel_thread,card); (void *)qeth_start_kernel_thread,card);
INIT_LIST_HEAD(&card->ip_list); INIT_LIST_HEAD(&card->ip_list);
INIT_LIST_HEAD(&card->ip_tbd_list); card->ip_tbd_list = kmalloc(sizeof(struct list_head), GFP_KERNEL);
if (!card->ip_tbd_list) {
QETH_DBF_TEXT(setup, 0, "iptbdnom");
return -ENOMEM;
}
INIT_LIST_HEAD(card->ip_tbd_list);
INIT_LIST_HEAD(&card->cmd_waiter_list); INIT_LIST_HEAD(&card->cmd_waiter_list);
init_waitqueue_head(&card->wait_q); init_waitqueue_head(&card->wait_q);
/* intial options */ /* intial options */
...@@ -1575,9 +1580,8 @@ qeth_reset_ip_addresses(struct qeth_card *card) ...@@ -1575,9 +1580,8 @@ qeth_reset_ip_addresses(struct qeth_card *card)
QETH_DBF_TEXT(trace, 2, "rstipadd"); QETH_DBF_TEXT(trace, 2, "rstipadd");
qeth_clear_ip_list(card, 0, 1); qeth_clear_ip_list(card, 0, 1);
if ( (qeth_set_thread_start_bit(card, QETH_SET_IP_THREAD) == 0) || /* this function will also schedule the SET_IP_THREAD */
(qeth_set_thread_start_bit(card, QETH_SET_MC_THREAD) == 0) ) qeth_set_multicast_list(card->dev);
schedule_work(&card->kernel_thread_starter);
} }
static struct qeth_ipa_cmd * static struct qeth_ipa_cmd *
...@@ -1600,10 +1604,7 @@ qeth_check_ipa_data(struct qeth_card *card, struct qeth_cmd_buffer *iob) ...@@ -1600,10 +1604,7 @@ qeth_check_ipa_data(struct qeth_card *card, struct qeth_cmd_buffer *iob)
card->info.if_name, card->info.if_name,
card->info.chpid); card->info.chpid);
card->lan_online = 0; card->lan_online = 0;
if (netif_carrier_ok(card->dev)) {
netif_carrier_off(card->dev); netif_carrier_off(card->dev);
netif_stop_queue(card->dev);
}
return NULL; return NULL;
case IPA_CMD_STARTLAN: case IPA_CMD_STARTLAN:
PRINT_INFO("Link reestablished on %s " PRINT_INFO("Link reestablished on %s "
...@@ -1612,10 +1613,7 @@ qeth_check_ipa_data(struct qeth_card *card, struct qeth_cmd_buffer *iob) ...@@ -1612,10 +1613,7 @@ qeth_check_ipa_data(struct qeth_card *card, struct qeth_cmd_buffer *iob)
card->info.if_name, card->info.if_name,
card->info.chpid); card->info.chpid);
card->lan_online = 1; card->lan_online = 1;
if (!netif_carrier_ok(card->dev)) {
netif_carrier_on(card->dev); netif_carrier_on(card->dev);
netif_wake_queue(card->dev);
}
qeth_reset_ip_addresses(card); qeth_reset_ip_addresses(card);
return NULL; return NULL;
case IPA_CMD_REGISTER_LOCAL_ADDR: case IPA_CMD_REGISTER_LOCAL_ADDR:
...@@ -2807,6 +2805,7 @@ qeth_qdio_output_handler(struct ccw_device * ccwdev, unsigned int status, ...@@ -2807,6 +2805,7 @@ qeth_qdio_output_handler(struct ccw_device * ccwdev, unsigned int status,
} }
atomic_sub(count, &queue->used_buffers); atomic_sub(count, &queue->used_buffers);
/* check if we need to do something on this outbound queue */ /* check if we need to do something on this outbound queue */
if (card->info.type != QETH_CARD_TYPE_IQD)
qeth_check_outbound_queue(queue); qeth_check_outbound_queue(queue);
netif_wake_queue(card->dev); netif_wake_queue(card->dev);
...@@ -3381,13 +3380,16 @@ qeth_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -3381,13 +3380,16 @@ qeth_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (skb==NULL) { if (skb==NULL) {
card->stats.tx_dropped++; card->stats.tx_dropped++;
card->stats.tx_errors++; card->stats.tx_errors++;
return -EIO; /* return OK; otherwise ksoftirqd goes to 100% */
return NETDEV_TX_OK;
} }
if ((card->state != CARD_STATE_UP) || !netif_carrier_ok(dev)) { if ((card->state != CARD_STATE_UP) || !card->lan_online) {
card->stats.tx_dropped++; card->stats.tx_dropped++;
card->stats.tx_errors++; card->stats.tx_errors++;
card->stats.tx_carrier_errors++; card->stats.tx_carrier_errors++;
return -EIO; dev_kfree_skb_any(skb);
/* return OK; otherwise ksoftirqd goes to 100% */
return NETDEV_TX_OK;
} }
#ifdef CONFIG_QETH_PERF_STATS #ifdef CONFIG_QETH_PERF_STATS
card->perf_stats.outbound_cnt++; card->perf_stats.outbound_cnt++;
...@@ -3398,8 +3400,18 @@ qeth_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -3398,8 +3400,18 @@ qeth_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
* got our own synchronization on queues we can keep the stack's * got our own synchronization on queues we can keep the stack's
* queue running. * queue running.
*/ */
if ((rc = qeth_send_packet(card, skb))) if ((rc = qeth_send_packet(card, skb))){
if (rc == -EBUSY) {
netif_stop_queue(dev); netif_stop_queue(dev);
rc = NETDEV_TX_BUSY;
} else {
card->stats.tx_errors++;
card->stats.tx_dropped++;
dev_kfree_skb_any(skb);
/* set to OK; otherwise ksoftirqd goes to 100% */
rc = NETDEV_TX_OK;
}
}
#ifdef CONFIG_QETH_PERF_STATS #ifdef CONFIG_QETH_PERF_STATS
card->perf_stats.outbound_time += qeth_get_micros() - card->perf_stats.outbound_time += qeth_get_micros() -
...@@ -3503,7 +3515,6 @@ qeth_open(struct net_device *dev) ...@@ -3503,7 +3515,6 @@ qeth_open(struct net_device *dev)
if (!card->lan_online){ if (!card->lan_online){
if (netif_carrier_ok(dev)) if (netif_carrier_ok(dev))
netif_carrier_off(dev); netif_carrier_off(dev);
netif_stop_queue(dev);
} }
return 0; return 0;
} }
...@@ -4988,12 +4999,28 @@ qeth_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) ...@@ -4988,12 +4999,28 @@ qeth_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
spin_unlock_irqrestore(&card->vlanlock, flags); spin_unlock_irqrestore(&card->vlanlock, flags);
if (card->options.layer2) if (card->options.layer2)
qeth_layer2_send_setdelvlan(card, vid, IPA_CMD_DELVLAN); qeth_layer2_send_setdelvlan(card, vid, IPA_CMD_DELVLAN);
if ( (qeth_set_thread_start_bit(card, QETH_SET_IP_THREAD) == 0) || qeth_set_multicast_list(card->dev);
(qeth_set_thread_start_bit(card, QETH_SET_MC_THREAD) == 0) )
schedule_work(&card->kernel_thread_starter);
} }
#endif #endif
/**
* set multicast address on card
*/
static void
qeth_set_multicast_list(struct net_device *dev)
{
struct qeth_card *card = (struct qeth_card *) dev->priv;
QETH_DBF_TEXT(trace,3,"setmulti");
qeth_delete_mc_addresses(card);
qeth_add_multicast_ipv4(card);
#ifdef CONFIG_QETH_IPV6
qeth_add_multicast_ipv6(card);
#endif
if (qeth_set_thread_start_bit(card, QETH_SET_IP_THREAD) == 0)
schedule_work(&card->kernel_thread_starter);
}
static int static int
qeth_neigh_setup(struct net_device *dev, struct neigh_parms *np) qeth_neigh_setup(struct net_device *dev, struct neigh_parms *np)
{ {
...@@ -5049,24 +5076,19 @@ qeth_get_addr_buffer(enum qeth_prot_versions prot) ...@@ -5049,24 +5076,19 @@ qeth_get_addr_buffer(enum qeth_prot_versions prot)
static void static void
qeth_delete_mc_addresses(struct qeth_card *card) qeth_delete_mc_addresses(struct qeth_card *card)
{ {
struct qeth_ipaddr *ipm, *iptodo; struct qeth_ipaddr *iptodo;
unsigned long flags; unsigned long flags;
QETH_DBF_TEXT(trace,4,"delmc"); QETH_DBF_TEXT(trace,4,"delmc");
spin_lock_irqsave(&card->ip_lock, flags); iptodo = qeth_get_addr_buffer(QETH_PROT_IPV4);
list_for_each_entry(ipm, &card->ip_list, entry){
if (!ipm->is_multicast)
continue;
iptodo = qeth_get_addr_buffer(ipm->proto);
if (!iptodo) { if (!iptodo) {
QETH_DBF_TEXT(trace, 2, "dmcnomem"); QETH_DBF_TEXT(trace, 2, "dmcnomem");
continue; return;
} }
memcpy(iptodo, ipm, sizeof(struct qeth_ipaddr)); iptodo->type = QETH_IP_TYPE_DEL_ALL_MC;
iptodo->users = iptodo->users * -1; spin_lock_irqsave(&card->ip_lock, flags);
if (!__qeth_insert_ip_todo(card, iptodo, 0)) if (!__qeth_insert_ip_todo(card, iptodo, 0))
kfree(iptodo); kfree(iptodo);
}
spin_unlock_irqrestore(&card->ip_lock, flags); spin_unlock_irqrestore(&card->ip_lock, flags);
} }
...@@ -5277,20 +5299,6 @@ qeth_layer2_set_mac_address(struct net_device *dev, void *p) ...@@ -5277,20 +5299,6 @@ qeth_layer2_set_mac_address(struct net_device *dev, void *p)
return rc; return rc;
} }
/**
* set multicast address on card
*/
static void
qeth_set_multicast_list(struct net_device *dev)
{
struct qeth_card *card;
QETH_DBF_TEXT(trace,3,"setmulti");
card = (struct qeth_card *) dev->priv;
if (qeth_set_thread_start_bit(card, QETH_SET_MC_THREAD) == 0)
schedule_work(&card->kernel_thread_starter);
}
static void static void
qeth_fill_ipacmd_header(struct qeth_card *card, struct qeth_ipa_cmd *cmd, qeth_fill_ipacmd_header(struct qeth_card *card, struct qeth_ipa_cmd *cmd,
...@@ -6635,7 +6643,7 @@ qeth_clear_ip_list(struct qeth_card *card, int clean, int recover) ...@@ -6635,7 +6643,7 @@ qeth_clear_ip_list(struct qeth_card *card, int clean, int recover)
QETH_DBF_TEXT(trace,4,"clearip"); QETH_DBF_TEXT(trace,4,"clearip");
spin_lock_irqsave(&card->ip_lock, flags); spin_lock_irqsave(&card->ip_lock, flags);
/* clear todo list */ /* clear todo list */
list_for_each_entry_safe(addr, tmp, &card->ip_tbd_list, entry){ list_for_each_entry_safe(addr, tmp, card->ip_tbd_list, entry){
list_del(&addr->entry); list_del(&addr->entry);
kfree(addr); kfree(addr);
} }
...@@ -6653,7 +6661,7 @@ qeth_clear_ip_list(struct qeth_card *card, int clean, int recover) ...@@ -6653,7 +6661,7 @@ qeth_clear_ip_list(struct qeth_card *card, int clean, int recover)
kfree(addr); kfree(addr);
continue; continue;
} }
list_add_tail(&addr->entry, &card->ip_tbd_list); list_add_tail(&addr->entry, card->ip_tbd_list);
} }
spin_unlock_irqrestore(&card->ip_lock, flags); spin_unlock_irqrestore(&card->ip_lock, flags);
} }
...@@ -6893,8 +6901,7 @@ qeth_start_again(struct qeth_card *card) ...@@ -6893,8 +6901,7 @@ qeth_start_again(struct qeth_card *card)
rtnl_lock(); rtnl_lock();
dev_open(card->dev); dev_open(card->dev);
rtnl_unlock(); rtnl_unlock();
if (qeth_set_thread_start_bit(card, QETH_SET_MC_THREAD) == 0) qeth_set_multicast_list(card->dev);
schedule_work(&card->kernel_thread_starter);
} }
...@@ -7008,9 +7015,7 @@ qeth_set_online(struct ccwgroup_device *gdev) ...@@ -7008,9 +7015,7 @@ qeth_set_online(struct ccwgroup_device *gdev)
/*maybe it was set offline without ifconfig down /*maybe it was set offline without ifconfig down
* we can also use this state for recovery purposes*/ * we can also use this state for recovery purposes*/
if (card->options.layer2) if (card->options.layer2)
qeth_set_allowed_threads(card, qeth_set_allowed_threads(card, QETH_RECOVER_THREAD, 0);
QETH_RECOVER_THREAD |
QETH_SET_MC_THREAD,0);
else else
qeth_set_allowed_threads(card, 0xffffffff, 0); qeth_set_allowed_threads(card, 0xffffffff, 0);
if (recover_flag == CARD_STATE_RECOVER) if (recover_flag == CARD_STATE_RECOVER)
...@@ -7339,7 +7344,7 @@ qeth_add_vipa(struct qeth_card *card, enum qeth_prot_versions proto, ...@@ -7339,7 +7344,7 @@ qeth_add_vipa(struct qeth_card *card, enum qeth_prot_versions proto,
return -ENOMEM; return -ENOMEM;
spin_lock_irqsave(&card->ip_lock, flags); spin_lock_irqsave(&card->ip_lock, flags);
if (__qeth_address_exists_in_list(&card->ip_list, ipaddr, 0) || if (__qeth_address_exists_in_list(&card->ip_list, ipaddr, 0) ||
__qeth_address_exists_in_list(&card->ip_tbd_list, ipaddr, 0)) __qeth_address_exists_in_list(card->ip_tbd_list, ipaddr, 0))
rc = -EEXIST; rc = -EEXIST;
spin_unlock_irqrestore(&card->ip_lock, flags); spin_unlock_irqrestore(&card->ip_lock, flags);
if (rc){ if (rc){
...@@ -7412,7 +7417,7 @@ qeth_add_rxip(struct qeth_card *card, enum qeth_prot_versions proto, ...@@ -7412,7 +7417,7 @@ qeth_add_rxip(struct qeth_card *card, enum qeth_prot_versions proto,
return -ENOMEM; return -ENOMEM;
spin_lock_irqsave(&card->ip_lock, flags); spin_lock_irqsave(&card->ip_lock, flags);
if (__qeth_address_exists_in_list(&card->ip_list, ipaddr, 0) || if (__qeth_address_exists_in_list(&card->ip_list, ipaddr, 0) ||
__qeth_address_exists_in_list(&card->ip_tbd_list, ipaddr, 0)) __qeth_address_exists_in_list(card->ip_tbd_list, ipaddr, 0))
rc = -EEXIST; rc = -EEXIST;
spin_unlock_irqrestore(&card->ip_lock, flags); spin_unlock_irqrestore(&card->ip_lock, flags);
if (rc){ if (rc){
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment