/*
* Copyright (c) 2006 - 2011 Intel-NE, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
#include <linux/skbuff.h>
#include <linux/etherdevice.h>
#include <linux/kthread.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <net/tcp.h>
#include "nes.h"
#include "nes_mgt.h"
atomic_t pau_qps_created;
atomic_t pau_qps_destroyed;
static void nes_replenish_mgt_rq(struct nes_vnic_mgt *mgtvnic)
{
unsigned long flags;
dma_addr_t bus_address;
struct sk_buff *skb;
struct nes_hw_nic_rq_wqe *nic_rqe;
struct nes_hw_mgt *nesmgt;
struct nes_device *nesdev;
struct nes_rskb_cb *cb;
u32 rx_wqes_posted = 0;
nesmgt = &mgtvnic->mgt;
nesdev = mgtvnic->nesvnic->nesdev;
spin_lock_irqsave(&nesmgt->rq_lock, flags);
if (nesmgt->replenishing_rq != 0) {
if (((nesmgt->rq_size - 1) == atomic_read(&mgtvnic->rx_skbs_needed)) &&
(atomic_read(&mgtvnic->rx_skb_timer_running) == 0)) {
atomic_set(&mgtvnic->rx_skb_timer_running, 1);
spin_unlock_irqrestore(&nesmgt->rq_lock, flags);
mgtvnic->rq_wqes_timer.expires = jiffies + (HZ / 2); /* 1/2 second */
add_timer(&mgtvnic->rq_wqes_timer);
} else {
spin_unlock_irqrestore(&nesmgt->rq_lock, flags);
}
return;
}
nesmgt->replenishing_rq = 1;
spin_unlock_irqrestore(&nesmgt->rq_lock, flags);
do {
skb = dev_alloc_skb(mgtvnic->nesvnic->max_frame_size);
if (skb) {
skb->dev = mgtvnic->nesvnic->netdev;
bus_address = pci_map_single(nesdev->pcidev,
skb->data, mgtvnic->nesvnic->max_frame_size, PCI_DMA_FROMDEVICE);
cb = (struct nes_rskb_cb *)&skb->cb[0];
cb->busaddr = bus_address;
cb->maplen = mgtvnic->nesvnic->max_frame_size;
nic_rqe = &nesmgt->rq_vbase[mgtvnic->mgt.rq_head];
nic_rqe->wqe_words[NES_NIC_RQ_WQE_LENGTH_1_0_IDX] =
cpu_to_le32(mgtvnic->nesvnic->max_frame_size);
nic_rqe->wqe_words[NES_NIC_RQ_WQE_LENGTH_3_2_IDX] = 0;
nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_LOW_IDX] =
cpu_to_le32((u32)bus_address);
nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_HIGH_IDX] =
cpu_to_le32((u32)((u64)bus_address >> 32));
nesmgt->rx_skb[nesmgt->rq_head] = skb;
nesmgt->rq_head++;
nesmgt->rq_head &= nesmgt->rq_size - 1;
atomic_dec(&mgtvnic->rx_skbs_needed);
barrier();
if (++rx_wqes_posted == 255