be2net: Add MCC queue mechanism for BE cmds

Currenlty all cmds use the blocking MCC mbox to post cmds. An mbox cmd is protected
via a spin_lock(cmd_lock) and not spin_lock_bh() as it is undesirable
to disable BHs while a blocking mbox cmd is in progress (and take long to finish.)
This can lockup a cmd in progress in process context. Instead cmds that may be
called in BH context must use the MCC queue to post cmds. The cmd completions
are rcvd in a separate completion queue and the events are placed in the tx-event
queue.

Signed-off-by: Sathya Perla <sathyap@serverengines.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Sathya Perla 2009-06-18 00:02:59 +00:00 committed by David S. Miller
parent e3453f6342
commit 5fb379ee67
5 changed files with 455 additions and 161 deletions

View file

@ -60,26 +60,6 @@ static int be_queue_alloc(struct be_adapter *adapter, struct be_queue_info *q,
return 0;
}
static inline void *queue_head_node(struct be_queue_info *q)
{
return q->dma_mem.va + q->head * q->entry_size;
}
static inline void *queue_tail_node(struct be_queue_info *q)
{
return q->dma_mem.va + q->tail * q->entry_size;
}
static inline void queue_head_inc(struct be_queue_info *q)
{
index_inc(&q->head, q->len);
}
static inline void queue_tail_inc(struct be_queue_info *q)
{
index_inc(&q->tail, q->len);
}
static void be_intr_set(struct be_ctrl_info *ctrl, bool enable)
{
u8 __iomem *addr = ctrl->pcicfg + PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET;
@ -127,7 +107,7 @@ static void be_eq_notify(struct be_ctrl_info *ctrl, u16 qid,
iowrite32(val, ctrl->db + DB_EQ_OFFSET);
}
static void be_cq_notify(struct be_ctrl_info *ctrl, u16 qid,
void be_cq_notify(struct be_ctrl_info *ctrl, u16 qid,
bool arm, u16 num_popped)
{
u32 val = 0;
@ -960,10 +940,8 @@ static void be_post_rx_frags(struct be_adapter *adapter)
return;
}
static struct be_eth_tx_compl *
be_tx_compl_get(struct be_adapter *adapter)
static struct be_eth_tx_compl *be_tx_compl_get(struct be_queue_info *tx_cq)
{
struct be_queue_info *tx_cq = &adapter->tx_obj.cq;
struct be_eth_tx_compl *txcp = queue_tail_node(tx_cq);
if (txcp->dw[offsetof(struct amap_eth_tx_compl, valid) / 32] == 0)
@ -1051,6 +1029,59 @@ static void be_tx_q_clean(struct be_adapter *adapter)
}
}
static void be_mcc_queues_destroy(struct be_adapter *adapter)
{
struct be_queue_info *q;
struct be_ctrl_info *ctrl = &adapter->ctrl;
q = &ctrl->mcc_obj.q;
if (q->created)
be_cmd_q_destroy(ctrl, q, QTYPE_MCCQ);
be_queue_free(adapter, q);
q = &ctrl->mcc_obj.cq;
if (q->created)
be_cmd_q_destroy(ctrl, q, QTYPE_CQ);
be_queue_free(adapter, q);
}
/* Must be called only after TX qs are created as MCC shares TX EQ */
static int be_mcc_queues_create(struct be_adapter *adapter)
{
struct be_queue_info *q, *cq;
struct be_ctrl_info *ctrl = &adapter->ctrl;
/* Alloc MCC compl queue */
cq = &ctrl->mcc_obj.cq;
if (be_queue_alloc(adapter, cq, MCC_CQ_LEN,
sizeof(struct be_mcc_cq_entry)))
goto err;
/* Ask BE to create MCC compl queue; share TX's eq */
if (be_cmd_cq_create(ctrl, cq, &adapter->tx_eq.q, false, true, 0))
goto mcc_cq_free;
/* Alloc MCC queue */
q = &ctrl->mcc_obj.q;
if (be_queue_alloc(adapter, q, MCC_Q_LEN, sizeof(struct be_mcc_wrb)))
goto mcc_cq_destroy;
/* Ask BE to create MCC queue */
if (be_cmd_mccq_create(ctrl, q, cq))
goto mcc_q_free;
return 0;
mcc_q_free:
be_queue_free(adapter, q);
mcc_cq_destroy:
be_cmd_q_destroy(ctrl, cq, QTYPE_CQ);
mcc_cq_free:
be_queue_free(adapter, cq);
err:
return -1;
}
static void be_tx_queues_destroy(struct be_adapter *adapter)
{
struct be_queue_info *q;
@ -1263,7 +1294,7 @@ static irqreturn_t be_msix_rx(int irq, void *dev)
return IRQ_HANDLED;
}
static irqreturn_t be_msix_tx(int irq, void *dev)
static irqreturn_t be_msix_tx_mcc(int irq, void *dev)
{
struct be_adapter *adapter = dev;
@ -1324,40 +1355,51 @@ int be_poll_rx(struct napi_struct *napi, int budget)
return work_done;
}
/* For TX we don't honour budget; consume everything */
int be_poll_tx(struct napi_struct *napi, int budget)
void be_process_tx(struct be_adapter *adapter)
{
struct be_eq_obj *tx_eq = container_of(napi, struct be_eq_obj, napi);
struct be_adapter *adapter =
container_of(tx_eq, struct be_adapter, tx_eq);
struct be_tx_obj *tx_obj = &adapter->tx_obj;
struct be_queue_info *tx_cq = &tx_obj->cq;
struct be_queue_info *txq = &tx_obj->q;
struct be_queue_info *txq = &adapter->tx_obj.q;
struct be_queue_info *tx_cq = &adapter->tx_obj.cq;
struct be_eth_tx_compl *txcp;
u32 num_cmpl = 0;
u16 end_idx;
while ((txcp = be_tx_compl_get(adapter))) {
while ((txcp = be_tx_compl_get(tx_cq))) {
end_idx = AMAP_GET_BITS(struct amap_eth_tx_compl,
wrb_index, txcp);
be_tx_compl_process(adapter, end_idx);
num_cmpl++;
}
/* As Tx wrbs have been freed up, wake up netdev queue if
* it was stopped due to lack of tx wrbs.
*/
if (netif_queue_stopped(adapter->netdev) &&
if (num_cmpl) {
be_cq_notify(&adapter->ctrl, tx_cq->id, true, num_cmpl);
/* As Tx wrbs have been freed up, wake up netdev queue if
* it was stopped due to lack of tx wrbs.
*/
if (netif_queue_stopped(adapter->netdev) &&
atomic_read(&txq->used) < txq->len / 2) {
netif_wake_queue(adapter->netdev);
netif_wake_queue(adapter->netdev);
}
drvr_stats(adapter)->be_tx_events++;
drvr_stats(adapter)->be_tx_compl += num_cmpl;
}
}
/* As TX and MCC share the same EQ check for both TX and MCC completions.
* For TX/MCC we don't honour budget; consume everything
*/
static int be_poll_tx_mcc(struct napi_struct *napi, int budget)
{
struct be_eq_obj *tx_eq = container_of(napi, struct be_eq_obj, napi);
struct be_adapter *adapter =
container_of(tx_eq, struct be_adapter, tx_eq);
napi_complete(napi);
be_cq_notify(&adapter->ctrl, tx_cq->id, true, num_cmpl);
be_process_tx(adapter);
drvr_stats(adapter)->be_tx_events++;
drvr_stats(adapter)->be_tx_compl += num_cmpl;
be_process_mcc(&adapter->ctrl);
return 1;
}
@ -1419,7 +1461,7 @@ static int be_msix_register(struct be_adapter *adapter)
sprintf(tx_eq->desc, "%s-tx", netdev->name);
vec = be_msix_vec_get(adapter, tx_eq->q.id);
status = request_irq(vec, be_msix_tx, 0, tx_eq->desc, adapter);
status = request_irq(vec, be_msix_tx_mcc, 0, tx_eq->desc, adapter);
if (status)
goto err;
@ -1495,6 +1537,34 @@ static int be_open(struct net_device *netdev)
struct be_ctrl_info *ctrl = &adapter->ctrl;
struct be_eq_obj *rx_eq = &adapter->rx_eq;
struct be_eq_obj *tx_eq = &adapter->tx_eq;
/* First time posting */
be_post_rx_frags(adapter);
napi_enable(&rx_eq->napi);
napi_enable(&tx_eq->napi);
be_irq_register(adapter);
be_intr_set(ctrl, true);
/* The evt queues are created in unarmed state; arm them */
be_eq_notify(ctrl, rx_eq->q.id, true, false, 0);
be_eq_notify(ctrl, tx_eq->q.id, true, false, 0);
/* Rx compl queue may be in unarmed state; rearm it */
be_cq_notify(ctrl, adapter->rx_obj.cq.id, true, 0);
be_link_status_update(adapter);
schedule_delayed_work(&adapter->work, msecs_to_jiffies(100));
return 0;
}
static int be_setup(struct be_adapter *adapter)
{
struct be_ctrl_info *ctrl = &adapter->ctrl;
struct net_device *netdev = adapter->netdev;
u32 if_flags;
int status;
@ -1521,29 +1591,14 @@ static int be_open(struct net_device *netdev)
if (status != 0)
goto tx_qs_destroy;
/* First time posting */
be_post_rx_frags(adapter);
status = be_mcc_queues_create(adapter);
if (status != 0)
goto rx_qs_destroy;
napi_enable(&rx_eq->napi);
napi_enable(&tx_eq->napi);
be_irq_register(adapter);
be_intr_set(ctrl, true);
/* The evt queues are created in the unarmed state; arm them */
be_eq_notify(ctrl, rx_eq->q.id, true, false, 0);
be_eq_notify(ctrl, tx_eq->q.id, true, false, 0);
/* The compl queues are created in the unarmed state; arm them */
be_cq_notify(ctrl, adapter->rx_obj.cq.id, true, 0);
be_cq_notify(ctrl, adapter->tx_obj.cq.id, true, 0);
be_link_status_update(adapter);
schedule_delayed_work(&adapter->work, msecs_to_jiffies(100));
return 0;
rx_qs_destroy:
be_rx_queues_destroy(adapter);
tx_qs_destroy:
be_tx_queues_destroy(adapter);
if_destroy:
@ -1552,6 +1607,19 @@ do_none:
return status;
}
static int be_clear(struct be_adapter *adapter)
{
struct be_ctrl_info *ctrl = &adapter->ctrl;
be_rx_queues_destroy(adapter);
be_tx_queues_destroy(adapter);
be_cmd_if_destroy(ctrl, adapter->if_handle);
be_mcc_queues_destroy(adapter);
return 0;
}
static int be_close(struct net_device *netdev)
{
struct be_adapter *adapter = netdev_priv(netdev);
@ -1581,10 +1649,6 @@ static int be_close(struct net_device *netdev)
napi_disable(&rx_eq->napi);
napi_disable(&tx_eq->napi);
be_rx_queues_destroy(adapter);
be_tx_queues_destroy(adapter);
be_cmd_if_destroy(ctrl, adapter->if_handle);
return 0;
}
@ -1673,7 +1737,7 @@ static void be_netdev_init(struct net_device *netdev)
netif_napi_add(netdev, &adapter->rx_eq.napi, be_poll_rx,
BE_NAPI_WEIGHT);
netif_napi_add(netdev, &adapter->tx_eq.napi, be_poll_tx,
netif_napi_add(netdev, &adapter->tx_eq.napi, be_poll_tx_mcc,
BE_NAPI_WEIGHT);
netif_carrier_off(netdev);
@ -1755,7 +1819,9 @@ static int be_ctrl_init(struct be_adapter *adapter)
mbox_mem_align->va = PTR_ALIGN(mbox_mem_alloc->va, 16);
mbox_mem_align->dma = PTR_ALIGN(mbox_mem_alloc->dma, 16);
memset(mbox_mem_align->va, 0, sizeof(struct be_mcc_mailbox));
spin_lock_init(&ctrl->cmd_lock);
spin_lock_init(&ctrl->mbox_lock);
spin_lock_init(&ctrl->mcc_lock);
spin_lock_init(&ctrl->mcc_cq_lock);
val = ioread32(ctrl->pcicfg + PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET);
ctrl->pci_func = (val >> MEMBAR_CTRL_INT_CTRL_PFUNC_SHIFT) &
@ -1793,6 +1859,8 @@ static void __devexit be_remove(struct pci_dev *pdev)
unregister_netdev(adapter->netdev);
be_clear(adapter);
be_stats_cleanup(adapter);
be_ctrl_cleanup(adapter);
@ -1890,13 +1958,18 @@ static int __devinit be_probe(struct pci_dev *pdev,
be_netdev_init(netdev);
SET_NETDEV_DEV(netdev, &adapter->pdev->dev);
status = be_setup(adapter);
if (status)
goto stats_clean;
status = register_netdev(netdev);
if (status != 0)
goto stats_clean;
goto unsetup;
dev_info(&pdev->dev, "%s port %d\n", nic_name(pdev), adapter->port_num);
return 0;
unsetup:
be_clear(adapter);
stats_clean:
be_stats_cleanup(adapter);
ctrl_clean:
@ -1921,6 +1994,7 @@ static int be_suspend(struct pci_dev *pdev, pm_message_t state)
if (netif_running(netdev)) {
rtnl_lock();
be_close(netdev);
be_clear(adapter);
rtnl_unlock();
}
@ -1947,6 +2021,7 @@ static int be_resume(struct pci_dev *pdev)
if (netif_running(netdev)) {
rtnl_lock();
be_setup(adapter);
be_open(netdev);
rtnl_unlock();
}