Newer
Older
case NETXEN_NIC_RESPONSE_DESC:
netxen_handle_fw_message(desc_cnt, consumer, sds_ring);
default:
goto skip;
}
WARN_ON(desc_cnt > 1);
index = netxen_get_sts_refhandle(sts_data);
length = netxen_get_sts_totallength(sts_data);
cksum = netxen_get_sts_status(sts_data);
pkt_offset = netxen_get_sts_pkt_offset(sts_data);
rxbuf = netxen_process_rcv(adapter, ring, index,
if (rxbuf)
list_add_tail(&rxbuf->list, &sds_ring->free_list[ring]);
skip:
for (; desc_cnt > 0; desc_cnt--) {
desc = &sds_ring->desc_head[consumer];
desc->status_desc_data[0] =
cpu_to_le64(STATUS_OWNER_PHANTOM);
consumer = get_next_index(consumer, sds_ring->num_desc);
}
for (ring = 0; ring < adapter->max_rds_rings; ring++) {
struct nx_host_rds_ring *rds_ring =
&adapter->recv_ctx.rds_rings[ring];
if (!list_empty(&sds_ring->free_list[ring])) {
list_for_each(cur, &sds_ring->free_list[ring]) {
rxbuf = list_entry(cur,
struct netxen_rx_buffer, list);
netxen_alloc_rx_skb(adapter, rds_ring, rxbuf);
}
spin_lock(&rds_ring->lock);
netxen_merge_rx_buffers(&sds_ring->free_list[ring],
&rds_ring->free_list);
spin_unlock(&rds_ring->lock);
}
netxen_post_rx_buffers_nodb(adapter, rds_ring);
}
sds_ring->consumer = consumer;
NXWR32(adapter, sds_ring->crb_sts_consumer, consumer);
}
return count;
}
/* Process Command status ring */
int netxen_process_cmd_ring(struct netxen_adapter *adapter)
struct pci_dev *pdev = adapter->pdev;
struct net_device *netdev = adapter->netdev;
struct nx_host_tx_ring *tx_ring = &adapter->tx_ring;
if (!spin_trylock(&adapter->tx_clean_lock))
return 1;
sw_consumer = tx_ring->sw_consumer;
barrier(); /* hw_consumer can change underneath */
hw_consumer = le32_to_cpu(*(tx_ring->hw_consumer));
while (sw_consumer != hw_consumer) {
buffer = &tx_ring->cmd_buf_arr[sw_consumer];
if (buffer->skb) {
frag = &buffer->frag_array[0];
pci_unmap_single(pdev, frag->dma, frag->length,
PCI_DMA_TODEVICE);
Dhananjay Phadke
committed
frag->dma = 0ULL;
for (i = 1; i < buffer->frag_count; i++) {
frag++; /* Get the next frag */
pci_unmap_page(pdev, frag->dma, frag->length,
PCI_DMA_TODEVICE);
Dhananjay Phadke
committed
frag->dma = 0ULL;
dev_kfree_skb_any(buffer->skb);
buffer->skb = NULL;
sw_consumer = get_next_index(sw_consumer, tx_ring->num_desc);
if (++count >= MAX_STATUS_HANDLE)
break;
smp_mb();
if (netif_queue_stopped(netdev) && netif_running(netdev)) {
netif_tx_lock(netdev);
netif_wake_queue(netdev);
smp_mb();
netif_tx_unlock(netdev);
/*
* If everything is freed up to consumer then check if the ring is full
* If the ring is full then check if more needs to be freed and
* schedule the call back again.
*
* This happens when there are 2 CPUs. One could be freeing and the
* other filling it. If the ring is full when we get out of here and
* the card has already interrupted the host then the host can miss the
* interrupt.
*
* There is still a possible race condition and the host could miss an
* interrupt. The card has to take care of this.
*/
barrier(); /* hw_consumer can change underneath */
hw_consumer = le32_to_cpu(*(tx_ring->hw_consumer));
done = (sw_consumer == hw_consumer);
spin_unlock(&adapter->tx_clean_lock);
return (done);
netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ringid,
struct nx_host_rds_ring *rds_ring)
{
struct rcv_desc *pdesc;
struct netxen_rx_buffer *buffer;
int producer, count = 0;
netxen_ctx_msg msg = 0;
spin_lock(&rds_ring->lock);
head = &rds_ring->free_list;
buffer = list_entry(head->next, struct netxen_rx_buffer, list);
if (!buffer->skb) {
if (netxen_alloc_rx_skb(adapter, rds_ring, buffer))
break;
/* make a rcv descriptor */
pdesc = &rds_ring->desc_head[producer];
pdesc->addr_buffer = cpu_to_le64(buffer->dma);
pdesc->reference_handle = cpu_to_le16(buffer->ref_handle);
pdesc->buffer_length = cpu_to_le32(rds_ring->dma_size);
producer = get_next_index(producer, rds_ring->num_desc);
spin_unlock(&rds_ring->lock);
if (count) {
NXWR32(adapter, rds_ring->crb_rcv_producer,
(producer-1) & (rds_ring->num_desc-1));
/*
* Write a doorbell msg to tell phanmon of change in
* receive ring producer
*/
netxen_set_msg_peg_id(msg, NETXEN_RCV_PEG_DB_ID);
netxen_set_msg_privid(msg);
netxen_set_msg_count(msg,
((producer - 1) &
(rds_ring->num_desc - 1)));
netxen_set_msg_ctxid(msg, adapter->portnum);
netxen_set_msg_opcode(msg, NETXEN_RCV_PRODUCER(ringid));
writel(msg,
DB_NORMALIZE(adapter,
NETXEN_RCV_PRODUCER_OFFSET));
}
}
netxen_post_rx_buffers_nodb(struct netxen_adapter *adapter,
struct nx_host_rds_ring *rds_ring)
{
struct rcv_desc *pdesc;
struct netxen_rx_buffer *buffer;
int producer, count = 0;
if (!spin_trylock(&rds_ring->lock))
return;
head = &rds_ring->free_list;
while (!list_empty(head)) {
buffer = list_entry(head->next, struct netxen_rx_buffer, list);
if (!buffer->skb) {
if (netxen_alloc_rx_skb(adapter, rds_ring, buffer))
break;
pdesc = &rds_ring->desc_head[producer];
pdesc->reference_handle = cpu_to_le16(buffer->ref_handle);
pdesc->buffer_length = cpu_to_le32(rds_ring->dma_size);
pdesc->addr_buffer = cpu_to_le64(buffer->dma);
producer = get_next_index(producer, rds_ring->num_desc);
NXWR32(adapter, rds_ring->crb_rcv_producer,
(producer - 1) & (rds_ring->num_desc - 1));
spin_unlock(&rds_ring->lock);
}
void netxen_nic_clear_stats(struct netxen_adapter *adapter)
{
memset(&adapter->stats, 0, sizeof(adapter->stats));