diff options
-rw-r--r-- | drivers/infiniband/hw/nes/Makefile | 2 | ||||
-rw-r--r-- | drivers/infiniband/hw/nes/nes.c | 8 | ||||
-rw-r--r-- | drivers/infiniband/hw/nes/nes.h | 17 | ||||
-rw-r--r-- | drivers/infiniband/hw/nes/nes_cm.c | 19 | ||||
-rw-r--r-- | drivers/infiniband/hw/nes/nes_cm.h | 2 | ||||
-rw-r--r-- | drivers/infiniband/hw/nes/nes_hw.c | 73 | ||||
-rw-r--r-- | drivers/infiniband/hw/nes/nes_hw.h | 35 | ||||
-rw-r--r-- | drivers/infiniband/hw/nes/nes_mgt.c | 1162 | ||||
-rw-r--r-- | drivers/infiniband/hw/nes/nes_mgt.h | 97 | ||||
-rw-r--r-- | drivers/infiniband/hw/nes/nes_nic.c | 4 | ||||
-rw-r--r-- | drivers/infiniband/hw/nes/nes_utils.c | 53 | ||||
-rw-r--r-- | drivers/infiniband/hw/nes/nes_verbs.c | 3 | ||||
-rw-r--r-- | drivers/infiniband/hw/nes/nes_verbs.h | 9 |
13 files changed, 1434 insertions, 50 deletions
diff --git a/drivers/infiniband/hw/nes/Makefile b/drivers/infiniband/hw/nes/Makefile index 35148513c47e..97820c23ecef 100644 --- a/drivers/infiniband/hw/nes/Makefile +++ b/drivers/infiniband/hw/nes/Makefile | |||
@@ -1,3 +1,3 @@ | |||
1 | obj-$(CONFIG_INFINIBAND_NES) += iw_nes.o | 1 | obj-$(CONFIG_INFINIBAND_NES) += iw_nes.o |
2 | 2 | ||
3 | iw_nes-objs := nes.o nes_hw.o nes_nic.o nes_utils.o nes_verbs.o nes_cm.o | 3 | iw_nes-objs := nes.o nes_hw.o nes_nic.o nes_utils.o nes_verbs.o nes_cm.o nes_mgt.o |
diff --git a/drivers/infiniband/hw/nes/nes.c b/drivers/infiniband/hw/nes/nes.c index 2d668c69f6d9..5965b3df8f2f 100644 --- a/drivers/infiniband/hw/nes/nes.c +++ b/drivers/infiniband/hw/nes/nes.c | |||
@@ -84,7 +84,7 @@ module_param(send_first, int, 0644); | |||
84 | MODULE_PARM_DESC(send_first, "Send RDMA Message First on Active Connection"); | 84 | MODULE_PARM_DESC(send_first, "Send RDMA Message First on Active Connection"); |
85 | 85 | ||
86 | 86 | ||
87 | unsigned int nes_drv_opt = 0; | 87 | unsigned int nes_drv_opt = NES_DRV_OPT_DISABLE_INT_MOD | NES_DRV_OPT_ENABLE_PAU; |
88 | module_param(nes_drv_opt, int, 0644); | 88 | module_param(nes_drv_opt, int, 0644); |
89 | MODULE_PARM_DESC(nes_drv_opt, "Driver option parameters"); | 89 | MODULE_PARM_DESC(nes_drv_opt, "Driver option parameters"); |
90 | 90 | ||
@@ -130,9 +130,6 @@ static struct notifier_block nes_net_notifier = { | |||
130 | .notifier_call = nes_net_event | 130 | .notifier_call = nes_net_event |
131 | }; | 131 | }; |
132 | 132 | ||
133 | |||
134 | |||
135 | |||
136 | /** | 133 | /** |
137 | * nes_inetaddr_event | 134 | * nes_inetaddr_event |
138 | */ | 135 | */ |
@@ -321,6 +318,9 @@ void nes_rem_ref(struct ib_qp *ibqp) | |||
321 | } | 318 | } |
322 | 319 | ||
323 | if (atomic_dec_and_test(&nesqp->refcount)) { | 320 | if (atomic_dec_and_test(&nesqp->refcount)) { |
321 | if (nesqp->pau_mode) | ||
322 | nes_destroy_pau_qp(nesdev, nesqp); | ||
323 | |||
324 | /* Destroy the QP */ | 324 | /* Destroy the QP */ |
325 | cqp_request = nes_get_cqp_request(nesdev); | 325 | cqp_request = nes_get_cqp_request(nesdev); |
326 | if (cqp_request == NULL) { | 326 | if (cqp_request == NULL) { |
diff --git a/drivers/infiniband/hw/nes/nes.h b/drivers/infiniband/hw/nes/nes.h index 6fe79876009e..568b4f11380a 100644 --- a/drivers/infiniband/hw/nes/nes.h +++ b/drivers/infiniband/hw/nes/nes.h | |||
@@ -102,6 +102,7 @@ | |||
102 | #define NES_DRV_OPT_NO_INLINE_DATA 0x00000080 | 102 | #define NES_DRV_OPT_NO_INLINE_DATA 0x00000080 |
103 | #define NES_DRV_OPT_DISABLE_INT_MOD 0x00000100 | 103 | #define NES_DRV_OPT_DISABLE_INT_MOD 0x00000100 |
104 | #define NES_DRV_OPT_DISABLE_VIRT_WQ 0x00000200 | 104 | #define NES_DRV_OPT_DISABLE_VIRT_WQ 0x00000200 |
105 | #define NES_DRV_OPT_ENABLE_PAU 0x00000400 | ||
105 | 106 | ||
106 | #define NES_AEQ_EVENT_TIMEOUT 2500 | 107 | #define NES_AEQ_EVENT_TIMEOUT 2500 |
107 | #define NES_DISCONNECT_EVENT_TIMEOUT 2000 | 108 | #define NES_DISCONNECT_EVENT_TIMEOUT 2000 |
@@ -128,6 +129,7 @@ | |||
128 | #define NES_DBG_IW_RX 0x00020000 | 129 | #define NES_DBG_IW_RX 0x00020000 |
129 | #define NES_DBG_IW_TX 0x00040000 | 130 | #define NES_DBG_IW_TX 0x00040000 |
130 | #define NES_DBG_SHUTDOWN 0x00080000 | 131 | #define NES_DBG_SHUTDOWN 0x00080000 |
132 | #define NES_DBG_PAU 0x00100000 | ||
131 | #define NES_DBG_RSVD1 0x10000000 | 133 | #define NES_DBG_RSVD1 0x10000000 |
132 | #define NES_DBG_RSVD2 0x20000000 | 134 | #define NES_DBG_RSVD2 0x20000000 |
133 | #define NES_DBG_RSVD3 0x40000000 | 135 | #define NES_DBG_RSVD3 0x40000000 |
@@ -162,6 +164,7 @@ do { \ | |||
162 | #include "nes_context.h" | 164 | #include "nes_context.h" |
163 | #include "nes_user.h" | 165 | #include "nes_user.h" |
164 | #include "nes_cm.h" | 166 | #include "nes_cm.h" |
167 | #include "nes_mgt.h" | ||
165 | 168 | ||
166 | extern int max_mtu; | 169 | extern int max_mtu; |
167 | #define max_frame_len (max_mtu+ETH_HLEN) | 170 | #define max_frame_len (max_mtu+ETH_HLEN) |
@@ -202,6 +205,8 @@ extern atomic_t cm_nodes_created; | |||
202 | extern atomic_t cm_nodes_destroyed; | 205 | extern atomic_t cm_nodes_destroyed; |
203 | extern atomic_t cm_accel_dropped_pkts; | 206 | extern atomic_t cm_accel_dropped_pkts; |
204 | extern atomic_t cm_resets_recvd; | 207 | extern atomic_t cm_resets_recvd; |
208 | extern atomic_t pau_qps_created; | ||
209 | extern atomic_t pau_qps_destroyed; | ||
205 | 210 | ||
206 | extern u32 int_mod_timer_init; | 211 | extern u32 int_mod_timer_init; |
207 | extern u32 int_mod_cq_depth_256; | 212 | extern u32 int_mod_cq_depth_256; |
@@ -273,6 +278,14 @@ struct nes_device { | |||
273 | u8 link_recheck; | 278 | u8 link_recheck; |
274 | }; | 279 | }; |
275 | 280 | ||
281 | /* Receive skb private area - must fit in skb->cb area */ | ||
282 | struct nes_rskb_cb { | ||
283 | u64 busaddr; | ||
284 | u32 maplen; | ||
285 | u32 seqnum; | ||
286 | u8 *data_start; | ||
287 | struct nes_qp *nesqp; | ||
288 | }; | ||
276 | 289 | ||
277 | static inline __le32 get_crc_value(struct nes_v4_quad *nes_quad) | 290 | static inline __le32 get_crc_value(struct nes_v4_quad *nes_quad) |
278 | { | 291 | { |
@@ -305,8 +318,8 @@ set_wqe_32bit_value(__le32 *wqe_words, u32 index, u32 value) | |||
305 | static inline void | 318 | static inline void |
306 | nes_fill_init_cqp_wqe(struct nes_hw_cqp_wqe *cqp_wqe, struct nes_device *nesdev) | 319 | nes_fill_init_cqp_wqe(struct nes_hw_cqp_wqe *cqp_wqe, struct nes_device *nesdev) |
307 | { | 320 | { |
308 | set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_COMP_CTX_LOW_IDX, | 321 | cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_LOW_IDX] = 0; |
309 | (u64)((unsigned long) &nesdev->cqp)); | 322 | cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_HIGH_IDX] = 0; |
310 | cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_LOW_IDX] = 0; | 323 | cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_LOW_IDX] = 0; |
311 | cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_HIGH_IDX] = 0; | 324 | cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_HIGH_IDX] = 0; |
312 | cqp_wqe->wqe_words[NES_CQP_STAG_WQE_PBL_BLK_COUNT_IDX] = 0; | 325 | cqp_wqe->wqe_words[NES_CQP_STAG_WQE_PBL_BLK_COUNT_IDX] = 0; |
diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c index c118663e4437..401b7bb828d0 100644 --- a/drivers/infiniband/hw/nes/nes_cm.c +++ b/drivers/infiniband/hw/nes/nes_cm.c | |||
@@ -159,6 +159,15 @@ atomic_t cm_connecteds; | |||
159 | atomic_t cm_connect_reqs; | 159 | atomic_t cm_connect_reqs; |
160 | atomic_t cm_rejects; | 160 | atomic_t cm_rejects; |
161 | 161 | ||
162 | int nes_add_ref_cm_node(struct nes_cm_node *cm_node) | ||
163 | { | ||
164 | return add_ref_cm_node(cm_node); | ||
165 | } | ||
166 | |||
167 | int nes_rem_ref_cm_node(struct nes_cm_node *cm_node) | ||
168 | { | ||
169 | return rem_ref_cm_node(cm_node->cm_core, cm_node); | ||
170 | } | ||
162 | 171 | ||
163 | /** | 172 | /** |
164 | * create_event | 173 | * create_event |
@@ -2331,9 +2340,13 @@ static int mini_cm_recv_pkt(struct nes_cm_core *cm_core, | |||
2331 | } | 2340 | } |
2332 | add_ref_cm_node(cm_node); | 2341 | add_ref_cm_node(cm_node); |
2333 | } else if (cm_node->state == NES_CM_STATE_TSA) { | 2342 | } else if (cm_node->state == NES_CM_STATE_TSA) { |
2334 | rem_ref_cm_node(cm_core, cm_node); | 2343 | if (cm_node->nesqp->pau_mode) |
2335 | atomic_inc(&cm_accel_dropped_pkts); | 2344 | nes_queue_mgt_skbs(skb, nesvnic, cm_node->nesqp); |
2336 | dev_kfree_skb_any(skb); | 2345 | else { |
2346 | rem_ref_cm_node(cm_core, cm_node); | ||
2347 | atomic_inc(&cm_accel_dropped_pkts); | ||
2348 | dev_kfree_skb_any(skb); | ||
2349 | } | ||
2337 | break; | 2350 | break; |
2338 | } | 2351 | } |
2339 | skb_reset_network_header(skb); | 2352 | skb_reset_network_header(skb); |
diff --git a/drivers/infiniband/hw/nes/nes_cm.h b/drivers/infiniband/hw/nes/nes_cm.h index d9825fda70a1..130c185cde0d 100644 --- a/drivers/infiniband/hw/nes/nes_cm.h +++ b/drivers/infiniband/hw/nes/nes_cm.h | |||
@@ -422,5 +422,7 @@ int nes_destroy_listen(struct iw_cm_id *); | |||
422 | int nes_cm_recv(struct sk_buff *, struct net_device *); | 422 | int nes_cm_recv(struct sk_buff *, struct net_device *); |
423 | int nes_cm_start(void); | 423 | int nes_cm_start(void); |
424 | int nes_cm_stop(void); | 424 | int nes_cm_stop(void); |
425 | int nes_add_ref_cm_node(struct nes_cm_node *cm_node); | ||
426 | int nes_rem_ref_cm_node(struct nes_cm_node *cm_node); | ||
425 | 427 | ||
426 | #endif /* NES_CM_H */ | 428 | #endif /* NES_CM_H */ |
diff --git a/drivers/infiniband/hw/nes/nes_hw.c b/drivers/infiniband/hw/nes/nes_hw.c index f85ccbad8fa2..7c0ff19ce382 100644 --- a/drivers/infiniband/hw/nes/nes_hw.c +++ b/drivers/infiniband/hw/nes/nes_hw.c | |||
@@ -1563,6 +1563,7 @@ static void nes_replenish_nic_rq(struct nes_vnic *nesvnic) | |||
1563 | struct nes_hw_nic_rq_wqe *nic_rqe; | 1563 | struct nes_hw_nic_rq_wqe *nic_rqe; |
1564 | struct nes_hw_nic *nesnic; | 1564 | struct nes_hw_nic *nesnic; |
1565 | struct nes_device *nesdev; | 1565 | struct nes_device *nesdev; |
1566 | struct nes_rskb_cb *cb; | ||
1566 | u32 rx_wqes_posted = 0; | 1567 | u32 rx_wqes_posted = 0; |
1567 | 1568 | ||
1568 | nesnic = &nesvnic->nic; | 1569 | nesnic = &nesvnic->nic; |
@@ -1588,6 +1589,9 @@ static void nes_replenish_nic_rq(struct nes_vnic *nesvnic) | |||
1588 | 1589 | ||
1589 | bus_address = pci_map_single(nesdev->pcidev, | 1590 | bus_address = pci_map_single(nesdev->pcidev, |
1590 | skb->data, nesvnic->max_frame_size, PCI_DMA_FROMDEVICE); | 1591 | skb->data, nesvnic->max_frame_size, PCI_DMA_FROMDEVICE); |
1592 | cb = (struct nes_rskb_cb *)&skb->cb[0]; | ||
1593 | cb->busaddr = bus_address; | ||
1594 | cb->maplen = nesvnic->max_frame_size; | ||
1591 | 1595 | ||
1592 | nic_rqe = &nesnic->rq_vbase[nesvnic->nic.rq_head]; | 1596 | nic_rqe = &nesnic->rq_vbase[nesvnic->nic.rq_head]; |
1593 | nic_rqe->wqe_words[NES_NIC_RQ_WQE_LENGTH_1_0_IDX] = | 1597 | nic_rqe->wqe_words[NES_NIC_RQ_WQE_LENGTH_1_0_IDX] = |
@@ -1677,6 +1681,7 @@ int nes_init_nic_qp(struct nes_device *nesdev, struct net_device *netdev) | |||
1677 | u32 cqp_head; | 1681 | u32 cqp_head; |
1678 | u32 counter; | 1682 | u32 counter; |
1679 | u32 wqe_count; | 1683 | u32 wqe_count; |
1684 | struct nes_rskb_cb *cb; | ||
1680 | u8 jumbomode=0; | 1685 | u8 jumbomode=0; |
1681 | 1686 | ||
1682 | /* Allocate fragment, SQ, RQ, and CQ; Reuse CEQ based on the PCI function */ | 1687 | /* Allocate fragment, SQ, RQ, and CQ; Reuse CEQ based on the PCI function */ |
@@ -1853,6 +1858,9 @@ int nes_init_nic_qp(struct nes_device *nesdev, struct net_device *netdev) | |||
1853 | 1858 | ||
1854 | pmem = pci_map_single(nesdev->pcidev, skb->data, | 1859 | pmem = pci_map_single(nesdev->pcidev, skb->data, |
1855 | nesvnic->max_frame_size, PCI_DMA_FROMDEVICE); | 1860 | nesvnic->max_frame_size, PCI_DMA_FROMDEVICE); |
1861 | cb = (struct nes_rskb_cb *)&skb->cb[0]; | ||
1862 | cb->busaddr = pmem; | ||
1863 | cb->maplen = nesvnic->max_frame_size; | ||
1856 | 1864 | ||
1857 | nic_rqe = &nesvnic->nic.rq_vbase[counter]; | 1865 | nic_rqe = &nesvnic->nic.rq_vbase[counter]; |
1858 | nic_rqe->wqe_words[NES_NIC_RQ_WQE_LENGTH_1_0_IDX] = cpu_to_le32(nesvnic->max_frame_size); | 1866 | nic_rqe->wqe_words[NES_NIC_RQ_WQE_LENGTH_1_0_IDX] = cpu_to_le32(nesvnic->max_frame_size); |
@@ -1881,6 +1889,13 @@ int nes_init_nic_qp(struct nes_device *nesdev, struct net_device *netdev) | |||
1881 | jumbomode = 1; | 1889 | jumbomode = 1; |
1882 | nes_nic_init_timer_defaults(nesdev, jumbomode); | 1890 | nes_nic_init_timer_defaults(nesdev, jumbomode); |
1883 | } | 1891 | } |
1892 | if ((nesdev->nesadapter->allow_unaligned_fpdus) && | ||
1893 | (nes_init_mgt_qp(nesdev, netdev, nesvnic))) { | ||
1894 | nes_debug(NES_DBG_INIT, "%s: Out of memory for pau nic\n", netdev->name); | ||
1895 | nes_destroy_nic_qp(nesvnic); | ||
1896 | return -ENOMEM; | ||
1897 | } | ||
1898 | |||
1884 | nesvnic->lro_mgr.max_aggr = nes_lro_max_aggr; | 1899 | nesvnic->lro_mgr.max_aggr = nes_lro_max_aggr; |
1885 | nesvnic->lro_mgr.max_desc = NES_MAX_LRO_DESCRIPTORS; | 1900 | nesvnic->lro_mgr.max_desc = NES_MAX_LRO_DESCRIPTORS; |
1886 | nesvnic->lro_mgr.lro_arr = nesvnic->lro_desc; | 1901 | nesvnic->lro_mgr.lro_arr = nesvnic->lro_desc; |
@@ -1903,28 +1918,29 @@ void nes_destroy_nic_qp(struct nes_vnic *nesvnic) | |||
1903 | struct nes_device *nesdev = nesvnic->nesdev; | 1918 | struct nes_device *nesdev = nesvnic->nesdev; |
1904 | struct nes_hw_cqp_wqe *cqp_wqe; | 1919 | struct nes_hw_cqp_wqe *cqp_wqe; |
1905 | struct nes_hw_nic_sq_wqe *nic_sqe; | 1920 | struct nes_hw_nic_sq_wqe *nic_sqe; |
1906 | struct nes_hw_nic_rq_wqe *nic_rqe; | ||
1907 | __le16 *wqe_fragment_length; | 1921 | __le16 *wqe_fragment_length; |
1908 | u16 wqe_fragment_index; | 1922 | u16 wqe_fragment_index; |
1909 | u64 wqe_frag; | ||
1910 | u32 cqp_head; | 1923 | u32 cqp_head; |
1911 | u32 wqm_cfg0; | 1924 | u32 wqm_cfg0; |
1912 | unsigned long flags; | 1925 | unsigned long flags; |
1926 | struct sk_buff *rx_skb; | ||
1927 | struct nes_rskb_cb *cb; | ||
1913 | int ret; | 1928 | int ret; |
1914 | 1929 | ||
1930 | if (nesdev->nesadapter->allow_unaligned_fpdus) | ||
1931 | nes_destroy_mgt(nesvnic); | ||
1932 | |||
1915 | /* clear wqe stall before destroying NIC QP */ | 1933 | /* clear wqe stall before destroying NIC QP */ |
1916 | wqm_cfg0 = nes_read_indexed(nesdev, NES_IDX_WQM_CONFIG0); | 1934 | wqm_cfg0 = nes_read_indexed(nesdev, NES_IDX_WQM_CONFIG0); |
1917 | nes_write_indexed(nesdev, NES_IDX_WQM_CONFIG0, wqm_cfg0 & 0xFFFF7FFF); | 1935 | nes_write_indexed(nesdev, NES_IDX_WQM_CONFIG0, wqm_cfg0 & 0xFFFF7FFF); |
1918 | 1936 | ||
1919 | /* Free remaining NIC receive buffers */ | 1937 | /* Free remaining NIC receive buffers */ |
1920 | while (nesvnic->nic.rq_head != nesvnic->nic.rq_tail) { | 1938 | while (nesvnic->nic.rq_head != nesvnic->nic.rq_tail) { |
1921 | nic_rqe = &nesvnic->nic.rq_vbase[nesvnic->nic.rq_tail]; | 1939 | rx_skb = nesvnic->nic.rx_skb[nesvnic->nic.rq_tail]; |
1922 | wqe_frag = (u64)le32_to_cpu( | 1940 | cb = (struct nes_rskb_cb *)&rx_skb->cb[0]; |
1923 | nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_LOW_IDX]); | 1941 | pci_unmap_single(nesdev->pcidev, cb->busaddr, cb->maplen, |
1924 | wqe_frag |= ((u64)le32_to_cpu( | 1942 | PCI_DMA_FROMDEVICE); |
1925 | nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_HIGH_IDX]))<<32; | 1943 | |
1926 | pci_unmap_single(nesdev->pcidev, (dma_addr_t)wqe_frag, | ||
1927 | nesvnic->max_frame_size, PCI_DMA_FROMDEVICE); | ||
1928 | dev_kfree_skb(nesvnic->nic.rx_skb[nesvnic->nic.rq_tail++]); | 1944 | dev_kfree_skb(nesvnic->nic.rx_skb[nesvnic->nic.rq_tail++]); |
1929 | nesvnic->nic.rq_tail &= (nesvnic->nic.rq_size - 1); | 1945 | nesvnic->nic.rq_tail &= (nesvnic->nic.rq_size - 1); |
1930 | } | 1946 | } |
@@ -2783,6 +2799,7 @@ void nes_nic_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq) | |||
2783 | struct nes_hw_nic_sq_wqe *nic_sqe; | 2799 | struct nes_hw_nic_sq_wqe *nic_sqe; |
2784 | struct sk_buff *skb; | 2800 | struct sk_buff *skb; |
2785 | struct sk_buff *rx_skb; | 2801 | struct sk_buff *rx_skb; |
2802 | struct nes_rskb_cb *cb; | ||
2786 | __le16 *wqe_fragment_length; | 2803 | __le16 *wqe_fragment_length; |
2787 | u32 head; | 2804 | u32 head; |
2788 | u32 cq_size; | 2805 | u32 cq_size; |
@@ -2867,6 +2884,8 @@ void nes_nic_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq) | |||
2867 | bus_address += ((u64)le32_to_cpu(nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_HIGH_IDX])) << 32; | 2884 | bus_address += ((u64)le32_to_cpu(nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_HIGH_IDX])) << 32; |
2868 | pci_unmap_single(nesdev->pcidev, bus_address, | 2885 | pci_unmap_single(nesdev->pcidev, bus_address, |
2869 | nesvnic->max_frame_size, PCI_DMA_FROMDEVICE); | 2886 | nesvnic->max_frame_size, PCI_DMA_FROMDEVICE); |
2887 | cb = (struct nes_rskb_cb *)&rx_skb->cb[0]; | ||
2888 | cb->busaddr = 0; | ||
2870 | /* rx_skb->tail = rx_skb->data + rx_pkt_size; */ | 2889 | /* rx_skb->tail = rx_skb->data + rx_pkt_size; */ |
2871 | /* rx_skb->len = rx_pkt_size; */ | 2890 | /* rx_skb->len = rx_pkt_size; */ |
2872 | rx_skb->len = 0; /* TODO: see if this is necessary */ | 2891 | rx_skb->len = 0; /* TODO: see if this is necessary */ |
@@ -2991,6 +3010,7 @@ skip_rx_indicate0: | |||
2991 | } | 3010 | } |
2992 | 3011 | ||
2993 | 3012 | ||
3013 | |||
2994 | /** | 3014 | /** |
2995 | * nes_cqp_ce_handler | 3015 | * nes_cqp_ce_handler |
2996 | */ | 3016 | */ |
@@ -3005,6 +3025,8 @@ static void nes_cqp_ce_handler(struct nes_device *nesdev, struct nes_hw_cq *cq) | |||
3005 | u32 cq_size; | 3025 | u32 cq_size; |
3006 | u32 cqe_count=0; | 3026 | u32 cqe_count=0; |
3007 | u32 error_code; | 3027 | u32 error_code; |
3028 | u32 opcode; | ||
3029 | u32 ctx_index; | ||
3008 | /* u32 counter; */ | 3030 | /* u32 counter; */ |
3009 | 3031 | ||
3010 | head = cq->cq_head; | 3032 | head = cq->cq_head; |
@@ -3015,12 +3037,9 @@ static void nes_cqp_ce_handler(struct nes_device *nesdev, struct nes_hw_cq *cq) | |||
3015 | /* nes_debug(NES_DBG_CQP, "head=%u cqe_words=%08X\n", head, | 3037 | /* nes_debug(NES_DBG_CQP, "head=%u cqe_words=%08X\n", head, |
3016 | le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX])); */ | 3038 | le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX])); */ |
3017 | 3039 | ||
3018 | if (le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX]) & NES_CQE_VALID) { | 3040 | opcode = le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX]); |
3019 | u64temp = (((u64)(le32_to_cpu(cq->cq_vbase[head]. | 3041 | if (opcode & NES_CQE_VALID) { |
3020 | cqe_words[NES_CQE_COMP_COMP_CTX_HIGH_IDX]))) << 32) | | 3042 | cqp = &nesdev->cqp; |
3021 | ((u64)(le32_to_cpu(cq->cq_vbase[head]. | ||
3022 | cqe_words[NES_CQE_COMP_COMP_CTX_LOW_IDX]))); | ||
3023 | cqp = *((struct nes_hw_cqp **)&u64temp); | ||
3024 | 3043 | ||
3025 | error_code = le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_CQE_ERROR_CODE_IDX]); | 3044 | error_code = le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_CQE_ERROR_CODE_IDX]); |
3026 | if (error_code) { | 3045 | if (error_code) { |
@@ -3029,15 +3048,14 @@ static void nes_cqp_ce_handler(struct nes_device *nesdev, struct nes_hw_cq *cq) | |||
3029 | le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX])&0x3f, | 3048 | le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX])&0x3f, |
3030 | (u16)(error_code >> 16), | 3049 | (u16)(error_code >> 16), |
3031 | (u16)error_code); | 3050 | (u16)error_code); |
3032 | nes_debug(NES_DBG_CQP, "cqp: qp_id=%u, sq_head=%u, sq_tail=%u\n", | ||
3033 | cqp->qp_id, cqp->sq_head, cqp->sq_tail); | ||
3034 | } | 3051 | } |
3035 | 3052 | ||
3036 | u64temp = (((u64)(le32_to_cpu(nesdev->cqp.sq_vbase[cqp->sq_tail]. | 3053 | u64temp = (((u64)(le32_to_cpu(cq->cq_vbase[head]. |
3037 | wqe_words[NES_CQP_WQE_COMP_SCRATCH_HIGH_IDX]))) << 32) | | 3054 | cqe_words[NES_CQE_COMP_COMP_CTX_HIGH_IDX]))) << 32) | |
3038 | ((u64)(le32_to_cpu(nesdev->cqp.sq_vbase[cqp->sq_tail]. | 3055 | ((u64)(le32_to_cpu(cq->cq_vbase[head]. |
3039 | wqe_words[NES_CQP_WQE_COMP_SCRATCH_LOW_IDX]))); | 3056 | cqe_words[NES_CQE_COMP_COMP_CTX_LOW_IDX]))); |
3040 | cqp_request = *((struct nes_cqp_request **)&u64temp); | 3057 | |
3058 | cqp_request = (struct nes_cqp_request *)(unsigned long)u64temp; | ||
3041 | if (cqp_request) { | 3059 | if (cqp_request) { |
3042 | if (cqp_request->waiting) { | 3060 | if (cqp_request->waiting) { |
3043 | /* nes_debug(NES_DBG_CQP, "%s: Waking up requestor\n"); */ | 3061 | /* nes_debug(NES_DBG_CQP, "%s: Waking up requestor\n"); */ |
@@ -3083,9 +3101,15 @@ static void nes_cqp_ce_handler(struct nes_device *nesdev, struct nes_hw_cq *cq) | |||
3083 | cqp_wqe = &nesdev->cqp.sq_vbase[head]; | 3101 | cqp_wqe = &nesdev->cqp.sq_vbase[head]; |
3084 | memcpy(cqp_wqe, &cqp_request->cqp_wqe, sizeof(*cqp_wqe)); | 3102 | memcpy(cqp_wqe, &cqp_request->cqp_wqe, sizeof(*cqp_wqe)); |
3085 | barrier(); | 3103 | barrier(); |
3086 | cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_LOW_IDX] = | 3104 | |
3105 | opcode = cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX]; | ||
3106 | if ((opcode & NES_CQP_OPCODE_MASK) == NES_CQP_DOWNLOAD_SEGMENT) | ||
3107 | ctx_index = NES_CQP_WQE_DL_COMP_CTX_LOW_IDX; | ||
3108 | else | ||
3109 | ctx_index = NES_CQP_WQE_COMP_CTX_LOW_IDX; | ||
3110 | cqp_wqe->wqe_words[ctx_index] = | ||
3087 | cpu_to_le32((u32)((unsigned long)cqp_request)); | 3111 | cpu_to_le32((u32)((unsigned long)cqp_request)); |
3088 | cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_HIGH_IDX] = | 3112 | cqp_wqe->wqe_words[ctx_index + 1] = |
3089 | cpu_to_le32((u32)(upper_32_bits((unsigned long)cqp_request))); | 3113 | cpu_to_le32((u32)(upper_32_bits((unsigned long)cqp_request))); |
3090 | nes_debug(NES_DBG_CQP, "CQP request %p (opcode 0x%02X) put on CQPs SQ wqe%u.\n", | 3114 | nes_debug(NES_DBG_CQP, "CQP request %p (opcode 0x%02X) put on CQPs SQ wqe%u.\n", |
3091 | cqp_request, le32_to_cpu(cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX])&0x3f, head); | 3115 | cqp_request, le32_to_cpu(cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX])&0x3f, head); |
@@ -3101,7 +3125,6 @@ static void nes_cqp_ce_handler(struct nes_device *nesdev, struct nes_hw_cq *cq) | |||
3101 | nes_read32(nesdev->regs+NES_CQE_ALLOC); | 3125 | nes_read32(nesdev->regs+NES_CQE_ALLOC); |
3102 | } | 3126 | } |
3103 | 3127 | ||
3104 | |||
3105 | static u8 *locate_mpa(u8 *pkt, u32 aeq_info) | 3128 | static u8 *locate_mpa(u8 *pkt, u32 aeq_info) |
3106 | { | 3129 | { |
3107 | if (aeq_info & NES_AEQE_Q2_DATA_ETHERNET) { | 3130 | if (aeq_info & NES_AEQE_Q2_DATA_ETHERNET) { |
diff --git a/drivers/infiniband/hw/nes/nes_hw.h b/drivers/infiniband/hw/nes/nes_hw.h index c3241479ec0e..0b590e152c6a 100644 --- a/drivers/infiniband/hw/nes/nes_hw.h +++ b/drivers/infiniband/hw/nes/nes_hw.h | |||
@@ -47,6 +47,11 @@ | |||
47 | #define NES_MULTICAST_PF_MAX 8 | 47 | #define NES_MULTICAST_PF_MAX 8 |
48 | #define NES_A0 3 | 48 | #define NES_A0 3 |
49 | 49 | ||
50 | #define NES_ENABLE_PAU 0x07000001 | ||
51 | #define NES_DISABLE_PAU 0x07000000 | ||
52 | #define NES_PAU_COUNTER 10 | ||
53 | #define NES_CQP_OPCODE_MASK 0x3f | ||
54 | |||
50 | enum pci_regs { | 55 | enum pci_regs { |
51 | NES_INT_STAT = 0x0000, | 56 | NES_INT_STAT = 0x0000, |
52 | NES_INT_MASK = 0x0004, | 57 | NES_INT_MASK = 0x0004, |
@@ -73,8 +78,10 @@ enum indexed_regs { | |||
73 | NES_IDX_QP_CONTROL = 0x0040, | 78 | NES_IDX_QP_CONTROL = 0x0040, |
74 | NES_IDX_FLM_CONTROL = 0x0080, | 79 | NES_IDX_FLM_CONTROL = 0x0080, |
75 | NES_IDX_INT_CPU_STATUS = 0x00a0, | 80 | NES_IDX_INT_CPU_STATUS = 0x00a0, |
81 | NES_IDX_GPR_TRIGGER = 0x00bc, | ||
76 | NES_IDX_GPIO_CONTROL = 0x00f0, | 82 | NES_IDX_GPIO_CONTROL = 0x00f0, |
77 | NES_IDX_GPIO_DATA = 0x00f4, | 83 | NES_IDX_GPIO_DATA = 0x00f4, |
84 | NES_IDX_GPR2 = 0x010c, | ||
78 | NES_IDX_TCP_CONFIG0 = 0x01e4, | 85 | NES_IDX_TCP_CONFIG0 = 0x01e4, |
79 | NES_IDX_TCP_TIMER_CONFIG = 0x01ec, | 86 | NES_IDX_TCP_TIMER_CONFIG = 0x01ec, |
80 | NES_IDX_TCP_NOW = 0x01f0, | 87 | NES_IDX_TCP_NOW = 0x01f0, |
@@ -202,6 +209,7 @@ enum nes_cqp_opcodes { | |||
202 | NES_CQP_REGISTER_SHARED_STAG = 0x0c, | 209 | NES_CQP_REGISTER_SHARED_STAG = 0x0c, |
203 | NES_CQP_DEALLOCATE_STAG = 0x0d, | 210 | NES_CQP_DEALLOCATE_STAG = 0x0d, |
204 | NES_CQP_MANAGE_ARP_CACHE = 0x0f, | 211 | NES_CQP_MANAGE_ARP_CACHE = 0x0f, |
212 | NES_CQP_DOWNLOAD_SEGMENT = 0x10, | ||
205 | NES_CQP_SUSPEND_QPS = 0x11, | 213 | NES_CQP_SUSPEND_QPS = 0x11, |
206 | NES_CQP_UPLOAD_CONTEXT = 0x13, | 214 | NES_CQP_UPLOAD_CONTEXT = 0x13, |
207 | NES_CQP_CREATE_CEQ = 0x16, | 215 | NES_CQP_CREATE_CEQ = 0x16, |
@@ -210,7 +218,8 @@ enum nes_cqp_opcodes { | |||
210 | NES_CQP_DESTROY_AEQ = 0x1b, | 218 | NES_CQP_DESTROY_AEQ = 0x1b, |
211 | NES_CQP_LMI_ACCESS = 0x20, | 219 | NES_CQP_LMI_ACCESS = 0x20, |
212 | NES_CQP_FLUSH_WQES = 0x22, | 220 | NES_CQP_FLUSH_WQES = 0x22, |
213 | NES_CQP_MANAGE_APBVT = 0x23 | 221 | NES_CQP_MANAGE_APBVT = 0x23, |
222 | NES_CQP_MANAGE_QUAD_HASH = 0x25 | ||
214 | }; | 223 | }; |
215 | 224 | ||
216 | enum nes_cqp_wqe_word_idx { | 225 | enum nes_cqp_wqe_word_idx { |
@@ -222,6 +231,14 @@ enum nes_cqp_wqe_word_idx { | |||
222 | NES_CQP_WQE_COMP_SCRATCH_HIGH_IDX = 5, | 231 | NES_CQP_WQE_COMP_SCRATCH_HIGH_IDX = 5, |
223 | }; | 232 | }; |
224 | 233 | ||
234 | enum nes_cqp_wqe_word_download_idx { /* format differs from other cqp ops */ | ||
235 | NES_CQP_WQE_DL_OPCODE_IDX = 0, | ||
236 | NES_CQP_WQE_DL_COMP_CTX_LOW_IDX = 1, | ||
237 | NES_CQP_WQE_DL_COMP_CTX_HIGH_IDX = 2, | ||
238 | NES_CQP_WQE_DL_LENGTH_0_TOTAL_IDX = 3 | ||
239 | /* For index values 4-15 use NES_NIC_SQ_WQE_ values */ | ||
240 | }; | ||
241 | |||
225 | enum nes_cqp_cq_wqeword_idx { | 242 | enum nes_cqp_cq_wqeword_idx { |
226 | NES_CQP_CQ_WQE_PBL_LOW_IDX = 6, | 243 | NES_CQP_CQ_WQE_PBL_LOW_IDX = 6, |
227 | NES_CQP_CQ_WQE_PBL_HIGH_IDX = 7, | 244 | NES_CQP_CQ_WQE_PBL_HIGH_IDX = 7, |
@@ -242,6 +259,7 @@ enum nes_cqp_stag_wqeword_idx { | |||
242 | NES_CQP_STAG_WQE_PBL_LEN_IDX = 14 | 259 | NES_CQP_STAG_WQE_PBL_LEN_IDX = 14 |
243 | }; | 260 | }; |
244 | 261 | ||
262 | #define NES_CQP_OP_LOGICAL_PORT_SHIFT 26 | ||
245 | #define NES_CQP_OP_IWARP_STATE_SHIFT 28 | 263 | #define NES_CQP_OP_IWARP_STATE_SHIFT 28 |
246 | #define NES_CQP_OP_TERMLEN_SHIFT 28 | 264 | #define NES_CQP_OP_TERMLEN_SHIFT 28 |
247 | 265 | ||
@@ -599,6 +617,7 @@ enum nes_nic_sq_wqe_bits { | |||
599 | 617 | ||
600 | enum nes_nic_cqe_word_idx { | 618 | enum nes_nic_cqe_word_idx { |
601 | NES_NIC_CQE_ACCQP_ID_IDX = 0, | 619 | NES_NIC_CQE_ACCQP_ID_IDX = 0, |
620 | NES_NIC_CQE_HASH_RCVNXT = 1, | ||
602 | NES_NIC_CQE_TAG_PKT_TYPE_IDX = 2, | 621 | NES_NIC_CQE_TAG_PKT_TYPE_IDX = 2, |
603 | NES_NIC_CQE_MISC_IDX = 3, | 622 | NES_NIC_CQE_MISC_IDX = 3, |
604 | }; | 623 | }; |
@@ -1005,6 +1024,11 @@ struct nes_arp_entry { | |||
1005 | #define NES_NIC_CQ_DOWNWARD_TREND 16 | 1024 | #define NES_NIC_CQ_DOWNWARD_TREND 16 |
1006 | #define NES_PFT_SIZE 48 | 1025 | #define NES_PFT_SIZE 48 |
1007 | 1026 | ||
1027 | #define NES_MGT_WQ_COUNT 32 | ||
1028 | #define NES_MGT_CTX_SIZE ((NES_NIC_CTX_RQ_SIZE_32) | (NES_NIC_CTX_SQ_SIZE_32)) | ||
1029 | #define NES_MGT_QP_OFFSET 36 | ||
1030 | #define NES_MGT_QP_COUNT 4 | ||
1031 | |||
1008 | struct nes_hw_tune_timer { | 1032 | struct nes_hw_tune_timer { |
1009 | /* u16 cq_count; */ | 1033 | /* u16 cq_count; */ |
1010 | u16 threshold_low; | 1034 | u16 threshold_low; |
@@ -1118,6 +1142,7 @@ struct nes_adapter { | |||
1118 | u32 et_rate_sample_interval; | 1142 | u32 et_rate_sample_interval; |
1119 | u32 timer_int_limit; | 1143 | u32 timer_int_limit; |
1120 | u32 wqm_quanta; | 1144 | u32 wqm_quanta; |
1145 | u8 allow_unaligned_fpdus; | ||
1121 | 1146 | ||
1122 | /* Adapter base MAC address */ | 1147 | /* Adapter base MAC address */ |
1123 | u32 mac_addr_low; | 1148 | u32 mac_addr_low; |
@@ -1251,6 +1276,14 @@ struct nes_vnic { | |||
1251 | enum ib_event_type delayed_event; | 1276 | enum ib_event_type delayed_event; |
1252 | enum ib_event_type last_dispatched_event; | 1277 | enum ib_event_type last_dispatched_event; |
1253 | spinlock_t port_ibevent_lock; | 1278 | spinlock_t port_ibevent_lock; |
1279 | u32 mgt_mem_size; | ||
1280 | void *mgt_vbase; | ||
1281 | dma_addr_t mgt_pbase; | ||
1282 | struct nes_vnic_mgt *mgtvnic[NES_MGT_QP_COUNT]; | ||
1283 | struct task_struct *mgt_thread; | ||
1284 | wait_queue_head_t mgt_wait_queue; | ||
1285 | struct sk_buff_head mgt_skb_list; | ||
1286 | |||
1254 | }; | 1287 | }; |
1255 | 1288 | ||
1256 | struct nes_ib_device { | 1289 | struct nes_ib_device { |
diff --git a/drivers/infiniband/hw/nes/nes_mgt.c b/drivers/infiniband/hw/nes/nes_mgt.c new file mode 100644 index 000000000000..b3b2a240c6e9 --- /dev/null +++ b/drivers/infiniband/hw/nes/nes_mgt.c | |||
@@ -0,0 +1,1162 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2006 - 2009 Intel-NE, Inc. All rights reserved. | ||
3 | * | ||
4 | * This software is available to you under a choice of one of two | ||
5 | * licenses. You may choose to be licensed under the terms of the GNU | ||
6 | * General Public License (GPL) Version 2, available from the file | ||
7 | * COPYING in the main directory of this source tree, or the | ||
8 | * OpenIB.org BSD license below: | ||
9 | * | ||
10 | * Redistribution and use in source and binary forms, with or | ||
11 | * without modification, are permitted provided that the following | ||
12 | * conditions are met: | ||
13 | * | ||
14 | * - Redistributions of source code must retain the above | ||
15 | * copyright notice, this list of conditions and the following | ||
16 | * disclaimer. | ||
17 | * | ||
18 | * - Redistributions in binary form must reproduce the above | ||
19 | * copyright notice, this list of conditions and the following | ||
20 | * disclaimer in the documentation and/or other materials | ||
21 | * provided with the distribution. | ||
22 | * | ||
23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
24 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
25 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
26 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
27 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
28 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
29 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
30 | * SOFTWARE. | ||
31 | * | ||
32 | */ | ||
33 | |||
34 | #include <linux/skbuff.h> | ||
35 | #include <linux/etherdevice.h> | ||
36 | #include <linux/kthread.h> | ||
37 | #include <linux/ip.h> | ||
38 | #include <linux/tcp.h> | ||
39 | #include <net/tcp.h> | ||
40 | #include "nes.h" | ||
41 | #include "nes_mgt.h" | ||
42 | |||
43 | atomic_t pau_qps_created; | ||
44 | atomic_t pau_qps_destroyed; | ||
45 | |||
46 | static void nes_replenish_mgt_rq(struct nes_vnic_mgt *mgtvnic) | ||
47 | { | ||
48 | unsigned long flags; | ||
49 | dma_addr_t bus_address; | ||
50 | struct sk_buff *skb; | ||
51 | struct nes_hw_nic_rq_wqe *nic_rqe; | ||
52 | struct nes_hw_mgt *nesmgt; | ||
53 | struct nes_device *nesdev; | ||
54 | struct nes_rskb_cb *cb; | ||
55 | u32 rx_wqes_posted = 0; | ||
56 | |||
57 | nesmgt = &mgtvnic->mgt; | ||
58 | nesdev = mgtvnic->nesvnic->nesdev; | ||
59 | spin_lock_irqsave(&nesmgt->rq_lock, flags); | ||
60 | if (nesmgt->replenishing_rq != 0) { | ||
61 | if (((nesmgt->rq_size - 1) == atomic_read(&mgtvnic->rx_skbs_needed)) && | ||
62 | (atomic_read(&mgtvnic->rx_skb_timer_running) == 0)) { | ||
63 | atomic_set(&mgtvnic->rx_skb_timer_running, 1); | ||
64 | spin_unlock_irqrestore(&nesmgt->rq_lock, flags); | ||
65 | mgtvnic->rq_wqes_timer.expires = jiffies + (HZ / 2); /* 1/2 second */ | ||
66 | add_timer(&mgtvnic->rq_wqes_timer); | ||
67 | } else { | ||
68 | spin_unlock_irqrestore(&nesmgt->rq_lock, flags); | ||
69 | } | ||
70 | return; | ||
71 | } | ||
72 | nesmgt->replenishing_rq = 1; | ||
73 | spin_unlock_irqrestore(&nesmgt->rq_lock, flags); | ||
74 | do { | ||
75 | skb = dev_alloc_skb(mgtvnic->nesvnic->max_frame_size); | ||
76 | if (skb) { | ||
77 | skb->dev = mgtvnic->nesvnic->netdev; | ||
78 | |||
79 | bus_address = pci_map_single(nesdev->pcidev, | ||
80 | skb->data, mgtvnic->nesvnic->max_frame_size, PCI_DMA_FROMDEVICE); | ||
81 | cb = (struct nes_rskb_cb *)&skb->cb[0]; | ||
82 | cb->busaddr = bus_address; | ||
83 | cb->maplen = mgtvnic->nesvnic->max_frame_size; | ||
84 | |||
85 | nic_rqe = &nesmgt->rq_vbase[mgtvnic->mgt.rq_head]; | ||
86 | nic_rqe->wqe_words[NES_NIC_RQ_WQE_LENGTH_1_0_IDX] = | ||
87 | cpu_to_le32(mgtvnic->nesvnic->max_frame_size); | ||
88 | nic_rqe->wqe_words[NES_NIC_RQ_WQE_LENGTH_3_2_IDX] = 0; | ||
89 | nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_LOW_IDX] = | ||
90 | cpu_to_le32((u32)bus_address); | ||
91 | nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_HIGH_IDX] = | ||
92 | cpu_to_le32((u32)((u64)bus_address >> 32)); | ||
93 | nesmgt->rx_skb[nesmgt->rq_head] = skb; | ||
94 | nesmgt->rq_head++; | ||
95 | nesmgt->rq_head &= nesmgt->rq_size - 1; | ||
96 | atomic_dec(&mgtvnic->rx_skbs_needed); | ||
97 | barrier(); | ||
98 | if (++rx_wqes_posted == 255) { | ||
99 | nes_write32(nesdev->regs + NES_WQE_ALLOC, (rx_wqes_posted << 24) | nesmgt->qp_id); | ||
100 | rx_wqes_posted = 0; | ||
101 | } | ||
102 | } else { | ||
103 | spin_lock_irqsave(&nesmgt->rq_lock, flags); | ||
104 | if (((nesmgt->rq_size - 1) == atomic_read(&mgtvnic->rx_skbs_needed)) && | ||
105 | (atomic_read(&mgtvnic->rx_skb_timer_running) == 0)) { | ||
106 | atomic_set(&mgtvnic->rx_skb_timer_running, 1); | ||
107 | spin_unlock_irqrestore(&nesmgt->rq_lock, flags); | ||
108 | mgtvnic->rq_wqes_timer.expires = jiffies + (HZ / 2); /* 1/2 second */ | ||
109 | add_timer(&mgtvnic->rq_wqes_timer); | ||
110 | } else { | ||
111 | spin_unlock_irqrestore(&nesmgt->rq_lock, flags); | ||
112 | } | ||
113 | break; | ||
114 | } | ||
115 | } while (atomic_read(&mgtvnic->rx_skbs_needed)); | ||
116 | barrier(); | ||
117 | if (rx_wqes_posted) | ||
118 | nes_write32(nesdev->regs + NES_WQE_ALLOC, (rx_wqes_posted << 24) | nesmgt->qp_id); | ||
119 | nesmgt->replenishing_rq = 0; | ||
120 | } | ||
121 | |||
122 | /** | ||
123 | * nes_mgt_rq_wqes_timeout | ||
124 | */ | ||
125 | static void nes_mgt_rq_wqes_timeout(unsigned long parm) | ||
126 | { | ||
127 | struct nes_vnic_mgt *mgtvnic = (struct nes_vnic_mgt *)parm; | ||
128 | |||
129 | atomic_set(&mgtvnic->rx_skb_timer_running, 0); | ||
130 | if (atomic_read(&mgtvnic->rx_skbs_needed)) | ||
131 | nes_replenish_mgt_rq(mgtvnic); | ||
132 | } | ||
133 | |||
134 | /** | ||
135 | * nes_mgt_free_skb - unmap and free skb | ||
136 | */ | ||
137 | static void nes_mgt_free_skb(struct nes_device *nesdev, struct sk_buff *skb, u32 dir) | ||
138 | { | ||
139 | struct nes_rskb_cb *cb; | ||
140 | |||
141 | cb = (struct nes_rskb_cb *)&skb->cb[0]; | ||
142 | pci_unmap_single(nesdev->pcidev, cb->busaddr, cb->maplen, dir); | ||
143 | cb->busaddr = 0; | ||
144 | dev_kfree_skb_any(skb); | ||
145 | } | ||
146 | |||
147 | /** | ||
148 | * nes_download_callback - handle download completions | ||
149 | */ | ||
150 | static void nes_download_callback(struct nes_device *nesdev, struct nes_cqp_request *cqp_request) | ||
151 | { | ||
152 | struct pau_fpdu_info *fpdu_info = cqp_request->cqp_callback_pointer; | ||
153 | struct nes_qp *nesqp = fpdu_info->nesqp; | ||
154 | struct sk_buff *skb; | ||
155 | int i; | ||
156 | |||
157 | for (i = 0; i < fpdu_info->frag_cnt; i++) { | ||
158 | skb = fpdu_info->frags[i].skb; | ||
159 | if (fpdu_info->frags[i].cmplt) { | ||
160 | nes_mgt_free_skb(nesdev, skb, PCI_DMA_TODEVICE); | ||
161 | nes_rem_ref_cm_node(nesqp->cm_node); | ||
162 | } | ||
163 | } | ||
164 | |||
165 | if (fpdu_info->hdr_vbase) | ||
166 | pci_free_consistent(nesdev->pcidev, fpdu_info->hdr_len, | ||
167 | fpdu_info->hdr_vbase, fpdu_info->hdr_pbase); | ||
168 | kfree(fpdu_info); | ||
169 | } | ||
170 | |||
171 | /** | ||
172 | * nes_get_seq - Get the seq, ack_seq and window from the packet | ||
173 | */ | ||
174 | static u32 nes_get_seq(struct sk_buff *skb, u32 *ack, u16 *wnd, u32 *fin_rcvd, u32 *rst_rcvd) | ||
175 | { | ||
176 | struct nes_rskb_cb *cb = (struct nes_rskb_cb *)&skb->cb[0]; | ||
177 | struct iphdr *iph = (struct iphdr *)(cb->data_start + ETH_HLEN); | ||
178 | struct tcphdr *tcph = (struct tcphdr *)(((char *)iph) + (4 * iph->ihl)); | ||
179 | |||
180 | *ack = be32_to_cpu(tcph->ack_seq); | ||
181 | *wnd = be16_to_cpu(tcph->window); | ||
182 | *fin_rcvd = tcph->fin; | ||
183 | *rst_rcvd = tcph->rst; | ||
184 | return be32_to_cpu(tcph->seq); | ||
185 | } | ||
186 | |||
187 | /** | ||
188 | * nes_get_next_skb - Get the next skb based on where current skb is in the queue | ||
189 | */ | ||
190 | static struct sk_buff *nes_get_next_skb(struct nes_device *nesdev, struct nes_qp *nesqp, | ||
191 | struct sk_buff *skb, u32 nextseq, u32 *ack, | ||
192 | u16 *wnd, u32 *fin_rcvd, u32 *rst_rcvd) | ||
193 | { | ||
194 | u32 seq; | ||
195 | bool processacks; | ||
196 | struct sk_buff *old_skb; | ||
197 | |||
198 | if (skb) { | ||
199 | /* Continue processing fpdu */ | ||
200 | if (skb->next == (struct sk_buff *)&nesqp->pau_list) | ||
201 | goto out; | ||
202 | skb = skb->next; | ||
203 | processacks = false; | ||
204 | } else { | ||
205 | /* Starting a new one */ | ||
206 | if (skb_queue_empty(&nesqp->pau_list)) | ||
207 | goto out; | ||
208 | skb = skb_peek(&nesqp->pau_list); | ||
209 | processacks = true; | ||
210 | } | ||
211 | |||
212 | while (1) { | ||
213 | seq = nes_get_seq(skb, ack, wnd, fin_rcvd, rst_rcvd); | ||
214 | if (seq == nextseq) { | ||
215 | if (skb->len || processacks) | ||
216 | break; | ||
217 | } else if (after(seq, nextseq)) { | ||
218 | goto out; | ||
219 | } | ||
220 | |||
221 | if (skb->next == (struct sk_buff *)&nesqp->pau_list) | ||
222 | goto out; | ||
223 | |||
224 | old_skb = skb; | ||
225 | skb = skb->next; | ||
226 | skb_unlink(old_skb, &nesqp->pau_list); | ||
227 | nes_mgt_free_skb(nesdev, old_skb, PCI_DMA_TODEVICE); | ||
228 | nes_rem_ref_cm_node(nesqp->cm_node); | ||
229 | } | ||
230 | return skb; | ||
231 | |||
232 | out: | ||
233 | return NULL; | ||
234 | } | ||
235 | |||
236 | /** | ||
237 | * get_fpdu_info - Find the next complete fpdu and return its fragments. | ||
238 | */ | ||
239 | static int get_fpdu_info(struct nes_device *nesdev, struct nes_qp *nesqp, | ||
240 | struct pau_fpdu_info **pau_fpdu_info) | ||
241 | { | ||
242 | struct sk_buff *skb; | ||
243 | struct iphdr *iph; | ||
244 | struct tcphdr *tcph; | ||
245 | struct nes_rskb_cb *cb; | ||
246 | struct pau_fpdu_info *fpdu_info = NULL; | ||
247 | struct pau_fpdu_frag frags[MAX_FPDU_FRAGS]; | ||
248 | unsigned long flags; | ||
249 | u32 fpdu_len = 0; | ||
250 | u32 tmp_len; | ||
251 | int frag_cnt = 0; | ||
252 | u32 tot_len; | ||
253 | u32 frag_tot; | ||
254 | u32 ack; | ||
255 | u32 fin_rcvd; | ||
256 | u32 rst_rcvd; | ||
257 | u16 wnd; | ||
258 | int i; | ||
259 | int rc = 0; | ||
260 | |||
261 | *pau_fpdu_info = NULL; | ||
262 | |||
263 | spin_lock_irqsave(&nesqp->pau_lock, flags); | ||
264 | skb = nes_get_next_skb(nesdev, nesqp, NULL, nesqp->pau_rcv_nxt, &ack, &wnd, &fin_rcvd, &rst_rcvd); | ||
265 | if (!skb) { | ||
266 | spin_unlock_irqrestore(&nesqp->pau_lock, flags); | ||
267 | goto out; | ||
268 | } | ||
269 | cb = (struct nes_rskb_cb *)&skb->cb[0]; | ||
270 | if (skb->len) { | ||
271 | fpdu_len = be16_to_cpu(*(__be16 *) skb->data) + MPA_FRAMING; | ||
272 | fpdu_len = (fpdu_len + 3) & 0xfffffffc; | ||
273 | tmp_len = fpdu_len; | ||
274 | |||
275 | /* See if we have all of the fpdu */ | ||
276 | frag_tot = 0; | ||
277 | memset(&frags, 0, sizeof frags); | ||
278 | for (i = 0; i < MAX_FPDU_FRAGS; i++) { | ||
279 | frags[i].physaddr = cb->busaddr; | ||
280 | frags[i].physaddr += skb->data - cb->data_start; | ||
281 | frags[i].frag_len = min(tmp_len, skb->len); | ||
282 | frags[i].skb = skb; | ||
283 | frags[i].cmplt = (skb->len == frags[i].frag_len); | ||
284 | frag_tot += frags[i].frag_len; | ||
285 | frag_cnt++; | ||
286 | |||
287 | tmp_len -= frags[i].frag_len; | ||
288 | if (tmp_len == 0) | ||
289 | break; | ||
290 | |||
291 | skb = nes_get_next_skb(nesdev, nesqp, skb, | ||
292 | nesqp->pau_rcv_nxt + frag_tot, &ack, &wnd, &fin_rcvd, &rst_rcvd); | ||
293 | if (!skb) { | ||
294 | spin_unlock_irqrestore(&nesqp->pau_lock, flags); | ||
295 | goto out; | ||
296 | } else if (rst_rcvd) { | ||
297 | /* rst received in the middle of fpdu */ | ||
298 | for (; i >= 0; i--) { | ||
299 | skb_unlink(frags[i].skb, &nesqp->pau_list); | ||
300 | nes_mgt_free_skb(nesdev, frags[i].skb, PCI_DMA_TODEVICE); | ||
301 | } | ||
302 | cb = (struct nes_rskb_cb *)&skb->cb[0]; | ||
303 | frags[0].physaddr = cb->busaddr; | ||
304 | frags[0].physaddr += skb->data - cb->data_start; | ||
305 | frags[0].frag_len = skb->len; | ||
306 | frags[0].skb = skb; | ||
307 | frags[0].cmplt = true; | ||
308 | frag_cnt = 1; | ||
309 | break; | ||
310 | } | ||
311 | |||
312 | cb = (struct nes_rskb_cb *)&skb->cb[0]; | ||
313 | } | ||
314 | } else { | ||
315 | /* no data */ | ||
316 | frags[0].physaddr = cb->busaddr; | ||
317 | frags[0].frag_len = 0; | ||
318 | frags[0].skb = skb; | ||
319 | frags[0].cmplt = true; | ||
320 | frag_cnt = 1; | ||
321 | } | ||
322 | |||
323 | spin_unlock_irqrestore(&nesqp->pau_lock, flags); | ||
324 | |||
325 | /* Found one */ | ||
326 | fpdu_info = kzalloc(sizeof(*fpdu_info), GFP_ATOMIC); | ||
327 | if (fpdu_info == NULL) { | ||
328 | nes_debug(NES_DBG_PAU, "Failed to alloc a fpdu_info.\n"); | ||
329 | rc = -ENOMEM; | ||
330 | goto out; | ||
331 | } | ||
332 | |||
333 | fpdu_info->cqp_request = nes_get_cqp_request(nesdev); | ||
334 | if (fpdu_info->cqp_request == NULL) { | ||
335 | nes_debug(NES_DBG_PAU, "Failed to get a cqp_request.\n"); | ||
336 | rc = -ENOMEM; | ||
337 | goto out; | ||
338 | } | ||
339 | |||
340 | cb = (struct nes_rskb_cb *)&frags[0].skb->cb[0]; | ||
341 | iph = (struct iphdr *)(cb->data_start + ETH_HLEN); | ||
342 | tcph = (struct tcphdr *)(((char *)iph) + (4 * iph->ihl)); | ||
343 | fpdu_info->hdr_len = (((unsigned char *)tcph) + 4 * (tcph->doff)) - cb->data_start; | ||
344 | fpdu_info->data_len = fpdu_len; | ||
345 | tot_len = fpdu_info->hdr_len + fpdu_len - ETH_HLEN; | ||
346 | |||
347 | if (frags[0].cmplt) { | ||
348 | fpdu_info->hdr_pbase = cb->busaddr; | ||
349 | fpdu_info->hdr_vbase = NULL; | ||
350 | } else { | ||
351 | fpdu_info->hdr_vbase = pci_alloc_consistent(nesdev->pcidev, | ||
352 | fpdu_info->hdr_len, &fpdu_info->hdr_pbase); | ||
353 | if (!fpdu_info->hdr_vbase) { | ||
354 | nes_debug(NES_DBG_PAU, "Unable to allocate memory for pau first frag\n"); | ||
355 | rc = -ENOMEM; | ||
356 | goto out; | ||
357 | } | ||
358 | |||
359 | /* Copy hdrs, adjusting len and seqnum */ | ||
360 | memcpy(fpdu_info->hdr_vbase, cb->data_start, fpdu_info->hdr_len); | ||
361 | iph = (struct iphdr *)(fpdu_info->hdr_vbase + ETH_HLEN); | ||
362 | tcph = (struct tcphdr *)(((char *)iph) + (4 * iph->ihl)); | ||
363 | } | ||
364 | |||
365 | iph->tot_len = cpu_to_be16(tot_len); | ||
366 | iph->saddr = cpu_to_be32(0x7f000001); | ||
367 | |||
368 | tcph->seq = cpu_to_be32(nesqp->pau_rcv_nxt); | ||
369 | tcph->ack_seq = cpu_to_be32(ack); | ||
370 | tcph->window = cpu_to_be16(wnd); | ||
371 | |||
372 | nesqp->pau_rcv_nxt += fpdu_len + fin_rcvd; | ||
373 | |||
374 | memcpy(fpdu_info->frags, frags, sizeof(fpdu_info->frags)); | ||
375 | fpdu_info->frag_cnt = frag_cnt; | ||
376 | fpdu_info->nesqp = nesqp; | ||
377 | *pau_fpdu_info = fpdu_info; | ||
378 | |||
379 | /* Update skb's for next pass */ | ||
380 | for (i = 0; i < frag_cnt; i++) { | ||
381 | cb = (struct nes_rskb_cb *)&frags[i].skb->cb[0]; | ||
382 | skb_pull(frags[i].skb, frags[i].frag_len); | ||
383 | |||
384 | if (frags[i].skb->len == 0) { | ||
385 | /* Pull skb off the list - it will be freed in the callback */ | ||
386 | spin_lock_irqsave(&nesqp->pau_lock, flags); | ||
387 | skb_unlink(frags[i].skb, &nesqp->pau_list); | ||
388 | spin_unlock_irqrestore(&nesqp->pau_lock, flags); | ||
389 | } else { | ||
390 | /* Last skb still has data so update the seq */ | ||
391 | iph = (struct iphdr *)(cb->data_start + ETH_HLEN); | ||
392 | tcph = (struct tcphdr *)(((char *)iph) + (4 * iph->ihl)); | ||
393 | tcph->seq = cpu_to_be32(nesqp->pau_rcv_nxt); | ||
394 | } | ||
395 | } | ||
396 | |||
397 | out: | ||
398 | if (rc) { | ||
399 | if (fpdu_info) { | ||
400 | if (fpdu_info->cqp_request) | ||
401 | nes_put_cqp_request(nesdev, fpdu_info->cqp_request); | ||
402 | kfree(fpdu_info); | ||
403 | } | ||
404 | } | ||
405 | return rc; | ||
406 | } | ||
407 | |||
408 | /** | ||
409 | * forward_fpdu - send complete fpdus, one at a time | ||
410 | */ | ||
411 | static int forward_fpdus(struct nes_vnic *nesvnic, struct nes_qp *nesqp) | ||
412 | { | ||
413 | struct nes_device *nesdev = nesvnic->nesdev; | ||
414 | struct pau_fpdu_info *fpdu_info; | ||
415 | struct nes_hw_cqp_wqe *cqp_wqe; | ||
416 | struct nes_cqp_request *cqp_request; | ||
417 | u64 u64tmp; | ||
418 | u32 u32tmp; | ||
419 | int rc; | ||
420 | |||
421 | while (1) { | ||
422 | rc = get_fpdu_info(nesdev, nesqp, &fpdu_info); | ||
423 | if (fpdu_info == NULL) | ||
424 | return rc; | ||
425 | |||
426 | cqp_request = fpdu_info->cqp_request; | ||
427 | cqp_wqe = &cqp_request->cqp_wqe; | ||
428 | nes_fill_init_cqp_wqe(cqp_wqe, nesdev); | ||
429 | set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_DL_OPCODE_IDX, | ||
430 | NES_CQP_DOWNLOAD_SEGMENT | | ||
431 | (((u32)nesvnic->logical_port) << NES_CQP_OP_LOGICAL_PORT_SHIFT)); | ||
432 | |||
433 | u32tmp = fpdu_info->hdr_len << 16; | ||
434 | u32tmp |= fpdu_info->hdr_len + (u32)fpdu_info->data_len; | ||
435 | set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_DL_LENGTH_0_TOTAL_IDX, | ||
436 | u32tmp); | ||
437 | |||
438 | u32tmp = (fpdu_info->frags[1].frag_len << 16) | fpdu_info->frags[0].frag_len; | ||
439 | set_wqe_32bit_value(cqp_wqe->wqe_words, NES_NIC_SQ_WQE_LENGTH_2_1_IDX, | ||
440 | u32tmp); | ||
441 | |||
442 | u32tmp = (fpdu_info->frags[3].frag_len << 16) | fpdu_info->frags[2].frag_len; | ||
443 | set_wqe_32bit_value(cqp_wqe->wqe_words, NES_NIC_SQ_WQE_LENGTH_4_3_IDX, | ||
444 | u32tmp); | ||
445 | |||
446 | u64tmp = (u64)fpdu_info->hdr_pbase; | ||
447 | set_wqe_32bit_value(cqp_wqe->wqe_words, NES_NIC_SQ_WQE_FRAG0_LOW_IDX, | ||
448 | lower_32_bits(u64tmp)); | ||
449 | set_wqe_32bit_value(cqp_wqe->wqe_words, NES_NIC_SQ_WQE_FRAG0_HIGH_IDX, | ||
450 | upper_32_bits(u64tmp >> 32)); | ||
451 | |||
452 | set_wqe_32bit_value(cqp_wqe->wqe_words, NES_NIC_SQ_WQE_FRAG1_LOW_IDX, | ||
453 | lower_32_bits(fpdu_info->frags[0].physaddr)); | ||
454 | set_wqe_32bit_value(cqp_wqe->wqe_words, NES_NIC_SQ_WQE_FRAG1_HIGH_IDX, | ||
455 | upper_32_bits(fpdu_info->frags[0].physaddr)); | ||
456 | |||
457 | set_wqe_32bit_value(cqp_wqe->wqe_words, NES_NIC_SQ_WQE_FRAG2_LOW_IDX, | ||
458 | lower_32_bits(fpdu_info->frags[1].physaddr)); | ||
459 | set_wqe_32bit_value(cqp_wqe->wqe_words, NES_NIC_SQ_WQE_FRAG2_HIGH_IDX, | ||
460 | upper_32_bits(fpdu_info->frags[1].physaddr)); | ||
461 | |||
462 | set_wqe_32bit_value(cqp_wqe->wqe_words, NES_NIC_SQ_WQE_FRAG3_LOW_IDX, | ||
463 | lower_32_bits(fpdu_info->frags[2].physaddr)); | ||
464 | set_wqe_32bit_value(cqp_wqe->wqe_words, NES_NIC_SQ_WQE_FRAG3_HIGH_IDX, | ||
465 | upper_32_bits(fpdu_info->frags[2].physaddr)); | ||
466 | |||
467 | set_wqe_32bit_value(cqp_wqe->wqe_words, NES_NIC_SQ_WQE_FRAG4_LOW_IDX, | ||
468 | lower_32_bits(fpdu_info->frags[3].physaddr)); | ||
469 | set_wqe_32bit_value(cqp_wqe->wqe_words, NES_NIC_SQ_WQE_FRAG4_HIGH_IDX, | ||
470 | upper_32_bits(fpdu_info->frags[3].physaddr)); | ||
471 | |||
472 | cqp_request->cqp_callback_pointer = fpdu_info; | ||
473 | cqp_request->callback = 1; | ||
474 | cqp_request->cqp_callback = nes_download_callback; | ||
475 | |||
476 | atomic_set(&cqp_request->refcount, 1); | ||
477 | nes_post_cqp_request(nesdev, cqp_request); | ||
478 | } | ||
479 | |||
480 | return 0; | ||
481 | } | ||
482 | |||
483 | static void process_fpdus(struct nes_vnic *nesvnic, struct nes_qp *nesqp) | ||
484 | { | ||
485 | int again = 1; | ||
486 | unsigned long flags; | ||
487 | |||
488 | do { | ||
489 | /* Ignore rc - if it failed, tcp retries will cause it to try again */ | ||
490 | forward_fpdus(nesvnic, nesqp); | ||
491 | |||
492 | spin_lock_irqsave(&nesqp->pau_lock, flags); | ||
493 | if (nesqp->pau_pending) { | ||
494 | nesqp->pau_pending = 0; | ||
495 | } else { | ||
496 | nesqp->pau_busy = 0; | ||
497 | again = 0; | ||
498 | } | ||
499 | |||
500 | spin_unlock_irqrestore(&nesqp->pau_lock, flags); | ||
501 | } while (again); | ||
502 | } | ||
503 | |||
504 | /** | ||
505 | * queue_fpdus - Handle fpdu's that hw passed up to sw | ||
506 | */ | ||
507 | static void queue_fpdus(struct sk_buff *skb, struct nes_vnic *nesvnic, struct nes_qp *nesqp) | ||
508 | { | ||
509 | struct sk_buff *tmpskb; | ||
510 | struct nes_rskb_cb *cb; | ||
511 | struct iphdr *iph; | ||
512 | struct tcphdr *tcph; | ||
513 | unsigned char *tcph_end; | ||
514 | u32 rcv_nxt; | ||
515 | u32 rcv_wnd; | ||
516 | u32 seqnum; | ||
517 | u32 len; | ||
518 | bool process_it = false; | ||
519 | unsigned long flags; | ||
520 | |||
521 | /* Move data ptr to after tcp header */ | ||
522 | iph = (struct iphdr *)skb->data; | ||
523 | tcph = (struct tcphdr *)(((char *)iph) + (4 * iph->ihl)); | ||
524 | seqnum = be32_to_cpu(tcph->seq); | ||
525 | tcph_end = (((char *)tcph) + (4 * tcph->doff)); | ||
526 | |||
527 | len = be16_to_cpu(iph->tot_len); | ||
528 | if (skb->len > len) | ||
529 | skb_trim(skb, len); | ||
530 | skb_pull(skb, tcph_end - skb->data); | ||
531 | |||
532 | /* Initialize tracking values */ | ||
533 | cb = (struct nes_rskb_cb *)&skb->cb[0]; | ||
534 | cb->seqnum = seqnum; | ||
535 | |||
536 | /* Make sure data is in the receive window */ | ||
537 | rcv_nxt = nesqp->pau_rcv_nxt; | ||
538 | rcv_wnd = le32_to_cpu(nesqp->nesqp_context->rcv_wnd); | ||
539 | if (!between(seqnum, rcv_nxt, (rcv_nxt + rcv_wnd))) { | ||
540 | nes_mgt_free_skb(nesvnic->nesdev, skb, PCI_DMA_TODEVICE); | ||
541 | nes_rem_ref_cm_node(nesqp->cm_node); | ||
542 | return; | ||
543 | } | ||
544 | |||
545 | spin_lock_irqsave(&nesqp->pau_lock, flags); | ||
546 | |||
547 | if (nesqp->pau_busy) | ||
548 | nesqp->pau_pending = 1; | ||
549 | else | ||
550 | nesqp->pau_busy = 1; | ||
551 | |||
552 | /* Queue skb by sequence number */ | ||
553 | if (skb_queue_len(&nesqp->pau_list) == 0) { | ||
554 | skb_queue_head(&nesqp->pau_list, skb); | ||
555 | } else { | ||
556 | tmpskb = nesqp->pau_list.next; | ||
557 | while (tmpskb != (struct sk_buff *)&nesqp->pau_list) { | ||
558 | cb = (struct nes_rskb_cb *)&tmpskb->cb[0]; | ||
559 | if (before(seqnum, cb->seqnum)) | ||
560 | break; | ||
561 | tmpskb = tmpskb->next; | ||
562 | } | ||
563 | skb_insert(tmpskb, skb, &nesqp->pau_list); | ||
564 | } | ||
565 | if (nesqp->pau_state == PAU_READY) | ||
566 | process_it = true; | ||
567 | spin_unlock_irqrestore(&nesqp->pau_lock, flags); | ||
568 | |||
569 | if (process_it) | ||
570 | process_fpdus(nesvnic, nesqp); | ||
571 | |||
572 | return; | ||
573 | } | ||
574 | |||
575 | /** | ||
576 | * mgt_thread - Handle mgt skbs in a safe context | ||
577 | */ | ||
578 | static int mgt_thread(void *context) | ||
579 | { | ||
580 | struct nes_vnic *nesvnic = context; | ||
581 | struct sk_buff *skb; | ||
582 | struct nes_rskb_cb *cb; | ||
583 | |||
584 | while (!kthread_should_stop()) { | ||
585 | wait_event_interruptible(nesvnic->mgt_wait_queue, | ||
586 | skb_queue_len(&nesvnic->mgt_skb_list) || kthread_should_stop()); | ||
587 | while ((skb_queue_len(&nesvnic->mgt_skb_list)) && !kthread_should_stop()) { | ||
588 | skb = skb_dequeue(&nesvnic->mgt_skb_list); | ||
589 | cb = (struct nes_rskb_cb *)&skb->cb[0]; | ||
590 | cb->data_start = skb->data - ETH_HLEN; | ||
591 | cb->busaddr = pci_map_single(nesvnic->nesdev->pcidev, cb->data_start, | ||
592 | nesvnic->max_frame_size, PCI_DMA_TODEVICE); | ||
593 | queue_fpdus(skb, nesvnic, cb->nesqp); | ||
594 | } | ||
595 | } | ||
596 | |||
597 | /* Closing down so delete any entries on the queue */ | ||
598 | while (skb_queue_len(&nesvnic->mgt_skb_list)) { | ||
599 | skb = skb_dequeue(&nesvnic->mgt_skb_list); | ||
600 | cb = (struct nes_rskb_cb *)&skb->cb[0]; | ||
601 | nes_rem_ref_cm_node(cb->nesqp->cm_node); | ||
602 | dev_kfree_skb_any(skb); | ||
603 | } | ||
604 | return 0; | ||
605 | } | ||
606 | |||
607 | /** | ||
608 | * nes_queue_skbs - Queue skb so it can be handled in a thread context | ||
609 | */ | ||
610 | void nes_queue_mgt_skbs(struct sk_buff *skb, struct nes_vnic *nesvnic, struct nes_qp *nesqp) | ||
611 | { | ||
612 | struct nes_rskb_cb *cb; | ||
613 | |||
614 | cb = (struct nes_rskb_cb *)&skb->cb[0]; | ||
615 | cb->nesqp = nesqp; | ||
616 | skb_queue_tail(&nesvnic->mgt_skb_list, skb); | ||
617 | wake_up_interruptible(&nesvnic->mgt_wait_queue); | ||
618 | } | ||
619 | |||
620 | void nes_destroy_pau_qp(struct nes_device *nesdev, struct nes_qp *nesqp) | ||
621 | { | ||
622 | struct sk_buff *skb; | ||
623 | unsigned long flags; | ||
624 | atomic_inc(&pau_qps_destroyed); | ||
625 | |||
626 | /* Free packets that have not yet been forwarded */ | ||
627 | /* Lock is acquired by skb_dequeue when removing the skb */ | ||
628 | spin_lock_irqsave(&nesqp->pau_lock, flags); | ||
629 | while (skb_queue_len(&nesqp->pau_list)) { | ||
630 | skb = skb_dequeue(&nesqp->pau_list); | ||
631 | nes_mgt_free_skb(nesdev, skb, PCI_DMA_TODEVICE); | ||
632 | nes_rem_ref_cm_node(nesqp->cm_node); | ||
633 | } | ||
634 | spin_unlock_irqrestore(&nesqp->pau_lock, flags); | ||
635 | } | ||
636 | |||
637 | static void nes_chg_qh_handler(struct nes_device *nesdev, struct nes_cqp_request *cqp_request) | ||
638 | { | ||
639 | struct pau_qh_chg *qh_chg = cqp_request->cqp_callback_pointer; | ||
640 | struct nes_cqp_request *new_request; | ||
641 | struct nes_hw_cqp_wqe *cqp_wqe; | ||
642 | struct nes_adapter *nesadapter; | ||
643 | struct nes_qp *nesqp; | ||
644 | struct nes_v4_quad nes_quad; | ||
645 | u32 crc_value; | ||
646 | u64 u64temp; | ||
647 | |||
648 | nesadapter = nesdev->nesadapter; | ||
649 | nesqp = qh_chg->nesqp; | ||
650 | |||
651 | /* Should we handle the bad completion */ | ||
652 | if (cqp_request->major_code) { | ||
653 | printk(KERN_ERR PFX "Invalid cqp_request major_code=0x%x\n", | ||
654 | cqp_request->major_code); | ||
655 | WARN_ON(1); | ||
656 | } | ||
657 | |||
658 | switch (nesqp->pau_state) { | ||
659 | case PAU_DEL_QH: | ||
660 | /* Old hash code deleted, now set the new one */ | ||
661 | nesqp->pau_state = PAU_ADD_LB_QH; | ||
662 | new_request = nes_get_cqp_request(nesdev); | ||
663 | if (new_request == NULL) { | ||
664 | nes_debug(NES_DBG_PAU, "Failed to get a new_request.\n"); | ||
665 | WARN_ON(1); | ||
666 | return; | ||
667 | } | ||
668 | |||
669 | memset(&nes_quad, 0, sizeof(nes_quad)); | ||
670 | nes_quad.DstIpAdrIndex = | ||
671 | cpu_to_le32((u32)PCI_FUNC(nesdev->pcidev->devfn) << 24); | ||
672 | nes_quad.SrcIpadr = cpu_to_be32(0x7f000001); | ||
673 | nes_quad.TcpPorts[0] = swab16(nesqp->nesqp_context->tcpPorts[1]); | ||
674 | nes_quad.TcpPorts[1] = swab16(nesqp->nesqp_context->tcpPorts[0]); | ||
675 | |||
676 | /* Produce hash key */ | ||
677 | crc_value = get_crc_value(&nes_quad); | ||
678 | nesqp->hte_index = cpu_to_be32(crc_value ^ 0xffffffff); | ||
679 | nes_debug(NES_DBG_PAU, "new HTE Index = 0x%08X, CRC = 0x%08X\n", | ||
680 | nesqp->hte_index, nesqp->hte_index & nesadapter->hte_index_mask); | ||
681 | |||
682 | nesqp->hte_index &= nesadapter->hte_index_mask; | ||
683 | nesqp->nesqp_context->hte_index = cpu_to_le32(nesqp->hte_index); | ||
684 | nesqp->nesqp_context->ip0 = cpu_to_le32(0x7f000001); | ||
685 | nesqp->nesqp_context->rcv_nxt = cpu_to_le32(nesqp->pau_rcv_nxt); | ||
686 | |||
687 | cqp_wqe = &new_request->cqp_wqe; | ||
688 | nes_fill_init_cqp_wqe(cqp_wqe, nesdev); | ||
689 | set_wqe_32bit_value(cqp_wqe->wqe_words, | ||
690 | NES_CQP_WQE_OPCODE_IDX, NES_CQP_MANAGE_QUAD_HASH | | ||
691 | NES_CQP_QP_TYPE_IWARP | NES_CQP_QP_CONTEXT_VALID | NES_CQP_QP_IWARP_STATE_RTS); | ||
692 | set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_ID_IDX, nesqp->hwqp.qp_id); | ||
693 | u64temp = (u64)nesqp->nesqp_context_pbase; | ||
694 | set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_QP_WQE_CONTEXT_LOW_IDX, u64temp); | ||
695 | |||
696 | nes_debug(NES_DBG_PAU, "Waiting for CQP completion for adding the quad hash.\n"); | ||
697 | |||
698 | new_request->cqp_callback_pointer = qh_chg; | ||
699 | new_request->callback = 1; | ||
700 | new_request->cqp_callback = nes_chg_qh_handler; | ||
701 | atomic_set(&new_request->refcount, 1); | ||
702 | nes_post_cqp_request(nesdev, new_request); | ||
703 | break; | ||
704 | |||
705 | case PAU_ADD_LB_QH: | ||
706 | /* Start processing the queued fpdu's */ | ||
707 | nesqp->pau_state = PAU_READY; | ||
708 | process_fpdus(qh_chg->nesvnic, qh_chg->nesqp); | ||
709 | kfree(qh_chg); | ||
710 | break; | ||
711 | } | ||
712 | } | ||
713 | |||
714 | /** | ||
715 | * nes_change_quad_hash | ||
716 | */ | ||
717 | static int nes_change_quad_hash(struct nes_device *nesdev, | ||
718 | struct nes_vnic *nesvnic, struct nes_qp *nesqp) | ||
719 | { | ||
720 | struct nes_cqp_request *cqp_request = NULL; | ||
721 | struct pau_qh_chg *qh_chg = NULL; | ||
722 | u64 u64temp; | ||
723 | struct nes_hw_cqp_wqe *cqp_wqe; | ||
724 | int ret = 0; | ||
725 | |||
726 | cqp_request = nes_get_cqp_request(nesdev); | ||
727 | if (cqp_request == NULL) { | ||
728 | nes_debug(NES_DBG_PAU, "Failed to get a cqp_request.\n"); | ||
729 | ret = -ENOMEM; | ||
730 | goto chg_qh_err; | ||
731 | } | ||
732 | |||
733 | qh_chg = kmalloc(sizeof *qh_chg, GFP_ATOMIC); | ||
734 | if (qh_chg == NULL) { | ||
735 | nes_debug(NES_DBG_PAU, "Failed to get a cqp_request.\n"); | ||
736 | ret = -ENOMEM; | ||
737 | goto chg_qh_err; | ||
738 | } | ||
739 | qh_chg->nesdev = nesdev; | ||
740 | qh_chg->nesvnic = nesvnic; | ||
741 | qh_chg->nesqp = nesqp; | ||
742 | nesqp->pau_state = PAU_DEL_QH; | ||
743 | |||
744 | cqp_wqe = &cqp_request->cqp_wqe; | ||
745 | nes_fill_init_cqp_wqe(cqp_wqe, nesdev); | ||
746 | set_wqe_32bit_value(cqp_wqe->wqe_words, | ||
747 | NES_CQP_WQE_OPCODE_IDX, NES_CQP_MANAGE_QUAD_HASH | NES_CQP_QP_DEL_HTE | | ||
748 | NES_CQP_QP_TYPE_IWARP | NES_CQP_QP_CONTEXT_VALID | NES_CQP_QP_IWARP_STATE_RTS); | ||
749 | set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_ID_IDX, nesqp->hwqp.qp_id); | ||
750 | u64temp = (u64)nesqp->nesqp_context_pbase; | ||
751 | set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_QP_WQE_CONTEXT_LOW_IDX, u64temp); | ||
752 | |||
753 | nes_debug(NES_DBG_PAU, "Waiting for CQP completion for deleting the quad hash.\n"); | ||
754 | |||
755 | cqp_request->cqp_callback_pointer = qh_chg; | ||
756 | cqp_request->callback = 1; | ||
757 | cqp_request->cqp_callback = nes_chg_qh_handler; | ||
758 | atomic_set(&cqp_request->refcount, 1); | ||
759 | nes_post_cqp_request(nesdev, cqp_request); | ||
760 | |||
761 | return ret; | ||
762 | |||
763 | chg_qh_err: | ||
764 | kfree(qh_chg); | ||
765 | if (cqp_request) | ||
766 | nes_put_cqp_request(nesdev, cqp_request); | ||
767 | return ret; | ||
768 | } | ||
769 | |||
770 | /** | ||
771 | * nes_mgt_ce_handler | ||
772 | * This management code deals with any packed and unaligned (pau) fpdu's | ||
773 | * that the hardware cannot handle. | ||
774 | */ | ||
775 | static void nes_mgt_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq) | ||
776 | { | ||
777 | struct nes_vnic_mgt *mgtvnic = container_of(cq, struct nes_vnic_mgt, mgt_cq); | ||
778 | struct nes_adapter *nesadapter = nesdev->nesadapter; | ||
779 | u32 head; | ||
780 | u32 cq_size; | ||
781 | u32 cqe_count = 0; | ||
782 | u32 cqe_misc; | ||
783 | u32 qp_id = 0; | ||
784 | u32 skbs_needed; | ||
785 | unsigned long context; | ||
786 | struct nes_qp *nesqp; | ||
787 | struct sk_buff *rx_skb; | ||
788 | struct nes_rskb_cb *cb; | ||
789 | |||
790 | head = cq->cq_head; | ||
791 | cq_size = cq->cq_size; | ||
792 | |||
793 | while (1) { | ||
794 | cqe_misc = le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_NIC_CQE_MISC_IDX]); | ||
795 | if (!(cqe_misc & NES_NIC_CQE_VALID)) | ||
796 | break; | ||
797 | |||
798 | nesqp = NULL; | ||
799 | if (cqe_misc & NES_NIC_CQE_ACCQP_VALID) { | ||
800 | qp_id = le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_NIC_CQE_ACCQP_ID_IDX]); | ||
801 | qp_id &= 0x001fffff; | ||
802 | if (qp_id < nesadapter->max_qp) { | ||
803 | context = (unsigned long)nesadapter->qp_table[qp_id - NES_FIRST_QPN]; | ||
804 | nesqp = (struct nes_qp *)context; | ||
805 | } | ||
806 | } | ||
807 | |||
808 | if (nesqp) { | ||
809 | if (nesqp->pau_mode == false) { | ||
810 | nesqp->pau_mode = true; /* First time for this qp */ | ||
811 | nesqp->pau_rcv_nxt = le32_to_cpu( | ||
812 | cq->cq_vbase[head].cqe_words[NES_NIC_CQE_HASH_RCVNXT]); | ||
813 | skb_queue_head_init(&nesqp->pau_list); | ||
814 | spin_lock_init(&nesqp->pau_lock); | ||
815 | atomic_inc(&pau_qps_created); | ||
816 | nes_change_quad_hash(nesdev, mgtvnic->nesvnic, nesqp); | ||
817 | } | ||
818 | |||
819 | rx_skb = mgtvnic->mgt.rx_skb[mgtvnic->mgt.rq_tail]; | ||
820 | rx_skb->len = 0; | ||
821 | skb_put(rx_skb, cqe_misc & 0x0000ffff); | ||
822 | rx_skb->protocol = eth_type_trans(rx_skb, mgtvnic->nesvnic->netdev); | ||
823 | cb = (struct nes_rskb_cb *)&rx_skb->cb[0]; | ||
824 | pci_unmap_single(nesdev->pcidev, cb->busaddr, cb->maplen, PCI_DMA_FROMDEVICE); | ||
825 | cb->busaddr = 0; | ||
826 | mgtvnic->mgt.rq_tail++; | ||
827 | mgtvnic->mgt.rq_tail &= mgtvnic->mgt.rq_size - 1; | ||
828 | |||
829 | nes_add_ref_cm_node(nesqp->cm_node); | ||
830 | nes_queue_mgt_skbs(rx_skb, mgtvnic->nesvnic, nesqp); | ||
831 | } else { | ||
832 | printk(KERN_ERR PFX "Invalid QP %d for packed/unaligned handling\n", qp_id); | ||
833 | } | ||
834 | |||
835 | cq->cq_vbase[head].cqe_words[NES_NIC_CQE_MISC_IDX] = 0; | ||
836 | cqe_count++; | ||
837 | if (++head >= cq_size) | ||
838 | head = 0; | ||
839 | |||
840 | if (cqe_count == 255) { | ||
841 | /* Replenish mgt CQ */ | ||
842 | nes_write32(nesdev->regs + NES_CQE_ALLOC, cq->cq_number | (cqe_count << 16)); | ||
843 | nesdev->currcq_count += cqe_count; | ||
844 | cqe_count = 0; | ||
845 | } | ||
846 | |||
847 | skbs_needed = atomic_inc_return(&mgtvnic->rx_skbs_needed); | ||
848 | if (skbs_needed > (mgtvnic->mgt.rq_size >> 1)) | ||
849 | nes_replenish_mgt_rq(mgtvnic); | ||
850 | } | ||
851 | |||
852 | cq->cq_head = head; | ||
853 | nes_write32(nesdev->regs + NES_CQE_ALLOC, NES_CQE_ALLOC_NOTIFY_NEXT | | ||
854 | cq->cq_number | (cqe_count << 16)); | ||
855 | nes_read32(nesdev->regs + NES_CQE_ALLOC); | ||
856 | nesdev->currcq_count += cqe_count; | ||
857 | } | ||
858 | |||
859 | /** | ||
860 | * nes_init_mgt_qp | ||
861 | */ | ||
862 | int nes_init_mgt_qp(struct nes_device *nesdev, struct net_device *netdev, struct nes_vnic *nesvnic) | ||
863 | { | ||
864 | struct nes_vnic_mgt *mgtvnic; | ||
865 | u32 counter; | ||
866 | void *vmem; | ||
867 | dma_addr_t pmem; | ||
868 | struct nes_hw_cqp_wqe *cqp_wqe; | ||
869 | u32 cqp_head; | ||
870 | unsigned long flags; | ||
871 | struct nes_hw_nic_qp_context *mgt_context; | ||
872 | u64 u64temp; | ||
873 | struct nes_hw_nic_rq_wqe *mgt_rqe; | ||
874 | struct sk_buff *skb; | ||
875 | u32 wqe_count; | ||
876 | struct nes_rskb_cb *cb; | ||
877 | u32 mgt_mem_size; | ||
878 | void *mgt_vbase; | ||
879 | dma_addr_t mgt_pbase; | ||
880 | int i; | ||
881 | int ret; | ||
882 | |||
883 | /* Allocate space the all mgt QPs once */ | ||
884 | mgtvnic = kzalloc(NES_MGT_QP_COUNT * sizeof(struct nes_vnic_mgt), GFP_KERNEL); | ||
885 | if (mgtvnic == NULL) { | ||
886 | nes_debug(NES_DBG_INIT, "Unable to allocate memory for mgt structure\n"); | ||
887 | return -ENOMEM; | ||
888 | } | ||
889 | |||
890 | /* Allocate fragment, RQ, and CQ; Reuse CEQ based on the PCI function */ | ||
891 | /* We are not sending from this NIC so sq is not allocated */ | ||
892 | mgt_mem_size = 256 + | ||
893 | (NES_MGT_WQ_COUNT * sizeof(struct nes_hw_nic_rq_wqe)) + | ||
894 | (NES_MGT_WQ_COUNT * sizeof(struct nes_hw_nic_cqe)) + | ||
895 | sizeof(struct nes_hw_nic_qp_context); | ||
896 | mgt_mem_size = (mgt_mem_size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); | ||
897 | mgt_vbase = pci_alloc_consistent(nesdev->pcidev, NES_MGT_QP_COUNT * mgt_mem_size, &mgt_pbase); | ||
898 | if (!mgt_vbase) { | ||
899 | kfree(mgtvnic); | ||
900 | nes_debug(NES_DBG_INIT, "Unable to allocate memory for mgt host descriptor rings\n"); | ||
901 | return -ENOMEM; | ||
902 | } | ||
903 | |||
904 | nesvnic->mgt_mem_size = NES_MGT_QP_COUNT * mgt_mem_size; | ||
905 | nesvnic->mgt_vbase = mgt_vbase; | ||
906 | nesvnic->mgt_pbase = mgt_pbase; | ||
907 | |||
908 | skb_queue_head_init(&nesvnic->mgt_skb_list); | ||
909 | init_waitqueue_head(&nesvnic->mgt_wait_queue); | ||
910 | nesvnic->mgt_thread = kthread_run(mgt_thread, nesvnic, "nes_mgt_thread"); | ||
911 | |||
912 | for (i = 0; i < NES_MGT_QP_COUNT; i++) { | ||
913 | mgtvnic->nesvnic = nesvnic; | ||
914 | mgtvnic->mgt.qp_id = nesdev->mac_index + NES_MGT_QP_OFFSET + i; | ||
915 | memset(mgt_vbase, 0, mgt_mem_size); | ||
916 | nes_debug(NES_DBG_INIT, "Allocated mgt QP structures at %p (phys = %016lX), size = %u.\n", | ||
917 | mgt_vbase, (unsigned long)mgt_pbase, mgt_mem_size); | ||
918 | |||
919 | vmem = (void *)(((unsigned long)mgt_vbase + (256 - 1)) & | ||
920 | ~(unsigned long)(256 - 1)); | ||
921 | pmem = (dma_addr_t)(((unsigned long long)mgt_pbase + (256 - 1)) & | ||
922 | ~(unsigned long long)(256 - 1)); | ||
923 | |||
924 | spin_lock_init(&mgtvnic->mgt.rq_lock); | ||
925 | |||
926 | /* setup the RQ */ | ||
927 | mgtvnic->mgt.rq_vbase = vmem; | ||
928 | mgtvnic->mgt.rq_pbase = pmem; | ||
929 | mgtvnic->mgt.rq_head = 0; | ||
930 | mgtvnic->mgt.rq_tail = 0; | ||
931 | mgtvnic->mgt.rq_size = NES_MGT_WQ_COUNT; | ||
932 | |||
933 | /* setup the CQ */ | ||
934 | vmem += (NES_MGT_WQ_COUNT * sizeof(struct nes_hw_nic_rq_wqe)); | ||
935 | pmem += (NES_MGT_WQ_COUNT * sizeof(struct nes_hw_nic_rq_wqe)); | ||
936 | |||
937 | mgtvnic->mgt_cq.cq_number = mgtvnic->mgt.qp_id; | ||
938 | mgtvnic->mgt_cq.cq_vbase = vmem; | ||
939 | mgtvnic->mgt_cq.cq_pbase = pmem; | ||
940 | mgtvnic->mgt_cq.cq_head = 0; | ||
941 | mgtvnic->mgt_cq.cq_size = NES_MGT_WQ_COUNT; | ||
942 | |||
943 | mgtvnic->mgt_cq.ce_handler = nes_mgt_ce_handler; | ||
944 | |||
945 | /* Send CreateCQ request to CQP */ | ||
946 | spin_lock_irqsave(&nesdev->cqp.lock, flags); | ||
947 | cqp_head = nesdev->cqp.sq_head; | ||
948 | |||
949 | cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head]; | ||
950 | nes_fill_init_cqp_wqe(cqp_wqe, nesdev); | ||
951 | |||
952 | cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32( | ||
953 | NES_CQP_CREATE_CQ | NES_CQP_CQ_CEQ_VALID | | ||
954 | ((u32)mgtvnic->mgt_cq.cq_size << 16)); | ||
955 | cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX] = cpu_to_le32( | ||
956 | mgtvnic->mgt_cq.cq_number | ((u32)nesdev->ceq_index << 16)); | ||
957 | u64temp = (u64)mgtvnic->mgt_cq.cq_pbase; | ||
958 | set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_CQ_WQE_PBL_LOW_IDX, u64temp); | ||
959 | cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_HIGH_IDX] = 0; | ||
960 | u64temp = (unsigned long)&mgtvnic->mgt_cq; | ||
961 | cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_LOW_IDX] = cpu_to_le32((u32)(u64temp >> 1)); | ||
962 | cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_HIGH_IDX] = | ||
963 | cpu_to_le32(((u32)((u64temp) >> 33)) & 0x7FFFFFFF); | ||
964 | cqp_wqe->wqe_words[NES_CQP_CQ_WQE_DOORBELL_INDEX_HIGH_IDX] = 0; | ||
965 | |||
966 | if (++cqp_head >= nesdev->cqp.sq_size) | ||
967 | cqp_head = 0; | ||
968 | cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head]; | ||
969 | nes_fill_init_cqp_wqe(cqp_wqe, nesdev); | ||
970 | |||
971 | /* Send CreateQP request to CQP */ | ||
972 | mgt_context = (void *)(&mgtvnic->mgt_cq.cq_vbase[mgtvnic->mgt_cq.cq_size]); | ||
973 | mgt_context->context_words[NES_NIC_CTX_MISC_IDX] = | ||
974 | cpu_to_le32((u32)NES_MGT_CTX_SIZE | | ||
975 | ((u32)PCI_FUNC(nesdev->pcidev->devfn) << 12)); | ||
976 | nes_debug(NES_DBG_INIT, "RX_WINDOW_BUFFER_PAGE_TABLE_SIZE = 0x%08X, RX_WINDOW_BUFFER_SIZE = 0x%08X\n", | ||
977 | nes_read_indexed(nesdev, NES_IDX_RX_WINDOW_BUFFER_PAGE_TABLE_SIZE), | ||
978 | nes_read_indexed(nesdev, NES_IDX_RX_WINDOW_BUFFER_SIZE)); | ||
979 | if (nes_read_indexed(nesdev, NES_IDX_RX_WINDOW_BUFFER_SIZE) != 0) | ||
980 | mgt_context->context_words[NES_NIC_CTX_MISC_IDX] |= cpu_to_le32(NES_NIC_BACK_STORE); | ||
981 | |||
982 | u64temp = (u64)mgtvnic->mgt.rq_pbase; | ||
983 | mgt_context->context_words[NES_NIC_CTX_SQ_LOW_IDX] = cpu_to_le32((u32)u64temp); | ||
984 | mgt_context->context_words[NES_NIC_CTX_SQ_HIGH_IDX] = cpu_to_le32((u32)(u64temp >> 32)); | ||
985 | u64temp = (u64)mgtvnic->mgt.rq_pbase; | ||
986 | mgt_context->context_words[NES_NIC_CTX_RQ_LOW_IDX] = cpu_to_le32((u32)u64temp); | ||
987 | mgt_context->context_words[NES_NIC_CTX_RQ_HIGH_IDX] = cpu_to_le32((u32)(u64temp >> 32)); | ||
988 | |||
989 | cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(NES_CQP_CREATE_QP | | ||
990 | NES_CQP_QP_TYPE_NIC); | ||
991 | cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX] = cpu_to_le32(mgtvnic->mgt.qp_id); | ||
992 | u64temp = (u64)mgtvnic->mgt_cq.cq_pbase + | ||
993 | (mgtvnic->mgt_cq.cq_size * sizeof(struct nes_hw_nic_cqe)); | ||
994 | set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_QP_WQE_CONTEXT_LOW_IDX, u64temp); | ||
995 | |||
996 | if (++cqp_head >= nesdev->cqp.sq_size) | ||
997 | cqp_head = 0; | ||
998 | nesdev->cqp.sq_head = cqp_head; | ||
999 | |||
1000 | barrier(); | ||
1001 | |||
1002 | /* Ring doorbell (2 WQEs) */ | ||
1003 | nes_write32(nesdev->regs + NES_WQE_ALLOC, 0x02800000 | nesdev->cqp.qp_id); | ||
1004 | |||
1005 | spin_unlock_irqrestore(&nesdev->cqp.lock, flags); | ||
1006 | nes_debug(NES_DBG_INIT, "Waiting for create MGT QP%u to complete.\n", | ||
1007 | mgtvnic->mgt.qp_id); | ||
1008 | |||
1009 | ret = wait_event_timeout(nesdev->cqp.waitq, (nesdev->cqp.sq_tail == cqp_head), | ||
1010 | NES_EVENT_TIMEOUT); | ||
1011 | nes_debug(NES_DBG_INIT, "Create MGT QP%u completed, wait_event_timeout ret = %u.\n", | ||
1012 | mgtvnic->mgt.qp_id, ret); | ||
1013 | if (!ret) { | ||
1014 | nes_debug(NES_DBG_INIT, "MGT QP%u create timeout expired\n", mgtvnic->mgt.qp_id); | ||
1015 | if (i == 0) { | ||
1016 | pci_free_consistent(nesdev->pcidev, nesvnic->mgt_mem_size, nesvnic->mgt_vbase, | ||
1017 | nesvnic->mgt_pbase); | ||
1018 | kfree(mgtvnic); | ||
1019 | } else { | ||
1020 | nes_destroy_mgt(nesvnic); | ||
1021 | } | ||
1022 | return -EIO; | ||
1023 | } | ||
1024 | |||
1025 | /* Populate the RQ */ | ||
1026 | for (counter = 0; counter < (NES_MGT_WQ_COUNT - 1); counter++) { | ||
1027 | skb = dev_alloc_skb(nesvnic->max_frame_size); | ||
1028 | if (!skb) { | ||
1029 | nes_debug(NES_DBG_INIT, "%s: out of memory for receive skb\n", netdev->name); | ||
1030 | return -ENOMEM; | ||
1031 | } | ||
1032 | |||
1033 | skb->dev = netdev; | ||
1034 | |||
1035 | pmem = pci_map_single(nesdev->pcidev, skb->data, | ||
1036 | nesvnic->max_frame_size, PCI_DMA_FROMDEVICE); | ||
1037 | cb = (struct nes_rskb_cb *)&skb->cb[0]; | ||
1038 | cb->busaddr = pmem; | ||
1039 | cb->maplen = nesvnic->max_frame_size; | ||
1040 | |||
1041 | mgt_rqe = &mgtvnic->mgt.rq_vbase[counter]; | ||
1042 | mgt_rqe->wqe_words[NES_NIC_RQ_WQE_LENGTH_1_0_IDX] = cpu_to_le32((u32)nesvnic->max_frame_size); | ||
1043 | mgt_rqe->wqe_words[NES_NIC_RQ_WQE_LENGTH_3_2_IDX] = 0; | ||
1044 | mgt_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_LOW_IDX] = cpu_to_le32((u32)pmem); | ||
1045 | mgt_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_HIGH_IDX] = cpu_to_le32((u32)((u64)pmem >> 32)); | ||
1046 | mgtvnic->mgt.rx_skb[counter] = skb; | ||
1047 | } | ||
1048 | |||
1049 | init_timer(&mgtvnic->rq_wqes_timer); | ||
1050 | mgtvnic->rq_wqes_timer.function = nes_mgt_rq_wqes_timeout; | ||
1051 | mgtvnic->rq_wqes_timer.data = (unsigned long)mgtvnic; | ||
1052 | |||
1053 | wqe_count = NES_MGT_WQ_COUNT - 1; | ||
1054 | mgtvnic->mgt.rq_head = wqe_count; | ||
1055 | barrier(); | ||
1056 | do { | ||
1057 | counter = min(wqe_count, ((u32)255)); | ||
1058 | wqe_count -= counter; | ||
1059 | nes_write32(nesdev->regs + NES_WQE_ALLOC, (counter << 24) | mgtvnic->mgt.qp_id); | ||
1060 | } while (wqe_count); | ||
1061 | |||
1062 | nes_write32(nesdev->regs + NES_CQE_ALLOC, NES_CQE_ALLOC_NOTIFY_NEXT | | ||
1063 | mgtvnic->mgt_cq.cq_number); | ||
1064 | nes_read32(nesdev->regs + NES_CQE_ALLOC); | ||
1065 | |||
1066 | mgt_vbase += mgt_mem_size; | ||
1067 | mgt_pbase += mgt_mem_size; | ||
1068 | nesvnic->mgtvnic[i] = mgtvnic++; | ||
1069 | } | ||
1070 | return 0; | ||
1071 | } | ||
1072 | |||
1073 | |||
1074 | void nes_destroy_mgt(struct nes_vnic *nesvnic) | ||
1075 | { | ||
1076 | struct nes_device *nesdev = nesvnic->nesdev; | ||
1077 | struct nes_vnic_mgt *mgtvnic; | ||
1078 | struct nes_vnic_mgt *first_mgtvnic; | ||
1079 | unsigned long flags; | ||
1080 | struct nes_hw_cqp_wqe *cqp_wqe; | ||
1081 | u32 cqp_head; | ||
1082 | struct sk_buff *rx_skb; | ||
1083 | int i; | ||
1084 | int ret; | ||
1085 | |||
1086 | kthread_stop(nesvnic->mgt_thread); | ||
1087 | |||
1088 | /* Free remaining NIC receive buffers */ | ||
1089 | first_mgtvnic = nesvnic->mgtvnic[0]; | ||
1090 | for (i = 0; i < NES_MGT_QP_COUNT; i++) { | ||
1091 | mgtvnic = nesvnic->mgtvnic[i]; | ||
1092 | if (mgtvnic == NULL) | ||
1093 | continue; | ||
1094 | |||
1095 | while (mgtvnic->mgt.rq_head != mgtvnic->mgt.rq_tail) { | ||
1096 | rx_skb = mgtvnic->mgt.rx_skb[mgtvnic->mgt.rq_tail]; | ||
1097 | nes_mgt_free_skb(nesdev, rx_skb, PCI_DMA_FROMDEVICE); | ||
1098 | mgtvnic->mgt.rq_tail++; | ||
1099 | mgtvnic->mgt.rq_tail &= (mgtvnic->mgt.rq_size - 1); | ||
1100 | } | ||
1101 | |||
1102 | spin_lock_irqsave(&nesdev->cqp.lock, flags); | ||
1103 | |||
1104 | /* Destroy NIC QP */ | ||
1105 | cqp_head = nesdev->cqp.sq_head; | ||
1106 | cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head]; | ||
1107 | nes_fill_init_cqp_wqe(cqp_wqe, nesdev); | ||
1108 | |||
1109 | set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX, | ||
1110 | (NES_CQP_DESTROY_QP | NES_CQP_QP_TYPE_NIC)); | ||
1111 | set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_ID_IDX, | ||
1112 | mgtvnic->mgt.qp_id); | ||
1113 | |||
1114 | if (++cqp_head >= nesdev->cqp.sq_size) | ||
1115 | cqp_head = 0; | ||
1116 | |||
1117 | cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head]; | ||
1118 | |||
1119 | /* Destroy NIC CQ */ | ||
1120 | nes_fill_init_cqp_wqe(cqp_wqe, nesdev); | ||
1121 | set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX, | ||
1122 | (NES_CQP_DESTROY_CQ | ((u32)mgtvnic->mgt_cq.cq_size << 16))); | ||
1123 | set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_ID_IDX, | ||
1124 | (mgtvnic->mgt_cq.cq_number | ((u32)nesdev->ceq_index << 16))); | ||
1125 | |||
1126 | if (++cqp_head >= nesdev->cqp.sq_size) | ||
1127 | cqp_head = 0; | ||
1128 | |||
1129 | nesdev->cqp.sq_head = cqp_head; | ||
1130 | barrier(); | ||
1131 | |||
1132 | /* Ring doorbell (2 WQEs) */ | ||
1133 | nes_write32(nesdev->regs + NES_WQE_ALLOC, 0x02800000 | nesdev->cqp.qp_id); | ||
1134 | |||
1135 | spin_unlock_irqrestore(&nesdev->cqp.lock, flags); | ||
1136 | nes_debug(NES_DBG_SHUTDOWN, "Waiting for CQP, cqp_head=%u, cqp.sq_head=%u," | ||
1137 | " cqp.sq_tail=%u, cqp.sq_size=%u\n", | ||
1138 | cqp_head, nesdev->cqp.sq_head, | ||
1139 | nesdev->cqp.sq_tail, nesdev->cqp.sq_size); | ||
1140 | |||
1141 | ret = wait_event_timeout(nesdev->cqp.waitq, (nesdev->cqp.sq_tail == cqp_head), | ||
1142 | NES_EVENT_TIMEOUT); | ||
1143 | |||
1144 | nes_debug(NES_DBG_SHUTDOWN, "Destroy MGT QP returned, wait_event_timeout ret = %u, cqp_head=%u," | ||
1145 | " cqp.sq_head=%u, cqp.sq_tail=%u\n", | ||
1146 | ret, cqp_head, nesdev->cqp.sq_head, nesdev->cqp.sq_tail); | ||
1147 | if (!ret) | ||
1148 | nes_debug(NES_DBG_SHUTDOWN, "MGT QP%u destroy timeout expired\n", | ||
1149 | mgtvnic->mgt.qp_id); | ||
1150 | |||
1151 | nesvnic->mgtvnic[i] = NULL; | ||
1152 | } | ||
1153 | |||
1154 | if (nesvnic->mgt_vbase) { | ||
1155 | pci_free_consistent(nesdev->pcidev, nesvnic->mgt_mem_size, nesvnic->mgt_vbase, | ||
1156 | nesvnic->mgt_pbase); | ||
1157 | nesvnic->mgt_vbase = NULL; | ||
1158 | nesvnic->mgt_pbase = 0; | ||
1159 | } | ||
1160 | |||
1161 | kfree(first_mgtvnic); | ||
1162 | } | ||
diff --git a/drivers/infiniband/hw/nes/nes_mgt.h b/drivers/infiniband/hw/nes/nes_mgt.h new file mode 100644 index 000000000000..8c8af254555a --- /dev/null +++ b/drivers/infiniband/hw/nes/nes_mgt.h | |||
@@ -0,0 +1,97 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2010 Intel-NE, Inc. All rights reserved. | ||
3 | * | ||
4 | * This software is available to you under a choice of one of two | ||
5 | * licenses. You may choose to be licensed under the terms of the GNU | ||
6 | * General Public License (GPL) Version 2, available from the file | ||
7 | * COPYING in the main directory of this source tree, or the | ||
8 | * OpenIB.org BSD license below: | ||
9 | * | ||
10 | * Redistribution and use in source and binary forms, with or | ||
11 | * without modification, are permitted provided that the following | ||
12 | * conditions are met: | ||
13 | * | ||
14 | * - Redistributions of source code must retain the above | ||
15 | * copyright notice, this list of conditions and the following | ||
16 | * disclaimer. | ||
17 | * | ||
18 | * - Redistributions in binary form must reproduce the above | ||
19 | * copyright notice, this list of conditions and the following | ||
20 | * disclaimer in the documentation and/or other materials | ||
21 | * provided with the distribution. | ||
22 | * | ||
23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
24 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
25 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
26 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
27 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
28 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
29 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
30 | * SOFTWARE. | ||
31 | */ | ||
32 | |||
33 | #ifndef __NES_MGT_H | ||
34 | #define __NES_MGT_H | ||
35 | |||
36 | #define MPA_FRAMING 6 /* length is 2 bytes, crc is 4 bytes */ | ||
37 | |||
38 | int nes_init_mgt_qp(struct nes_device *nesdev, struct net_device *netdev, struct nes_vnic *nesvnic); | ||
39 | void nes_queue_mgt_skbs(struct sk_buff *skb, struct nes_vnic *nesvnic, struct nes_qp *nesqp); | ||
40 | void nes_destroy_mgt(struct nes_vnic *nesvnic); | ||
41 | void nes_destroy_pau_qp(struct nes_device *nesdev, struct nes_qp *nesqp); | ||
42 | |||
43 | struct nes_hw_mgt { | ||
44 | struct nes_hw_nic_rq_wqe *rq_vbase; /* virtual address of rq */ | ||
45 | dma_addr_t rq_pbase; /* PCI memory for host rings */ | ||
46 | struct sk_buff *rx_skb[NES_NIC_WQ_SIZE]; | ||
47 | u16 qp_id; | ||
48 | u16 sq_head; | ||
49 | u16 rq_head; | ||
50 | u16 rq_tail; | ||
51 | u16 rq_size; | ||
52 | u8 replenishing_rq; | ||
53 | u8 reserved; | ||
54 | spinlock_t rq_lock; | ||
55 | }; | ||
56 | |||
57 | struct nes_vnic_mgt { | ||
58 | struct nes_vnic *nesvnic; | ||
59 | struct nes_hw_mgt mgt; | ||
60 | struct nes_hw_nic_cq mgt_cq; | ||
61 | atomic_t rx_skbs_needed; | ||
62 | struct timer_list rq_wqes_timer; | ||
63 | atomic_t rx_skb_timer_running; | ||
64 | }; | ||
65 | |||
66 | #define MAX_FPDU_FRAGS 4 | ||
67 | struct pau_fpdu_frag { | ||
68 | struct sk_buff *skb; | ||
69 | u64 physaddr; | ||
70 | u32 frag_len; | ||
71 | bool cmplt; | ||
72 | }; | ||
73 | |||
74 | struct pau_fpdu_info { | ||
75 | struct nes_qp *nesqp; | ||
76 | struct nes_cqp_request *cqp_request; | ||
77 | void *hdr_vbase; | ||
78 | dma_addr_t hdr_pbase; | ||
79 | int hdr_len; | ||
80 | u16 data_len; | ||
81 | u16 frag_cnt; | ||
82 | struct pau_fpdu_frag frags[MAX_FPDU_FRAGS]; | ||
83 | }; | ||
84 | |||
85 | enum pau_qh_state { | ||
86 | PAU_DEL_QH, | ||
87 | PAU_ADD_LB_QH, | ||
88 | PAU_READY | ||
89 | }; | ||
90 | |||
91 | struct pau_qh_chg { | ||
92 | struct nes_device *nesdev; | ||
93 | struct nes_vnic *nesvnic; | ||
94 | struct nes_qp *nesqp; | ||
95 | }; | ||
96 | |||
97 | #endif /* __NES_MGT_H */ | ||
diff --git a/drivers/infiniband/hw/nes/nes_nic.c b/drivers/infiniband/hw/nes/nes_nic.c index 9d7ffebff213..64f91d840366 100644 --- a/drivers/infiniband/hw/nes/nes_nic.c +++ b/drivers/infiniband/hw/nes/nes_nic.c | |||
@@ -1090,6 +1090,8 @@ static const char nes_ethtool_stringset[][ETH_GSTRING_LEN] = { | |||
1090 | "LRO aggregated", | 1090 | "LRO aggregated", |
1091 | "LRO flushed", | 1091 | "LRO flushed", |
1092 | "LRO no_desc", | 1092 | "LRO no_desc", |
1093 | "PAU CreateQPs", | ||
1094 | "PAU DestroyQPs", | ||
1093 | }; | 1095 | }; |
1094 | #define NES_ETHTOOL_STAT_COUNT ARRAY_SIZE(nes_ethtool_stringset) | 1096 | #define NES_ETHTOOL_STAT_COUNT ARRAY_SIZE(nes_ethtool_stringset) |
1095 | 1097 | ||
@@ -1305,6 +1307,8 @@ static void nes_netdev_get_ethtool_stats(struct net_device *netdev, | |||
1305 | target_stat_values[++index] = nesvnic->lro_mgr.stats.aggregated; | 1307 | target_stat_values[++index] = nesvnic->lro_mgr.stats.aggregated; |
1306 | target_stat_values[++index] = nesvnic->lro_mgr.stats.flushed; | 1308 | target_stat_values[++index] = nesvnic->lro_mgr.stats.flushed; |
1307 | target_stat_values[++index] = nesvnic->lro_mgr.stats.no_desc; | 1309 | target_stat_values[++index] = nesvnic->lro_mgr.stats.no_desc; |
1310 | target_stat_values[++index] = atomic_read(&pau_qps_created); | ||
1311 | target_stat_values[++index] = atomic_read(&pau_qps_destroyed); | ||
1308 | } | 1312 | } |
1309 | 1313 | ||
1310 | /** | 1314 | /** |
diff --git a/drivers/infiniband/hw/nes/nes_utils.c b/drivers/infiniband/hw/nes/nes_utils.c index f9c417c6b3b3..cd10968bfa22 100644 --- a/drivers/infiniband/hw/nes/nes_utils.c +++ b/drivers/infiniband/hw/nes/nes_utils.c | |||
@@ -51,13 +51,34 @@ | |||
51 | 51 | ||
52 | #include "nes.h" | 52 | #include "nes.h" |
53 | 53 | ||
54 | |||
55 | |||
56 | static u16 nes_read16_eeprom(void __iomem *addr, u16 offset); | 54 | static u16 nes_read16_eeprom(void __iomem *addr, u16 offset); |
57 | 55 | ||
58 | u32 mh_detected; | 56 | u32 mh_detected; |
59 | u32 mh_pauses_sent; | 57 | u32 mh_pauses_sent; |
60 | 58 | ||
59 | u32 nes_set_pau(struct nes_device *nesdev) | ||
60 | { | ||
61 | u32 ret = 0; | ||
62 | u32 counter; | ||
63 | |||
64 | nes_write_indexed(nesdev, NES_IDX_GPR2, NES_ENABLE_PAU); | ||
65 | nes_write_indexed(nesdev, NES_IDX_GPR_TRIGGER, 1); | ||
66 | |||
67 | for (counter = 0; counter < NES_PAU_COUNTER; counter++) { | ||
68 | udelay(30); | ||
69 | if (!nes_read_indexed(nesdev, NES_IDX_GPR2)) { | ||
70 | printk(KERN_INFO PFX "PAU is supported.\n"); | ||
71 | break; | ||
72 | } | ||
73 | nes_write_indexed(nesdev, NES_IDX_GPR_TRIGGER, 1); | ||
74 | } | ||
75 | if (counter == NES_PAU_COUNTER) { | ||
76 | printk(KERN_INFO PFX "PAU is not supported.\n"); | ||
77 | return -EPERM; | ||
78 | } | ||
79 | return ret; | ||
80 | } | ||
81 | |||
61 | /** | 82 | /** |
62 | * nes_read_eeprom_values - | 83 | * nes_read_eeprom_values - |
63 | */ | 84 | */ |
@@ -187,6 +208,11 @@ int nes_read_eeprom_values(struct nes_device *nesdev, struct nes_adapter *nesada | |||
187 | if (((major_ver == 3) && (minor_ver >= 16)) || (major_ver > 3)) | 208 | if (((major_ver == 3) && (minor_ver >= 16)) || (major_ver > 3)) |
188 | nesadapter->send_term_ok = 1; | 209 | nesadapter->send_term_ok = 1; |
189 | 210 | ||
211 | if (nes_drv_opt & NES_DRV_OPT_ENABLE_PAU) { | ||
212 | if (!nes_set_pau(nesdev)) | ||
213 | nesadapter->allow_unaligned_fpdus = 1; | ||
214 | } | ||
215 | |||
190 | nesadapter->firmware_version = (((u32)(u8)(eeprom_data>>8)) << 16) + | 216 | nesadapter->firmware_version = (((u32)(u8)(eeprom_data>>8)) << 16) + |
191 | (u32)((u8)eeprom_data); | 217 | (u32)((u8)eeprom_data); |
192 | 218 | ||
@@ -594,6 +620,7 @@ void nes_put_cqp_request(struct nes_device *nesdev, | |||
594 | nes_free_cqp_request(nesdev, cqp_request); | 620 | nes_free_cqp_request(nesdev, cqp_request); |
595 | } | 621 | } |
596 | 622 | ||
623 | |||
597 | /** | 624 | /** |
598 | * nes_post_cqp_request | 625 | * nes_post_cqp_request |
599 | */ | 626 | */ |
@@ -604,6 +631,8 @@ void nes_post_cqp_request(struct nes_device *nesdev, | |||
604 | unsigned long flags; | 631 | unsigned long flags; |
605 | u32 cqp_head; | 632 | u32 cqp_head; |
606 | u64 u64temp; | 633 | u64 u64temp; |
634 | u32 opcode; | ||
635 | int ctx_index = NES_CQP_WQE_COMP_CTX_LOW_IDX; | ||
607 | 636 | ||
608 | spin_lock_irqsave(&nesdev->cqp.lock, flags); | 637 | spin_lock_irqsave(&nesdev->cqp.lock, flags); |
609 | 638 | ||
@@ -614,17 +643,20 @@ void nes_post_cqp_request(struct nes_device *nesdev, | |||
614 | nesdev->cqp.sq_head &= nesdev->cqp.sq_size-1; | 643 | nesdev->cqp.sq_head &= nesdev->cqp.sq_size-1; |
615 | cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head]; | 644 | cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head]; |
616 | memcpy(cqp_wqe, &cqp_request->cqp_wqe, sizeof(*cqp_wqe)); | 645 | memcpy(cqp_wqe, &cqp_request->cqp_wqe, sizeof(*cqp_wqe)); |
646 | opcode = le32_to_cpu(cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX]); | ||
647 | if ((opcode & NES_CQP_OPCODE_MASK) == NES_CQP_DOWNLOAD_SEGMENT) | ||
648 | ctx_index = NES_CQP_WQE_DL_COMP_CTX_LOW_IDX; | ||
617 | barrier(); | 649 | barrier(); |
618 | u64temp = (unsigned long)cqp_request; | 650 | u64temp = (unsigned long)cqp_request; |
619 | set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_COMP_SCRATCH_LOW_IDX, | 651 | set_wqe_64bit_value(cqp_wqe->wqe_words, ctx_index, u64temp); |
620 | u64temp); | ||
621 | nes_debug(NES_DBG_CQP, "CQP request (opcode 0x%02X), line 1 = 0x%08X put on CQPs SQ," | 652 | nes_debug(NES_DBG_CQP, "CQP request (opcode 0x%02X), line 1 = 0x%08X put on CQPs SQ," |
622 | " request = %p, cqp_head = %u, cqp_tail = %u, cqp_size = %u," | 653 | " request = %p, cqp_head = %u, cqp_tail = %u, cqp_size = %u," |
623 | " waiting = %d, refcount = %d.\n", | 654 | " waiting = %d, refcount = %d.\n", |
624 | le32_to_cpu(cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX])&0x3f, | 655 | opcode & NES_CQP_OPCODE_MASK, |
625 | le32_to_cpu(cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX]), cqp_request, | 656 | le32_to_cpu(cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX]), cqp_request, |
626 | nesdev->cqp.sq_head, nesdev->cqp.sq_tail, nesdev->cqp.sq_size, | 657 | nesdev->cqp.sq_head, nesdev->cqp.sq_tail, nesdev->cqp.sq_size, |
627 | cqp_request->waiting, atomic_read(&cqp_request->refcount)); | 658 | cqp_request->waiting, atomic_read(&cqp_request->refcount)); |
659 | |||
628 | barrier(); | 660 | barrier(); |
629 | 661 | ||
630 | /* Ring doorbell (1 WQEs) */ | 662 | /* Ring doorbell (1 WQEs) */ |
@@ -645,7 +677,6 @@ void nes_post_cqp_request(struct nes_device *nesdev, | |||
645 | return; | 677 | return; |
646 | } | 678 | } |
647 | 679 | ||
648 | |||
649 | /** | 680 | /** |
650 | * nes_arp_table | 681 | * nes_arp_table |
651 | */ | 682 | */ |
diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c index 394d0e7e4a5c..5095bc41c6cc 100644 --- a/drivers/infiniband/hw/nes/nes_verbs.c +++ b/drivers/infiniband/hw/nes/nes_verbs.c | |||
@@ -1458,7 +1458,7 @@ static int nes_destroy_qp(struct ib_qp *ibqp) | |||
1458 | struct ib_qp_attr attr; | 1458 | struct ib_qp_attr attr; |
1459 | struct iw_cm_id *cm_id; | 1459 | struct iw_cm_id *cm_id; |
1460 | struct iw_cm_event cm_event; | 1460 | struct iw_cm_event cm_event; |
1461 | int ret; | 1461 | int ret = 0; |
1462 | 1462 | ||
1463 | atomic_inc(&sw_qps_destroyed); | 1463 | atomic_inc(&sw_qps_destroyed); |
1464 | nesqp->destroyed = 1; | 1464 | nesqp->destroyed = 1; |
@@ -1511,7 +1511,6 @@ static int nes_destroy_qp(struct ib_qp *ibqp) | |||
1511 | if ((nesqp->nesrcq) && (nesqp->nesrcq != nesqp->nesscq)) | 1511 | if ((nesqp->nesrcq) && (nesqp->nesrcq != nesqp->nesscq)) |
1512 | nes_clean_cq(nesqp, nesqp->nesrcq); | 1512 | nes_clean_cq(nesqp, nesqp->nesrcq); |
1513 | } | 1513 | } |
1514 | |||
1515 | nes_rem_ref(&nesqp->ibqp); | 1514 | nes_rem_ref(&nesqp->ibqp); |
1516 | return 0; | 1515 | return 0; |
1517 | } | 1516 | } |
diff --git a/drivers/infiniband/hw/nes/nes_verbs.h b/drivers/infiniband/hw/nes/nes_verbs.h index 2df9993e0cac..280057353343 100644 --- a/drivers/infiniband/hw/nes/nes_verbs.h +++ b/drivers/infiniband/hw/nes/nes_verbs.h | |||
@@ -154,6 +154,7 @@ struct nes_qp { | |||
154 | u32 mmap_sq_db_index; | 154 | u32 mmap_sq_db_index; |
155 | u32 mmap_rq_db_index; | 155 | u32 mmap_rq_db_index; |
156 | spinlock_t lock; | 156 | spinlock_t lock; |
157 | spinlock_t pau_lock; | ||
157 | struct nes_qp_context *nesqp_context; | 158 | struct nes_qp_context *nesqp_context; |
158 | dma_addr_t nesqp_context_pbase; | 159 | dma_addr_t nesqp_context_pbase; |
159 | void *pbl_vbase; | 160 | void *pbl_vbase; |
@@ -161,6 +162,8 @@ struct nes_qp { | |||
161 | struct page *page; | 162 | struct page *page; |
162 | struct timer_list terminate_timer; | 163 | struct timer_list terminate_timer; |
163 | enum ib_event_type terminate_eventtype; | 164 | enum ib_event_type terminate_eventtype; |
165 | struct sk_buff_head pau_list; | ||
166 | u32 pau_rcv_nxt; | ||
164 | u16 active_conn:1; | 167 | u16 active_conn:1; |
165 | u16 skip_lsmm:1; | 168 | u16 skip_lsmm:1; |
166 | u16 user_mode:1; | 169 | u16 user_mode:1; |
@@ -168,7 +171,8 @@ struct nes_qp { | |||
168 | u16 flush_issued:1; | 171 | u16 flush_issued:1; |
169 | u16 destroyed:1; | 172 | u16 destroyed:1; |
170 | u16 sig_all:1; | 173 | u16 sig_all:1; |
171 | u16 rsvd:9; | 174 | u16 pau_mode:1; |
175 | u16 rsvd:8; | ||
172 | u16 private_data_len; | 176 | u16 private_data_len; |
173 | u16 term_sq_flush_code; | 177 | u16 term_sq_flush_code; |
174 | u16 term_rq_flush_code; | 178 | u16 term_rq_flush_code; |
@@ -176,5 +180,8 @@ struct nes_qp { | |||
176 | u8 hw_tcp_state; | 180 | u8 hw_tcp_state; |
177 | u8 term_flags; | 181 | u8 term_flags; |
178 | u8 sq_kmapped; | 182 | u8 sq_kmapped; |
183 | u8 pau_busy; | ||
184 | u8 pau_pending; | ||
185 | u8 pau_state; | ||
179 | }; | 186 | }; |
180 | #endif /* NES_VERBS_H */ | 187 | #endif /* NES_VERBS_H */ |