Commit 8d21a7e3 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] s390: network device drivers.

From: Martin Schwidefsky <schwidefsky@de.ibm.com>

Network driver changes:
 - qeth: Fix reference counting in regard to sysfs backing store patches.
 - qeth: Prefix kernel thread names with qeth_.
 - qeth: Remove inbound and outbound tasklets. Handle buffers directly
         in the interrupts handlers.
 - iucv: Add missing kfree in iucv_register_program.
 - iucv: Add missing return in netiucv_transmit_skb.
 - iucv: Check for NULL pointer in conn_action_txdone.
parent c6f7f898
/* /*
* $Id: iucv.c,v 1.27 2004/03/22 07:43:43 braunu Exp $ * $Id: iucv.c,v 1.28 2004/04/15 06:34:58 braunu Exp $
* *
* IUCV network driver * IUCV network driver
* *
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,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: IUCV lowlevel driver $Revision: 1.27 $ * RELEASE-TAG: IUCV lowlevel driver $Revision: 1.28 $
* *
*/ */
...@@ -351,7 +351,7 @@ do { \ ...@@ -351,7 +351,7 @@ do { \
static void static void
iucv_banner(void) iucv_banner(void)
{ {
char vbuf[] = "$Revision: 1.27 $"; char vbuf[] = "$Revision: 1.28 $";
char *version = vbuf; char *version = vbuf;
if ((version = strchr(version, ':'))) { if ((version = strchr(version, ':'))) {
...@@ -800,6 +800,7 @@ iucv_register_program (__u8 pgmname[16], ...@@ -800,6 +800,7 @@ iucv_register_program (__u8 pgmname[16],
if (iucv_pathid_table == NULL) { if (iucv_pathid_table == NULL) {
printk(KERN_WARNING "%s: iucv_pathid_table storage " printk(KERN_WARNING "%s: iucv_pathid_table storage "
"allocation failed\n", __FUNCTION__); "allocation failed\n", __FUNCTION__);
kfree(new_handler);
return NULL; return NULL;
} }
memset (iucv_pathid_table, 0, max_connections * sizeof(handler *)); memset (iucv_pathid_table, 0, max_connections * sizeof(handler *));
......
/* /*
* $Id: netiucv.c,v 1.48 2004/04/01 13:42:09 braunu Exp $ * $Id: netiucv.c,v 1.49 2004/04/15 06:37:54 braunu Exp $
* *
* IUCV network driver * IUCV network driver
* *
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,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: IUCV network driver $Revision: 1.48 $ * RELEASE-TAG: IUCV network driver $Revision: 1.49 $
* *
*/ */
...@@ -601,11 +601,12 @@ conn_action_txdone(fsm_instance *fi, int event, void *arg) ...@@ -601,11 +601,12 @@ conn_action_txdone(fsm_instance *fi, int event, void *arg)
if ((skb = skb_dequeue(&conn->commit_queue))) { if ((skb = skb_dequeue(&conn->commit_queue))) {
atomic_dec(&skb->users); atomic_dec(&skb->users);
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
}
if (privptr) { if (privptr) {
privptr->stats.tx_packets++; privptr->stats.tx_packets++;
privptr->stats.tx_bytes += privptr->stats.tx_bytes +=
(skb->len - NETIUCV_HDRLEN - NETIUCV_HDRLEN); (skb->len - NETIUCV_HDRLEN
- NETIUCV_HDRLEN);
}
} }
} }
conn->tx_buff->data = conn->tx_buff->tail = conn->tx_buff->head; conn->tx_buff->data = conn->tx_buff->tail = conn->tx_buff->head;
...@@ -1078,6 +1079,7 @@ netiucv_transmit_skb(struct iucv_connection *conn, struct sk_buff *skb) { ...@@ -1078,6 +1079,7 @@ netiucv_transmit_skb(struct iucv_connection *conn, struct sk_buff *skb) {
"%s: Could not allocate tx_skb\n", "%s: Could not allocate tx_skb\n",
conn->netdev->name); conn->netdev->name);
rc = -ENOMEM; rc = -ENOMEM;
return rc;
} else { } else {
skb_reserve(nskb, NETIUCV_HDRLEN); skb_reserve(nskb, NETIUCV_HDRLEN);
memcpy(skb_put(nskb, skb->len), memcpy(skb_put(nskb, skb->len),
...@@ -1880,7 +1882,7 @@ static struct device_driver netiucv_driver = { ...@@ -1880,7 +1882,7 @@ static struct device_driver netiucv_driver = {
static void static void
netiucv_banner(void) netiucv_banner(void)
{ {
char vbuf[] = "$Revision: 1.48 $"; char vbuf[] = "$Revision: 1.49 $";
char *version = vbuf; char *version = vbuf;
if ((version = strchr(version, ':'))) { if ((version = strchr(version, ':'))) {
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
#include "qeth_mpc.h" #include "qeth_mpc.h"
#define VERSION_QETH_H "$Revision: 1.98 $" #define VERSION_QETH_H "$Revision: 1.100 $"
#ifdef CONFIG_QETH_IPV6 #ifdef CONFIG_QETH_IPV6
#define QETH_VERSION_IPV6 ":IPv6" #define QETH_VERSION_IPV6 ":IPv6"
...@@ -423,14 +423,12 @@ struct qeth_qdio_out_q { ...@@ -423,14 +423,12 @@ struct qeth_qdio_out_q {
struct qeth_qdio_out_buffer bufs[QDIO_MAX_BUFFERS_PER_Q]; struct qeth_qdio_out_buffer bufs[QDIO_MAX_BUFFERS_PER_Q];
int queue_no; int queue_no;
struct qeth_card *card; struct qeth_card *card;
struct tasklet_struct tasklet;
spinlock_t lock; spinlock_t lock;
volatile int do_pack; volatile int do_pack;
/* /*
* index of buffer to be filled by driver; state EMPTY or PACKING * index of buffer to be filled by driver; state EMPTY or PACKING
*/ */
volatile int next_buf_to_fill; volatile int next_buf_to_fill;
volatile int next_buf_to_flush;
/* /*
* number of buffers that are currently filled (PRIMED) * number of buffers that are currently filled (PRIMED)
* -> these buffers are hardware-owned * -> these buffers are hardware-owned
...@@ -447,7 +445,6 @@ struct qeth_qdio_info { ...@@ -447,7 +445,6 @@ struct qeth_qdio_info {
struct qeth_qdio_buffer_pool in_buf_pool; struct qeth_qdio_buffer_pool in_buf_pool;
struct qeth_qdio_buffer_pool init_pool; struct qeth_qdio_buffer_pool init_pool;
int in_buf_size; int in_buf_size;
struct tasklet_struct in_tasklet;
/* output */ /* output */
int no_out_queues; int no_out_queues;
......
/* /*
* *
* linux/drivers/s390/net/qeth_main.c ($Revision: 1.77 $) * linux/drivers/s390/net/qeth_main.c ($Revision: 1.82 $)
* *
* 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.77 $ $Date: 2004/04/06 14:38:19 $ * $Revision: 1.82 $ $Date: 2004/04/21 08:27:21 $
* *
* 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.77 $" #define VERSION_QETH_C "$Revision: 1.82 $"
static const char *version = "qeth S/390 OSA-Express driver (" static const char *version = "qeth S/390 OSA-Express driver ("
VERSION_QETH_C "/" VERSION_QETH_H "/" VERSION_QETH_MPC_H VERSION_QETH_C "/" VERSION_QETH_H "/" VERSION_QETH_MPC_H
QETH_VERSION_IPV6 QETH_VERSION_VLAN ")"; QETH_VERSION_IPV6 QETH_VERSION_VLAN ")";
...@@ -486,6 +486,7 @@ qeth_remove_device(struct ccwgroup_device *cgdev) ...@@ -486,6 +486,7 @@ qeth_remove_device(struct ccwgroup_device *cgdev)
list_del(&card->list); list_del(&card->list);
write_unlock_irqrestore(&qeth_card_list.rwlock, flags); write_unlock_irqrestore(&qeth_card_list.rwlock, flags);
unregister_netdev(card->dev); unregister_netdev(card->dev);
qeth_remove_device_attributes(&cgdev->dev);
qeth_free_card(card); qeth_free_card(card);
cgdev->dev.driver_data = NULL; cgdev->dev.driver_data = NULL;
put_device(&cgdev->dev); put_device(&cgdev->dev);
...@@ -822,7 +823,7 @@ qeth_register_mc_addresses(void *ptr) ...@@ -822,7 +823,7 @@ qeth_register_mc_addresses(void *ptr)
struct qeth_card *card; struct qeth_card *card;
card = (struct qeth_card *) ptr; card = (struct qeth_card *) ptr;
daemonize("getmcaddr"); daemonize("qeth_reg_mcaddrs");
QETH_DBF_TEXT(trace,4,"regmcth1"); QETH_DBF_TEXT(trace,4,"regmcth1");
if (!qeth_do_run_thread(card, QETH_SET_MC_THREAD)) if (!qeth_do_run_thread(card, QETH_SET_MC_THREAD))
return 0; return 0;
...@@ -843,7 +844,7 @@ qeth_register_ip_address(void *ptr) ...@@ -843,7 +844,7 @@ qeth_register_ip_address(void *ptr)
struct qeth_card *card; struct qeth_card *card;
card = (struct qeth_card *) ptr; card = (struct qeth_card *) ptr;
daemonize("regip"); daemonize("qeth_reg_ip");
QETH_DBF_TEXT(trace,4,"regipth1"); QETH_DBF_TEXT(trace,4,"regipth1");
if (!qeth_do_run_thread(card, QETH_SET_IP_THREAD)) if (!qeth_do_run_thread(card, QETH_SET_IP_THREAD))
return 0; return 0;
...@@ -860,7 +861,7 @@ qeth_recover(void *ptr) ...@@ -860,7 +861,7 @@ qeth_recover(void *ptr)
int rc = 0; int rc = 0;
card = (struct qeth_card *) ptr; card = (struct qeth_card *) ptr;
daemonize("recover"); daemonize("qeth_recover");
QETH_DBF_TEXT(trace,2,"recover1"); QETH_DBF_TEXT(trace,2,"recover1");
QETH_DBF_HEX(trace, 2, &card, sizeof(void *)); QETH_DBF_HEX(trace, 2, &card, sizeof(void *));
if (!qeth_do_run_thread(card, QETH_RECOVER_THREAD)) if (!qeth_do_run_thread(card, QETH_RECOVER_THREAD))
...@@ -1969,45 +1970,6 @@ qeth_check_for_inbound_error(struct qeth_qdio_buffer *buf, ...@@ -1969,45 +1970,6 @@ qeth_check_for_inbound_error(struct qeth_qdio_buffer *buf,
return rc; return rc;
} }
static void
qeth_qdio_input_handler(struct ccw_device * ccwdev, unsigned int status,
unsigned int qdio_err, unsigned int siga_err,
unsigned int queue, int first_element, int count,
unsigned long card_ptr)
{
struct net_device *net_dev;
struct qeth_card *card;
struct qeth_qdio_buffer *buffer;
int i;
QETH_DBF_TEXT(trace, 6, "qdinput");
card = (struct qeth_card *) card_ptr;
net_dev = card->dev;
#ifdef CONFIG_QETH_PERF_STATS
card->perf_stats.inbound_start_time = qeth_get_micros();
#endif
if (status & QDIO_STATUS_LOOK_FOR_ERROR) {
if (status & QDIO_STATUS_ACTIVATE_CHECK_CONDITION){
QETH_DBF_TEXT(trace, 1,"qdinchk");
QETH_DBF_TEXT_(trace,1,"%s",CARD_BUS_ID(card));
QETH_DBF_TEXT_(trace,1,"%04X%04X",first_element,count);
QETH_DBF_TEXT_(trace,1,"%04X%04X", queue, status);
qeth_schedule_recovery(card);
return;
}
}
for (i = first_element; i < (first_element + count); ++i) {
buffer = &card->qdio.in_q->bufs[i % QDIO_MAX_BUFFERS_PER_Q];
if ((status == QDIO_STATUS_LOOK_FOR_ERROR) &&
qeth_check_for_inbound_error(buffer, qdio_err, siga_err))
buffer->state = QETH_QDIO_BUF_ERROR;
else
buffer->state = QETH_QDIO_BUF_PRIMED;
}
tasklet_schedule(&card->qdio.in_tasklet);
}
static inline struct sk_buff * static inline struct sk_buff *
qeth_get_skb(unsigned int length) qeth_get_skb(unsigned int length)
{ {
...@@ -2127,7 +2089,6 @@ qeth_type_trans(struct sk_buff *skb, struct net_device *dev) ...@@ -2127,7 +2089,6 @@ qeth_type_trans(struct sk_buff *skb, struct net_device *dev)
return htons(ETH_P_802_2); return htons(ETH_P_802_2);
} }
static inline void static inline void
qeth_rebuild_skb_fake_ll(struct qeth_card *card, struct sk_buff *skb, qeth_rebuild_skb_fake_ll(struct qeth_card *card, struct sk_buff *skb,
struct qeth_hdr *hdr) struct qeth_hdr *hdr)
...@@ -2193,7 +2154,6 @@ qeth_rebuild_skb_vlan(struct qeth_card *card, struct sk_buff *skb, ...@@ -2193,7 +2154,6 @@ qeth_rebuild_skb_vlan(struct qeth_card *card, struct sk_buff *skb,
#endif /* CONFIG_QETH_VLAN */ #endif /* CONFIG_QETH_VLAN */
} }
static inline void static inline void
qeth_rebuild_skb(struct qeth_card *card, struct sk_buff *skb, qeth_rebuild_skb(struct qeth_card *card, struct sk_buff *skb,
struct qeth_hdr *hdr) struct qeth_hdr *hdr)
...@@ -2241,6 +2201,38 @@ qeth_rebuild_skb(struct qeth_card *card, struct sk_buff *skb, ...@@ -2241,6 +2201,38 @@ qeth_rebuild_skb(struct qeth_card *card, struct sk_buff *skb,
qeth_rebuild_skb_vlan(card, skb, hdr); qeth_rebuild_skb_vlan(card, skb, hdr);
} }
static inline void
qeth_process_inbound_buffer(struct qeth_card *card,
struct qeth_qdio_buffer *buf, int index)
{
struct qdio_buffer_element *element;
int offset;
struct sk_buff *skb;
struct qeth_hdr *hdr;
int rxrc;
/* get first element of current buffer */
element = (struct qdio_buffer_element *)&buf->buffer->element[0];
offset = 0;
#ifdef CONFIG_QETH_PERF_STATS
card->perf_stats.bufs_rec++;
#endif
while((skb = qeth_get_next_skb(card, buf->buffer, &element,
&offset, &hdr))){
qeth_rebuild_skb(card, skb, hdr);
#ifdef CONFIG_QETH_PERF_STATS
card->perf_stats.inbound_time += qeth_get_micros() -
card->perf_stats.inbound_start_time;
card->perf_stats.inbound_cnt++;
#endif
skb->dev = card->dev;
rxrc = netif_rx(skb);
card->dev->last_rx = jiffies;
card->stats.rx_packets++;
card->stats.rx_bytes += skb->len;
}
}
static inline struct qeth_buffer_pool_entry * static inline struct qeth_buffer_pool_entry *
qeth_get_buffer_pool_entry(struct qeth_card *card) qeth_get_buffer_pool_entry(struct qeth_card *card)
...@@ -2284,7 +2276,7 @@ qeth_init_input_buffer(struct qeth_card *card, struct qeth_qdio_buffer *buf) ...@@ -2284,7 +2276,7 @@ qeth_init_input_buffer(struct qeth_card *card, struct qeth_qdio_buffer *buf)
buf->state = QETH_QDIO_BUF_EMPTY; buf->state = QETH_QDIO_BUF_EMPTY;
} }
static void static inline void
qeth_clear_output_buffer(struct qeth_card *card, qeth_clear_output_buffer(struct qeth_card *card,
struct qeth_qdio_out_buffer *buf) struct qeth_qdio_out_buffer *buf)
{ {
...@@ -2355,61 +2347,43 @@ qeth_put_buffer_pool_entry(struct qeth_card *card, ...@@ -2355,61 +2347,43 @@ qeth_put_buffer_pool_entry(struct qeth_card *card,
} }
static void static void
qeth_qdio_input_tasklet(unsigned long data) qeth_qdio_input_handler(struct ccw_device * ccwdev, unsigned int status,
unsigned int qdio_err, unsigned int siga_err,
unsigned int queue, int first_element, int count,
unsigned long card_ptr)
{ {
struct qeth_card *card = (struct qeth_card *) data; struct net_device *net_dev;
int current_buf = card->qdio.in_q->next_buf_to_process; struct qeth_card *card;
struct qeth_qdio_buffer *buf; struct qeth_qdio_buffer *buffer;
struct qdio_buffer_element *element; int index;
int offset; int i;
struct sk_buff *skb;
struct qeth_hdr *hdr;
int rxrc;
QETH_DBF_TEXT(trace,6,"qdintlet");
buf = &card->qdio.in_q->bufs[current_buf];
while((buf->state == QETH_QDIO_BUF_PRIMED) ||
(buf->state == QETH_QDIO_BUF_ERROR)){
if (buf->state == QETH_QDIO_BUF_ERROR)
goto clear_buffer;
if (netif_queue_stopped(card->dev))
goto clear_buffer;
/* get first element of current buffer */
element = (struct qdio_buffer_element *)
&buf->buffer->element[0];
offset = 0;
#ifdef CONFIG_QETH_PERF_STATS
card->perf_stats.bufs_rec++;
#endif
while((skb = qeth_get_next_skb(card, buf->buffer, &element,
&offset, &hdr))){
qeth_rebuild_skb(card, skb, hdr); QETH_DBF_TEXT(trace, 6, "qdinput");
card = (struct qeth_card *) card_ptr;
net_dev = card->dev;
#ifdef CONFIG_QETH_PERF_STATS #ifdef CONFIG_QETH_PERF_STATS
card->perf_stats.inbound_time += qeth_get_micros() - card->perf_stats.inbound_start_time = qeth_get_micros();
card->perf_stats.inbound_start_time;
card->perf_stats.inbound_cnt++;
#endif #endif
skb->dev = card->dev; if (status & QDIO_STATUS_LOOK_FOR_ERROR) {
if (netif_queue_stopped(card->dev)) { if (status & QDIO_STATUS_ACTIVATE_CHECK_CONDITION){
dev_kfree_skb_irq(skb); QETH_DBF_TEXT(trace, 1,"qdinchk");
card->stats.rx_dropped++; QETH_DBF_TEXT_(trace,1,"%s",CARD_BUS_ID(card));
} else { QETH_DBF_TEXT_(trace,1,"%04X%04X",first_element,count);
rxrc = netif_rx(skb); QETH_DBF_TEXT_(trace,1,"%04X%04X", queue, status);
card->dev->last_rx = jiffies; qeth_schedule_recovery(card);
card->stats.rx_packets++; return;
card->stats.rx_bytes += skb->len;
} }
} }
clear_buffer: for (i = first_element; i < (first_element + count); ++i) {
qeth_put_buffer_pool_entry(card, buf->pool_entry); index = i % QDIO_MAX_BUFFERS_PER_Q;
/* give buffer back to hardware */ buffer = &card->qdio.in_q->bufs[index];
qeth_queue_input_buffer(card, current_buf); if (!((status == QDIO_STATUS_LOOK_FOR_ERROR) &&
current_buf = (current_buf + 1) % QDIO_MAX_BUFFERS_PER_Q; qeth_check_for_inbound_error(buffer, qdio_err, siga_err)))
buf = &card->qdio.in_q->bufs[current_buf]; qeth_process_inbound_buffer(card, buffer, index);
/* clear buffer and give back to hardware */
qeth_put_buffer_pool_entry(card, buffer->pool_entry);
qeth_queue_input_buffer(card, index);
} }
/* set index for next time the tasklet is scheduled */
card->qdio.in_q->next_buf_to_process = current_buf;
} }
static inline int static inline int
...@@ -2524,10 +2498,11 @@ qeth_flush_buffers(struct qeth_qdio_out_q *queue, int under_int, ...@@ -2524,10 +2498,11 @@ qeth_flush_buffers(struct qeth_qdio_out_q *queue, int under_int,
* switches between PACKING and non-PACKING state if needed. * switches between PACKING and non-PACKING state if needed.
* has to be called holding queue->lock * has to be called holding queue->lock
*/ */
static inline void static inline int
qeth_switch_packing_state(struct qeth_qdio_out_q *queue) qeth_switch_packing_state(struct qeth_qdio_out_q *queue)
{ {
struct qeth_qdio_out_buffer *buffer; struct qeth_qdio_out_buffer *buffer;
int flush_count = 0;
QETH_DBF_TEXT(trace, 6, "swipack"); QETH_DBF_TEXT(trace, 6, "swipack");
if (!queue->do_pack) { if (!queue->do_pack) {
...@@ -2554,6 +2529,7 @@ qeth_switch_packing_state(struct qeth_qdio_out_q *queue) ...@@ -2554,6 +2529,7 @@ qeth_switch_packing_state(struct qeth_qdio_out_q *queue)
BUG_ON(buffer->state == QETH_QDIO_BUF_PRIMED); BUG_ON(buffer->state == QETH_QDIO_BUF_PRIMED);
if (buffer->next_element_to_fill > 0) { if (buffer->next_element_to_fill > 0) {
buffer->state = QETH_QDIO_BUF_PRIMED; buffer->state = QETH_QDIO_BUF_PRIMED;
flush_count++;
atomic_inc(&queue->used_buffers); atomic_inc(&queue->used_buffers);
queue->next_buf_to_fill = queue->next_buf_to_fill =
(queue->next_buf_to_fill + 1) % (queue->next_buf_to_fill + 1) %
...@@ -2561,6 +2537,25 @@ qeth_switch_packing_state(struct qeth_qdio_out_q *queue) ...@@ -2561,6 +2537,25 @@ qeth_switch_packing_state(struct qeth_qdio_out_q *queue)
} }
} }
} }
return flush_count;
}
static inline void
qeth_flush_buffers_on_no_pci(struct qeth_qdio_out_q *queue, int under_int)
{
struct qeth_qdio_out_buffer *buffer;
buffer = &queue->bufs[queue->next_buf_to_fill];
BUG_ON(buffer->state == QETH_QDIO_BUF_PRIMED);
if (buffer->next_element_to_fill > 0){
/* it's a packing buffer */
buffer->state = QETH_QDIO_BUF_PRIMED;
atomic_inc(&queue->used_buffers);
qeth_flush_buffers(queue, under_int, queue->next_buf_to_fill,
1);
queue->next_buf_to_fill =
(queue->next_buf_to_fill + 1) % QDIO_MAX_BUFFERS_PER_Q;
}
} }
static void static void
...@@ -2603,58 +2598,12 @@ qeth_qdio_output_handler(struct ccw_device * ccwdev, unsigned int status, ...@@ -2603,58 +2598,12 @@ qeth_qdio_output_handler(struct ccw_device * ccwdev, unsigned int status,
atomic_dec(&queue->set_pci_flags_count); atomic_dec(&queue->set_pci_flags_count);
qeth_clear_output_buffer(card, buffer); qeth_clear_output_buffer(card, buffer);
atomic_dec(&queue->used_buffers);
} }
atomic_sub(count, &queue->used_buffers);
//if (!atomic_read(&queue->set_pci_flags_count))
tasklet_schedule(&queue->tasklet);
netif_wake_queue(card->dev); netif_wake_queue(card->dev);
} }
static void
qeth_qdio_output_tasklet(unsigned long data)
{
struct qeth_qdio_out_q *queue = (struct qeth_qdio_out_q *) data;
struct qeth_qdio_out_buffer *buffer;
int index;
int count;
QETH_DBF_TEXT(trace, 6, "outtlet");
/* flush all PRIMED buffers */
index = queue->next_buf_to_flush;
count = 0;
while (queue->bufs[index].state == QETH_QDIO_BUF_PRIMED) {
count++;
index = (index + 1) % QDIO_MAX_BUFFERS_PER_Q;
}
qeth_flush_buffers(queue, 0, queue->next_buf_to_flush, count);
queue->next_buf_to_flush = index;
/* flush a buffer with data, if no more PCIs are
* outstanding */
if (!atomic_read(&queue->set_pci_flags_count)){
spin_lock(&queue->lock);
buffer = &queue->bufs[index];
if (buffer->state == QETH_QDIO_BUF_PRIMED){
qeth_flush_buffers(queue, 0, index, 1);
index = (index + 1) % QDIO_MAX_BUFFERS_PER_Q;
queue->next_buf_to_flush = index;
} else if (buffer->next_element_to_fill > 0){
/* it's a packing buffer */
BUG_ON(index != queue->next_buf_to_fill);
buffer->state = QETH_QDIO_BUF_PRIMED;
atomic_inc(&queue->used_buffers);
qeth_flush_buffers(queue, 0, index, 1);
index = (index + 1) % QDIO_MAX_BUFFERS_PER_Q;
queue->next_buf_to_flush = index;
queue->next_buf_to_fill = index;
}
spin_unlock(&queue->lock);
}
}
static char* static char*
qeth_create_qib_param_field(struct qeth_card *card) qeth_create_qib_param_field(struct qeth_card *card)
{ {
...@@ -2858,8 +2807,6 @@ qeth_init_qdio_info(struct qeth_card *card) ...@@ -2858,8 +2807,6 @@ qeth_init_qdio_info(struct qeth_card *card)
card->qdio.in_buf_pool.buf_count = card->qdio.init_pool.buf_count; card->qdio.in_buf_pool.buf_count = card->qdio.init_pool.buf_count;
INIT_LIST_HEAD(&card->qdio.in_buf_pool.entry_list); INIT_LIST_HEAD(&card->qdio.in_buf_pool.entry_list);
INIT_LIST_HEAD(&card->qdio.init_pool.entry_list); INIT_LIST_HEAD(&card->qdio.init_pool.entry_list);
card->qdio.in_tasklet.data = (unsigned long) card;
card->qdio.in_tasklet.func = qeth_qdio_input_tasklet;
/* outbound */ /* outbound */
card->qdio.do_prio_queueing = QETH_PRIOQ_DEFAULT; card->qdio.do_prio_queueing = QETH_PRIOQ_DEFAULT;
card->qdio.default_out_queue = QETH_DEFAULT_QUEUE; card->qdio.default_out_queue = QETH_DEFAULT_QUEUE;
...@@ -2903,13 +2850,9 @@ qeth_init_qdio_queues(struct qeth_card *card) ...@@ -2903,13 +2850,9 @@ qeth_init_qdio_queues(struct qeth_card *card)
} }
card->qdio.out_qs[i]->card = card; card->qdio.out_qs[i]->card = card;
card->qdio.out_qs[i]->next_buf_to_fill = 0; card->qdio.out_qs[i]->next_buf_to_fill = 0;
card->qdio.out_qs[i]->next_buf_to_flush = 0;
card->qdio.out_qs[i]->do_pack = 0; card->qdio.out_qs[i]->do_pack = 0;
atomic_set(&card->qdio.out_qs[i]->used_buffers,0); atomic_set(&card->qdio.out_qs[i]->used_buffers,0);
atomic_set(&card->qdio.out_qs[i]->set_pci_flags_count, 0); atomic_set(&card->qdio.out_qs[i]->set_pci_flags_count, 0);
card->qdio.out_qs[i]->tasklet.data =
(unsigned long) card->qdio.out_qs[i];
card->qdio.out_qs[i]->tasklet.func = qeth_qdio_output_tasklet;
spin_lock_init(&card->qdio.out_qs[i]->lock); spin_lock_init(&card->qdio.out_qs[i]->lock);
} }
return 0; return 0;
...@@ -3653,6 +3596,8 @@ qeth_do_send_packet(struct qeth_card *card, struct sk_buff *skb, ...@@ -3653,6 +3596,8 @@ qeth_do_send_packet(struct qeth_card *card, struct sk_buff *skb,
struct qeth_hdr *hdr; struct qeth_hdr *hdr;
struct qeth_qdio_out_buffer *buffer; struct qeth_qdio_out_buffer *buffer;
int elements_needed; int elements_needed;
int start_index;
int flush_count = 0;
int rc; int rc;
QETH_DBF_TEXT(trace, 6, "dosndpkt"); QETH_DBF_TEXT(trace, 6, "dosndpkt");
...@@ -3671,9 +3616,7 @@ qeth_do_send_packet(struct qeth_card *card, struct sk_buff *skb, ...@@ -3671,9 +3616,7 @@ qeth_do_send_packet(struct qeth_card *card, struct sk_buff *skb,
} }
spin_lock(&queue->lock); spin_lock(&queue->lock);
/* check if we need to switch packing state of this queue */ start_index = queue->next_buf_to_fill;
if (card->info.type != QETH_CARD_TYPE_IQD)
qeth_switch_packing_state(queue);
buffer = &queue->bufs[queue->next_buf_to_fill]; buffer = &queue->bufs[queue->next_buf_to_fill];
BUG_ON(buffer->state == QETH_QDIO_BUF_PRIMED); BUG_ON(buffer->state == QETH_QDIO_BUF_PRIMED);
if (queue->do_pack){ if (queue->do_pack){
...@@ -3682,6 +3625,7 @@ qeth_do_send_packet(struct qeth_card *card, struct sk_buff *skb, ...@@ -3682,6 +3625,7 @@ qeth_do_send_packet(struct qeth_card *card, struct sk_buff *skb,
< elements_needed){ < elements_needed){
/* ... no -> set state PRIMED */ /* ... no -> set state PRIMED */
buffer->state = QETH_QDIO_BUF_PRIMED; buffer->state = QETH_QDIO_BUF_PRIMED;
flush_count++;
atomic_inc(&queue->used_buffers); atomic_inc(&queue->used_buffers);
queue->next_buf_to_fill = queue->next_buf_to_fill =
(queue->next_buf_to_fill + 1) % (queue->next_buf_to_fill + 1) %
...@@ -3695,18 +3639,24 @@ qeth_do_send_packet(struct qeth_card *card, struct sk_buff *skb, ...@@ -3695,18 +3639,24 @@ qeth_do_send_packet(struct qeth_card *card, struct sk_buff *skb,
PRINT_WARN("qeth_do_send_packet: error during " PRINT_WARN("qeth_do_send_packet: error during "
"qeth_fill_buffer."); "qeth_fill_buffer.");
card->stats.tx_dropped++; card->stats.tx_dropped++;
spin_unlock(&queue->lock); } else if (buffer->state == QETH_QDIO_BUF_PRIMED){
return rc;
}
if (buffer->state == QETH_QDIO_BUF_PRIMED){
/* next time fill the next buffer */ /* next time fill the next buffer */
flush_count++;
atomic_inc(&queue->used_buffers); atomic_inc(&queue->used_buffers);
queue->next_buf_to_fill = (queue->next_buf_to_fill + 1) % queue->next_buf_to_fill = (queue->next_buf_to_fill + 1) %
QDIO_MAX_BUFFERS_PER_Q; QDIO_MAX_BUFFERS_PER_Q;
} }
spin_unlock(&queue->lock); /* check if we need to switch packing state of this queue */
if (card->info.type != QETH_CARD_TYPE_IQD)
flush_count += qeth_switch_packing_state(queue);
tasklet_schedule(&queue->tasklet); if (flush_count)
qeth_flush_buffers(queue, 0, start_index, flush_count);
if (!atomic_read(&queue->set_pci_flags_count))
qeth_flush_buffers_on_no_pci(queue, 0);
spin_unlock(&queue->lock);
return rc; return rc;
} }
...@@ -4424,6 +4374,10 @@ qeth_delete_mc_addresses(struct qeth_card *card) ...@@ -4424,6 +4374,10 @@ qeth_delete_mc_addresses(struct qeth_card *card)
if (!ipm->is_multicast) if (!ipm->is_multicast)
continue; continue;
iptodo = qeth_get_addr_buffer(ipm->proto); iptodo = qeth_get_addr_buffer(ipm->proto);
if (!iptodo) {
QETH_DBF_TEXT(trace, 2, "dmcnomem");
continue;
}
memcpy(iptodo, ipm, sizeof(struct qeth_ipaddr)); memcpy(iptodo, ipm, sizeof(struct qeth_ipaddr));
iptodo->users = iptodo->users * -1; iptodo->users = iptodo->users * -1;
if (!__qeth_insert_ip_todo(card, iptodo, 0)) if (!__qeth_insert_ip_todo(card, iptodo, 0))
...@@ -4694,14 +4648,14 @@ qeth_register_addr_entry(struct qeth_card *card, struct qeth_ipaddr *addr) ...@@ -4694,14 +4648,14 @@ qeth_register_addr_entry(struct qeth_card *card, struct qeth_ipaddr *addr)
if (addr->proto == QETH_PROT_IPV4) { if (addr->proto == QETH_PROT_IPV4) {
QETH_DBF_TEXT(trace, 2,"setaddr4"); QETH_DBF_TEXT(trace, 2,"setaddr4");
QETH_DBF_HEX(trace, 4, &addr->u.a4.addr, sizeof(int)); QETH_DBF_HEX(trace, 3, &addr->u.a4.addr, sizeof(int));
} else if (addr->proto == QETH_PROT_IPV6) { } else if (addr->proto == QETH_PROT_IPV6) {
QETH_DBF_TEXT(trace, 2, "setaddr6"); QETH_DBF_TEXT(trace, 2, "setaddr6");
QETH_DBF_HEX(trace,4,&addr->u.a6.addr,4); QETH_DBF_HEX(trace,3,&addr->u.a6.addr,8);
QETH_DBF_HEX(trace,4,((char *)&addr->u.a6.addr)+4,4); QETH_DBF_HEX(trace,3,((char *)&addr->u.a6.addr)+8,8);
} else { } else {
QETH_DBF_TEXT(trace, 2, "setaddr?"); QETH_DBF_TEXT(trace, 2, "setaddr?");
QETH_DBF_HEX(trace, 4, addr, sizeof(struct qeth_ipaddr)); QETH_DBF_HEX(trace, 3, addr, sizeof(struct qeth_ipaddr));
} }
do { do {
if (addr->is_multicast) if (addr->is_multicast)
...@@ -4732,14 +4686,14 @@ qeth_deregister_addr_entry(struct qeth_card *card, struct qeth_ipaddr *addr) ...@@ -4732,14 +4686,14 @@ qeth_deregister_addr_entry(struct qeth_card *card, struct qeth_ipaddr *addr)
if (addr->proto == QETH_PROT_IPV4) { if (addr->proto == QETH_PROT_IPV4) {
QETH_DBF_TEXT(trace, 2,"deladdr4"); QETH_DBF_TEXT(trace, 2,"deladdr4");
QETH_DBF_HEX(trace, 2, &addr->u.a4.addr, sizeof(int)); QETH_DBF_HEX(trace, 3, &addr->u.a4.addr, sizeof(int));
} else if (addr->proto == QETH_PROT_IPV6) { } else if (addr->proto == QETH_PROT_IPV6) {
QETH_DBF_TEXT(trace, 2, "deladdr6"); QETH_DBF_TEXT(trace, 2, "deladdr6");
QETH_DBF_HEX(trace, 2, &addr->u.a6.addr, QETH_DBF_HEX(trace,3,&addr->u.a6.addr,8);
sizeof(struct in6_addr)); QETH_DBF_HEX(trace,3,((char *)&addr->u.a6.addr)+8,8);
} else { } else {
QETH_DBF_TEXT(trace, 2, "deladdr?"); QETH_DBF_TEXT(trace, 2, "deladdr?");
QETH_DBF_HEX(trace, 2, addr, sizeof(struct qeth_ipaddr)); QETH_DBF_HEX(trace, 3, addr, sizeof(struct qeth_ipaddr));
} }
if (addr->is_multicast) if (addr->is_multicast)
rc = qeth_send_setdelmc(card, addr, IPA_CMD_DELIPM); rc = qeth_send_setdelmc(card, addr, IPA_CMD_DELIPM);
...@@ -6515,26 +6469,24 @@ qeth_ip_event(struct notifier_block *this, ...@@ -6515,26 +6469,24 @@ qeth_ip_event(struct notifier_block *this,
addr->u.a4.addr = ifa->ifa_address; addr->u.a4.addr = ifa->ifa_address;
addr->u.a4.mask = ifa->ifa_mask; addr->u.a4.mask = ifa->ifa_mask;
addr->type = QETH_IP_TYPE_NORMAL; addr->type = QETH_IP_TYPE_NORMAL;
} } else
goto out;
switch(event) { switch(event) {
case NETDEV_UP: case NETDEV_UP:
if (addr) {
if (!qeth_add_ip(card, addr)) if (!qeth_add_ip(card, addr))
kfree(addr); kfree(addr);
}
break; break;
case NETDEV_DOWN: case NETDEV_DOWN:
if (addr) {
if (!qeth_delete_ip(card, addr)) if (!qeth_delete_ip(card, addr))
kfree(addr); kfree(addr);
}
break; break;
default: default:
break; break;
} }
qeth_set_thread_start_bit(card, QETH_SET_IP_THREAD); qeth_set_thread_start_bit(card, QETH_SET_IP_THREAD);
schedule_work(&card->kernel_thread_starter); schedule_work(&card->kernel_thread_starter);
out:
return NOTIFY_DONE; return NOTIFY_DONE;
} }
...@@ -6570,26 +6522,24 @@ qeth_ip6_event(struct notifier_block *this, ...@@ -6570,26 +6522,24 @@ qeth_ip6_event(struct notifier_block *this,
memcpy(&addr->u.a6.addr, &ifa->addr, sizeof(struct in6_addr)); memcpy(&addr->u.a6.addr, &ifa->addr, sizeof(struct in6_addr));
addr->u.a6.pfxlen = ifa->prefix_len; addr->u.a6.pfxlen = ifa->prefix_len;
addr->type = QETH_IP_TYPE_NORMAL; addr->type = QETH_IP_TYPE_NORMAL;
} } else
goto out;
switch(event) { switch(event) {
case NETDEV_UP: case NETDEV_UP:
if (addr){
if (!qeth_add_ip(card, addr)) if (!qeth_add_ip(card, addr))
kfree(addr); kfree(addr);
}
break; break;
case NETDEV_DOWN: case NETDEV_DOWN:
if (addr){
if (!qeth_delete_ip(card, addr)) if (!qeth_delete_ip(card, addr))
kfree(addr); kfree(addr);
}
break; break;
default: default:
break; break;
} }
qeth_set_thread_start_bit(card, QETH_SET_IP_THREAD); qeth_set_thread_start_bit(card, QETH_SET_IP_THREAD);
schedule_work(&card->kernel_thread_starter); schedule_work(&card->kernel_thread_starter);
out:
return NOTIFY_DONE; return NOTIFY_DONE;
} }
......
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