This commit was manufactured by cvs2svn to create tag
[linux-2.6.git] / drivers / s390 / net / qeth_main.c
index 17f0f67..0f75e58 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- * linux/drivers/s390/net/qeth_main.c ($Revision: 1.130 $)
+ * linux/drivers/s390/net/qeth_main.c ($Revision: 1.125 $)
  *
  * Linux on zSeries OSA Express and HiperSockets support
  *
@@ -12,7 +12,7 @@
  *                       Frank Pavlic (pavlic@de.ibm.com) and
  *                       Thomas Spatzier <tspat@de.ibm.com>
  *
- *    $Revision: 1.130 $        $Date: 2004/08/05 11:21:50 $
+ *    $Revision: 1.125 $        $Date: 2004/06/29 17:28:24 $
  *
  * 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
@@ -78,7 +78,7 @@ qeth_eyecatcher(void)
 #include "qeth_mpc.h"
 #include "qeth_fs.h"
 
-#define VERSION_QETH_C "$Revision: 1.130 $"
+#define VERSION_QETH_C "$Revision: 1.125 $"
 static const char *version = "qeth S/390 OSA-Express driver";
 
 /**
@@ -1801,7 +1801,7 @@ qeth_send_control_data(struct qeth_card *card, int len,
        }
        add_timer(&timer);
        wait_event(reply->wait_q, reply->received);
-       del_timer_sync(&timer);
+       del_timer(&timer);
        rc = reply->rc;
        qeth_put_reply(reply);
        return rc;
@@ -2105,7 +2105,7 @@ qeth_get_next_skb(struct qeth_card *card, struct qdio_buffer *buffer,
                                QETH_DBF_TEXT(qerr,2,"unexeob");
                                QETH_DBF_TEXT_(qerr,2,"%s",CARD_BUS_ID(card));
                                QETH_DBF_HEX(misc,4,buffer,sizeof(*buffer));
-                               dev_kfree_skb_any(skb);
+                               dev_kfree_skb_irq(skb);
                                card->stats.rx_errors++;
                                return NULL;
                        }
@@ -2297,7 +2297,7 @@ qeth_process_inbound_buffer(struct qeth_card *card,
                qeth_rebuild_skb(card, skb, hdr);
                /* is device UP ? */
                if (!(card->dev->flags & IFF_UP)){
-                       dev_kfree_skb_any(skb);
+                       dev_kfree_skb_irq(skb);
                        continue;
                }
                skb->dev = card->dev;
