X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fs390%2Fnet%2Fqeth_main.c;h=0f75e58f988d1536cb95afe486d814c97324b78f;hb=3e3ff47c8527c5ba0be4e9f358d49e4b076bd6ef;hp=17f0f67d8e5558f7a8aededaa3212efa89b2a6cd;hpb=a91482bdcc2e0f6035702e46f1b99043a0893346;p=linux-2.6.git diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c index 17f0f67d8..0f75e58f9 100644 --- a/drivers/s390/net/qeth_main.c +++ b/drivers/s390/net/qeth_main.c @@ -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 * - * $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 */