qla3xxx: bugfix: Dropping interrupt under heavy network load.

Update the rx queue pointer when exiting NAPI poll rather than
at the end of each iteration.  Remove unnecessary PCI flushes
that occurred after every write.  Now write all regs and
flush once.

Signed-off-by: Ron Mercer <ron.mercer@qlogic.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
This commit is contained in:
Ron Mercer 2007-03-26 13:42:59 -07:00 committed by Jeff Garzik
parent b6967eb9cb
commit f67cac0190

View File

@ -1688,6 +1688,27 @@ static int ql_populate_free_queue(struct ql3_adapter *qdev)
return 0; return 0;
} }
/*
* Caller holds hw_lock.
*/
static void ql_update_small_bufq_prod_index(struct ql3_adapter *qdev)
{
struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
if (qdev->small_buf_release_cnt >= 16) {
while (qdev->small_buf_release_cnt >= 16) {
qdev->small_buf_q_producer_index++;
if (qdev->small_buf_q_producer_index ==
NUM_SBUFQ_ENTRIES)
qdev->small_buf_q_producer_index = 0;
qdev->small_buf_release_cnt -= 8;
}
wmb();
writel(qdev->small_buf_q_producer_index,
&port_regs->CommonRegs.rxSmallQProducerIndex);
}
}
/* /*
* Caller holds hw_lock. * Caller holds hw_lock.
*/ */
@ -1732,13 +1753,10 @@ static void ql_update_lrg_bufq_prod_index(struct ql3_adapter *qdev)
lrg_buf_q_ele = qdev->lrg_buf_q_virt_addr; lrg_buf_q_ele = qdev->lrg_buf_q_virt_addr;
} }
} }
wmb();
qdev->lrg_buf_next_free = lrg_buf_q_ele; qdev->lrg_buf_next_free = lrg_buf_q_ele;
writel(qdev->lrg_buf_q_producer_index,
ql_write_common_reg(qdev, &port_regs->CommonRegs.rxLargeQProducerIndex);
&port_regs->CommonRegs.
rxLargeQProducerIndex,
qdev->lrg_buf_q_producer_index);
} }
} }
@ -1944,16 +1962,12 @@ static void ql_process_macip_rx_intr(struct ql3_adapter *qdev,
static int ql_tx_rx_clean(struct ql3_adapter *qdev, static int ql_tx_rx_clean(struct ql3_adapter *qdev,
int *tx_cleaned, int *rx_cleaned, int work_to_do) int *tx_cleaned, int *rx_cleaned, int work_to_do)
{ {
struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
struct net_rsp_iocb *net_rsp; struct net_rsp_iocb *net_rsp;
struct net_device *ndev = qdev->ndev; struct net_device *ndev = qdev->ndev;
unsigned long hw_flags;
int work_done = 0; int work_done = 0;
u32 rsp_producer_index = le32_to_cpu(*(qdev->prsp_producer_index));
/* While there are entries in the completion queue. */ /* While there are entries in the completion queue. */
while ((rsp_producer_index != while ((le32_to_cpu(*(qdev->prsp_producer_index)) !=
qdev->rsp_consumer_index) && (work_done < work_to_do)) { qdev->rsp_consumer_index) && (work_done < work_to_do)) {
net_rsp = qdev->rsp_current; net_rsp = qdev->rsp_current;
@ -2009,33 +2023,7 @@ static int ql_tx_rx_clean(struct ql3_adapter *qdev,
work_done = *tx_cleaned + *rx_cleaned; work_done = *tx_cleaned + *rx_cleaned;
} }
if(work_done) { return work_done;
spin_lock_irqsave(&qdev->hw_lock, hw_flags);
ql_update_lrg_bufq_prod_index(qdev);
if (qdev->small_buf_release_cnt >= 16) {
while (qdev->small_buf_release_cnt >= 16) {
qdev->small_buf_q_producer_index++;
if (qdev->small_buf_q_producer_index ==
NUM_SBUFQ_ENTRIES)
qdev->small_buf_q_producer_index = 0;
qdev->small_buf_release_cnt -= 8;
}
wmb();
ql_write_common_reg(qdev,
&port_regs->CommonRegs.
rxSmallQProducerIndex,
qdev->small_buf_q_producer_index);
}
spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
}
return *tx_cleaned + *rx_cleaned;
} }
static int ql_poll(struct net_device *ndev, int *budget) static int ql_poll(struct net_device *ndev, int *budget)
@ -2059,9 +2047,10 @@ static int ql_poll(struct net_device *ndev, int *budget)
netif_rx_complete(ndev); netif_rx_complete(ndev);
spin_lock_irqsave(&qdev->hw_lock, hw_flags); spin_lock_irqsave(&qdev->hw_lock, hw_flags);
ql_write_common_reg(qdev, ql_update_small_bufq_prod_index(qdev);
&port_regs->CommonRegs.rspQConsumerIndex, ql_update_lrg_bufq_prod_index(qdev);
qdev->rsp_consumer_index); writel(qdev->rsp_consumer_index,
&port_regs->CommonRegs.rspQConsumerIndex);
spin_unlock_irqrestore(&qdev->hw_lock, hw_flags); spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
ql_enable_interrupts(qdev); ql_enable_interrupts(qdev);