@@ -2311,16 +2311,16 @@ qeth_process_inbound_buffer(struct qeth_card *card,
 static inline struct qeth_buffer_pool_entry *
 qeth_get_buffer_pool_entry(struct qeth_card *card)
 {
-       struct qeth_buffer_pool_entry *entry;
+       struct qeth_buffer_pool_entry *entry, *tmp;
 
        QETH_DBF_TEXT(trace, 6, "gtbfplen");
-       if (!list_empty(&card->qdio.in_buf_pool.entry_list)) {
-               entry = list_entry(card->qdio.in_buf_pool.entry_list.next,
-                               struct qeth_buffer_pool_entry, list);
+       entry = NULL;
+       list_for_each_entry_safe(entry, tmp,
+                                &card->qdio.in_buf_pool.entry_list, list){
                list_del_init(&entry->list);
-               return entry;
+               break;
        }
-       return NULL;
+       return entry;
 }
 
 static inline void
@@ -2367,7 +2367,7 @@ qeth_clear_output_buffer(struct qeth_qdio_out_q *queue,
                buf->buffer->element[i].flags = 0;
                while ((skb = skb_dequeue(&buf->skb_list))){
                        atomic_dec(&skb->users);
-                       dev_kfree_skb_any(skb);
+                       dev_kfree_skb_irq(skb);
                }
        }
        buf->next_element_to_fill = 0;
@@ -2588,9 +2588,14 @@ qeth_flush_buffers(struct qeth_qdio_out_q *queue, int under_int,
                QETH_DBF_TEXT(trace, 2, "flushbuf");
                QETH_DBF_TEXT_(trace, 2, " err%d", rc);
                queue->card->stats.tx_errors += count;
-               /* this must not happen under normal circumstances. if it
-                * happens something is really wrong -> recover */
-               qeth_schedule_recovery(queue->card);
+               /* ok, since do_QDIO went wrong the buffers have not been given
+                * to the hardware. they still belong to us, so we can clear
+                * them and reuse then, i.e. set back next_buf_to_fill*/
+               for (i = index; i < index + count; ++i) {
+                       buf = &queue->bufs[i % QDIO_MAX_BUFFERS_PER_Q];
+                       qeth_clear_output_buffer(queue, buf);
+               }
+               queue->next_buf_to_fill = index;
                return;
        }
        atomic_add(count, &queue->used_buffers);
@@ -2600,12 +2605,16 @@ qeth_flush_buffers(struct qeth_qdio_out_q *queue, int under_int,
 }
 
 /*
- * Switched to packing state if the number of used buffers on a queue
- * reaches a certain limit.
+ * switches between PACKING and non-PACKING state if needed.
+ * has to be called holding queue->lock
  */
-static inline void
-qeth_switch_to_packing_if_needed(struct qeth_qdio_out_q *queue)
+static inline int
+qeth_switch_packing_state(struct qeth_qdio_out_q *queue)
 {
+       struct qeth_qdio_out_buffer *buffer;
+       int flush_count = 0;
+
+       QETH_DBF_TEXT(trace, 6, "swipack");
        if (!queue->do_pack) {
                if (atomic_read(&queue->used_buffers)
                    >= QETH_HIGH_WATERMARK_PACK){
@@ -2616,22 +2625,7 @@ qeth_switch_to_packing_if_needed(struct qeth_qdio_out_q *queue)
 #endif
                        queue->do_pack = 1;
                }
-       }
-}
-
-/*
- * Switches from packing to non-packing mode. If there is a packing
- * buffer on the queue this buffer will be prepared to be flushed.
- * In that case 1 is returned to inform the caller. If no buffer
- * has to be flushed, zero is returned.
- */
-static inline int
-qeth_switch_to_nonpacking_if_needed(struct qeth_qdio_out_q *queue)
-{
-       struct qeth_qdio_out_buffer *buffer;
-       int flush_count = 0;
-
-       if (queue->do_pack) {
+       } else {
                if (atomic_read(&queue->used_buffers)
                    <= QETH_LOW_WATERMARK_PACK) {
                        /* switch PACKING -> non-PACKING */
@@ -2656,62 +2650,21 @@ qeth_switch_to_nonpacking_if_needed(struct qeth_qdio_out_q *queue)
        return flush_count;
 }
 
-/*
- * Called to flush a packing buffer if no more pci flags are on the queue.
- * Checks if there is a packing buffer and prepares it to be flushed.
- * In that case returns 1, otherwise zero.
- */
-static inline int
-qeth_flush_buffers_on_no_pci(struct qeth_qdio_out_q *queue)
+static inline void
+qeth_flush_buffers_on_no_pci(struct qeth_qdio_out_q *queue, int under_int)
 {
        struct qeth_qdio_out_buffer *buffer;
+       int index;
 
-       buffer = &queue->bufs[queue->next_buf_to_fill];
+       index = queue->next_buf_to_fill;
+       buffer = &queue->bufs[index];
        if((atomic_read(&buffer->state) == QETH_QDIO_BUF_EMPTY) &&
           (buffer->next_element_to_fill > 0)){
                /* it's a packing buffer */
                atomic_set(&buffer->state, QETH_QDIO_BUF_PRIMED);
                queue->next_buf_to_fill =
                        (queue->next_buf_to_fill + 1) % QDIO_MAX_BUFFERS_PER_Q;
-               return 1;
-       }
-       return 0;
-}
-
-static inline void
-qeth_check_outbound_queue(struct qeth_qdio_out_q *queue)
-{
-       int index;
-       int flush_cnt = 0;
-
-       /*
-        * check if weed have to switch to non-packing mode or if
-        * we have to get a pci flag out on the queue
-        */
-       if ((atomic_read(&queue->used_buffers) <= QETH_LOW_WATERMARK_PACK) ||
-           !atomic_read(&queue->set_pci_flags_count)){
-               if (atomic_swap(&queue->state, QETH_OUT_Q_LOCKED_FLUSH) ==
-                               QETH_OUT_Q_UNLOCKED) {
-                       /*
-                        * If we get in here, there was no action in
-                        * do_send_packet. So, we check if there is a
-                        * packing buffer to be flushed here.
-                        */
-                       /* TODO: try if we get a performance improvement
-                        * by calling netif_stop_queue here */
-                       /* save start index for flushing */
-                       index = queue->next_buf_to_fill;
-                       flush_cnt += qeth_switch_to_nonpacking_if_needed(queue);
-                       if (!flush_cnt &&
-                           !atomic_read(&queue->set_pci_flags_count))
-                               flush_cnt +=
-                                       qeth_flush_buffers_on_no_pci(queue);
-                       /* were done with updating critical queue members */
-                       atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED);
-                       /* flushing can be done outside the lock */
-                       if (flush_cnt)
-                               qeth_flush_buffers(queue, 1, index, flush_cnt);
-               }
+               qeth_flush_buffers(queue, under_int, index, 1);
        }
 }
 
@@ -2757,8 +2710,6 @@ qeth_qdio_output_handler(struct ccw_device * ccwdev, unsigned int status,
                qeth_clear_output_buffer(queue, buffer);
        }
        atomic_sub(count, &queue->used_buffers);
-       /* check if we need to do something on this outbound queue */
-       qeth_check_outbound_queue(queue);
 
        netif_wake_queue(card->dev);
 #ifdef CONFIG_QETH_PERF_STATS
@@ -3030,8 +2981,7 @@ qeth_init_qdio_queues(struct qeth_card *card)
                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]->set_pci_flags_count, 0);
-               atomic_set(&card->qdio.out_qs[i]->state,
-                          QETH_OUT_Q_UNLOCKED);
+               spin_lock_init(&card->qdio.out_qs[i]->lock);
        }
        return 0;
 }
