diff options
author | Sathya Perla <sathyap@serverengines.com> | 2009-06-17 20:02:59 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-06-19 03:18:39 -0400 |
commit | 5fb379ee67a7ec55ff65b467b472f3d69b60ba16 (patch) | |
tree | 23d8c00fd535abb6f9d56e98ade838b8ed253e99 /drivers/net/benet/be_main.c | |
parent | e3453f6342110d60edb37be92c4a4f668ca8b0c4 (diff) |
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>
Diffstat (limited to 'drivers/net/benet/be_main.c')
-rw-r--r-- | drivers/net/benet/be_main.c | 215 |
1 files changed, 145 insertions, 70 deletions
diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 66bb56874d9b..a4ce80e776b6 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c | |||
@@ -60,26 +60,6 @@ static int be_queue_alloc(struct be_adapter *adapter, struct be_queue_info *q, | |||
60 | return 0; | 60 | return 0; |
61 | } | 61 | } |
62 | 62 | ||
63 | static inline void *queue_head_node(struct be_queue_info *q) | ||
64 | { | ||
65 | return q->dma_mem.va + q->head * q->entry_size; | ||
66 | } | ||
67 | |||
68 | static inline void *queue_tail_node(struct be_queue_info *q) | ||
69 | { | ||
70 | return q->dma_mem.va + q->tail * q->entry_size; | ||
71 | } | ||
72 | |||
73 | static inline void queue_head_inc(struct be_queue_info *q) | ||
74 | { | ||
75 | index_inc(&q->head, q->len); | ||
76 | } | ||
77 | |||
78 | static inline void queue_tail_inc(struct be_queue_info *q) | ||
79 | { | ||
80 | index_inc(&q->tail, q->len); | ||
81 | } | ||
82 | |||
83 | static void be_intr_set(struct be_ctrl_info *ctrl, bool enable) | 63 | static void be_intr_set(struct be_ctrl_info *ctrl, bool enable) |
84 | { | 64 | { |
85 | u8 __iomem *addr = ctrl->pcicfg + PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET; | 65 | 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, | |||
127 | iowrite32(val, ctrl->db + DB_EQ_OFFSET); | 107 | iowrite32(val, ctrl->db + DB_EQ_OFFSET); |
128 | } | 108 | } |
129 | 109 | ||
130 | static void be_cq_notify(struct be_ctrl_info *ctrl, u16 qid, | 110 | void be_cq_notify(struct be_ctrl_info *ctrl, u16 qid, |
131 | bool arm, u16 num_popped) | 111 | bool arm, u16 num_popped) |
132 | { | 112 | { |
133 | u32 val = 0; | 113 | u32 val = 0; |
@@ -960,10 +940,8 @@ static void be_post_rx_frags(struct be_adapter *adapter) | |||
960 | return; | 940 | return; |
961 | } | 941 | } |
962 | 942 | ||
963 | static struct be_eth_tx_compl * | 943 | static struct be_eth_tx_compl *be_tx_compl_get(struct be_queue_info *tx_cq) |
964 | be_tx_compl_get(struct be_adapter *adapter) | ||
965 | { | 944 | { |
966 | struct be_queue_info *tx_cq = &adapter->tx_obj.cq; | ||
967 | struct be_eth_tx_compl *txcp = queue_tail_node(tx_cq); | 945 | struct be_eth_tx_compl *txcp = queue_tail_node(tx_cq); |
968 | 946 | ||
969 | if (txcp->dw[offsetof(struct amap_eth_tx_compl, valid) / 32] == 0) | 947 | 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) | |||
1051 | } | 1029 | } |
1052 | } | 1030 | } |
1053 | 1031 | ||
1032 | static void be_mcc_queues_destroy(struct be_adapter *adapter) | ||
1033 | { | ||
1034 | struct be_queue_info *q; | ||
1035 | struct be_ctrl_info *ctrl = &adapter->ctrl; | ||
1036 | |||
1037 | q = &ctrl->mcc_obj.q; | ||
1038 | if (q->created) | ||
1039 | be_cmd_q_destroy(ctrl, q, QTYPE_MCCQ); | ||
1040 | be_queue_free(adapter, q); | ||
1041 | |||
1042 | q = &ctrl->mcc_obj.cq; | ||
1043 | if (q->created) | ||
1044 | be_cmd_q_destroy(ctrl, q, QTYPE_CQ); | ||
1045 | be_queue_free(adapter, q); | ||
1046 | } | ||
1047 | |||
1048 | /* Must be called only after TX qs are created as MCC shares TX EQ */ | ||
1049 | static int be_mcc_queues_create(struct be_adapter *adapter) | ||
1050 | { | ||
1051 | struct be_queue_info *q, *cq; | ||
1052 | struct be_ctrl_info *ctrl = &adapter->ctrl; | ||
1053 | |||
1054 | /* Alloc MCC compl queue */ | ||
1055 | cq = &ctrl->mcc_obj.cq; | ||
1056 | if (be_queue_alloc(adapter, cq, MCC_CQ_LEN, | ||
1057 | sizeof(struct be_mcc_cq_entry))) | ||
1058 | goto err; | ||
1059 | |||
1060 | /* Ask BE to create MCC compl queue; share TX's eq */ | ||
1061 | if (be_cmd_cq_create(ctrl, cq, &adapter->tx_eq.q, false, true, 0)) | ||
1062 | goto mcc_cq_free; | ||
1063 | |||
1064 | /* Alloc MCC queue */ | ||
1065 | q = &ctrl->mcc_obj.q; | ||
1066 | if (be_queue_alloc(adapter, q, MCC_Q_LEN, sizeof(struct be_mcc_wrb))) | ||
1067 | goto mcc_cq_destroy; | ||
1068 | |||
1069 | /* Ask BE to create MCC queue */ | ||
1070 | if (be_cmd_mccq_create(ctrl, q, cq)) | ||
1071 | goto mcc_q_free; | ||
1072 | |||
1073 | return 0; | ||
1074 | |||
1075 | mcc_q_free: | ||
1076 | be_queue_free(adapter, q); | ||
1077 | mcc_cq_destroy: | ||
1078 | be_cmd_q_destroy(ctrl, cq, QTYPE_CQ); | ||
1079 | mcc_cq_free: | ||
1080 | be_queue_free(adapter, cq); | ||
1081 | err: | ||
1082 | return -1; | ||
1083 | } | ||
1084 | |||
1054 | static void be_tx_queues_destroy(struct be_adapter *adapter) | 1085 | static void be_tx_queues_destroy(struct be_adapter *adapter) |
1055 | { | 1086 | { |
1056 | struct be_queue_info *q; | 1087 | struct be_queue_info *q; |
@@ -1263,7 +1294,7 @@ static irqreturn_t be_msix_rx(int irq, void *dev) | |||
1263 | return IRQ_HANDLED; | 1294 | return IRQ_HANDLED; |
1264 | } | 1295 | } |
1265 | 1296 | ||
1266 | static irqreturn_t be_msix_tx(int irq, void *dev) | 1297 | static irqreturn_t be_msix_tx_mcc(int irq, void *dev) |
1267 | { | 1298 | { |
1268 | struct be_adapter *adapter = dev; | 1299 | struct be_adapter *adapter = dev; |
1269 | 1300 | ||
@@ -1324,40 +1355,51 @@ int be_poll_rx(struct napi_struct *napi, int budget) | |||
1324 | return work_done; | 1355 | return work_done; |
1325 | } | 1356 | } |
1326 | 1357 | ||
1327 | /* For TX we don't honour budget; consume everything */ | 1358 | void be_process_tx(struct be_adapter *adapter) |
1328 | int be_poll_tx(struct napi_struct *napi, int budget) | ||
1329 | { | 1359 | { |
1330 | struct be_eq_obj *tx_eq = container_of(napi, struct be_eq_obj, napi); | 1360 | struct be_queue_info *txq = &adapter->tx_obj.q; |
1331 | struct be_adapter *adapter = | 1361 | struct be_queue_info *tx_cq = &adapter->tx_obj.cq; |
1332 | container_of(tx_eq, struct be_adapter, tx_eq); | ||
1333 | struct be_tx_obj *tx_obj = &adapter->tx_obj; | ||
1334 | struct be_queue_info *tx_cq = &tx_obj->cq; | ||
1335 | struct be_queue_info *txq = &tx_obj->q; | ||
1336 | struct be_eth_tx_compl *txcp; | 1362 | struct be_eth_tx_compl *txcp; |
1337 | u32 num_cmpl = 0; | 1363 | u32 num_cmpl = 0; |
1338 | u16 end_idx; | 1364 | u16 end_idx; |
1339 | 1365 | ||
1340 | while ((txcp = be_tx_compl_get(adapter))) { | 1366 | while ((txcp = be_tx_compl_get(tx_cq))) { |
1341 | end_idx = AMAP_GET_BITS(struct amap_eth_tx_compl, | 1367 | end_idx = AMAP_GET_BITS(struct amap_eth_tx_compl, |
1342 | wrb_index, txcp); | 1368 | wrb_index, txcp); |
1343 | be_tx_compl_process(adapter, end_idx); | 1369 | be_tx_compl_process(adapter, end_idx); |
1344 | num_cmpl++; | 1370 | num_cmpl++; |
1345 | } | 1371 | } |
1346 | 1372 | ||
1347 | /* As Tx wrbs have been freed up, wake up netdev queue if | 1373 | if (num_cmpl) { |
1348 | * it was stopped due to lack of tx wrbs. | 1374 | be_cq_notify(&adapter->ctrl, tx_cq->id, true, num_cmpl); |
1349 | */ | 1375 | |
1350 | if (netif_queue_stopped(adapter->netdev) && | 1376 | /* As Tx wrbs have been freed up, wake up netdev queue if |
1377 | * it was stopped due to lack of tx wrbs. | ||
1378 | */ | ||
1379 | if (netif_queue_stopped(adapter->netdev) && | ||
1351 | atomic_read(&txq->used) < txq->len / 2) { | 1380 | atomic_read(&txq->used) < txq->len / 2) { |
1352 | netif_wake_queue(adapter->netdev); | 1381 | netif_wake_queue(adapter->netdev); |
1382 | } | ||
1383 | |||
1384 | drvr_stats(adapter)->be_tx_events++; | ||
1385 | drvr_stats(adapter)->be_tx_compl += num_cmpl; | ||
1353 | } | 1386 | } |
1387 | } | ||
1388 | |||
1389 | /* As TX and MCC share the same EQ check for both TX and MCC completions. | ||
1390 | * For TX/MCC we don't honour budget; consume everything | ||
1391 | */ | ||
1392 | static int be_poll_tx_mcc(struct napi_struct *napi, int budget) | ||
1393 | { | ||
1394 | struct be_eq_obj *tx_eq = container_of(napi, struct be_eq_obj, napi); | ||
1395 | struct be_adapter *adapter = | ||
1396 | container_of(tx_eq, struct be_adapter, tx_eq); | ||
1354 | 1397 | ||
1355 | napi_complete(napi); | 1398 | napi_complete(napi); |
1356 | 1399 | ||
1357 | be_cq_notify(&adapter->ctrl, tx_cq->id, true, num_cmpl); | 1400 | be_process_tx(adapter); |
1358 | 1401 | ||
1359 | drvr_stats(adapter)->be_tx_events++; | 1402 | be_process_mcc(&adapter->ctrl); |
1360 | drvr_stats(adapter)->be_tx_compl += num_cmpl; | ||
1361 | 1403 | ||
1362 | return 1; | 1404 | return 1; |
1363 | } | 1405 | } |
@@ -1419,7 +1461,7 @@ static int be_msix_register(struct be_adapter *adapter) | |||
1419 | 1461 | ||
1420 | sprintf(tx_eq->desc, "%s-tx", netdev->name); | 1462 | sprintf(tx_eq->desc, "%s-tx", netdev->name); |
1421 | vec = be_msix_vec_get(adapter, tx_eq->q.id); | 1463 | vec = be_msix_vec_get(adapter, tx_eq->q.id); |
1422 | status = request_irq(vec, be_msix_tx, 0, tx_eq->desc, adapter); | 1464 | status = request_irq(vec, be_msix_tx_mcc, 0, tx_eq->desc, adapter); |
1423 | if (status) | 1465 | if (status) |
1424 | goto err; | 1466 | goto err; |
1425 | 1467 | ||
@@ -1495,6 +1537,34 @@ static int be_open(struct net_device *netdev) | |||
1495 | struct be_ctrl_info *ctrl = &adapter->ctrl; | 1537 | struct be_ctrl_info *ctrl = &adapter->ctrl; |
1496 | struct be_eq_obj *rx_eq = &adapter->rx_eq; | 1538 | struct be_eq_obj *rx_eq = &adapter->rx_eq; |
1497 | struct be_eq_obj *tx_eq = &adapter->tx_eq; | 1539 | struct be_eq_obj *tx_eq = &adapter->tx_eq; |
1540 | |||
1541 | /* First time posting */ | ||
1542 | be_post_rx_frags(adapter); | ||
1543 | |||
1544 | napi_enable(&rx_eq->napi); | ||
1545 | napi_enable(&tx_eq->napi); | ||
1546 | |||
1547 | be_irq_register(adapter); | ||
1548 | |||
1549 | be_intr_set(ctrl, true); | ||
1550 | |||
1551 | /* The evt queues are created in unarmed state; arm them */ | ||
1552 | be_eq_notify(ctrl, rx_eq->q.id, true, false, 0); | ||
1553 | be_eq_notify(ctrl, tx_eq->q.id, true, false, 0); | ||
1554 | |||
1555 | /* Rx compl queue may be in unarmed state; rearm it */ | ||
1556 | be_cq_notify(ctrl, adapter->rx_obj.cq.id, true, 0); | ||
1557 | |||
1558 | be_link_status_update(adapter); | ||
1559 | |||
1560 | schedule_delayed_work(&adapter->work, msecs_to_jiffies(100)); | ||
1561 | return 0; | ||
1562 | } | ||
1563 | |||
1564 | static int be_setup(struct be_adapter *adapter) | ||
1565 | { | ||
1566 | struct be_ctrl_info *ctrl = &adapter->ctrl; | ||
1567 | struct net_device *netdev = adapter->netdev; | ||
1498 | u32 if_flags; | 1568 | u32 if_flags; |
1499 | int status; | 1569 | int status; |
1500 | 1570 | ||
@@ -1521,29 +1591,14 @@ static int be_open(struct net_device *netdev) | |||
1521 | if (status != 0) | 1591 | if (status != 0) |
1522 | goto tx_qs_destroy; | 1592 | goto tx_qs_destroy; |
1523 | 1593 | ||
1524 | /* First time posting */ | 1594 | status = be_mcc_queues_create(adapter); |
1525 | be_post_rx_frags(adapter); | 1595 | if (status != 0) |
1526 | 1596 | goto rx_qs_destroy; | |
1527 | napi_enable(&rx_eq->napi); | ||
1528 | napi_enable(&tx_eq->napi); | ||
1529 | |||
1530 | be_irq_register(adapter); | ||
1531 | |||
1532 | be_intr_set(ctrl, true); | ||
1533 | |||
1534 | /* The evt queues are created in the unarmed state; arm them */ | ||
1535 | be_eq_notify(ctrl, rx_eq->q.id, true, false, 0); | ||
1536 | be_eq_notify(ctrl, tx_eq->q.id, true, false, 0); | ||
1537 | |||
1538 | /* The compl queues are created in the unarmed state; arm them */ | ||
1539 | be_cq_notify(ctrl, adapter->rx_obj.cq.id, true, 0); | ||
1540 | be_cq_notify(ctrl, adapter->tx_obj.cq.id, true, 0); | ||
1541 | |||
1542 | be_link_status_update(adapter); | ||
1543 | 1597 | ||
1544 | schedule_delayed_work(&adapter->work, msecs_to_jiffies(100)); | ||
1545 | return 0; | 1598 | return 0; |
1546 | 1599 | ||
1600 | rx_qs_destroy: | ||
1601 | be_rx_queues_destroy(adapter); | ||
1547 | tx_qs_destroy: | 1602 | tx_qs_destroy: |
1548 | be_tx_queues_destroy(adapter); | 1603 | be_tx_queues_destroy(adapter); |
1549 | if_destroy: | 1604 | if_destroy: |
@@ -1552,6 +1607,19 @@ do_none: | |||
1552 | return status; | 1607 | return status; |
1553 | } | 1608 | } |
1554 | 1609 | ||
1610 | static int be_clear(struct be_adapter *adapter) | ||
1611 | { | ||
1612 | struct be_ctrl_info *ctrl = &adapter->ctrl; | ||
1613 | |||
1614 | be_rx_queues_destroy(adapter); | ||
1615 | be_tx_queues_destroy(adapter); | ||
1616 | |||
1617 | be_cmd_if_destroy(ctrl, adapter->if_handle); | ||
1618 | |||
1619 | be_mcc_queues_destroy(adapter); | ||
1620 | return 0; | ||
1621 | } | ||
1622 | |||
1555 | static int be_close(struct net_device *netdev) | 1623 | static int be_close(struct net_device *netdev) |
1556 | { | 1624 | { |
1557 | struct be_adapter *adapter = netdev_priv(netdev); | 1625 | struct be_adapter *adapter = netdev_priv(netdev); |
@@ -1581,10 +1649,6 @@ static int be_close(struct net_device *netdev) | |||
1581 | napi_disable(&rx_eq->napi); | 1649 | napi_disable(&rx_eq->napi); |
1582 | napi_disable(&tx_eq->napi); | 1650 | napi_disable(&tx_eq->napi); |
1583 | 1651 | ||
1584 | be_rx_queues_destroy(adapter); | ||
1585 | be_tx_queues_destroy(adapter); | ||
1586 | |||
1587 | be_cmd_if_destroy(ctrl, adapter->if_handle); | ||
1588 | return 0; | 1652 | return 0; |
1589 | } | 1653 | } |
1590 | 1654 | ||
@@ -1673,7 +1737,7 @@ static void be_netdev_init(struct net_device *netdev) | |||
1673 | 1737 | ||
1674 | netif_napi_add(netdev, &adapter->rx_eq.napi, be_poll_rx, | 1738 | netif_napi_add(netdev, &adapter->rx_eq.napi, be_poll_rx, |
1675 | BE_NAPI_WEIGHT); | 1739 | BE_NAPI_WEIGHT); |
1676 | netif_napi_add(netdev, &adapter->tx_eq.napi, be_poll_tx, | 1740 | netif_napi_add(netdev, &adapter->tx_eq.napi, be_poll_tx_mcc, |
1677 | BE_NAPI_WEIGHT); | 1741 | BE_NAPI_WEIGHT); |
1678 | 1742 | ||
1679 | netif_carrier_off(netdev); | 1743 | netif_carrier_off(netdev); |
@@ -1755,7 +1819,9 @@ static int be_ctrl_init(struct be_adapter *adapter) | |||
1755 | mbox_mem_align->va = PTR_ALIGN(mbox_mem_alloc->va, 16); | 1819 | mbox_mem_align->va = PTR_ALIGN(mbox_mem_alloc->va, 16); |
1756 | mbox_mem_align->dma = PTR_ALIGN(mbox_mem_alloc->dma, 16); | 1820 | mbox_mem_align->dma = PTR_ALIGN(mbox_mem_alloc->dma, 16); |
1757 | memset(mbox_mem_align->va, 0, sizeof(struct be_mcc_mailbox)); | 1821 | memset(mbox_mem_align->va, 0, sizeof(struct be_mcc_mailbox)); |
1758 | spin_lock_init(&ctrl->cmd_lock); | 1822 | spin_lock_init(&ctrl->mbox_lock); |
1823 | spin_lock_init(&ctrl->mcc_lock); | ||
1824 | spin_lock_init(&ctrl->mcc_cq_lock); | ||
1759 | 1825 | ||
1760 | val = ioread32(ctrl->pcicfg + PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET); | 1826 | val = ioread32(ctrl->pcicfg + PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET); |
1761 | ctrl->pci_func = (val >> MEMBAR_CTRL_INT_CTRL_PFUNC_SHIFT) & | 1827 | ctrl->pci_func = (val >> MEMBAR_CTRL_INT_CTRL_PFUNC_SHIFT) & |
@@ -1793,6 +1859,8 @@ static void __devexit be_remove(struct pci_dev *pdev) | |||
1793 | 1859 | ||
1794 | unregister_netdev(adapter->netdev); | 1860 | unregister_netdev(adapter->netdev); |
1795 | 1861 | ||
1862 | be_clear(adapter); | ||
1863 | |||
1796 | be_stats_cleanup(adapter); | 1864 | be_stats_cleanup(adapter); |
1797 | 1865 | ||
1798 | be_ctrl_cleanup(adapter); | 1866 | be_ctrl_cleanup(adapter); |
@@ -1890,13 +1958,18 @@ static int __devinit be_probe(struct pci_dev *pdev, | |||
1890 | be_netdev_init(netdev); | 1958 | be_netdev_init(netdev); |
1891 | SET_NETDEV_DEV(netdev, &adapter->pdev->dev); | 1959 | SET_NETDEV_DEV(netdev, &adapter->pdev->dev); |
1892 | 1960 | ||
1961 | status = be_setup(adapter); | ||
1962 | if (status) | ||
1963 | goto stats_clean; | ||
1893 | status = register_netdev(netdev); | 1964 | status = register_netdev(netdev); |
1894 | if (status != 0) | 1965 | if (status != 0) |
1895 | goto stats_clean; | 1966 | goto unsetup; |
1896 | 1967 | ||
1897 | dev_info(&pdev->dev, "%s port %d\n", nic_name(pdev), adapter->port_num); | 1968 | dev_info(&pdev->dev, "%s port %d\n", nic_name(pdev), adapter->port_num); |
1898 | return 0; | 1969 | return 0; |
1899 | 1970 | ||
1971 | unsetup: | ||
1972 | be_clear(adapter); | ||
1900 | stats_clean: | 1973 | stats_clean: |
1901 | be_stats_cleanup(adapter); | 1974 | be_stats_cleanup(adapter); |
1902 | ctrl_clean: | 1975 | ctrl_clean: |
@@ -1921,6 +1994,7 @@ static int be_suspend(struct pci_dev *pdev, pm_message_t state) | |||
1921 | if (netif_running(netdev)) { | 1994 | if (netif_running(netdev)) { |
1922 | rtnl_lock(); | 1995 | rtnl_lock(); |
1923 | be_close(netdev); | 1996 | be_close(netdev); |
1997 | be_clear(adapter); | ||
1924 | rtnl_unlock(); | 1998 | rtnl_unlock(); |
1925 | } | 1999 | } |
1926 | 2000 | ||
@@ -1947,6 +2021,7 @@ static int be_resume(struct pci_dev *pdev) | |||
1947 | 2021 | ||
1948 | if (netif_running(netdev)) { | 2022 | if (netif_running(netdev)) { |
1949 | rtnl_lock(); | 2023 | rtnl_lock(); |
2024 | be_setup(adapter); | ||
1950 | be_open(netdev); | 2025 | be_open(netdev); |
1951 | rtnl_unlock(); | 2026 | rtnl_unlock(); |
1952 | } | 2027 | } |