@@ -3345,12 +3295,12 @@ qeth_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
        card->perf_stats.outbound_start_time = qeth_get_micros();
 #endif
        /*
-        * We only call netif_stop_queue in case of errors. Since we've
-        * got our own synchronization on queues we can keep the stack's
-        * queue running.
+        * dev_queue_xmit should ensure that we are called packet
+        * after packet
         */
-       if ((rc = qeth_send_packet(card, skb)))
-               netif_stop_queue(dev);
+       netif_stop_queue(dev);
+       if (!(rc = qeth_send_packet(card, skb)))
+               netif_wake_queue(dev);
 
 #ifdef CONFIG_QETH_PERF_STATS
        card->perf_stats.outbound_time += qeth_get_micros() -
@@ -3764,11 +3714,7 @@ qeth_do_send_packet_fast(struct qeth_card *card, struct qeth_qdio_out_q *queue,
 
        QETH_DBF_TEXT(trace, 6, "dosndpfa");
 
-       /* spin until we get the queue ... */
-       while (atomic_compare_and_swap(QETH_OUT_Q_UNLOCKED,
-                                      QETH_OUT_Q_LOCKED,
-                                      &queue->state));
-       /* ... now we've got the queue */
+       spin_lock(&queue->lock);
        index = queue->next_buf_to_fill;
        buffer = &queue->bufs[queue->next_buf_to_fill];
        /*
@@ -3777,14 +3723,14 @@ qeth_do_send_packet_fast(struct qeth_card *card, struct qeth_qdio_out_q *queue,
         */
        if (atomic_read(&buffer->state) != QETH_QDIO_BUF_EMPTY) {
                card->stats.tx_dropped++;
-               atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED);
+               spin_unlock(&queue->lock);
                return -EBUSY;
        }
        queue->next_buf_to_fill = (queue->next_buf_to_fill + 1) %
                                  QDIO_MAX_BUFFERS_PER_Q;
-       atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED);
        qeth_fill_buffer(queue, buffer, (char *)hdr, skb);
        qeth_flush_buffers(queue, 0, index, 1);
+       spin_unlock(&queue->lock);
        return 0;
 }
 
@@ -3800,10 +3746,7 @@ qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue,
 
        QETH_DBF_TEXT(trace, 6, "dosndpkt");
 
-       /* spin until we get the queue ... */
-       while (atomic_compare_and_swap(QETH_OUT_Q_UNLOCKED,
-                                      QETH_OUT_Q_LOCKED,
-                                      &queue->state));
+       spin_lock(&queue->lock);
        start_index = queue->next_buf_to_fill;
        buffer = &queue->bufs[queue->next_buf_to_fill];
        /*
@@ -3812,11 +3755,9 @@ qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue,
         */
        if (atomic_read(&buffer->state) != QETH_QDIO_BUF_EMPTY){
                card->stats.tx_dropped++;
-               atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED);
+               spin_unlock(&queue->lock);
                return -EBUSY;
        }
-       /* check if we need to switch packing state of this queue */
-       qeth_switch_to_packing_if_needed(queue);
        if (queue->do_pack){
                /* does packet fit in current buffer? */
                if((QETH_MAX_BUFFER_ELEMENTS(card) -
@@ -3831,10 +3772,11 @@ qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue,
                        /* we did a step forward, so check buffer state again */
                        if (atomic_read(&buffer->state) != QETH_QDIO_BUF_EMPTY){
                                card->stats.tx_dropped++;
+                               qeth_flush_buffers(queue, 0, start_index, 1);
+                               spin_unlock(&queue->lock);
                                /* return EBUSY because we sent old packet, not
                                 * the current one */
-                               rc = -EBUSY;
-                               goto out;
+                               return -EBUSY;
                        }
                }
        }
@@ -3845,27 +3787,16 @@ qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue,
                queue->next_buf_to_fill = (queue->next_buf_to_fill + 1) %
                        QDIO_MAX_BUFFERS_PER_Q;
        }
-       /*
-        * queue->state will go from LOCKED -> UNLOCKED or from
-        * LOCKED_FLUSH -> LOCKED if output_handler wanted to 'notify' us
-        * (switch packing state or flush buffer to get another pci flag out).
-        * In that case we will enter this loop
-        */
-       while (atomic_dec_return(&queue->state)){
-               /* check if we can go back to non-packing state */
-               flush_count += qeth_switch_to_nonpacking_if_needed(queue);
-               /*
-                * check if we need to flush a packing buffer to get a pci
-                * flag out on the queue
-                */
-               if (!flush_count && !atomic_read(&queue->set_pci_flags_count))
-                       flush_count += qeth_flush_buffers_on_no_pci(queue);
-       }
-       /* at this point the queue is UNLOCKED again */
-out:
+       /* check if we need to switch packing state of this queue */
+       flush_count += qeth_switch_packing_state(queue);
+
        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;
 }
 
@@ -3922,8 +3853,7 @@ qeth_mdio_read(struct net_device *dev, int phy_id, int regnum)
        switch(regnum){
        case MII_BMCR: /* Basic mode control register */
                rc = BMCR_FULLDPLX;
-               if ((card->info.link_type != QETH_LINK_TYPE_GBIT_ETH)&&
-                   (card->info.link_type != QETH_LINK_TYPE_10GBIT_ETH))
+               if(card->info.link_type != QETH_LINK_TYPE_GBIT_ETH)
                        rc |= BMCR_SPEED100;
                break;
        case MII_BMSR: /* Basic mode status register */