[PATCH net 3/3] qed: Fix LL2 race during connection terminate

2018-05-16 Thread Michal Kalderon
Stress on qedi/qedr load unload lead to list_del corruption.
This is due to ll2 connection terminate freeing resources without
verifying that no more ll2 processing will occur.

This patch unregisters the ll2 status block before terminating
the connection to assure this race does not occur.

Fixes: 1d6cff4fca4366 ("qed: Add iSCSI out of order packet handling")
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed_ll2.c | 24 ++--
 1 file changed, 14 insertions(+), 10 deletions(-)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.c 
b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
index 851561f..468c59d 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_ll2.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
@@ -829,6 +829,9 @@ static int qed_ll2_lb_rxq_completion(struct qed_hwfn 
*p_hwfn, void *p_cookie)
struct qed_ll2_info *p_ll2_conn = (struct qed_ll2_info *)p_cookie;
int rc;
 
+   if (!QED_LL2_RX_REGISTERED(p_ll2_conn))
+   return 0;
+
rc = qed_ll2_lb_rxq_handler(p_hwfn, p_ll2_conn);
if (rc)
return rc;
@@ -849,6 +852,9 @@ static int qed_ll2_lb_txq_completion(struct qed_hwfn 
*p_hwfn, void *p_cookie)
u16 new_idx = 0, num_bds = 0;
int rc;
 
+   if (!QED_LL2_TX_REGISTERED(p_ll2_conn))
+   return 0;
+
new_idx = le16_to_cpu(*p_tx->p_fw_cons);
num_bds = ((s16)new_idx - (s16)p_tx->bds_idx);
 
@@ -1902,17 +1908,25 @@ int qed_ll2_terminate_connection(void *cxt, u8 
connection_handle)
 
/* Stop Tx & Rx of connection, if needed */
if (QED_LL2_TX_REGISTERED(p_ll2_conn)) {
+   p_ll2_conn->tx_queue.b_cb_registred = false;
+   smp_wmb(); /* Make sure this is seen by ll2_lb_rxq_completion */
rc = qed_sp_ll2_tx_queue_stop(p_hwfn, p_ll2_conn);
if (rc)
goto out;
+
qed_ll2_txq_flush(p_hwfn, connection_handle);
+   qed_int_unregister_cb(p_hwfn, p_ll2_conn->tx_queue.tx_sb_index);
}
 
if (QED_LL2_RX_REGISTERED(p_ll2_conn)) {
+   p_ll2_conn->rx_queue.b_cb_registred = false;
+   smp_wmb(); /* Make sure this is seen by ll2_lb_rxq_completion */
rc = qed_sp_ll2_rx_queue_stop(p_hwfn, p_ll2_conn);
if (rc)
goto out;
+
qed_ll2_rxq_flush(p_hwfn, connection_handle);
+   qed_int_unregister_cb(p_hwfn, p_ll2_conn->rx_queue.rx_sb_index);
}
 
if (p_ll2_conn->input.conn_type == QED_LL2_TYPE_OOO)
@@ -1960,16 +1974,6 @@ void qed_ll2_release_connection(void *cxt, u8 
connection_handle)
if (!p_ll2_conn)
return;
 
-   if (QED_LL2_RX_REGISTERED(p_ll2_conn)) {
-   p_ll2_conn->rx_queue.b_cb_registred = false;
-   qed_int_unregister_cb(p_hwfn, p_ll2_conn->rx_queue.rx_sb_index);
-   }
-
-   if (QED_LL2_TX_REGISTERED(p_ll2_conn)) {
-   p_ll2_conn->tx_queue.b_cb_registred = false;
-   qed_int_unregister_cb(p_hwfn, p_ll2_conn->tx_queue.tx_sb_index);
-   }
-
kfree(p_ll2_conn->tx_queue.descq_mem);
qed_chain_free(p_hwfn->cdev, _ll2_conn->tx_queue.txq_chain);
 
-- 
2.9.5



[PATCH net 2/3] qed: Fix possibility of list corruption during rmmod flows

2018-05-16 Thread Michal Kalderon
The ll2 flows of flushing the txq/rxq need to be synchronized with the
regular fp processing. Caused list corruption during load/unload stress
tests.

Fixes: 0a7fb11c23c0f ("qed: Add Light L2 support")
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed_ll2.c | 11 ++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.c 
b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
index b5918bd..851561f 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_ll2.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
@@ -292,6 +292,7 @@ static void qed_ll2_txq_flush(struct qed_hwfn *p_hwfn, u8 
connection_handle)
struct qed_ll2_tx_packet *p_pkt = NULL;
struct qed_ll2_info *p_ll2_conn;
struct qed_ll2_tx_queue *p_tx;
+   unsigned long flags = 0;
dma_addr_t tx_frag;
 
p_ll2_conn = qed_ll2_handle_sanity_inactive(p_hwfn, connection_handle);
@@ -300,6 +301,7 @@ static void qed_ll2_txq_flush(struct qed_hwfn *p_hwfn, u8 
connection_handle)
 
p_tx = _ll2_conn->tx_queue;
 
+   spin_lock_irqsave(_tx->lock, flags);
while (!list_empty(_tx->active_descq)) {
p_pkt = list_first_entry(_tx->active_descq,
 struct qed_ll2_tx_packet, list_entry);
@@ -309,6 +311,7 @@ static void qed_ll2_txq_flush(struct qed_hwfn *p_hwfn, u8 
connection_handle)
list_del(_pkt->list_entry);
b_last_packet = list_empty(_tx->active_descq);
list_add_tail(_pkt->list_entry, _tx->free_descq);
+   spin_unlock_irqrestore(_tx->lock, flags);
if (p_ll2_conn->input.conn_type == QED_LL2_TYPE_OOO) {
struct qed_ooo_buffer *p_buffer;
 
@@ -328,7 +331,9 @@ static void qed_ll2_txq_flush(struct qed_hwfn *p_hwfn, u8 
connection_handle)
  b_last_frag,
  b_last_packet);
}
+   spin_lock_irqsave(_tx->lock, flags);
}
+   spin_unlock_irqrestore(_tx->lock, flags);
 }
 
 static int qed_ll2_txq_completion(struct qed_hwfn *p_hwfn, void *p_cookie)
@@ -556,6 +561,7 @@ static void qed_ll2_rxq_flush(struct qed_hwfn *p_hwfn, u8 
connection_handle)
struct qed_ll2_info *p_ll2_conn = NULL;
struct qed_ll2_rx_packet *p_pkt = NULL;
struct qed_ll2_rx_queue *p_rx;
+   unsigned long flags = 0;
 
p_ll2_conn = qed_ll2_handle_sanity_inactive(p_hwfn, connection_handle);
if (!p_ll2_conn)
@@ -563,13 +569,14 @@ static void qed_ll2_rxq_flush(struct qed_hwfn *p_hwfn, u8 
connection_handle)
 
p_rx = _ll2_conn->rx_queue;
 
+   spin_lock_irqsave(_rx->lock, flags);
while (!list_empty(_rx->active_descq)) {
p_pkt = list_first_entry(_rx->active_descq,
 struct qed_ll2_rx_packet, list_entry);
if (!p_pkt)
break;
-
list_move_tail(_pkt->list_entry, _rx->free_descq);
+   spin_unlock_irqrestore(_rx->lock, flags);
 
if (p_ll2_conn->input.conn_type == QED_LL2_TYPE_OOO) {
struct qed_ooo_buffer *p_buffer;
@@ -588,7 +595,9 @@ static void qed_ll2_rxq_flush(struct qed_hwfn *p_hwfn, u8 
connection_handle)
  cookie,
  rx_buf_addr, b_last);
}
+   spin_lock_irqsave(_rx->lock, flags);
}
+   spin_unlock_irqrestore(_rx->lock, flags);
 }
 
 static bool
-- 
2.9.5



[PATCH net 1/3] qed: LL2 flush isles when connection is closed

2018-05-16 Thread Michal Kalderon
Driver should free all pending isles once it gets a FLUSH cqe from FW.
Part of iSCSI out of order flow.

Fixes: 1d6cff4fca4366 ("qed: Add iSCSI out of order packet handling")
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed_ll2.c | 26 ++
 1 file changed, 26 insertions(+)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.c 
b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
index 3850281..b5918bd 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_ll2.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
@@ -591,6 +591,27 @@ static void qed_ll2_rxq_flush(struct qed_hwfn *p_hwfn, u8 
connection_handle)
}
 }
 
+static bool
+qed_ll2_lb_rxq_handler_slowpath(struct qed_hwfn *p_hwfn,
+   struct core_rx_slow_path_cqe *p_cqe)
+{
+   struct ooo_opaque *iscsi_ooo;
+   u32 cid;
+
+   if (p_cqe->ramrod_cmd_id != CORE_RAMROD_RX_QUEUE_FLUSH)
+   return false;
+
+   iscsi_ooo = (struct ooo_opaque *)_cqe->opaque_data;
+   if (iscsi_ooo->ooo_opcode != TCP_EVENT_DELETE_ISLES)
+   return false;
+
+   /* Need to make a flush */
+   cid = le32_to_cpu(iscsi_ooo->cid);
+   qed_ooo_release_connection_isles(p_hwfn, p_hwfn->p_ooo_info, cid);
+
+   return true;
+}
+
 static int qed_ll2_lb_rxq_handler(struct qed_hwfn *p_hwfn,
  struct qed_ll2_info *p_ll2_conn)
 {
@@ -617,6 +638,11 @@ static int qed_ll2_lb_rxq_handler(struct qed_hwfn *p_hwfn,
cq_old_idx = qed_chain_get_cons_idx(_rx->rcq_chain);
cqe_type = cqe->rx_cqe_sp.type;
 
+   if (cqe_type == CORE_RX_CQE_TYPE_SLOW_PATH)
+   if (qed_ll2_lb_rxq_handler_slowpath(p_hwfn,
+   >rx_cqe_sp))
+   continue;
+
if (cqe_type != CORE_RX_CQE_TYPE_REGULAR) {
DP_NOTICE(p_hwfn,
  "Got a non-regular LB LL2 completion [type 
0x%02x]\n",
-- 
2.9.5



[PATCH net 0/3] qed: LL2 fixes

2018-05-16 Thread Michal Kalderon
This series fixes some issues in ll2 related to synchronization
and resource freeing

Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>

Michal Kalderon (3):
  qed: LL2 flush isles when connection is closed
  qed: Fix possibility of list corruption during rmmod flows
  qed: Fix LL2 race during connection terminate

 drivers/net/ethernet/qlogic/qed/qed_ll2.c | 61 +--
 1 file changed, 50 insertions(+), 11 deletions(-)

-- 
2.9.5



[PATCH net] qede: Fix ref-cnt usage count

2018-05-13 Thread Michal Kalderon
Rebooting while qedr is loaded with a VLAN interface present
results in unregister_netdevice waiting for the usage count
to become free.
The fix is that rdma devices should be removed before unregistering
the netdevice, to assure all references to ndev are decreased.

Fixes: cee9fbd8e2e9 ("qede: Add qedr framework")
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
---
 drivers/net/ethernet/qlogic/qede/qede_main.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/qlogic/qede/qede_main.c 
b/drivers/net/ethernet/qlogic/qede/qede_main.c
index a01e7d6..f6655e2 100644
--- a/drivers/net/ethernet/qlogic/qede/qede_main.c
+++ b/drivers/net/ethernet/qlogic/qede/qede_main.c
@@ -1066,13 +1066,12 @@ static void __qede_remove(struct pci_dev *pdev, enum 
qede_remove_mode mode)
 
DP_INFO(edev, "Starting qede_remove\n");
 
+   qede_rdma_dev_remove(edev);
unregister_netdev(ndev);
cancel_delayed_work_sync(>sp_task);
 
qede_ptp_disable(edev);
 
-   qede_rdma_dev_remove(edev);
-
edev->ops->common->set_power_state(cdev, PCI_D0);
 
pci_set_drvdata(pdev, NULL);
-- 
2.9.5



[PATCH net 2/2] qede: Fix gfp flags sent to rdma event node allocation

2018-05-08 Thread Michal Kalderon
A previous commit 4609adc27175 ("qede: Fix qedr link update")
added a flow that could allocate rdma event objects from an
interrupt path (link notification). Therefore the kzalloc call
should be done with GFP_ATOMIC.

fixes: 4609adc27175 ("qede: Fix qedr link update")
Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Sudarsana Kalluru <sudarsana.kall...@cavium.com>
---
 drivers/net/ethernet/qlogic/qede/qede_rdma.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/qlogic/qede/qede_rdma.c 
b/drivers/net/ethernet/qlogic/qede/qede_rdma.c
index 50b142f..1900bf7 100644
--- a/drivers/net/ethernet/qlogic/qede/qede_rdma.c
+++ b/drivers/net/ethernet/qlogic/qede/qede_rdma.c
@@ -238,7 +238,7 @@ qede_rdma_get_free_event_node(struct qede_dev *edev)
}
 
if (!found) {
-   event_node = kzalloc(sizeof(*event_node), GFP_KERNEL);
+   event_node = kzalloc(sizeof(*event_node), GFP_ATOMIC);
if (!event_node) {
DP_NOTICE(edev,
  "qedr: Could not allocate memory for rdma 
work\n");
-- 
2.9.5



[PATCH net 1/2] qed: Fix l2 initializations over iWARP personality

2018-05-08 Thread Michal Kalderon
If qede driver was loaded on a device configured for iWARP
the l2 mutex wouldn't be allocated, and some l2 related
resources wouldn't be freed.

fixes: c851a9dc4359 ("qed: Introduce iWARP personality")
Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Sudarsana Kalluru <sudarsana.kall...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed_l2.c | 6 ++
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_l2.c 
b/drivers/net/ethernet/qlogic/qed/qed_l2.c
index e874504..8667799 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_l2.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_l2.c
@@ -115,8 +115,7 @@ int qed_l2_alloc(struct qed_hwfn *p_hwfn)
 
 void qed_l2_setup(struct qed_hwfn *p_hwfn)
 {
-   if (p_hwfn->hw_info.personality != QED_PCI_ETH &&
-   p_hwfn->hw_info.personality != QED_PCI_ETH_ROCE)
+   if (!QED_IS_L2_PERSONALITY(p_hwfn))
return;
 
mutex_init(_hwfn->p_l2_info->lock);
@@ -126,8 +125,7 @@ void qed_l2_free(struct qed_hwfn *p_hwfn)
 {
u32 i;
 
-   if (p_hwfn->hw_info.personality != QED_PCI_ETH &&
-   p_hwfn->hw_info.personality != QED_PCI_ETH_ROCE)
+   if (!QED_IS_L2_PERSONALITY(p_hwfn))
return;
 
if (!p_hwfn->p_l2_info)
-- 
2.9.5



[PATCH net 0/2] qed*: Rdma fixes

2018-05-08 Thread Michal Kalderon
This patch series include two fixes for bugs related to rdma.
The first has to do with loading the driver over an iWARP
device. 
The second fixes a previous commit that added proper link
indication for iWARP / RoCE.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Sudarsana Kalluru <sudarsana.kall...@cavium.com>

Michal Kalderon (2):
  qed: Fix l2 initializations over iWARP personality
  qede: Fix gfp flags sent to rdma event node allocation

 drivers/net/ethernet/qlogic/qed/qed_l2.c | 6 ++
 drivers/net/ethernet/qlogic/qede/qede_rdma.c | 2 +-
 2 files changed, 3 insertions(+), 5 deletions(-)

-- 
2.9.5



[PATCH net] qede: Fix qedr link update

2018-03-14 Thread Michal Kalderon
Link updates were not reported to qedr correctly.
Leading to cases where a link could be down, but qedr
would see it as up.
In addition, once qede was loaded, link state would be up,
regardless of the actual link state.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>

---
 drivers/net/ethernet/qlogic/qede/qede_main.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/qlogic/qede/qede_main.c 
b/drivers/net/ethernet/qlogic/qede/qede_main.c
index 2db70ea..5c28209 100644
--- a/drivers/net/ethernet/qlogic/qede/qede_main.c
+++ b/drivers/net/ethernet/qlogic/qede/qede_main.c
@@ -2067,8 +2067,6 @@ static int qede_load(struct qede_dev *edev, enum 
qede_load_mode mode,
link_params.link_up = true;
edev->ops->common->set_link(edev->cdev, _params);
 
-   qede_rdma_dev_event_open(edev);
-
edev->state = QEDE_STATE_OPEN;
 
DP_INFO(edev, "Ending successfully qede load\n");
@@ -2169,12 +2167,14 @@ static void qede_link_update(void *dev, struct 
qed_link_output *link)
DP_NOTICE(edev, "Link is up\n");
netif_tx_start_all_queues(edev->ndev);
netif_carrier_on(edev->ndev);
+   qede_rdma_dev_event_open(edev);
}
} else {
if (netif_carrier_ok(edev->ndev)) {
DP_NOTICE(edev, "Link is down\n");
netif_tx_disable(edev->ndev);
netif_carrier_off(edev->ndev);
+   qede_rdma_dev_event_close(edev);
}
}
 }
-- 
2.9.5



[PATCH net 1/2] qed: Fix MPA unalign flow in case header is split across two packets.

2018-03-14 Thread Michal Kalderon
There is a corner case in the MPA unalign flow where a FPDU header is
split over two tcp segments. The length of the first fragment in this
case was not initialized properly and should be '1'

Fixes: c7d1d839 ("qed: Add support for MPA header being split over two tcp 
packets")

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed_iwarp.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c 
b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
index ca4a81d..fefe527 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
@@ -1928,8 +1928,8 @@ qed_iwarp_update_fpdu_length(struct qed_hwfn *p_hwfn,
/* Missing lower byte is now available */
mpa_len = fpdu->fpdu_length | *mpa_data;
fpdu->fpdu_length = QED_IWARP_FPDU_LEN_WITH_PAD(mpa_len);
-   fpdu->mpa_frag_len = fpdu->fpdu_length;
/* one byte of hdr */
+   fpdu->mpa_frag_len = 1;
fpdu->incomplete_bytes = fpdu->fpdu_length - 1;
DP_VERBOSE(p_hwfn,
   QED_MSG_RDMA,
-- 
2.9.5



[PATCH net 2/2] qed: Fix non TCP packets should be dropped on iWARP ll2 connection

2018-03-14 Thread Michal Kalderon
FW workaround. The iWARP LL2 connection did not expect TCP packets
to arrive on it's connection. The fix drops any non-tcp packets

Fixes b5c29ca ("qed: iWARP CM - setup a ll2 connection for handling
SYN packets")

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed_iwarp.c | 15 +++
 1 file changed, 15 insertions(+)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c 
b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
index fefe527..d5d02be 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
@@ -1703,6 +1703,13 @@ qed_iwarp_parse_rx_pkt(struct qed_hwfn *p_hwfn,
iph = (struct iphdr *)((u8 *)(ethh) + eth_hlen);
 
if (eth_type == ETH_P_IP) {
+   if (iph->protocol != IPPROTO_TCP) {
+   DP_NOTICE(p_hwfn,
+ "Unexpected ip protocol on ll2 %x\n",
+ iph->protocol);
+   return -EINVAL;
+   }
+
cm_info->local_ip[0] = ntohl(iph->daddr);
cm_info->remote_ip[0] = ntohl(iph->saddr);
cm_info->ip_version = TCP_IPV4;
@@ -1711,6 +1718,14 @@ qed_iwarp_parse_rx_pkt(struct qed_hwfn *p_hwfn,
*payload_len = ntohs(iph->tot_len) - ip_hlen;
} else if (eth_type == ETH_P_IPV6) {
ip6h = (struct ipv6hdr *)iph;
+
+   if (ip6h->nexthdr != IPPROTO_TCP) {
+   DP_NOTICE(p_hwfn,
+ "Unexpected ip protocol on ll2 %x\n",
+ iph->protocol);
+   return -EINVAL;
+   }
+
for (i = 0; i < 4; i++) {
cm_info->local_ip[i] =
ntohl(ip6h->daddr.in6_u.u6_addr32[i]);
-- 
2.9.5



[PATCH net 0/2] qed: iWARP related fixes

2018-03-14 Thread Michal Kalderon
This series contains two fixes related to iWARP flow. 

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>

Michal Kalderon (2):
  qed: Fix MPA unalign flow in case header is split across two packets.
  qed: Fix non TCP packets should be dropped on iWARP ll2 connection

 drivers/net/ethernet/qlogic/qed/qed_iwarp.c | 17 -
 1 file changed, 16 insertions(+), 1 deletion(-)

-- 
2.9.5



[PATCH V3 net] qed: Free RoCE ILT Memory on rmmod qedr

2018-03-05 Thread Michal Kalderon
Rdma requires ILT Memory to be allocated for it's QPs.
Each ILT entry points to a page used by several Rdma QPs.
To avoid allocating all the memory in advance, the rdma
implementation dynamically allocates memory as more QPs are
added, however it does not dynamically free the memory.
The memory should have been freed on rmmod qedr, but isn't.
This patch adds the memory freeing on rmmod qedr (currently
it will be freed with qed is removed).

An outcome of this bug, is that if qedr is unloaded and loaded
without unloaded qed, there will be no more RoCE traffic.

The reason these are related, is that the logic of detecting the
first QP ever opened is by asking whether ILT memory for RoCE has
been allocated.

In addition, this patch modifies freeing of the Task context to
always use the PROTOCOLID_ROCE and not the protocol passed,
this is because task context for iWARP and ROCE both use the
ROCE protocol id, as opposed to the connection context.

Fixes: dbb799c39717 ("qed: Initialize hardware for new protocols")

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
Difference from V2:

Fixed Broken parenthesis In comment


---
 drivers/net/ethernet/qlogic/qed/qed_cxt.c  | 5 -
 drivers/net/ethernet/qlogic/qed/qed_rdma.c | 1 +
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_cxt.c 
b/drivers/net/ethernet/qlogic/qed/qed_cxt.c
index 6f546e8..b6f55bc 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_cxt.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_cxt.c
@@ -2480,7 +2480,10 @@ int qed_cxt_free_proto_ilt(struct qed_hwfn *p_hwfn, enum 
protocol_type proto)
if (rc)
return rc;
 
-   /* Free Task CXT */
+   /* Free Task CXT ( Intentionally RoCE as task-id is shared between
+* RoCE and iWARP )
+*/
+   proto = PROTOCOLID_ROCE;
rc = qed_cxt_free_ilt_range(p_hwfn, QED_ELEM_TASK, 0,
qed_cxt_get_proto_tid_count(p_hwfn, proto));
if (rc)
diff --git a/drivers/net/ethernet/qlogic/qed/qed_rdma.c 
b/drivers/net/ethernet/qlogic/qed/qed_rdma.c
index 5d040b8..f3ee653 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_rdma.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_rdma.c
@@ -380,6 +380,7 @@ static void qed_rdma_free(struct qed_hwfn *p_hwfn)
 
qed_rdma_free_reserved_lkey(p_hwfn);
qed_rdma_resc_free(p_hwfn);
+   qed_cxt_free_proto_ilt(p_hwfn, p_hwfn->p_rdma_info->proto);
 }
 
 static void qed_rdma_get_guid(struct qed_hwfn *p_hwfn, u8 *guid)
-- 
2.9.5



[PATCH V2 net] qed: Free RoCE ILT Memory on rmmod qedr

2018-03-05 Thread Michal Kalderon
Rdma requires ILT Memory to be allocated for it's QPs.
Each ILT entry points to a page used by several Rdma QPs.
To avoid allocating all the memory in advance, the rdma
implementation dynamically allocates memory as more QPs are
added, however it does not dynamically free the memory.
The memory should have been freed on rmmod qedr, but isn't.
This patch adds the memory freeing on rmmod qedr (currently
it will be freed with qed is removed).

An outcome of this bug, is that if qedr is unloaded and loaded
without unloaded qed, there will be no more RoCE traffic.

The reason these are related, is that the logic of detecting the
first QP ever opened is by asking whether ILT memory for RoCE has
been allocated.

In addition, this patch modifies freeing of the Task context to
always use the PROTOCOLID_ROCE and not the protocol passed,
this is because task context for iWARP and ROCE both use the
ROCE protocol id, as opposed to the connection context.

Fixes: dbb799c39717 ("qed: Initialize hardware for new protocols")

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
Difference from V1: 

Fixes line was truncated

---
 drivers/net/ethernet/qlogic/qed/qed_cxt.c  | 5 -
 drivers/net/ethernet/qlogic/qed/qed_rdma.c | 1 +
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_cxt.c 
b/drivers/net/ethernet/qlogic/qed/qed_cxt.c
index 6f546e8..b6f55bc 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_cxt.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_cxt.c
@@ -2480,7 +2480,10 @@ int qed_cxt_free_proto_ilt(struct qed_hwfn *p_hwfn, enum 
protocol_type proto)
if (rc)
return rc;
 
-   /* Free Task CXT */
+   /* Free Task CXT ( Intentionally RoCE as task-id is shared between
+* RoCE and iWARP
+*/
+   proto = PROTOCOLID_ROCE;
rc = qed_cxt_free_ilt_range(p_hwfn, QED_ELEM_TASK, 0,
qed_cxt_get_proto_tid_count(p_hwfn, proto));
if (rc)
diff --git a/drivers/net/ethernet/qlogic/qed/qed_rdma.c 
b/drivers/net/ethernet/qlogic/qed/qed_rdma.c
index 5d040b8..f3ee653 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_rdma.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_rdma.c
@@ -380,6 +380,7 @@ static void qed_rdma_free(struct qed_hwfn *p_hwfn)
 
qed_rdma_free_reserved_lkey(p_hwfn);
qed_rdma_resc_free(p_hwfn);
+   qed_cxt_free_proto_ilt(p_hwfn, p_hwfn->p_rdma_info->proto);
 }
 
 static void qed_rdma_get_guid(struct qed_hwfn *p_hwfn, u8 *guid)
-- 
2.9.5



[PATCH net] qed: Free RoCE ILT Memory on rmmod qedr

2018-03-05 Thread Michal Kalderon
Rdma requires ILT Memory to be allocated for it's QPs.
Each ILT entry points to a page used by several Rdma QPs.
To avoid allocating all the memory in advance, the rdma
implementation dynamically allocates memory as more QPs are
added, however it does not dynamically free the memory.
The memory should have been freed on rmmod qedr, but isn't.
This patch adds the memory freeing on rmmod qedr (currently
it will be freed with qed is removed).

An outcome of this bug, is that if qedr is unloaded and loaded
without unloaded qed, there will be no more RoCE traffic.

The reason these are related, is that the logic of detecting the
first QP ever opened is by asking whether ILT memory for RoCE has
been allocated.

In addition, this patch modifies freeing of the Task context to
always use the PROTOCOLID_ROCE and not the protocol passed,
this is because task context for iWARP and ROCE both use the
ROCE protocol id, as opposed to the connection context.

Fixes: dbb799c39717e7b7
Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed_cxt.c  | 5 -
 drivers/net/ethernet/qlogic/qed/qed_rdma.c | 1 +
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_cxt.c 
b/drivers/net/ethernet/qlogic/qed/qed_cxt.c
index 6f546e8..b6f55bc 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_cxt.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_cxt.c
@@ -2480,7 +2480,10 @@ int qed_cxt_free_proto_ilt(struct qed_hwfn *p_hwfn, enum 
protocol_type proto)
if (rc)
return rc;
 
-   /* Free Task CXT */
+   /* Free Task CXT ( Intentionally RoCE as task-id is shared between
+* RoCE and iWARP
+*/
+   proto = PROTOCOLID_ROCE;
rc = qed_cxt_free_ilt_range(p_hwfn, QED_ELEM_TASK, 0,
qed_cxt_get_proto_tid_count(p_hwfn, proto));
if (rc)
diff --git a/drivers/net/ethernet/qlogic/qed/qed_rdma.c 
b/drivers/net/ethernet/qlogic/qed/qed_rdma.c
index 5d040b8..f3ee653 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_rdma.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_rdma.c
@@ -380,6 +380,7 @@ static void qed_rdma_free(struct qed_hwfn *p_hwfn)
 
qed_rdma_free_reserved_lkey(p_hwfn);
qed_rdma_resc_free(p_hwfn);
+   qed_cxt_free_proto_ilt(p_hwfn, p_hwfn->p_rdma_info->proto);
 }
 
 static void qed_rdma_get_guid(struct qed_hwfn *p_hwfn, u8 *guid)
-- 
2.9.5



[PATCH net 0/2] qed: rdma bug fixes

2018-01-23 Thread Michal Kalderon
This patch contains two small bug fixes related to RDMA. 
Both related to resource reservations.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>

Michal Kalderon (2):
  qed: Remove reserveration of dpi for kernel
  qed: Free reserved MR tid

 drivers/net/ethernet/qlogic/qed/qed_rdma.c | 31 --
 1 file changed, 17 insertions(+), 14 deletions(-)

-- 
1.8.3.1



[PATCH net 2/2] qed: Free reserved MR tid

2018-01-23 Thread Michal Kalderon
A tid was allocated for reserved MR during initialization but
not freed. This lead to an annoying output message during
rdma unload flow.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed_rdma.c | 28 +---
 1 file changed, 17 insertions(+), 11 deletions(-)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_rdma.c 
b/drivers/net/ethernet/qlogic/qed/qed_rdma.c
index 9d6e2d4..b7abb82 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_rdma.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_rdma.c
@@ -358,10 +358,27 @@ static void qed_rdma_resc_free(struct qed_hwfn *p_hwfn)
kfree(p_rdma_info);
 }
 
+static void qed_rdma_free_tid(void *rdma_cxt, u32 itid)
+{
+struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt;
+
+DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "itid = %08x\n", itid);
+
+spin_lock_bh(_hwfn->p_rdma_info->lock);
+qed_bmap_release_id(p_hwfn, _hwfn->p_rdma_info->tid_map, itid);
+spin_unlock_bh(_hwfn->p_rdma_info->lock);
+}
+
+static void qed_rdma_free_reserved_lkey(struct qed_hwfn *p_hwfn)
+{
+   qed_rdma_free_tid(p_hwfn, p_hwfn->p_rdma_info->dev->reserved_lkey);
+}
+
 static void qed_rdma_free(struct qed_hwfn *p_hwfn)
 {
DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Freeing RDMA\n");
 
+   qed_rdma_free_reserved_lkey(p_hwfn);
qed_rdma_resc_free(p_hwfn);
 }
 
@@ -794,17 +811,6 @@ static struct qed_rdma_device *qed_rdma_query_device(void 
*rdma_cxt)
return p_hwfn->p_rdma_info->dev;
 }
 
-static void qed_rdma_free_tid(void *rdma_cxt, u32 itid)
-{
-   struct qed_hwfn *p_hwfn = (struct qed_hwfn *)rdma_cxt;
-
-   DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "itid = %08x\n", itid);
-
-   spin_lock_bh(_hwfn->p_rdma_info->lock);
-   qed_bmap_release_id(p_hwfn, _hwfn->p_rdma_info->tid_map, itid);
-   spin_unlock_bh(_hwfn->p_rdma_info->lock);
-}
-
 static void qed_rdma_cnq_prod_update(void *rdma_cxt, u8 qz_offset, u16 prod)
 {
struct qed_hwfn *p_hwfn;
-- 
1.8.3.1



[PATCH net 1/2] qed: Remove reserveration of dpi for kernel

2018-01-23 Thread Michal Kalderon
Double reservation for kernel dedicated dpi was performed.
Once in the core module and once in qedr.
Remove the reservation from core.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed_rdma.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_rdma.c 
b/drivers/net/ethernet/qlogic/qed/qed_rdma.c
index c8c4b39..9d6e2d4 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_rdma.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_rdma.c
@@ -615,9 +615,6 @@ static int qed_rdma_reserve_lkey(struct qed_hwfn *p_hwfn)
 {
struct qed_rdma_device *dev = p_hwfn->p_rdma_info->dev;
 
-   /* The first DPI is reserved for the Kernel */
-   __set_bit(0, p_hwfn->p_rdma_info->dpi_map.bitmap);
-
/* Tid 0 will be used as the key for "reserved MR".
 * The driver should allocate memory for it so it can be loaded but no
 * ramrod should be passed on it.
-- 
1.8.3.1



[PATCH net-next] qed: Fix iWARP out of order flow

2017-10-17 Thread Michal Kalderon
Out of order flow is not working for iWARP.
This patch got cut out from initial series that added out
of order support for iWARP.

Make out of order code common for iWARP and iSCSI.
Add new configuration option CONFIG_QED_OOO. Set by
qedr and qedi Kconfigs.

Fixes: d1abfd0b4ee2 ("qed: Add iWARP out of order support")

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Manish Rangankar <manish.rangan...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>

---
 drivers/infiniband/hw/qedr/Kconfig  |  1 +
 drivers/net/ethernet/qlogic/Kconfig |  3 +++
 drivers/net/ethernet/qlogic/qed/Makefile|  3 ++-
 drivers/net/ethernet/qlogic/qed/qed_iwarp.c |  7 ++-
 drivers/net/ethernet/qlogic/qed/qed_ooo.c   | 16 +---
 drivers/net/ethernet/qlogic/qed/qed_ooo.h   |  2 +-
 drivers/scsi/qedi/Kconfig   |  1 +
 7 files changed, 27 insertions(+), 6 deletions(-)

diff --git a/drivers/infiniband/hw/qedr/Kconfig 
b/drivers/infiniband/hw/qedr/Kconfig
index 6c9f392..60e867d 100644
--- a/drivers/infiniband/hw/qedr/Kconfig
+++ b/drivers/infiniband/hw/qedr/Kconfig
@@ -2,6 +2,7 @@ config INFINIBAND_QEDR
tristate "QLogic RoCE driver"
depends on 64BIT && QEDE
select QED_LL2
+   select QED_OOO
select QED_RDMA
---help---
  This driver provides low-level InfiniBand over Ethernet
diff --git a/drivers/net/ethernet/qlogic/Kconfig 
b/drivers/net/ethernet/qlogic/Kconfig
index c2e24af..26ddf09 100644
--- a/drivers/net/ethernet/qlogic/Kconfig
+++ b/drivers/net/ethernet/qlogic/Kconfig
@@ -117,4 +117,7 @@ config QED_ISCSI
 config QED_FCOE
bool
 
+config QED_OOO
+   bool
+
 endif # NET_VENDOR_QLOGIC
diff --git a/drivers/net/ethernet/qlogic/qed/Makefile 
b/drivers/net/ethernet/qlogic/qed/Makefile
index 82dd470..c3c5999 100644
--- a/drivers/net/ethernet/qlogic/qed/Makefile
+++ b/drivers/net/ethernet/qlogic/qed/Makefile
@@ -6,5 +6,6 @@ qed-y := qed_cxt.o qed_dev.o qed_hw.o qed_init_fw_funcs.o 
qed_init_ops.o \
 qed-$(CONFIG_QED_SRIOV) += qed_sriov.o qed_vf.o
 qed-$(CONFIG_QED_LL2) += qed_ll2.o
 qed-$(CONFIG_QED_RDMA) += qed_roce.o qed_rdma.o qed_iwarp.o
-qed-$(CONFIG_QED_ISCSI) += qed_iscsi.o qed_ooo.o
+qed-$(CONFIG_QED_ISCSI) += qed_iscsi.o
 qed-$(CONFIG_QED_FCOE) += qed_fcoe.o
+qed-$(CONFIG_QED_OOO) += qed_ooo.o
diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c 
b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
index b2b1f87..409041e 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
@@ -1410,13 +1410,18 @@ int qed_iwarp_alloc(struct qed_hwfn *p_hwfn)
INIT_LIST_HEAD(_hwfn->p_rdma_info->iwarp.ep_free_list);
spin_lock_init(_hwfn->p_rdma_info->iwarp.iw_lock);
 
-   return qed_iwarp_prealloc_ep(p_hwfn, true);
+   rc = qed_iwarp_prealloc_ep(p_hwfn, true);
+   if (rc)
+   return rc;
+
+   return qed_ooo_alloc(p_hwfn);
 }
 
 void qed_iwarp_resc_free(struct qed_hwfn *p_hwfn)
 {
struct qed_iwarp_info *iwarp_info = _hwfn->p_rdma_info->iwarp;
 
+   qed_ooo_free(p_hwfn);
qed_rdma_bmap_free(p_hwfn, _hwfn->p_rdma_info->tcp_cid_map, 1);
kfree(iwarp_info->mpa_bufs);
kfree(iwarp_info->partial_fpdus);
diff --git a/drivers/net/ethernet/qlogic/qed/qed_ooo.c 
b/drivers/net/ethernet/qlogic/qed/qed_ooo.c
index 0006365..6172354 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_ooo.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_ooo.c
@@ -103,18 +103,28 @@ int qed_ooo_alloc(struct qed_hwfn *p_hwfn)
 {
u16 max_num_archipelagos = 0, cid_base;
struct qed_ooo_info *p_ooo_info;
+   enum protocol_type proto;
u16 max_num_isles = 0;
u32 i;
 
-   if (p_hwfn->hw_info.personality != QED_PCI_ISCSI) {
+   switch (p_hwfn->hw_info.personality) {
+   case QED_PCI_ISCSI:
+   proto = PROTOCOLID_ISCSI;
+   break;
+   case QED_PCI_ETH_RDMA:
+   case QED_PCI_ETH_IWARP:
+   proto = PROTOCOLID_IWARP;
+   break;
+   default:
DP_NOTICE(p_hwfn,
  "Failed to allocate qed_ooo_info: unknown 
personality\n");
return -EINVAL;
}
 
-   max_num_archipelagos = p_hwfn->pf_params.iscsi_pf_params.num_cons;
+   max_num_archipelagos = (u16)qed_cxt_get_proto_cid_count(p_hwfn, proto,
+   NULL);
max_num_isles = QED_MAX_NUM_ISLES + max_num_archipelagos;
-   cid_base = (u16)qed_cxt_get_proto_cid_start(p_hwfn, PROTOCOLID_ISCSI);
+   cid_base = (u16)qed_cxt_get_proto_cid_start(p_hwfn, proto);
 
if (!max_num_archipelagos) {
DP_NOTICE(p_hwfn,
diff --git a/drivers/net/ethernet/qlogic/qed/qed_ooo.h 
b/drivers/net/ethernet/qlogic/qed/qed_ooo.h
index e8ed40b..49c4e75 100644

[PATCH v3 net-next 05/12] qed: Add the source of a packet sent on an iWARP ll2 connection

2017-10-09 Thread Michal Kalderon
When a packet is sent back to iWARP FW via the tx ll2 connection
the FW needs to know the source of the packet. Whether it is
OOO or unaligned MPA related. Since OOO is implemented entirely
inside the ll2 code (and shared with iSCSI), packets are marked
as IN_ORDER inside the ll2 code. For unaligned mpa the value
will be determined in the iWARP code and sent on the pkt->vlan
field.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed_ll2.c | 7 ++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.c 
b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
index 6d14474..8eb9645 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_ll2.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
@@ -1613,7 +1613,12 @@ static void qed_ll2_prepare_tx_packet_set(struct 
qed_hwfn *p_hwfn,
}
 
start_bd = (struct core_tx_bd *)qed_chain_produce(p_tx_chain);
-   start_bd->nw_vlan_or_lb_echo = cpu_to_le16(pkt->vlan);
+   if (QED_IS_IWARP_PERSONALITY(p_hwfn) &&
+   p_ll2->input.conn_type == QED_LL2_TYPE_OOO)
+   start_bd->nw_vlan_or_lb_echo =
+   cpu_to_le16(IWARP_LL2_IN_ORDER_TX_QUEUE);
+   else
+   start_bd->nw_vlan_or_lb_echo = cpu_to_le16(pkt->vlan);
SET_FIELD(start_bd->bitfield1, CORE_TX_BD_L4_HDR_OFFSET_W,
  cpu_to_le16(pkt->l4_hdr_offset_w));
SET_FIELD(start_bd->bitfield1, CORE_TX_BD_TX_DST, tx_dest);
-- 
1.8.3.1



[PATCH v3 net-next 09/12] qed: Add unaligned and packed packet processing

2017-10-09 Thread Michal Kalderon
The fpdu data structure is preallocated per connection.
Each connection stores the current status of the connection:
either nothing pending, or there is a partial fpdu that is waiting for
the rest of the fpdu (incomplete bytes != 0).
The same structure is also used for splitting a packet when there are
packed fpdus. The structure is initialized with all data required
for sending the fpdu back to the FW. A fpdu will always be spanned across
a maximum of 3 tx bds. One for the header, one for the partial fdpu
received and one for the remainder (unaligned) packet.
In case of packed fpdu's, two fragments are used, one for the header
and one for the data.
Corner cases are not handled in the patch for clarity, and will be added
as a separate patch.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed_iwarp.c | 257 
 drivers/net/ethernet/qlogic/qed/qed_iwarp.h |  13 ++
 2 files changed, 270 insertions(+)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c 
b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
index efd4861..83b147f 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
@@ -1419,6 +1419,7 @@ void qed_iwarp_resc_free(struct qed_hwfn *p_hwfn)
 
qed_rdma_bmap_free(p_hwfn, _hwfn->p_rdma_info->tcp_cid_map, 1);
kfree(iwarp_info->mpa_bufs);
+   kfree(iwarp_info->partial_fpdus);
 }
 
 int qed_iwarp_accept(void *rdma_cxt, struct qed_iwarp_accept_in *iparams)
@@ -1716,8 +1717,170 @@ int qed_iwarp_reject(void *rdma_cxt, struct 
qed_iwarp_reject_in *iparams)
return 0;
 }
 
+static struct qed_iwarp_fpdu *qed_iwarp_get_curr_fpdu(struct qed_hwfn *p_hwfn,
+ u16 cid)
+{
+   struct qed_iwarp_info *iwarp_info = _hwfn->p_rdma_info->iwarp;
+   struct qed_iwarp_fpdu *partial_fpdu;
+   u32 idx;
+
+   idx = cid - qed_cxt_get_proto_cid_start(p_hwfn, PROTOCOLID_IWARP);
+   if (idx >= iwarp_info->max_num_partial_fpdus) {
+   DP_ERR(p_hwfn, "Invalid cid %x max_num_partial_fpdus=%x\n", cid,
+  iwarp_info->max_num_partial_fpdus);
+   return NULL;
+   }
+
+   partial_fpdu = _info->partial_fpdus[idx];
+
+   return partial_fpdu;
+}
+
+enum qed_iwarp_mpa_pkt_type {
+   QED_IWARP_MPA_PKT_PACKED,
+   QED_IWARP_MPA_PKT_PARTIAL,
+   QED_IWARP_MPA_PKT_UNALIGNED
+};
+
+#define QED_IWARP_MPA_FPDU_LENGTH_SIZE (2)
+#define QED_IWARP_MPA_CRC32_DIGEST_SIZE (4)
+
+/* Pad to multiple of 4 */
+#define QED_IWARP_PDU_DATA_LEN_WITH_PAD(data_len) ALIGN(data_len, 4)
+#define QED_IWARP_FPDU_LEN_WITH_PAD(_mpa_len) \
+   (QED_IWARP_PDU_DATA_LEN_WITH_PAD((_mpa_len) +  \
+QED_IWARP_MPA_FPDU_LENGTH_SIZE) + \
+QED_IWARP_MPA_CRC32_DIGEST_SIZE)
+
 /* fpdu can be fragmented over maximum 3 bds: header, partial mpa, unaligned */
 #define QED_IWARP_MAX_BDS_PER_FPDU 3
+
+char *pkt_type_str[] = {
+   "QED_IWARP_MPA_PKT_PACKED",
+   "QED_IWARP_MPA_PKT_PARTIAL",
+   "QED_IWARP_MPA_PKT_UNALIGNED"
+};
+
+static enum qed_iwarp_mpa_pkt_type
+qed_iwarp_mpa_classify(struct qed_hwfn *p_hwfn,
+  struct qed_iwarp_fpdu *fpdu,
+  u16 tcp_payload_len, u8 *mpa_data)
+{
+   enum qed_iwarp_mpa_pkt_type pkt_type;
+   u16 mpa_len;
+
+   if (fpdu->incomplete_bytes) {
+   pkt_type = QED_IWARP_MPA_PKT_UNALIGNED;
+   goto out;
+   }
+
+   mpa_len = ntohs(*((u16 *)(mpa_data)));
+   fpdu->fpdu_length = QED_IWARP_FPDU_LEN_WITH_PAD(mpa_len);
+
+   if (fpdu->fpdu_length <= tcp_payload_len)
+   pkt_type = QED_IWARP_MPA_PKT_PACKED;
+   else
+   pkt_type = QED_IWARP_MPA_PKT_PARTIAL;
+
+out:
+   DP_VERBOSE(p_hwfn, QED_MSG_RDMA,
+  "MPA_ALIGN: %s: fpdu_length=0x%x tcp_payload_len:0x%x\n",
+  pkt_type_str[pkt_type], fpdu->fpdu_length, tcp_payload_len);
+
+   return pkt_type;
+}
+
+static void
+qed_iwarp_init_fpdu(struct qed_iwarp_ll2_buff *buf,
+   struct qed_iwarp_fpdu *fpdu,
+   struct unaligned_opaque_data *pkt_data,
+   u16 tcp_payload_size, u8 placement_offset)
+{
+   fpdu->mpa_buf = buf;
+   fpdu->pkt_hdr = buf->data_phys_addr + placement_offset;
+   fpdu->pkt_hdr_size = pkt_data->tcp_payload_offset;
+   fpdu->mpa_frag = buf->data_phys_addr + pkt_data->first_mpa_offset;
+   fpdu->mpa_frag_virt = (u8 *)(buf->data) + pkt_data->first_mpa_offset;
+
+   if (tcp_payload_size < fpdu->fpdu_length)
+   fpdu->incomplete_bytes = fpdu-

[PATCH v3 net-next 10/12] qed: Add support for freeing two ll2 buffers for corner cases

2017-10-09 Thread Michal Kalderon
When posting a packet on the ll2 tx, we can provide a cookie that
will be returned upon tx completion. This cookie is the ll2 iwarp buffer
which is then reposted to the rx ring. Part of the unaligned mpa flow
is determining when a buffer can be reposted. Each buffer needs to be
sent only once as a cookie for on the tx ring. In packed fpdu case, only
the last packet will be sent with the buffer, meaning we need to handle the
case that a cookie can be NULL on tx complete. In addition, when a fpdu
splits over two buffers, but there are no more fpdus on the second buffer,
two buffers need to be provided as a cookie. To avoid changing the ll2
interface to provide two cookies, we introduce a piggy buf pointer,
relevant for iWARP only, that holds a pointer to a second buffer that
needs to be released during tx completion.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed_iwarp.c | 25 +
 drivers/net/ethernet/qlogic/qed/qed_iwarp.h |  1 +
 2 files changed, 26 insertions(+)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c 
b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
index 83b147f..8b17369 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
@@ -1846,6 +1846,12 @@ enum qed_iwarp_mpa_pkt_type {
/* vlan overload with enum iwarp_ll2_tx_queues */
tx_pkt.vlan = IWARP_LL2_ALIGNED_TX_QUEUE;
 
+   /* special case of unaligned packet and not packed, need to send
+* both buffers as cookie to release.
+*/
+   if (tcp_payload_size == fpdu->incomplete_bytes)
+   fpdu->mpa_buf->piggy_buf = buf;
+
ll2_handle = p_hwfn->p_rdma_info->iwarp.ll2_mpa_handle;
 
/* Set first fragment to header */
@@ -2195,9 +2201,19 @@ static void qed_iwarp_ll2_comp_tx_pkt(void *cxt, u8 
connection_handle,
  bool b_last_fragment, bool b_last_packet)
 {
struct qed_iwarp_ll2_buff *buffer = cookie;
+   struct qed_iwarp_ll2_buff *piggy;
struct qed_hwfn *p_hwfn = cxt;
 
+   if (!buffer)/* can happen in packed mpa unaligned... */
+   return;
+
/* this was originally an rx packet, post it back */
+   piggy = buffer->piggy_buf;
+   if (piggy) {
+   buffer->piggy_buf = NULL;
+   qed_iwarp_ll2_post_rx(p_hwfn, piggy, connection_handle);
+   }
+
qed_iwarp_ll2_post_rx(p_hwfn, buffer, connection_handle);
 
if (connection_handle == p_hwfn->p_rdma_info->iwarp.ll2_mpa_handle)
@@ -2216,6 +2232,15 @@ static void qed_iwarp_ll2_rel_tx_pkt(void *cxt, u8 
connection_handle,
if (!buffer)
return;
 
+   if (buffer->piggy_buf) {
+   dma_free_coherent(_hwfn->cdev->pdev->dev,
+ buffer->piggy_buf->buff_size,
+ buffer->piggy_buf->data,
+ buffer->piggy_buf->data_phys_addr);
+
+   kfree(buffer->piggy_buf);
+   }
+
dma_free_coherent(_hwfn->cdev->pdev->dev, buffer->buff_size,
  buffer->data, buffer->data_phys_addr);
 
diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.h 
b/drivers/net/ethernet/qlogic/qed/qed_iwarp.h
index 858755c..58db51a 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.h
+++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.h
@@ -55,6 +55,7 @@ enum qed_iwarp_qp_state {
 #define QED_IWARP_HANDLE_INVAL (0xff)
 
 struct qed_iwarp_ll2_buff {
+   struct qed_iwarp_ll2_buff *piggy_buf;
void *data;
dma_addr_t data_phys_addr;
u32 buff_size;
-- 
1.8.3.1



[PATCH v3 net-next 11/12] qed: Add support for MPA header being split over two tcp packets

2017-10-09 Thread Michal Kalderon
There is a special case where an MPA header is split over to tcp
packets, in this case we need to wait for the next packet to
get the fpdu length. We use the incomplete_bytes to mark this
fpdu as a "special" one which requires updating the length with
the next packet

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed_iwarp.c | 36 -
 drivers/net/ethernet/qlogic/qed/qed_iwarp.h |  6 +
 2 files changed, 41 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c 
b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
index 8b17369..2994942 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
@@ -1742,6 +1742,7 @@ enum qed_iwarp_mpa_pkt_type {
QED_IWARP_MPA_PKT_UNALIGNED
 };
 
+#define QED_IWARP_INVALID_FPDU_LENGTH 0x
 #define QED_IWARP_MPA_FPDU_LENGTH_SIZE (2)
 #define QED_IWARP_MPA_CRC32_DIGEST_SIZE (4)
 
@@ -1774,6 +1775,15 @@ enum qed_iwarp_mpa_pkt_type {
goto out;
}
 
+   /* special case of one byte remaining...
+* lower byte will be read next packet
+*/
+   if (tcp_payload_len == 1) {
+   fpdu->fpdu_length = *mpa_data << BITS_PER_BYTE;
+   pkt_type = QED_IWARP_MPA_PKT_PARTIAL;
+   goto out;
+   }
+
mpa_len = ntohs(*((u16 *)(mpa_data)));
fpdu->fpdu_length = QED_IWARP_FPDU_LEN_WITH_PAD(mpa_len);
 
@@ -1802,7 +1812,9 @@ enum qed_iwarp_mpa_pkt_type {
fpdu->mpa_frag = buf->data_phys_addr + pkt_data->first_mpa_offset;
fpdu->mpa_frag_virt = (u8 *)(buf->data) + pkt_data->first_mpa_offset;
 
-   if (tcp_payload_size < fpdu->fpdu_length)
+   if (tcp_payload_size == 1)
+   fpdu->incomplete_bytes = QED_IWARP_INVALID_FPDU_LENGTH;
+   else if (tcp_payload_size < fpdu->fpdu_length)
fpdu->incomplete_bytes = fpdu->fpdu_length - tcp_payload_size;
else
fpdu->incomplete_bytes = 0; /* complete fpdu */
@@ -1810,6 +1822,27 @@ enum qed_iwarp_mpa_pkt_type {
fpdu->mpa_frag_len = fpdu->fpdu_length - fpdu->incomplete_bytes;
 }
 
+static void
+qed_iwarp_update_fpdu_length(struct qed_hwfn *p_hwfn,
+struct qed_iwarp_fpdu *fpdu, u8 *mpa_data)
+{
+   u16 mpa_len;
+
+   /* Update incomplete packets if needed */
+   if (fpdu->incomplete_bytes == QED_IWARP_INVALID_FPDU_LENGTH) {
+   /* Missing lower byte is now available */
+   mpa_len = fpdu->fpdu_length | *mpa_data;
+   fpdu->fpdu_length = QED_IWARP_FPDU_LEN_WITH_PAD(mpa_len);
+   fpdu->mpa_frag_len = fpdu->fpdu_length;
+   /* one byte of hdr */
+   fpdu->incomplete_bytes = fpdu->fpdu_length - 1;
+   DP_VERBOSE(p_hwfn,
+  QED_MSG_RDMA,
+  "MPA_ALIGN: Partial header mpa_len=%x fpdu_length=%x 
incomplete_bytes=%x\n",
+  mpa_len, fpdu->fpdu_length, fpdu->incomplete_bytes);
+   }
+}
+
 static int
 qed_iwarp_send_fpdu(struct qed_hwfn *p_hwfn,
struct qed_iwarp_fpdu *fpdu,
@@ -1960,6 +1993,7 @@ enum qed_iwarp_mpa_pkt_type {
curr_pkt->first_mpa_offset += fpdu->fpdu_length;
break;
case QED_IWARP_MPA_PKT_UNALIGNED:
+   qed_iwarp_update_fpdu_length(p_hwfn, fpdu, mpa_data);
rc = qed_iwarp_send_fpdu(p_hwfn, fpdu, curr_pkt, buf,
 mpa_buf->tcp_payload_len,
 pkt_type);
diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.h 
b/drivers/net/ethernet/qlogic/qed/qed_iwarp.h
index 58db51a..c58793a 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.h
+++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.h
@@ -69,6 +69,12 @@ struct qed_iwarp_ll2_mpa_buf {
u8 placement_offset;
 };
 
+/* In some cases a fpdu will arrive with only one byte of the header, in this
+ * case the fpdu_length will be partial (contain only higher byte and
+ * incomplete bytes will contain the invalid value
+ */
+#define QED_IWARP_INVALID_INCOMPLETE_BYTES 0x
+
 struct qed_iwarp_fpdu {
struct qed_iwarp_ll2_buff *mpa_buf;
void *mpa_frag_virt;
-- 
1.8.3.1



[PATCH v3 net-next 12/12] qed: Add iWARP support for fpdu spanned over more than two tcp packets

2017-10-09 Thread Michal Kalderon
We continue to maintain a maximum of three buffers per fpdu, to ensure
that there are enough buffers for additional unaligned mpa packets.
To support this, if a fpdu is split over more than two tcp packets, we
use an intermediate buffer to copy the data to the previous buffer, then
we can release the data. We need an intermediate buffer as the initial
buffer partial packet could be located at the end of the packet, not
leaving room for additional data. This is a corner case, and will usually
not be the case.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed_iwarp.c | 193 
 drivers/net/ethernet/qlogic/qed/qed_iwarp.h |   1 +
 2 files changed, 194 insertions(+)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c 
b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
index 2994942..b2b1f87 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
@@ -1420,6 +1420,7 @@ void qed_iwarp_resc_free(struct qed_hwfn *p_hwfn)
qed_rdma_bmap_free(p_hwfn, _hwfn->p_rdma_info->tcp_cid_map, 1);
kfree(iwarp_info->mpa_bufs);
kfree(iwarp_info->partial_fpdus);
+   kfree(iwarp_info->mpa_intermediate_buf);
 }
 
 int qed_iwarp_accept(void *rdma_cxt, struct qed_iwarp_accept_in *iparams)
@@ -1762,6 +1763,11 @@ enum qed_iwarp_mpa_pkt_type {
"QED_IWARP_MPA_PKT_UNALIGNED"
 };
 
+static int
+qed_iwarp_recycle_pkt(struct qed_hwfn *p_hwfn,
+ struct qed_iwarp_fpdu *fpdu,
+ struct qed_iwarp_ll2_buff *buf);
+
 static enum qed_iwarp_mpa_pkt_type
 qed_iwarp_mpa_classify(struct qed_hwfn *p_hwfn,
   struct qed_iwarp_fpdu *fpdu,
@@ -1822,6 +1828,68 @@ enum qed_iwarp_mpa_pkt_type {
fpdu->mpa_frag_len = fpdu->fpdu_length - fpdu->incomplete_bytes;
 }
 
+static int
+qed_iwarp_cp_pkt(struct qed_hwfn *p_hwfn,
+struct qed_iwarp_fpdu *fpdu,
+struct unaligned_opaque_data *pkt_data,
+struct qed_iwarp_ll2_buff *buf, u16 tcp_payload_size)
+{
+   u8 *tmp_buf = p_hwfn->p_rdma_info->iwarp.mpa_intermediate_buf;
+   int rc;
+
+   /* need to copy the data from the partial packet stored in fpdu
+* to the new buf, for this we also need to move the data currently
+* placed on the buf. The assumption is that the buffer is big enough
+* since fpdu_length <= mss, we use an intermediate buffer since
+* we may need to copy the new data to an overlapping location
+*/
+   if ((fpdu->mpa_frag_len + tcp_payload_size) > (u16)buf->buff_size) {
+   DP_ERR(p_hwfn,
+  "MPA ALIGN: Unexpected: buffer is not large enough for 
split fpdu buff_size = %d mpa_frag_len = %d, tcp_payload_size = %d, 
incomplete_bytes = %d\n",
+  buf->buff_size, fpdu->mpa_frag_len,
+  tcp_payload_size, fpdu->incomplete_bytes);
+   return -EINVAL;
+   }
+
+   DP_VERBOSE(p_hwfn, QED_MSG_RDMA,
+  "MPA ALIGN Copying fpdu: [%p, %d] [%p, %d]\n",
+  fpdu->mpa_frag_virt, fpdu->mpa_frag_len,
+  (u8 *)(buf->data) + pkt_data->first_mpa_offset,
+  tcp_payload_size);
+
+   memcpy(tmp_buf, fpdu->mpa_frag_virt, fpdu->mpa_frag_len);
+   memcpy(tmp_buf + fpdu->mpa_frag_len,
+  (u8 *)(buf->data) + pkt_data->first_mpa_offset,
+  tcp_payload_size);
+
+   rc = qed_iwarp_recycle_pkt(p_hwfn, fpdu, fpdu->mpa_buf);
+   if (rc)
+   return rc;
+
+   /* If we managed to post the buffer copy the data to the new buffer
+* o/w this will occur in the next round...
+*/
+   memcpy((u8 *)(buf->data), tmp_buf,
+  fpdu->mpa_frag_len + tcp_payload_size);
+
+   fpdu->mpa_buf = buf;
+   /* fpdu->pkt_hdr remains as is */
+   /* fpdu->mpa_frag is overridden with new buf */
+   fpdu->mpa_frag = buf->data_phys_addr;
+   fpdu->mpa_frag_virt = buf->data;
+   fpdu->mpa_frag_len += tcp_payload_size;
+
+   fpdu->incomplete_bytes -= tcp_payload_size;
+
+   DP_VERBOSE(p_hwfn,
+  QED_MSG_RDMA,
+  "MPA ALIGN: split fpdu buff_size = %d mpa_frag_len = %d, 
tcp_payload_size = %d, incomplete_bytes = %d\n",
+  buf->buff_size, fpdu->mpa_frag_len, tcp_payload_size,
+  fpdu->incomplete_bytes);
+
+   return 0;
+}
+
 static void
 qed_iwarp_update_fpdu_length(struct qed_hwfn *p_hwfn,
 struct qed_iwarp_fpdu *fpdu, u8 *mpa_data)
@@ -1843,6 +1911,90 @@ enum qed_iwarp_mpa_pkt_type {
}
 }
 
+#define QED_IWARP_IS_RIGHT_EDGE(_curr_pkt) \
+   (GET_

[PATCH v3 net-next 08/12] qed: Add mpa buffer descriptors for storing and processing mpa fpdus

2017-10-09 Thread Michal Kalderon
The mpa buff is a descriptor for iwarp ll2 buffers that contains
additional information required for aligining fpdu's.
In some cases, an additional packet will arrive which will complete
the alignment of a fpdu, but we won't be able to post the fpdu due to
insufficient place on the tx ring. In this case we can't loose the data
and require storing it for later. Processing is therefore done
in two places, during rx completion, where we initialize a mpa buffer
descriptor and add it to the pending list, and during tx-completion, since
we free up an entry in the tx chain we can process any pending mpa packets.
The mpa buff descriptors are pre-allocated since we have to ensure that
we won't reach a state where we can't store an incoming unaligned packet.
All packets received on the ll2 MUST be processed by the driver at some
stage. Since they are preallocated, we hold a free list.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed_iwarp.c | 116 
 drivers/net/ethernet/qlogic/qed/qed_iwarp.h |  11 +++
 2 files changed, 127 insertions(+)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c 
b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
index f413621..efd4861 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
@@ -1415,7 +1415,10 @@ int qed_iwarp_alloc(struct qed_hwfn *p_hwfn)
 
 void qed_iwarp_resc_free(struct qed_hwfn *p_hwfn)
 {
+   struct qed_iwarp_info *iwarp_info = _hwfn->p_rdma_info->iwarp;
+
qed_rdma_bmap_free(p_hwfn, _hwfn->p_rdma_info->tcp_cid_map, 1);
+   kfree(iwarp_info->mpa_bufs);
 }
 
 int qed_iwarp_accept(void *rdma_cxt, struct qed_iwarp_accept_in *iparams)
@@ -1716,12 +1719,103 @@ int qed_iwarp_reject(void *rdma_cxt, struct 
qed_iwarp_reject_in *iparams)
 /* fpdu can be fragmented over maximum 3 bds: header, partial mpa, unaligned */
 #define QED_IWARP_MAX_BDS_PER_FPDU 3
 static void
+qed_iwarp_mpa_get_data(struct qed_hwfn *p_hwfn,
+  struct unaligned_opaque_data *curr_pkt,
+  u32 opaque_data0, u32 opaque_data1)
+{
+   u64 opaque_data;
+
+   opaque_data = HILO_64(opaque_data1, opaque_data0);
+   *curr_pkt = *((struct unaligned_opaque_data *)_data);
+
+   curr_pkt->first_mpa_offset = curr_pkt->tcp_payload_offset +
+le16_to_cpu(curr_pkt->first_mpa_offset);
+   curr_pkt->cid = le32_to_cpu(curr_pkt->cid);
+}
+
+/* This function is called when an unaligned or incomplete MPA packet arrives
+ * driver needs to align the packet, perhaps using previous data and send
+ * it down to FW once it is aligned.
+ */
+static int
+qed_iwarp_process_mpa_pkt(struct qed_hwfn *p_hwfn,
+ struct qed_iwarp_ll2_mpa_buf *mpa_buf)
+{
+   struct qed_iwarp_ll2_buff *buf = mpa_buf->ll2_buf;
+   int rc = -EINVAL;
+
+   qed_iwarp_ll2_post_rx(p_hwfn,
+ buf,
+ p_hwfn->p_rdma_info->iwarp.ll2_mpa_handle);
+   return rc;
+}
+
+static void qed_iwarp_process_pending_pkts(struct qed_hwfn *p_hwfn)
+{
+   struct qed_iwarp_info *iwarp_info = _hwfn->p_rdma_info->iwarp;
+   struct qed_iwarp_ll2_mpa_buf *mpa_buf = NULL;
+   int rc;
+
+   while (!list_empty(_info->mpa_buf_pending_list)) {
+   mpa_buf = list_first_entry(_info->mpa_buf_pending_list,
+  struct qed_iwarp_ll2_mpa_buf,
+  list_entry);
+
+   rc = qed_iwarp_process_mpa_pkt(p_hwfn, mpa_buf);
+
+   /* busy means break and continue processing later, don't
+* remove the buf from the pending list.
+*/
+   if (rc == -EBUSY)
+   break;
+
+   list_del(_buf->list_entry);
+   list_add_tail(_buf->list_entry, _info->mpa_buf_list);
+
+   if (rc) {   /* different error, don't continue */
+   DP_NOTICE(p_hwfn, "process pkts failed rc=%d\n", rc);
+   break;
+   }
+   }
+}
+
+static void
 qed_iwarp_ll2_comp_mpa_pkt(void *cxt, struct qed_ll2_comp_rx_data *data)
 {
+   struct qed_iwarp_ll2_mpa_buf *mpa_buf;
struct qed_iwarp_info *iwarp_info;
struct qed_hwfn *p_hwfn = cxt;
 
iwarp_info = _hwfn->p_rdma_info->iwarp;
+   mpa_buf = list_first_entry(_info->mpa_buf_list,
+  struct qed_iwarp_ll2_mpa_buf, list_entry);
+   if (!mpa_buf) {
+   DP_ERR(p_hwfn, "No free mpa buf\n");
+   goto err;
+   }
+
+   list_del(_buf->list_entry);
+   qed_iwarp_mpa_get_data(p_hwfn, _buf->data,
+  data->opaque_data_

[PATCH v3 net-next 07/12] qed: Add ll2 connection for processing unaligned MPA packets

2017-10-09 Thread Michal Kalderon
This patch adds only the establishment and termination of the
ll2 connection that handles unaligned MPA packets.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed_iwarp.c | 65 +
 drivers/net/ethernet/qlogic/qed/qed_iwarp.h |  1 +
 2 files changed, 66 insertions(+)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c 
b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
index 8fc9c811..f413621 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
@@ -1713,6 +1713,19 @@ int qed_iwarp_reject(void *rdma_cxt, struct 
qed_iwarp_reject_in *iparams)
return 0;
 }
 
+/* fpdu can be fragmented over maximum 3 bds: header, partial mpa, unaligned */
+#define QED_IWARP_MAX_BDS_PER_FPDU 3
+static void
+qed_iwarp_ll2_comp_mpa_pkt(void *cxt, struct qed_ll2_comp_rx_data *data)
+{
+   struct qed_iwarp_info *iwarp_info;
+   struct qed_hwfn *p_hwfn = cxt;
+
+   iwarp_info = _hwfn->p_rdma_info->iwarp;
+   qed_iwarp_ll2_post_rx(p_hwfn, data->cookie,
+ iwarp_info->ll2_mpa_handle);
+}
+
 static void
 qed_iwarp_ll2_comp_syn_pkt(void *cxt, struct qed_ll2_comp_rx_data *data)
 {
@@ -1877,6 +1890,13 @@ static void qed_iwarp_ll2_rel_tx_pkt(void *cxt, u8 
connection_handle,
kfree(buffer);
 }
 
+void
+qed_iwarp_ll2_slowpath(void *cxt,
+  u8 connection_handle,
+  u32 opaque_data_0, u32 opaque_data_1)
+{
+}
+
 static int qed_iwarp_ll2_stop(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
 {
struct qed_iwarp_info *iwarp_info = _hwfn->p_rdma_info->iwarp;
@@ -1902,6 +1922,16 @@ static int qed_iwarp_ll2_stop(struct qed_hwfn *p_hwfn, 
struct qed_ptt *p_ptt)
iwarp_info->ll2_ooo_handle = QED_IWARP_HANDLE_INVAL;
}
 
+   if (iwarp_info->ll2_mpa_handle != QED_IWARP_HANDLE_INVAL) {
+   rc = qed_ll2_terminate_connection(p_hwfn,
+ iwarp_info->ll2_mpa_handle);
+   if (rc)
+   DP_INFO(p_hwfn, "Failed to terminate mpa connection\n");
+
+   qed_ll2_release_connection(p_hwfn, iwarp_info->ll2_mpa_handle);
+   iwarp_info->ll2_mpa_handle = QED_IWARP_HANDLE_INVAL;
+   }
+
qed_llh_remove_mac_filter(p_hwfn,
  p_ptt, p_hwfn->p_rdma_info->iwarp.mac_addr);
return rc;
@@ -1953,12 +1983,14 @@ static int qed_iwarp_ll2_stop(struct qed_hwfn *p_hwfn, 
struct qed_ptt *p_ptt)
struct qed_iwarp_info *iwarp_info;
struct qed_ll2_acquire_data data;
struct qed_ll2_cbs cbs;
+   u32 mpa_buff_size;
u16 n_ooo_bufs;
int rc = 0;
 
iwarp_info = _hwfn->p_rdma_info->iwarp;
iwarp_info->ll2_syn_handle = QED_IWARP_HANDLE_INVAL;
iwarp_info->ll2_ooo_handle = QED_IWARP_HANDLE_INVAL;
+   iwarp_info->ll2_mpa_handle = QED_IWARP_HANDLE_INVAL;
 
iwarp_info->max_mtu = params->max_mtu;
 
@@ -2029,6 +2061,39 @@ static int qed_iwarp_ll2_stop(struct qed_hwfn *p_hwfn, 
struct qed_ptt *p_ptt)
if (rc)
goto err;
 
+   /* Start Unaligned MPA connection */
+   cbs.rx_comp_cb = qed_iwarp_ll2_comp_mpa_pkt;
+   cbs.slowpath_cb = qed_iwarp_ll2_slowpath;
+
+   memset(, 0, sizeof(data));
+   data.input.conn_type = QED_LL2_TYPE_IWARP;
+   data.input.mtu = params->max_mtu;
+   /* FW requires that once a packet arrives OOO, it must have at
+* least 2 rx buffers available on the unaligned connection
+* for handling the case that it is a partial fpdu.
+*/
+   data.input.rx_num_desc = n_ooo_bufs * 2;
+   data.input.tx_num_desc = data.input.rx_num_desc;
+   data.input.tx_max_bds_per_packet = QED_IWARP_MAX_BDS_PER_FPDU;
+   data.p_connection_handle = _info->ll2_mpa_handle;
+   data.input.secondary_queue = true;
+   data.cbs = 
+
+   rc = qed_ll2_acquire_connection(p_hwfn, );
+   if (rc)
+   goto err;
+
+   rc = qed_ll2_establish_connection(p_hwfn, iwarp_info->ll2_mpa_handle);
+   if (rc)
+   goto err;
+
+   mpa_buff_size = QED_IWARP_MAX_BUF_SIZE(params->max_mtu);
+   rc = qed_iwarp_ll2_alloc_buffers(p_hwfn,
+data.input.rx_num_desc,
+mpa_buff_size,
+iwarp_info->ll2_mpa_handle);
+   if (rc)
+   goto err;
return rc;
 err:
qed_iwarp_ll2_stop(p_hwfn, p_ptt);
diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.h 
b/drivers/net/ethernet/qlogic/qed/qed_iwarp.h
index 9e2bfde..9d33a1f 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.h
+++ b/drivers/net/ethernet/qlogic/qed/qed_

[PATCH v3 net-next 03/12] qed: Add ll2 option for dropping a tx packet

2017-10-09 Thread Michal Kalderon
The option of sending a packet on the ll2 and dropping it exists in
hardware and was not used until now, thus not exposed.
The iWARP unaligned MPA flow requires this functionality for
flushing the tx queue.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed_ll2.c | 16 ++--
 include/linux/qed/qed_ll2_if.h|  1 +
 2 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.c 
b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
index 3c695da..ad67d36 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_ll2.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
@@ -1597,8 +1597,20 @@ static void qed_ll2_prepare_tx_packet_set(struct 
qed_hwfn *p_hwfn,
roce_flavor = (pkt->qed_roce_flavor == QED_LL2_ROCE) ? CORE_ROCE
 : CORE_RROCE;
 
-   tx_dest = (pkt->tx_dest == QED_LL2_TX_DEST_NW) ? CORE_TX_DEST_NW
-  : CORE_TX_DEST_LB;
+   switch (pkt->tx_dest) {
+   case QED_LL2_TX_DEST_NW:
+   tx_dest = CORE_TX_DEST_NW;
+   break;
+   case QED_LL2_TX_DEST_LB:
+   tx_dest = CORE_TX_DEST_LB;
+   break;
+   case QED_LL2_TX_DEST_DROP:
+   tx_dest = CORE_TX_DEST_DROP;
+   break;
+   default:
+   tx_dest = CORE_TX_DEST_LB;
+   break;
+   }
 
start_bd = (struct core_tx_bd *)qed_chain_produce(p_tx_chain);
start_bd->nw_vlan_or_lb_echo = cpu_to_le16(pkt->vlan);
diff --git a/include/linux/qed/qed_ll2_if.h b/include/linux/qed/qed_ll2_if.h
index d7cca59..95fdf02 100644
--- a/include/linux/qed/qed_ll2_if.h
+++ b/include/linux/qed/qed_ll2_if.h
@@ -64,6 +64,7 @@ enum qed_ll2_roce_flavor_type {
 enum qed_ll2_tx_dest {
QED_LL2_TX_DEST_NW, /* Light L2 TX Destination to the Network */
QED_LL2_TX_DEST_LB, /* Light L2 TX Destination to the Loopback */
+   QED_LL2_TX_DEST_DROP, /* Light L2 Drop the TX packet */
QED_LL2_TX_DEST_MAX
 };
 
-- 
1.8.3.1



[PATCH v3 net-next 06/12] qed: Add LL2 slowpath handling

2017-10-09 Thread Michal Kalderon
For iWARP unaligned MPA flow, a slowpath event of flushing an
MPA connection that entered an unaligned state is required.
The flush ramrod is received on the ll2 queue, and a pre-registered
callback function is called to handle the flush event.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed_ll2.c | 40 +--
 include/linux/qed/qed_ll2_if.h|  5 
 2 files changed, 43 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.c 
b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
index 8eb9645..047f556 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_ll2.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
@@ -423,6 +423,41 @@ static void qed_ll2_rxq_parse_reg(struct qed_hwfn *p_hwfn,
 }
 
 static int
+qed_ll2_handle_slowpath(struct qed_hwfn *p_hwfn,
+   struct qed_ll2_info *p_ll2_conn,
+   union core_rx_cqe_union *p_cqe,
+   unsigned long *p_lock_flags)
+{
+   struct qed_ll2_rx_queue *p_rx = _ll2_conn->rx_queue;
+   struct core_rx_slow_path_cqe *sp_cqe;
+
+   sp_cqe = _cqe->rx_cqe_sp;
+   if (sp_cqe->ramrod_cmd_id != CORE_RAMROD_RX_QUEUE_FLUSH) {
+   DP_NOTICE(p_hwfn,
+ "LL2 - unexpected Rx CQE slowpath ramrod_cmd_id:%d\n",
+ sp_cqe->ramrod_cmd_id);
+   return -EINVAL;
+   }
+
+   if (!p_ll2_conn->cbs.slowpath_cb) {
+   DP_NOTICE(p_hwfn,
+ "LL2 - received RX_QUEUE_FLUSH but no callback was 
provided\n");
+   return -EINVAL;
+   }
+
+   spin_unlock_irqrestore(_rx->lock, *p_lock_flags);
+
+   p_ll2_conn->cbs.slowpath_cb(p_ll2_conn->cbs.cookie,
+   p_ll2_conn->my_id,
+   le32_to_cpu(sp_cqe->opaque_data.data[0]),
+   le32_to_cpu(sp_cqe->opaque_data.data[1]));
+
+   spin_lock_irqsave(_rx->lock, *p_lock_flags);
+
+   return 0;
+}
+
+static int
 qed_ll2_rxq_handle_completion(struct qed_hwfn *p_hwfn,
  struct qed_ll2_info *p_ll2_conn,
  union core_rx_cqe_union *p_cqe,
@@ -495,8 +530,8 @@ static int qed_ll2_rxq_completion(struct qed_hwfn *p_hwfn, 
void *cookie)
 
switch (cqe->rx_cqe_sp.type) {
case CORE_RX_CQE_TYPE_SLOW_PATH:
-   DP_NOTICE(p_hwfn, "LL2 - unexpected Rx CQE slowpath\n");
-   rc = -EINVAL;
+   rc = qed_ll2_handle_slowpath(p_hwfn, p_ll2_conn,
+cqe, );
break;
case CORE_RX_CQE_TYPE_GSI_OFFLOAD:
case CORE_RX_CQE_TYPE_REGULAR:
@@ -1214,6 +1249,7 @@ static int qed_ll2_acquire_connection_tx(struct qed_hwfn 
*p_hwfn,
p_ll2_info->cbs.rx_release_cb = cbs->rx_release_cb;
p_ll2_info->cbs.tx_comp_cb = cbs->tx_comp_cb;
p_ll2_info->cbs.tx_release_cb = cbs->tx_release_cb;
+   p_ll2_info->cbs.slowpath_cb = cbs->slowpath_cb;
p_ll2_info->cbs.cookie = cbs->cookie;
 
return 0;
diff --git a/include/linux/qed/qed_ll2_if.h b/include/linux/qed/qed_ll2_if.h
index 95fdf02..e755954 100644
--- a/include/linux/qed/qed_ll2_if.h
+++ b/include/linux/qed/qed_ll2_if.h
@@ -151,11 +151,16 @@ struct qed_ll2_comp_rx_data {
 dma_addr_t first_frag_addr,
 bool b_last_fragment, bool b_last_packet);
 
+typedef
+void (*qed_ll2_slowpath_cb)(void *cxt, u8 connection_handle,
+   u32 opaque_data_0, u32 opaque_data_1);
+
 struct qed_ll2_cbs {
qed_ll2_complete_rx_packet_cb rx_comp_cb;
qed_ll2_release_rx_packet_cb rx_release_cb;
qed_ll2_complete_tx_packet_cb tx_comp_cb;
qed_ll2_release_tx_packet_cb tx_release_cb;
+   qed_ll2_slowpath_cb slowpath_cb;
void *cookie;
 };
 
-- 
1.8.3.1



[PATCH v3 net-next 04/12] qed: Fix initialization of ll2 offload feature

2017-10-09 Thread Michal Kalderon
enable_ip_cksum, enable_l4_cksum, calc_ip_len were added in
commit stated below but not passed through to FW. This was OK
until now as it wasn't used, but is required for the iWARP
unaligned flow

Fixes:7c7973b2ae27 ("qed: LL2 to use packed information for tx")

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed_ll2.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.c 
b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
index ad67d36..6d14474 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_ll2.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
@@ -1621,6 +1621,9 @@ static void qed_ll2_prepare_tx_packet_set(struct qed_hwfn 
*p_hwfn,
SET_FIELD(bd_data, CORE_TX_BD_DATA_START_BD, 0x1);
SET_FIELD(bd_data, CORE_TX_BD_DATA_NBDS, pkt->num_of_bds);
SET_FIELD(bd_data, CORE_TX_BD_DATA_ROCE_FLAV, roce_flavor);
+   SET_FIELD(bd_data, CORE_TX_BD_DATA_IP_CSUM, !!(pkt->enable_ip_cksum));
+   SET_FIELD(bd_data, CORE_TX_BD_DATA_L4_CSUM, !!(pkt->enable_l4_cksum));
+   SET_FIELD(bd_data, CORE_TX_BD_DATA_IP_LEN, !!(pkt->calc_ip_len));
start_bd->bd_data.as_bitfield = cpu_to_le16(bd_data);
DMA_REGPAIR_LE(start_bd->addr, pkt->first_frag);
start_bd->nbytes = cpu_to_le16(pkt->first_frag_len);
-- 
1.8.3.1



[PATCH v3 net-next 01/12] qed: Add ll2 option to limit the number of bds per packet

2017-10-09 Thread Michal Kalderon
iWARP uses 3 ll2 connections, the maximum number of bds is known
during connection setup. This patch modifies the static array in
the ll2_tx_packet descriptor to be a flexible array and
significantlly reduces memory size.

In addition, some redundant fields in the ll2_tx_packet were
removed, which also contributed to decreasing the descriptor size.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed_ll2.c | 29 +
 drivers/net/ethernet/qlogic/qed/qed_ll2.h |  9 +++--
 2 files changed, 24 insertions(+), 14 deletions(-)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.c 
b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
index 250afa5..75af40a 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_ll2.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
@@ -1105,6 +1105,7 @@ static int qed_ll2_acquire_connection_tx(struct qed_hwfn 
*p_hwfn,
 struct qed_ll2_info *p_ll2_info)
 {
struct qed_ll2_tx_packet *p_descq;
+   u32 desc_size;
u32 capacity;
int rc = 0;
 
@@ -1122,13 +1123,17 @@ static int qed_ll2_acquire_connection_tx(struct 
qed_hwfn *p_hwfn,
goto out;
 
capacity = qed_chain_get_capacity(_ll2_info->tx_queue.txq_chain);
-   p_descq = kcalloc(capacity, sizeof(struct qed_ll2_tx_packet),
- GFP_KERNEL);
+   /* First element is part of the packet, rest are flexibly added */
+   desc_size = (sizeof(*p_descq) +
+(p_ll2_info->input.tx_max_bds_per_packet - 1) *
+sizeof(p_descq->bds_set));
+
+   p_descq = kcalloc(capacity, desc_size, GFP_KERNEL);
if (!p_descq) {
rc = -ENOMEM;
goto out;
}
-   p_ll2_info->tx_queue.descq_array = p_descq;
+   p_ll2_info->tx_queue.descq_mem = p_descq;
 
DP_VERBOSE(p_hwfn, QED_MSG_LL2,
   "Allocated LL2 Txq [Type %08x] with 0x%08x buffers\n",
@@ -1359,11 +1364,13 @@ int qed_ll2_establish_connection(void *cxt, u8 
connection_handle)
 {
struct qed_hwfn *p_hwfn = cxt;
struct qed_ll2_info *p_ll2_conn;
+   struct qed_ll2_tx_packet *p_pkt;
struct qed_ll2_rx_queue *p_rx;
struct qed_ll2_tx_queue *p_tx;
struct qed_ptt *p_ptt;
int rc = -EINVAL;
u32 i, capacity;
+   u32 desc_size;
u8 qid;
 
p_ptt = qed_ptt_acquire(p_hwfn);
@@ -1397,9 +1404,15 @@ int qed_ll2_establish_connection(void *cxt, u8 
connection_handle)
INIT_LIST_HEAD(_tx->sending_descq);
spin_lock_init(_tx->lock);
capacity = qed_chain_get_capacity(_tx->txq_chain);
-   for (i = 0; i < capacity; i++)
-   list_add_tail(_tx->descq_array[i].list_entry,
- _tx->free_descq);
+   /* First element is part of the packet, rest are flexibly added */
+   desc_size = (sizeof(*p_pkt) +
+(p_ll2_conn->input.tx_max_bds_per_packet - 1) *
+sizeof(p_pkt->bds_set));
+
+   for (i = 0; i < capacity; i++) {
+   p_pkt = p_tx->descq_mem + desc_size * i;
+   list_add_tail(_pkt->list_entry, _tx->free_descq);
+   }
p_tx->cur_completing_bd_idx = 0;
p_tx->bds_idx = 0;
p_tx->b_completing_packet = false;
@@ -1698,7 +1711,7 @@ int qed_ll2_prepare_tx_packet(void *cxt,
p_tx = _ll2_conn->tx_queue;
p_tx_chain = _tx->txq_chain;
 
-   if (pkt->num_of_bds > CORE_LL2_TX_MAX_BDS_PER_PACKET)
+   if (pkt->num_of_bds > p_ll2_conn->input.tx_max_bds_per_packet)
return -EIO;
 
spin_lock_irqsave(_tx->lock, flags);
@@ -1858,7 +1871,7 @@ void qed_ll2_release_connection(void *cxt, u8 
connection_handle)
qed_int_unregister_cb(p_hwfn, p_ll2_conn->tx_queue.tx_sb_index);
}
 
-   kfree(p_ll2_conn->tx_queue.descq_array);
+   kfree(p_ll2_conn->tx_queue.descq_mem);
qed_chain_free(p_hwfn->cdev, _ll2_conn->tx_queue.txq_chain);
 
kfree(p_ll2_conn->rx_queue.descq_array);
diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.h 
b/drivers/net/ethernet/qlogic/qed/qed_ll2.h
index a822528..9bdd08f 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_ll2.h
+++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.h
@@ -63,17 +63,14 @@ struct qed_ll2_rx_packet {
 struct qed_ll2_tx_packet {
struct list_head list_entry;
u16 bd_used;
-   u16 vlan;
-   u16 l4_hdr_offset_w;
-   u8 bd_flags;
bool notify_fw;
void *cookie;
-
+   /* Flexible Array of bds_set determined by max_bds_per_packet */
struct {
struct core_tx_bd *txq_bd;
dma_addr_t tx_frag;
u16 frag_len;
-   } bds_set[ETH_TX_MAX_BDS_PER_NON_LSO

[PATCH v3 net-next 02/12] qed: Add ll2 ability of opening a secondary queue

2017-10-09 Thread Michal Kalderon
When more than one ll2 queue is opened ( that is not an OOO queue )
ll2 code does not have enough information to determine whether
the queue is the main one or not, so a new field is added to the
acquire input data to expose the control of determining whether
the queue is the main queue or a secondary queue.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed_ll2.c | 7 ++-
 drivers/net/ethernet/qlogic/qed/qed_ll2.h | 1 +
 include/linux/qed/qed_ll2_if.h| 1 +
 3 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.c 
b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
index 75af40a..3c695da 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_ll2.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
@@ -894,7 +894,7 @@ static int qed_sp_ll2_rx_queue_start(struct qed_hwfn 
*p_hwfn,
p_ramrod->drop_ttl0_flg = p_ll2_conn->input.rx_drop_ttl0_flg;
p_ramrod->inner_vlan_removal_en = p_ll2_conn->input.rx_vlan_removal_en;
p_ramrod->queue_id = p_ll2_conn->queue_id;
-   p_ramrod->main_func_queue = (conn_type == QED_LL2_TYPE_OOO) ? 0 : 1;
+   p_ramrod->main_func_queue = p_ll2_conn->main_func_queue ? 1 : 0;
 
if ((IS_MF_DEFAULT(p_hwfn) || IS_MF_SI(p_hwfn)) &&
p_ramrod->main_func_queue && (conn_type != QED_LL2_TYPE_ROCE) &&
@@ -1265,6 +1265,11 @@ int qed_ll2_acquire_connection(void *cxt, struct 
qed_ll2_acquire_data *data)
 
p_ll2_info->tx_dest = (data->input.tx_dest == QED_LL2_TX_DEST_NW) ?
  CORE_TX_DEST_NW : CORE_TX_DEST_LB;
+   if (data->input.conn_type == QED_LL2_TYPE_OOO ||
+   data->input.secondary_queue)
+   p_ll2_info->main_func_queue = false;
+   else
+   p_ll2_info->main_func_queue = true;
 
/* Correct maximum number of Tx BDs */
p_tx_max = _ll2_info->input.tx_max_bds_per_packet;
diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.h 
b/drivers/net/ethernet/qlogic/qed/qed_ll2.h
index 9bdd08f..f658170 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_ll2.h
+++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.h
@@ -121,6 +121,7 @@ struct qed_ll2_info {
bool b_active;
enum core_tx_dest tx_dest;
u8 tx_stats_en;
+   bool main_func_queue;
struct qed_ll2_rx_queue rx_queue;
struct qed_ll2_tx_queue tx_queue;
struct qed_ll2_cbs cbs;
diff --git a/include/linux/qed/qed_ll2_if.h b/include/linux/qed/qed_ll2_if.h
index 89fa0bb..d7cca59 100644
--- a/include/linux/qed/qed_ll2_if.h
+++ b/include/linux/qed/qed_ll2_if.h
@@ -171,6 +171,7 @@ struct qed_ll2_acquire_data_inputs {
enum qed_ll2_tx_dest tx_dest;
enum qed_ll2_error_handle ai_err_packet_too_big;
enum qed_ll2_error_handle ai_err_no_buf;
+   bool secondary_queue;
u8 gsi_enable;
 };
 
-- 
1.8.3.1



[PATCH v3 net-next 00/12] qed: Add iWARP support for unaligned MPA packets

2017-10-09 Thread Michal Kalderon
This patch series adds support for handling unaligned MPA packets.
(FPDUs split over more than one tcp packet).
When FW detects a packet is unaligned it fowards the packet to 
the driver via a light l2 dedicated connection. The driver then 
stores this packet until the remainder of the packet is received.
Once the driver reconstructs the full FPDU, it sends it down
to fw via the ll2 connection. Driver also breaks down any packed
PDUs into separate packets for FW. 

Patches 1-6 are all slight modifications to ll2 to support additional
requirements for the unaligned MPA ll2 client.

Patch 7 opens the additional ll2 connection for iWARP.
Patches 8-12 contain the algorithm for aligning packets.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
No changes from v2:
Request for changes in ll2 rxq completion locking is deferred
to a separate patch series.
    
Michal Kalderon (12):
  qed: Add ll2 option to limit the number of bds per packet
  qed: Add ll2 ability of opening a secondary queue
  qed: Add ll2 option for dropping a tx packet
  qed: Fix initialization of ll2 offload feature
  qed: Add the source of a packet sent on an iWARP ll2 connection
  qed: Add LL2 slowpath handling
  qed: Add ll2 connection for processing unaligned MPA packets
  qed: Add mpa buffer descriptors for storing and processing mpa fpdus
  qed: Add unaligned and packed packet processing
  qed: Add support for freeing two ll2 buffers for corner cases
  qed: Add support for MPA header being split over two tcp packets
  qed: Add iWARP support for fpdu spanned over more than two tcp packets

 drivers/net/ethernet/qlogic/qed/qed_iwarp.c | 690 
 drivers/net/ethernet/qlogic/qed/qed_iwarp.h |  33 ++
 drivers/net/ethernet/qlogic/qed/qed_ll2.c   | 102 +++-
 drivers/net/ethernet/qlogic/qed/qed_ll2.h   |  10 +-
 include/linux/qed/qed_ll2_if.h  |   7 +
 5 files changed, 822 insertions(+), 20 deletions(-)

-- 
1.8.3.1



[PATCH v2 net-next 08/12] qed: Add mpa buffer descriptors for storing and processing mpa fpdus

2017-10-03 Thread Michal Kalderon
The mpa buff is a descriptor for iwarp ll2 buffers that contains
additional information required for aligining fpdu's.
In some cases, an additional packet will arrive which will complete
the alignment of a fpdu, but we won't be able to post the fpdu due to
insufficient place on the tx ring. In this case we can't loose the data
and require storing it for later. Processing is therefore done
in two places, during rx completion, where we initialize a mpa buffer
descriptor and add it to the pending list, and during tx-completion, since
we free up an entry in the tx chain we can process any pending mpa packets.
The mpa buff descriptors are pre-allocated since we have to ensure that
we won't reach a state where we can't store an incoming unaligned packet.
All packets received on the ll2 MUST be processed by the driver at some
stage. Since they are preallocated, we hold a free list.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed_iwarp.c | 116 
 drivers/net/ethernet/qlogic/qed/qed_iwarp.h |  11 +++
 2 files changed, 127 insertions(+)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c 
b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
index f413621..efd4861 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
@@ -1415,7 +1415,10 @@ int qed_iwarp_alloc(struct qed_hwfn *p_hwfn)
 
 void qed_iwarp_resc_free(struct qed_hwfn *p_hwfn)
 {
+   struct qed_iwarp_info *iwarp_info = _hwfn->p_rdma_info->iwarp;
+
qed_rdma_bmap_free(p_hwfn, _hwfn->p_rdma_info->tcp_cid_map, 1);
+   kfree(iwarp_info->mpa_bufs);
 }
 
 int qed_iwarp_accept(void *rdma_cxt, struct qed_iwarp_accept_in *iparams)
@@ -1716,12 +1719,103 @@ int qed_iwarp_reject(void *rdma_cxt, struct 
qed_iwarp_reject_in *iparams)
 /* fpdu can be fragmented over maximum 3 bds: header, partial mpa, unaligned */
 #define QED_IWARP_MAX_BDS_PER_FPDU 3
 static void
+qed_iwarp_mpa_get_data(struct qed_hwfn *p_hwfn,
+  struct unaligned_opaque_data *curr_pkt,
+  u32 opaque_data0, u32 opaque_data1)
+{
+   u64 opaque_data;
+
+   opaque_data = HILO_64(opaque_data1, opaque_data0);
+   *curr_pkt = *((struct unaligned_opaque_data *)_data);
+
+   curr_pkt->first_mpa_offset = curr_pkt->tcp_payload_offset +
+le16_to_cpu(curr_pkt->first_mpa_offset);
+   curr_pkt->cid = le32_to_cpu(curr_pkt->cid);
+}
+
+/* This function is called when an unaligned or incomplete MPA packet arrives
+ * driver needs to align the packet, perhaps using previous data and send
+ * it down to FW once it is aligned.
+ */
+static int
+qed_iwarp_process_mpa_pkt(struct qed_hwfn *p_hwfn,
+ struct qed_iwarp_ll2_mpa_buf *mpa_buf)
+{
+   struct qed_iwarp_ll2_buff *buf = mpa_buf->ll2_buf;
+   int rc = -EINVAL;
+
+   qed_iwarp_ll2_post_rx(p_hwfn,
+ buf,
+ p_hwfn->p_rdma_info->iwarp.ll2_mpa_handle);
+   return rc;
+}
+
+static void qed_iwarp_process_pending_pkts(struct qed_hwfn *p_hwfn)
+{
+   struct qed_iwarp_info *iwarp_info = _hwfn->p_rdma_info->iwarp;
+   struct qed_iwarp_ll2_mpa_buf *mpa_buf = NULL;
+   int rc;
+
+   while (!list_empty(_info->mpa_buf_pending_list)) {
+   mpa_buf = list_first_entry(_info->mpa_buf_pending_list,
+  struct qed_iwarp_ll2_mpa_buf,
+  list_entry);
+
+   rc = qed_iwarp_process_mpa_pkt(p_hwfn, mpa_buf);
+
+   /* busy means break and continue processing later, don't
+* remove the buf from the pending list.
+*/
+   if (rc == -EBUSY)
+   break;
+
+   list_del(_buf->list_entry);
+   list_add_tail(_buf->list_entry, _info->mpa_buf_list);
+
+   if (rc) {   /* different error, don't continue */
+   DP_NOTICE(p_hwfn, "process pkts failed rc=%d\n", rc);
+   break;
+   }
+   }
+}
+
+static void
 qed_iwarp_ll2_comp_mpa_pkt(void *cxt, struct qed_ll2_comp_rx_data *data)
 {
+   struct qed_iwarp_ll2_mpa_buf *mpa_buf;
struct qed_iwarp_info *iwarp_info;
struct qed_hwfn *p_hwfn = cxt;
 
iwarp_info = _hwfn->p_rdma_info->iwarp;
+   mpa_buf = list_first_entry(_info->mpa_buf_list,
+  struct qed_iwarp_ll2_mpa_buf, list_entry);
+   if (!mpa_buf) {
+   DP_ERR(p_hwfn, "No free mpa buf\n");
+   goto err;
+   }
+
+   list_del(_buf->list_entry);
+   qed_iwarp_mpa_get_data(p_hwfn, _buf->data,
+  data->opaque_data_

[PATCH v2 net-next 07/12] qed: Add ll2 connection for processing unaligned MPA packets

2017-10-03 Thread Michal Kalderon
This patch adds only the establishment and termination of the
ll2 connection that handles unaligned MPA packets.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed_iwarp.c | 65 +
 drivers/net/ethernet/qlogic/qed/qed_iwarp.h |  1 +
 2 files changed, 66 insertions(+)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c 
b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
index 8fc9c811..f413621 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
@@ -1713,6 +1713,19 @@ int qed_iwarp_reject(void *rdma_cxt, struct 
qed_iwarp_reject_in *iparams)
return 0;
 }
 
+/* fpdu can be fragmented over maximum 3 bds: header, partial mpa, unaligned */
+#define QED_IWARP_MAX_BDS_PER_FPDU 3
+static void
+qed_iwarp_ll2_comp_mpa_pkt(void *cxt, struct qed_ll2_comp_rx_data *data)
+{
+   struct qed_iwarp_info *iwarp_info;
+   struct qed_hwfn *p_hwfn = cxt;
+
+   iwarp_info = _hwfn->p_rdma_info->iwarp;
+   qed_iwarp_ll2_post_rx(p_hwfn, data->cookie,
+ iwarp_info->ll2_mpa_handle);
+}
+
 static void
 qed_iwarp_ll2_comp_syn_pkt(void *cxt, struct qed_ll2_comp_rx_data *data)
 {
@@ -1877,6 +1890,13 @@ static void qed_iwarp_ll2_rel_tx_pkt(void *cxt, u8 
connection_handle,
kfree(buffer);
 }
 
+void
+qed_iwarp_ll2_slowpath(void *cxt,
+  u8 connection_handle,
+  u32 opaque_data_0, u32 opaque_data_1)
+{
+}
+
 static int qed_iwarp_ll2_stop(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
 {
struct qed_iwarp_info *iwarp_info = _hwfn->p_rdma_info->iwarp;
@@ -1902,6 +1922,16 @@ static int qed_iwarp_ll2_stop(struct qed_hwfn *p_hwfn, 
struct qed_ptt *p_ptt)
iwarp_info->ll2_ooo_handle = QED_IWARP_HANDLE_INVAL;
}
 
+   if (iwarp_info->ll2_mpa_handle != QED_IWARP_HANDLE_INVAL) {
+   rc = qed_ll2_terminate_connection(p_hwfn,
+ iwarp_info->ll2_mpa_handle);
+   if (rc)
+   DP_INFO(p_hwfn, "Failed to terminate mpa connection\n");
+
+   qed_ll2_release_connection(p_hwfn, iwarp_info->ll2_mpa_handle);
+   iwarp_info->ll2_mpa_handle = QED_IWARP_HANDLE_INVAL;
+   }
+
qed_llh_remove_mac_filter(p_hwfn,
  p_ptt, p_hwfn->p_rdma_info->iwarp.mac_addr);
return rc;
@@ -1953,12 +1983,14 @@ static int qed_iwarp_ll2_stop(struct qed_hwfn *p_hwfn, 
struct qed_ptt *p_ptt)
struct qed_iwarp_info *iwarp_info;
struct qed_ll2_acquire_data data;
struct qed_ll2_cbs cbs;
+   u32 mpa_buff_size;
u16 n_ooo_bufs;
int rc = 0;
 
iwarp_info = _hwfn->p_rdma_info->iwarp;
iwarp_info->ll2_syn_handle = QED_IWARP_HANDLE_INVAL;
iwarp_info->ll2_ooo_handle = QED_IWARP_HANDLE_INVAL;
+   iwarp_info->ll2_mpa_handle = QED_IWARP_HANDLE_INVAL;
 
iwarp_info->max_mtu = params->max_mtu;
 
@@ -2029,6 +2061,39 @@ static int qed_iwarp_ll2_stop(struct qed_hwfn *p_hwfn, 
struct qed_ptt *p_ptt)
if (rc)
goto err;
 
+   /* Start Unaligned MPA connection */
+   cbs.rx_comp_cb = qed_iwarp_ll2_comp_mpa_pkt;
+   cbs.slowpath_cb = qed_iwarp_ll2_slowpath;
+
+   memset(, 0, sizeof(data));
+   data.input.conn_type = QED_LL2_TYPE_IWARP;
+   data.input.mtu = params->max_mtu;
+   /* FW requires that once a packet arrives OOO, it must have at
+* least 2 rx buffers available on the unaligned connection
+* for handling the case that it is a partial fpdu.
+*/
+   data.input.rx_num_desc = n_ooo_bufs * 2;
+   data.input.tx_num_desc = data.input.rx_num_desc;
+   data.input.tx_max_bds_per_packet = QED_IWARP_MAX_BDS_PER_FPDU;
+   data.p_connection_handle = _info->ll2_mpa_handle;
+   data.input.secondary_queue = true;
+   data.cbs = 
+
+   rc = qed_ll2_acquire_connection(p_hwfn, );
+   if (rc)
+   goto err;
+
+   rc = qed_ll2_establish_connection(p_hwfn, iwarp_info->ll2_mpa_handle);
+   if (rc)
+   goto err;
+
+   mpa_buff_size = QED_IWARP_MAX_BUF_SIZE(params->max_mtu);
+   rc = qed_iwarp_ll2_alloc_buffers(p_hwfn,
+data.input.rx_num_desc,
+mpa_buff_size,
+iwarp_info->ll2_mpa_handle);
+   if (rc)
+   goto err;
return rc;
 err:
qed_iwarp_ll2_stop(p_hwfn, p_ptt);
diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.h 
b/drivers/net/ethernet/qlogic/qed/qed_iwarp.h
index 9e2bfde..9d33a1f 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.h
+++ b/drivers/net/ethernet/qlogic/qed/qed_

[PATCH v2 net-next 06/12] qed: Add LL2 slowpath handling

2017-10-03 Thread Michal Kalderon
For iWARP unaligned MPA flow, a slowpath event of flushing an
MPA connection that entered an unaligned state is required.
The flush ramrod is received on the ll2 queue, and a pre-registered
callback function is called to handle the flush event.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed_ll2.c | 40 +--
 include/linux/qed/qed_ll2_if.h|  5 
 2 files changed, 43 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.c 
b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
index 8eb9645..047f556 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_ll2.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
@@ -423,6 +423,41 @@ static void qed_ll2_rxq_parse_reg(struct qed_hwfn *p_hwfn,
 }
 
 static int
+qed_ll2_handle_slowpath(struct qed_hwfn *p_hwfn,
+   struct qed_ll2_info *p_ll2_conn,
+   union core_rx_cqe_union *p_cqe,
+   unsigned long *p_lock_flags)
+{
+   struct qed_ll2_rx_queue *p_rx = _ll2_conn->rx_queue;
+   struct core_rx_slow_path_cqe *sp_cqe;
+
+   sp_cqe = _cqe->rx_cqe_sp;
+   if (sp_cqe->ramrod_cmd_id != CORE_RAMROD_RX_QUEUE_FLUSH) {
+   DP_NOTICE(p_hwfn,
+ "LL2 - unexpected Rx CQE slowpath ramrod_cmd_id:%d\n",
+ sp_cqe->ramrod_cmd_id);
+   return -EINVAL;
+   }
+
+   if (!p_ll2_conn->cbs.slowpath_cb) {
+   DP_NOTICE(p_hwfn,
+ "LL2 - received RX_QUEUE_FLUSH but no callback was 
provided\n");
+   return -EINVAL;
+   }
+
+   spin_unlock_irqrestore(_rx->lock, *p_lock_flags);
+
+   p_ll2_conn->cbs.slowpath_cb(p_ll2_conn->cbs.cookie,
+   p_ll2_conn->my_id,
+   le32_to_cpu(sp_cqe->opaque_data.data[0]),
+   le32_to_cpu(sp_cqe->opaque_data.data[1]));
+
+   spin_lock_irqsave(_rx->lock, *p_lock_flags);
+
+   return 0;
+}
+
+static int
 qed_ll2_rxq_handle_completion(struct qed_hwfn *p_hwfn,
  struct qed_ll2_info *p_ll2_conn,
  union core_rx_cqe_union *p_cqe,
@@ -495,8 +530,8 @@ static int qed_ll2_rxq_completion(struct qed_hwfn *p_hwfn, 
void *cookie)
 
switch (cqe->rx_cqe_sp.type) {
case CORE_RX_CQE_TYPE_SLOW_PATH:
-   DP_NOTICE(p_hwfn, "LL2 - unexpected Rx CQE slowpath\n");
-   rc = -EINVAL;
+   rc = qed_ll2_handle_slowpath(p_hwfn, p_ll2_conn,
+cqe, );
break;
case CORE_RX_CQE_TYPE_GSI_OFFLOAD:
case CORE_RX_CQE_TYPE_REGULAR:
@@ -1214,6 +1249,7 @@ static int qed_ll2_acquire_connection_tx(struct qed_hwfn 
*p_hwfn,
p_ll2_info->cbs.rx_release_cb = cbs->rx_release_cb;
p_ll2_info->cbs.tx_comp_cb = cbs->tx_comp_cb;
p_ll2_info->cbs.tx_release_cb = cbs->tx_release_cb;
+   p_ll2_info->cbs.slowpath_cb = cbs->slowpath_cb;
p_ll2_info->cbs.cookie = cbs->cookie;
 
return 0;
diff --git a/include/linux/qed/qed_ll2_if.h b/include/linux/qed/qed_ll2_if.h
index 95fdf02..e755954 100644
--- a/include/linux/qed/qed_ll2_if.h
+++ b/include/linux/qed/qed_ll2_if.h
@@ -151,11 +151,16 @@ struct qed_ll2_comp_rx_data {
 dma_addr_t first_frag_addr,
 bool b_last_fragment, bool b_last_packet);
 
+typedef
+void (*qed_ll2_slowpath_cb)(void *cxt, u8 connection_handle,
+   u32 opaque_data_0, u32 opaque_data_1);
+
 struct qed_ll2_cbs {
qed_ll2_complete_rx_packet_cb rx_comp_cb;
qed_ll2_release_rx_packet_cb rx_release_cb;
qed_ll2_complete_tx_packet_cb tx_comp_cb;
qed_ll2_release_tx_packet_cb tx_release_cb;
+   qed_ll2_slowpath_cb slowpath_cb;
void *cookie;
 };
 
-- 
1.8.3.1



[PATCH v2 net-next 10/12] qed: Add support for freeing two ll2 buffers for corner cases

2017-10-03 Thread Michal Kalderon
When posting a packet on the ll2 tx, we can provide a cookie that
will be returned upon tx completion. This cookie is the ll2 iwarp buffer
which is then reposted to the rx ring. Part of the unaligned mpa flow
is determining when a buffer can be reposted. Each buffer needs to be
sent only once as a cookie for on the tx ring. In packed fpdu case, only
the last packet will be sent with the buffer, meaning we need to handle the
case that a cookie can be NULL on tx complete. In addition, when a fpdu
splits over two buffers, but there are no more fpdus on the second buffer,
two buffers need to be provided as a cookie. To avoid changing the ll2
interface to provide two cookies, we introduce a piggy buf pointer,
relevant for iWARP only, that holds a pointer to a second buffer that
needs to be released during tx completion.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed_iwarp.c | 25 +
 drivers/net/ethernet/qlogic/qed/qed_iwarp.h |  1 +
 2 files changed, 26 insertions(+)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c 
b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
index 83b147f..8b17369 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
@@ -1846,6 +1846,12 @@ enum qed_iwarp_mpa_pkt_type {
/* vlan overload with enum iwarp_ll2_tx_queues */
tx_pkt.vlan = IWARP_LL2_ALIGNED_TX_QUEUE;
 
+   /* special case of unaligned packet and not packed, need to send
+* both buffers as cookie to release.
+*/
+   if (tcp_payload_size == fpdu->incomplete_bytes)
+   fpdu->mpa_buf->piggy_buf = buf;
+
ll2_handle = p_hwfn->p_rdma_info->iwarp.ll2_mpa_handle;
 
/* Set first fragment to header */
@@ -2195,9 +2201,19 @@ static void qed_iwarp_ll2_comp_tx_pkt(void *cxt, u8 
connection_handle,
  bool b_last_fragment, bool b_last_packet)
 {
struct qed_iwarp_ll2_buff *buffer = cookie;
+   struct qed_iwarp_ll2_buff *piggy;
struct qed_hwfn *p_hwfn = cxt;
 
+   if (!buffer)/* can happen in packed mpa unaligned... */
+   return;
+
/* this was originally an rx packet, post it back */
+   piggy = buffer->piggy_buf;
+   if (piggy) {
+   buffer->piggy_buf = NULL;
+   qed_iwarp_ll2_post_rx(p_hwfn, piggy, connection_handle);
+   }
+
qed_iwarp_ll2_post_rx(p_hwfn, buffer, connection_handle);
 
if (connection_handle == p_hwfn->p_rdma_info->iwarp.ll2_mpa_handle)
@@ -2216,6 +2232,15 @@ static void qed_iwarp_ll2_rel_tx_pkt(void *cxt, u8 
connection_handle,
if (!buffer)
return;
 
+   if (buffer->piggy_buf) {
+   dma_free_coherent(_hwfn->cdev->pdev->dev,
+ buffer->piggy_buf->buff_size,
+ buffer->piggy_buf->data,
+ buffer->piggy_buf->data_phys_addr);
+
+   kfree(buffer->piggy_buf);
+   }
+
dma_free_coherent(_hwfn->cdev->pdev->dev, buffer->buff_size,
  buffer->data, buffer->data_phys_addr);
 
diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.h 
b/drivers/net/ethernet/qlogic/qed/qed_iwarp.h
index 858755c..58db51a 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.h
+++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.h
@@ -55,6 +55,7 @@ enum qed_iwarp_qp_state {
 #define QED_IWARP_HANDLE_INVAL (0xff)
 
 struct qed_iwarp_ll2_buff {
+   struct qed_iwarp_ll2_buff *piggy_buf;
void *data;
dma_addr_t data_phys_addr;
u32 buff_size;
-- 
1.8.3.1



[PATCH v2 net-next 12/12] qed: Add iWARP support for fpdu spanned over more than two tcp packets

2017-10-03 Thread Michal Kalderon
We continue to maintain a maximum of three buffers per fpdu, to ensure
that there are enough buffers for additional unaligned mpa packets.
To support this, if a fpdu is split over more than two tcp packets, we
use an intermediate buffer to copy the data to the previous buffer, then
we can release the data. We need an intermediate buffer as the initial
buffer partial packet could be located at the end of the packet, not
leaving room for additional data. This is a corner case, and will usually
not be the case.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed_iwarp.c | 193 
 drivers/net/ethernet/qlogic/qed/qed_iwarp.h |   1 +
 2 files changed, 194 insertions(+)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c 
b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
index 2994942..b2b1f87 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
@@ -1420,6 +1420,7 @@ void qed_iwarp_resc_free(struct qed_hwfn *p_hwfn)
qed_rdma_bmap_free(p_hwfn, _hwfn->p_rdma_info->tcp_cid_map, 1);
kfree(iwarp_info->mpa_bufs);
kfree(iwarp_info->partial_fpdus);
+   kfree(iwarp_info->mpa_intermediate_buf);
 }
 
 int qed_iwarp_accept(void *rdma_cxt, struct qed_iwarp_accept_in *iparams)
@@ -1762,6 +1763,11 @@ enum qed_iwarp_mpa_pkt_type {
"QED_IWARP_MPA_PKT_UNALIGNED"
 };
 
+static int
+qed_iwarp_recycle_pkt(struct qed_hwfn *p_hwfn,
+ struct qed_iwarp_fpdu *fpdu,
+ struct qed_iwarp_ll2_buff *buf);
+
 static enum qed_iwarp_mpa_pkt_type
 qed_iwarp_mpa_classify(struct qed_hwfn *p_hwfn,
   struct qed_iwarp_fpdu *fpdu,
@@ -1822,6 +1828,68 @@ enum qed_iwarp_mpa_pkt_type {
fpdu->mpa_frag_len = fpdu->fpdu_length - fpdu->incomplete_bytes;
 }
 
+static int
+qed_iwarp_cp_pkt(struct qed_hwfn *p_hwfn,
+struct qed_iwarp_fpdu *fpdu,
+struct unaligned_opaque_data *pkt_data,
+struct qed_iwarp_ll2_buff *buf, u16 tcp_payload_size)
+{
+   u8 *tmp_buf = p_hwfn->p_rdma_info->iwarp.mpa_intermediate_buf;
+   int rc;
+
+   /* need to copy the data from the partial packet stored in fpdu
+* to the new buf, for this we also need to move the data currently
+* placed on the buf. The assumption is that the buffer is big enough
+* since fpdu_length <= mss, we use an intermediate buffer since
+* we may need to copy the new data to an overlapping location
+*/
+   if ((fpdu->mpa_frag_len + tcp_payload_size) > (u16)buf->buff_size) {
+   DP_ERR(p_hwfn,
+  "MPA ALIGN: Unexpected: buffer is not large enough for 
split fpdu buff_size = %d mpa_frag_len = %d, tcp_payload_size = %d, 
incomplete_bytes = %d\n",
+  buf->buff_size, fpdu->mpa_frag_len,
+  tcp_payload_size, fpdu->incomplete_bytes);
+   return -EINVAL;
+   }
+
+   DP_VERBOSE(p_hwfn, QED_MSG_RDMA,
+  "MPA ALIGN Copying fpdu: [%p, %d] [%p, %d]\n",
+  fpdu->mpa_frag_virt, fpdu->mpa_frag_len,
+  (u8 *)(buf->data) + pkt_data->first_mpa_offset,
+  tcp_payload_size);
+
+   memcpy(tmp_buf, fpdu->mpa_frag_virt, fpdu->mpa_frag_len);
+   memcpy(tmp_buf + fpdu->mpa_frag_len,
+  (u8 *)(buf->data) + pkt_data->first_mpa_offset,
+  tcp_payload_size);
+
+   rc = qed_iwarp_recycle_pkt(p_hwfn, fpdu, fpdu->mpa_buf);
+   if (rc)
+   return rc;
+
+   /* If we managed to post the buffer copy the data to the new buffer
+* o/w this will occur in the next round...
+*/
+   memcpy((u8 *)(buf->data), tmp_buf,
+  fpdu->mpa_frag_len + tcp_payload_size);
+
+   fpdu->mpa_buf = buf;
+   /* fpdu->pkt_hdr remains as is */
+   /* fpdu->mpa_frag is overridden with new buf */
+   fpdu->mpa_frag = buf->data_phys_addr;
+   fpdu->mpa_frag_virt = buf->data;
+   fpdu->mpa_frag_len += tcp_payload_size;
+
+   fpdu->incomplete_bytes -= tcp_payload_size;
+
+   DP_VERBOSE(p_hwfn,
+  QED_MSG_RDMA,
+  "MPA ALIGN: split fpdu buff_size = %d mpa_frag_len = %d, 
tcp_payload_size = %d, incomplete_bytes = %d\n",
+  buf->buff_size, fpdu->mpa_frag_len, tcp_payload_size,
+  fpdu->incomplete_bytes);
+
+   return 0;
+}
+
 static void
 qed_iwarp_update_fpdu_length(struct qed_hwfn *p_hwfn,
 struct qed_iwarp_fpdu *fpdu, u8 *mpa_data)
@@ -1843,6 +1911,90 @@ enum qed_iwarp_mpa_pkt_type {
}
 }
 
+#define QED_IWARP_IS_RIGHT_EDGE(_curr_pkt) \
+   (GET_

[PATCH v2 net-next 11/12] qed: Add support for MPA header being split over two tcp packets

2017-10-03 Thread Michal Kalderon
There is a special case where an MPA header is split over to tcp
packets, in this case we need to wait for the next packet to
get the fpdu length. We use the incomplete_bytes to mark this
fpdu as a "special" one which requires updating the length with
the next packet

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed_iwarp.c | 36 -
 drivers/net/ethernet/qlogic/qed/qed_iwarp.h |  6 +
 2 files changed, 41 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c 
b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
index 8b17369..2994942 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
@@ -1742,6 +1742,7 @@ enum qed_iwarp_mpa_pkt_type {
QED_IWARP_MPA_PKT_UNALIGNED
 };
 
+#define QED_IWARP_INVALID_FPDU_LENGTH 0x
 #define QED_IWARP_MPA_FPDU_LENGTH_SIZE (2)
 #define QED_IWARP_MPA_CRC32_DIGEST_SIZE (4)
 
@@ -1774,6 +1775,15 @@ enum qed_iwarp_mpa_pkt_type {
goto out;
}
 
+   /* special case of one byte remaining...
+* lower byte will be read next packet
+*/
+   if (tcp_payload_len == 1) {
+   fpdu->fpdu_length = *mpa_data << BITS_PER_BYTE;
+   pkt_type = QED_IWARP_MPA_PKT_PARTIAL;
+   goto out;
+   }
+
mpa_len = ntohs(*((u16 *)(mpa_data)));
fpdu->fpdu_length = QED_IWARP_FPDU_LEN_WITH_PAD(mpa_len);
 
@@ -1802,7 +1812,9 @@ enum qed_iwarp_mpa_pkt_type {
fpdu->mpa_frag = buf->data_phys_addr + pkt_data->first_mpa_offset;
fpdu->mpa_frag_virt = (u8 *)(buf->data) + pkt_data->first_mpa_offset;
 
-   if (tcp_payload_size < fpdu->fpdu_length)
+   if (tcp_payload_size == 1)
+   fpdu->incomplete_bytes = QED_IWARP_INVALID_FPDU_LENGTH;
+   else if (tcp_payload_size < fpdu->fpdu_length)
fpdu->incomplete_bytes = fpdu->fpdu_length - tcp_payload_size;
else
fpdu->incomplete_bytes = 0; /* complete fpdu */
@@ -1810,6 +1822,27 @@ enum qed_iwarp_mpa_pkt_type {
fpdu->mpa_frag_len = fpdu->fpdu_length - fpdu->incomplete_bytes;
 }
 
+static void
+qed_iwarp_update_fpdu_length(struct qed_hwfn *p_hwfn,
+struct qed_iwarp_fpdu *fpdu, u8 *mpa_data)
+{
+   u16 mpa_len;
+
+   /* Update incomplete packets if needed */
+   if (fpdu->incomplete_bytes == QED_IWARP_INVALID_FPDU_LENGTH) {
+   /* Missing lower byte is now available */
+   mpa_len = fpdu->fpdu_length | *mpa_data;
+   fpdu->fpdu_length = QED_IWARP_FPDU_LEN_WITH_PAD(mpa_len);
+   fpdu->mpa_frag_len = fpdu->fpdu_length;
+   /* one byte of hdr */
+   fpdu->incomplete_bytes = fpdu->fpdu_length - 1;
+   DP_VERBOSE(p_hwfn,
+  QED_MSG_RDMA,
+  "MPA_ALIGN: Partial header mpa_len=%x fpdu_length=%x 
incomplete_bytes=%x\n",
+  mpa_len, fpdu->fpdu_length, fpdu->incomplete_bytes);
+   }
+}
+
 static int
 qed_iwarp_send_fpdu(struct qed_hwfn *p_hwfn,
struct qed_iwarp_fpdu *fpdu,
@@ -1960,6 +1993,7 @@ enum qed_iwarp_mpa_pkt_type {
curr_pkt->first_mpa_offset += fpdu->fpdu_length;
break;
case QED_IWARP_MPA_PKT_UNALIGNED:
+   qed_iwarp_update_fpdu_length(p_hwfn, fpdu, mpa_data);
rc = qed_iwarp_send_fpdu(p_hwfn, fpdu, curr_pkt, buf,
 mpa_buf->tcp_payload_len,
 pkt_type);
diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.h 
b/drivers/net/ethernet/qlogic/qed/qed_iwarp.h
index 58db51a..c58793a 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.h
+++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.h
@@ -69,6 +69,12 @@ struct qed_iwarp_ll2_mpa_buf {
u8 placement_offset;
 };
 
+/* In some cases a fpdu will arrive with only one byte of the header, in this
+ * case the fpdu_length will be partial (contain only higher byte and
+ * incomplete bytes will contain the invalid value
+ */
+#define QED_IWARP_INVALID_INCOMPLETE_BYTES 0x
+
 struct qed_iwarp_fpdu {
struct qed_iwarp_ll2_buff *mpa_buf;
void *mpa_frag_virt;
-- 
1.8.3.1



[PATCH v2 net-next 05/12] qed: Add the source of a packet sent on an iWARP ll2 connection

2017-10-03 Thread Michal Kalderon
When a packet is sent back to iWARP FW via the tx ll2 connection
the FW needs to know the source of the packet. Whether it is
OOO or unaligned MPA related. Since OOO is implemented entirely
inside the ll2 code (and shared with iSCSI), packets are marked
as IN_ORDER inside the ll2 code. For unaligned mpa the value
will be determined in the iWARP code and sent on the pkt->vlan
field.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed_ll2.c | 7 ++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.c 
b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
index 6d14474..8eb9645 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_ll2.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
@@ -1613,7 +1613,12 @@ static void qed_ll2_prepare_tx_packet_set(struct 
qed_hwfn *p_hwfn,
}
 
start_bd = (struct core_tx_bd *)qed_chain_produce(p_tx_chain);
-   start_bd->nw_vlan_or_lb_echo = cpu_to_le16(pkt->vlan);
+   if (QED_IS_IWARP_PERSONALITY(p_hwfn) &&
+   p_ll2->input.conn_type == QED_LL2_TYPE_OOO)
+   start_bd->nw_vlan_or_lb_echo =
+   cpu_to_le16(IWARP_LL2_IN_ORDER_TX_QUEUE);
+   else
+   start_bd->nw_vlan_or_lb_echo = cpu_to_le16(pkt->vlan);
SET_FIELD(start_bd->bitfield1, CORE_TX_BD_L4_HDR_OFFSET_W,
  cpu_to_le16(pkt->l4_hdr_offset_w));
SET_FIELD(start_bd->bitfield1, CORE_TX_BD_TX_DST, tx_dest);
-- 
1.8.3.1



[PATCH v2 net-next 04/12] qed: Fix initialization of ll2 offload feature

2017-10-03 Thread Michal Kalderon
enable_ip_cksum, enable_l4_cksum, calc_ip_len were added in
commit stated below but not passed through to FW. This was OK
until now as it wasn't used, but is required for the iWARP
unaligned flow

Fixes:7c7973b2ae27 ("qed: LL2 to use packed information for tx")

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed_ll2.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.c 
b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
index ad67d36..6d14474 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_ll2.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
@@ -1621,6 +1621,9 @@ static void qed_ll2_prepare_tx_packet_set(struct qed_hwfn 
*p_hwfn,
SET_FIELD(bd_data, CORE_TX_BD_DATA_START_BD, 0x1);
SET_FIELD(bd_data, CORE_TX_BD_DATA_NBDS, pkt->num_of_bds);
SET_FIELD(bd_data, CORE_TX_BD_DATA_ROCE_FLAV, roce_flavor);
+   SET_FIELD(bd_data, CORE_TX_BD_DATA_IP_CSUM, !!(pkt->enable_ip_cksum));
+   SET_FIELD(bd_data, CORE_TX_BD_DATA_L4_CSUM, !!(pkt->enable_l4_cksum));
+   SET_FIELD(bd_data, CORE_TX_BD_DATA_IP_LEN, !!(pkt->calc_ip_len));
start_bd->bd_data.as_bitfield = cpu_to_le16(bd_data);
DMA_REGPAIR_LE(start_bd->addr, pkt->first_frag);
start_bd->nbytes = cpu_to_le16(pkt->first_frag_len);
-- 
1.8.3.1



[PATCH v2 net-next 09/12] qed: Add unaligned and packed packet processing

2017-10-03 Thread Michal Kalderon
The fpdu data structure is preallocated per connection.
Each connection stores the current status of the connection:
either nothing pending, or there is a partial fpdu that is waiting for
the rest of the fpdu (incomplete bytes != 0).
The same structure is also used for splitting a packet when there are
packed fpdus. The structure is initialized with all data required
for sending the fpdu back to the FW. A fpdu will always be spanned across
a maximum of 3 tx bds. One for the header, one for the partial fdpu
received and one for the remainder (unaligned) packet.
In case of packed fpdu's, two fragments are used, one for the header
and one for the data.
Corner cases are not handled in the patch for clarity, and will be added
as a separate patch.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed_iwarp.c | 257 
 drivers/net/ethernet/qlogic/qed/qed_iwarp.h |  13 ++
 2 files changed, 270 insertions(+)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c 
b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
index efd4861..83b147f 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
@@ -1419,6 +1419,7 @@ void qed_iwarp_resc_free(struct qed_hwfn *p_hwfn)
 
qed_rdma_bmap_free(p_hwfn, _hwfn->p_rdma_info->tcp_cid_map, 1);
kfree(iwarp_info->mpa_bufs);
+   kfree(iwarp_info->partial_fpdus);
 }
 
 int qed_iwarp_accept(void *rdma_cxt, struct qed_iwarp_accept_in *iparams)
@@ -1716,8 +1717,170 @@ int qed_iwarp_reject(void *rdma_cxt, struct 
qed_iwarp_reject_in *iparams)
return 0;
 }
 
+static struct qed_iwarp_fpdu *qed_iwarp_get_curr_fpdu(struct qed_hwfn *p_hwfn,
+ u16 cid)
+{
+   struct qed_iwarp_info *iwarp_info = _hwfn->p_rdma_info->iwarp;
+   struct qed_iwarp_fpdu *partial_fpdu;
+   u32 idx;
+
+   idx = cid - qed_cxt_get_proto_cid_start(p_hwfn, PROTOCOLID_IWARP);
+   if (idx >= iwarp_info->max_num_partial_fpdus) {
+   DP_ERR(p_hwfn, "Invalid cid %x max_num_partial_fpdus=%x\n", cid,
+  iwarp_info->max_num_partial_fpdus);
+   return NULL;
+   }
+
+   partial_fpdu = _info->partial_fpdus[idx];
+
+   return partial_fpdu;
+}
+
+enum qed_iwarp_mpa_pkt_type {
+   QED_IWARP_MPA_PKT_PACKED,
+   QED_IWARP_MPA_PKT_PARTIAL,
+   QED_IWARP_MPA_PKT_UNALIGNED
+};
+
+#define QED_IWARP_MPA_FPDU_LENGTH_SIZE (2)
+#define QED_IWARP_MPA_CRC32_DIGEST_SIZE (4)
+
+/* Pad to multiple of 4 */
+#define QED_IWARP_PDU_DATA_LEN_WITH_PAD(data_len) ALIGN(data_len, 4)
+#define QED_IWARP_FPDU_LEN_WITH_PAD(_mpa_len) \
+   (QED_IWARP_PDU_DATA_LEN_WITH_PAD((_mpa_len) +  \
+QED_IWARP_MPA_FPDU_LENGTH_SIZE) + \
+QED_IWARP_MPA_CRC32_DIGEST_SIZE)
+
 /* fpdu can be fragmented over maximum 3 bds: header, partial mpa, unaligned */
 #define QED_IWARP_MAX_BDS_PER_FPDU 3
+
+char *pkt_type_str[] = {
+   "QED_IWARP_MPA_PKT_PACKED",
+   "QED_IWARP_MPA_PKT_PARTIAL",
+   "QED_IWARP_MPA_PKT_UNALIGNED"
+};
+
+static enum qed_iwarp_mpa_pkt_type
+qed_iwarp_mpa_classify(struct qed_hwfn *p_hwfn,
+  struct qed_iwarp_fpdu *fpdu,
+  u16 tcp_payload_len, u8 *mpa_data)
+{
+   enum qed_iwarp_mpa_pkt_type pkt_type;
+   u16 mpa_len;
+
+   if (fpdu->incomplete_bytes) {
+   pkt_type = QED_IWARP_MPA_PKT_UNALIGNED;
+   goto out;
+   }
+
+   mpa_len = ntohs(*((u16 *)(mpa_data)));
+   fpdu->fpdu_length = QED_IWARP_FPDU_LEN_WITH_PAD(mpa_len);
+
+   if (fpdu->fpdu_length <= tcp_payload_len)
+   pkt_type = QED_IWARP_MPA_PKT_PACKED;
+   else
+   pkt_type = QED_IWARP_MPA_PKT_PARTIAL;
+
+out:
+   DP_VERBOSE(p_hwfn, QED_MSG_RDMA,
+  "MPA_ALIGN: %s: fpdu_length=0x%x tcp_payload_len:0x%x\n",
+  pkt_type_str[pkt_type], fpdu->fpdu_length, tcp_payload_len);
+
+   return pkt_type;
+}
+
+static void
+qed_iwarp_init_fpdu(struct qed_iwarp_ll2_buff *buf,
+   struct qed_iwarp_fpdu *fpdu,
+   struct unaligned_opaque_data *pkt_data,
+   u16 tcp_payload_size, u8 placement_offset)
+{
+   fpdu->mpa_buf = buf;
+   fpdu->pkt_hdr = buf->data_phys_addr + placement_offset;
+   fpdu->pkt_hdr_size = pkt_data->tcp_payload_offset;
+   fpdu->mpa_frag = buf->data_phys_addr + pkt_data->first_mpa_offset;
+   fpdu->mpa_frag_virt = (u8 *)(buf->data) + pkt_data->first_mpa_offset;
+
+   if (tcp_payload_size < fpdu->fpdu_length)
+   fpdu->incomplete_bytes = fpdu-

[PATCH v2 net-next 01/12] qed: Add ll2 option to limit the number of bds per packet

2017-10-03 Thread Michal Kalderon
iWARP uses 3 ll2 connections, the maximum number of bds is known
during connection setup. This patch modifies the static array in
the ll2_tx_packet descriptor to be a flexible array and
significantlly reduces memory size.

In addition, some redundant fields in the ll2_tx_packet were
removed, which also contributed to decreasing the descriptor size.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed_ll2.c | 29 +
 drivers/net/ethernet/qlogic/qed/qed_ll2.h |  9 +++--
 2 files changed, 24 insertions(+), 14 deletions(-)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.c 
b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
index 250afa5..75af40a 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_ll2.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
@@ -1105,6 +1105,7 @@ static int qed_ll2_acquire_connection_tx(struct qed_hwfn 
*p_hwfn,
 struct qed_ll2_info *p_ll2_info)
 {
struct qed_ll2_tx_packet *p_descq;
+   u32 desc_size;
u32 capacity;
int rc = 0;
 
@@ -1122,13 +1123,17 @@ static int qed_ll2_acquire_connection_tx(struct 
qed_hwfn *p_hwfn,
goto out;
 
capacity = qed_chain_get_capacity(_ll2_info->tx_queue.txq_chain);
-   p_descq = kcalloc(capacity, sizeof(struct qed_ll2_tx_packet),
- GFP_KERNEL);
+   /* First element is part of the packet, rest are flexibly added */
+   desc_size = (sizeof(*p_descq) +
+(p_ll2_info->input.tx_max_bds_per_packet - 1) *
+sizeof(p_descq->bds_set));
+
+   p_descq = kcalloc(capacity, desc_size, GFP_KERNEL);
if (!p_descq) {
rc = -ENOMEM;
goto out;
}
-   p_ll2_info->tx_queue.descq_array = p_descq;
+   p_ll2_info->tx_queue.descq_mem = p_descq;
 
DP_VERBOSE(p_hwfn, QED_MSG_LL2,
   "Allocated LL2 Txq [Type %08x] with 0x%08x buffers\n",
@@ -1359,11 +1364,13 @@ int qed_ll2_establish_connection(void *cxt, u8 
connection_handle)
 {
struct qed_hwfn *p_hwfn = cxt;
struct qed_ll2_info *p_ll2_conn;
+   struct qed_ll2_tx_packet *p_pkt;
struct qed_ll2_rx_queue *p_rx;
struct qed_ll2_tx_queue *p_tx;
struct qed_ptt *p_ptt;
int rc = -EINVAL;
u32 i, capacity;
+   u32 desc_size;
u8 qid;
 
p_ptt = qed_ptt_acquire(p_hwfn);
@@ -1397,9 +1404,15 @@ int qed_ll2_establish_connection(void *cxt, u8 
connection_handle)
INIT_LIST_HEAD(_tx->sending_descq);
spin_lock_init(_tx->lock);
capacity = qed_chain_get_capacity(_tx->txq_chain);
-   for (i = 0; i < capacity; i++)
-   list_add_tail(_tx->descq_array[i].list_entry,
- _tx->free_descq);
+   /* First element is part of the packet, rest are flexibly added */
+   desc_size = (sizeof(*p_pkt) +
+(p_ll2_conn->input.tx_max_bds_per_packet - 1) *
+sizeof(p_pkt->bds_set));
+
+   for (i = 0; i < capacity; i++) {
+   p_pkt = p_tx->descq_mem + desc_size * i;
+   list_add_tail(_pkt->list_entry, _tx->free_descq);
+   }
p_tx->cur_completing_bd_idx = 0;
p_tx->bds_idx = 0;
p_tx->b_completing_packet = false;
@@ -1698,7 +1711,7 @@ int qed_ll2_prepare_tx_packet(void *cxt,
p_tx = _ll2_conn->tx_queue;
p_tx_chain = _tx->txq_chain;
 
-   if (pkt->num_of_bds > CORE_LL2_TX_MAX_BDS_PER_PACKET)
+   if (pkt->num_of_bds > p_ll2_conn->input.tx_max_bds_per_packet)
return -EIO;
 
spin_lock_irqsave(_tx->lock, flags);
@@ -1858,7 +1871,7 @@ void qed_ll2_release_connection(void *cxt, u8 
connection_handle)
qed_int_unregister_cb(p_hwfn, p_ll2_conn->tx_queue.tx_sb_index);
}
 
-   kfree(p_ll2_conn->tx_queue.descq_array);
+   kfree(p_ll2_conn->tx_queue.descq_mem);
qed_chain_free(p_hwfn->cdev, _ll2_conn->tx_queue.txq_chain);
 
kfree(p_ll2_conn->rx_queue.descq_array);
diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.h 
b/drivers/net/ethernet/qlogic/qed/qed_ll2.h
index a822528..9bdd08f 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_ll2.h
+++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.h
@@ -63,17 +63,14 @@ struct qed_ll2_rx_packet {
 struct qed_ll2_tx_packet {
struct list_head list_entry;
u16 bd_used;
-   u16 vlan;
-   u16 l4_hdr_offset_w;
-   u8 bd_flags;
bool notify_fw;
void *cookie;
-
+   /* Flexible Array of bds_set determined by max_bds_per_packet */
struct {
struct core_tx_bd *txq_bd;
dma_addr_t tx_frag;
u16 frag_len;
-   } bds_set[ETH_TX_MAX_BDS_PER_NON_LSO

[PATCH v2 net-next 00/12] qed: Add iWARP support for unaligned MPA packets

2017-10-03 Thread Michal Kalderon
This patch series adds support for handling unaligned MPA packets.
(FPDUs split over more than one tcp packet).
When FW detects a packet is unaligned it fowards the packet to 
the driver via a light l2 dedicated connection. The driver then 
stores this packet until the remainder of the packet is received.
Once the driver reconstructs the full FPDU, it sends it down
to fw via the ll2 connection. Driver also breaks down any packed
PDUs into separate packets for FW. 

Patches 1-6 are all slight modifications to ll2 to support additional
requirements for the unaligned MPA ll2 client.

Patch 7 opens the additional ll2 connection for iWARP.
Patches 8-12 contain the algorithm for aligning packets.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
Changes from v1:
patch #1: tx descq_array changed to void pointer and name
  changed accordingly to descq_mem.
patch #2: modify boolean variables to be of type bool.

Michal Kalderon (12):
  qed: Add ll2 option to limit the number of bds per packet
  qed: Add ll2 ability of opening a secondary queue
  qed: Add ll2 option for dropping a tx packet
  qed: Fix initialization of ll2 offload feature
  qed: Add the source of a packet sent on an iWARP ll2 connection
  qed: Add LL2 slowpath handling
  qed: Add ll2 connection for processing unaligned MPA packets
  qed: Add mpa buffer descriptors for storing and processing mpa fpdus
  qed: Add unaligned and packed packet processing
  qed: Add support for freeing two ll2 buffers for corner cases
  qed: Add support for MPA header being split over two tcp packets
  qed: Add iWARP support for fpdu spanned over more than two tcp packets

 drivers/net/ethernet/qlogic/qed/qed_iwarp.c | 690 
 drivers/net/ethernet/qlogic/qed/qed_iwarp.h |  33 ++
 drivers/net/ethernet/qlogic/qed/qed_ll2.c   | 102 +++-
 drivers/net/ethernet/qlogic/qed/qed_ll2.h   |  10 +-
 include/linux/qed/qed_ll2_if.h  |   7 +
 5 files changed, 822 insertions(+), 20 deletions(-)

-- 
1.8.3.1



[PATCH v2 net-next 03/12] qed: Add ll2 option for dropping a tx packet

2017-10-03 Thread Michal Kalderon
The option of sending a packet on the ll2 and dropping it exists in
hardware and was not used until now, thus not exposed.
The iWARP unaligned MPA flow requires this functionality for
flushing the tx queue.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed_ll2.c | 16 ++--
 include/linux/qed/qed_ll2_if.h|  1 +
 2 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.c 
b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
index 3c695da..ad67d36 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_ll2.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
@@ -1597,8 +1597,20 @@ static void qed_ll2_prepare_tx_packet_set(struct 
qed_hwfn *p_hwfn,
roce_flavor = (pkt->qed_roce_flavor == QED_LL2_ROCE) ? CORE_ROCE
 : CORE_RROCE;
 
-   tx_dest = (pkt->tx_dest == QED_LL2_TX_DEST_NW) ? CORE_TX_DEST_NW
-  : CORE_TX_DEST_LB;
+   switch (pkt->tx_dest) {
+   case QED_LL2_TX_DEST_NW:
+   tx_dest = CORE_TX_DEST_NW;
+   break;
+   case QED_LL2_TX_DEST_LB:
+   tx_dest = CORE_TX_DEST_LB;
+   break;
+   case QED_LL2_TX_DEST_DROP:
+   tx_dest = CORE_TX_DEST_DROP;
+   break;
+   default:
+   tx_dest = CORE_TX_DEST_LB;
+   break;
+   }
 
start_bd = (struct core_tx_bd *)qed_chain_produce(p_tx_chain);
start_bd->nw_vlan_or_lb_echo = cpu_to_le16(pkt->vlan);
diff --git a/include/linux/qed/qed_ll2_if.h b/include/linux/qed/qed_ll2_if.h
index d7cca59..95fdf02 100644
--- a/include/linux/qed/qed_ll2_if.h
+++ b/include/linux/qed/qed_ll2_if.h
@@ -64,6 +64,7 @@ enum qed_ll2_roce_flavor_type {
 enum qed_ll2_tx_dest {
QED_LL2_TX_DEST_NW, /* Light L2 TX Destination to the Network */
QED_LL2_TX_DEST_LB, /* Light L2 TX Destination to the Loopback */
+   QED_LL2_TX_DEST_DROP, /* Light L2 Drop the TX packet */
QED_LL2_TX_DEST_MAX
 };
 
-- 
1.8.3.1



[PATCH v2 net-next 02/12] qed: Add ll2 ability of opening a secondary queue

2017-10-03 Thread Michal Kalderon
When more than one ll2 queue is opened ( that is not an OOO queue )
ll2 code does not have enough information to determine whether
the queue is the main one or not, so a new field is added to the
acquire input data to expose the control of determining whether
the queue is the main queue or a secondary queue.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed_ll2.c | 7 ++-
 drivers/net/ethernet/qlogic/qed/qed_ll2.h | 1 +
 include/linux/qed/qed_ll2_if.h| 1 +
 3 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.c 
b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
index 75af40a..3c695da 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_ll2.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
@@ -894,7 +894,7 @@ static int qed_sp_ll2_rx_queue_start(struct qed_hwfn 
*p_hwfn,
p_ramrod->drop_ttl0_flg = p_ll2_conn->input.rx_drop_ttl0_flg;
p_ramrod->inner_vlan_removal_en = p_ll2_conn->input.rx_vlan_removal_en;
p_ramrod->queue_id = p_ll2_conn->queue_id;
-   p_ramrod->main_func_queue = (conn_type == QED_LL2_TYPE_OOO) ? 0 : 1;
+   p_ramrod->main_func_queue = p_ll2_conn->main_func_queue ? 1 : 0;
 
if ((IS_MF_DEFAULT(p_hwfn) || IS_MF_SI(p_hwfn)) &&
p_ramrod->main_func_queue && (conn_type != QED_LL2_TYPE_ROCE) &&
@@ -1265,6 +1265,11 @@ int qed_ll2_acquire_connection(void *cxt, struct 
qed_ll2_acquire_data *data)
 
p_ll2_info->tx_dest = (data->input.tx_dest == QED_LL2_TX_DEST_NW) ?
  CORE_TX_DEST_NW : CORE_TX_DEST_LB;
+   if (data->input.conn_type == QED_LL2_TYPE_OOO ||
+   data->input.secondary_queue)
+   p_ll2_info->main_func_queue = false;
+   else
+   p_ll2_info->main_func_queue = true;
 
/* Correct maximum number of Tx BDs */
p_tx_max = _ll2_info->input.tx_max_bds_per_packet;
diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.h 
b/drivers/net/ethernet/qlogic/qed/qed_ll2.h
index 9bdd08f..f658170 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_ll2.h
+++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.h
@@ -121,6 +121,7 @@ struct qed_ll2_info {
bool b_active;
enum core_tx_dest tx_dest;
u8 tx_stats_en;
+   bool main_func_queue;
struct qed_ll2_rx_queue rx_queue;
struct qed_ll2_tx_queue tx_queue;
struct qed_ll2_cbs cbs;
diff --git a/include/linux/qed/qed_ll2_if.h b/include/linux/qed/qed_ll2_if.h
index 89fa0bb..d7cca59 100644
--- a/include/linux/qed/qed_ll2_if.h
+++ b/include/linux/qed/qed_ll2_if.h
@@ -171,6 +171,7 @@ struct qed_ll2_acquire_data_inputs {
enum qed_ll2_tx_dest tx_dest;
enum qed_ll2_error_handle ai_err_packet_too_big;
enum qed_ll2_error_handle ai_err_no_buf;
+   bool secondary_queue;
u8 gsi_enable;
 };
 
-- 
1.8.3.1



[PATCH net-next 11/12] qed: Add support for MPA header being split over two tcp packets

2017-10-02 Thread Michal Kalderon
There is a special case where an MPA header is split over to tcp
packets, in this case we need to wait for the next packet to
get the fpdu length. We use the incomplete_bytes to mark this
fpdu as a "special" one which requires updating the length with
the next packet

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed_iwarp.c | 36 -
 drivers/net/ethernet/qlogic/qed/qed_iwarp.h |  6 +
 2 files changed, 41 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c 
b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
index 8b17369..2994942 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
@@ -1742,6 +1742,7 @@ enum qed_iwarp_mpa_pkt_type {
QED_IWARP_MPA_PKT_UNALIGNED
 };
 
+#define QED_IWARP_INVALID_FPDU_LENGTH 0x
 #define QED_IWARP_MPA_FPDU_LENGTH_SIZE (2)
 #define QED_IWARP_MPA_CRC32_DIGEST_SIZE (4)
 
@@ -1774,6 +1775,15 @@ enum qed_iwarp_mpa_pkt_type {
goto out;
}
 
+   /* special case of one byte remaining...
+* lower byte will be read next packet
+*/
+   if (tcp_payload_len == 1) {
+   fpdu->fpdu_length = *mpa_data << BITS_PER_BYTE;
+   pkt_type = QED_IWARP_MPA_PKT_PARTIAL;
+   goto out;
+   }
+
mpa_len = ntohs(*((u16 *)(mpa_data)));
fpdu->fpdu_length = QED_IWARP_FPDU_LEN_WITH_PAD(mpa_len);
 
@@ -1802,7 +1812,9 @@ enum qed_iwarp_mpa_pkt_type {
fpdu->mpa_frag = buf->data_phys_addr + pkt_data->first_mpa_offset;
fpdu->mpa_frag_virt = (u8 *)(buf->data) + pkt_data->first_mpa_offset;
 
-   if (tcp_payload_size < fpdu->fpdu_length)
+   if (tcp_payload_size == 1)
+   fpdu->incomplete_bytes = QED_IWARP_INVALID_FPDU_LENGTH;
+   else if (tcp_payload_size < fpdu->fpdu_length)
fpdu->incomplete_bytes = fpdu->fpdu_length - tcp_payload_size;
else
fpdu->incomplete_bytes = 0; /* complete fpdu */
@@ -1810,6 +1822,27 @@ enum qed_iwarp_mpa_pkt_type {
fpdu->mpa_frag_len = fpdu->fpdu_length - fpdu->incomplete_bytes;
 }
 
+static void
+qed_iwarp_update_fpdu_length(struct qed_hwfn *p_hwfn,
+struct qed_iwarp_fpdu *fpdu, u8 *mpa_data)
+{
+   u16 mpa_len;
+
+   /* Update incomplete packets if needed */
+   if (fpdu->incomplete_bytes == QED_IWARP_INVALID_FPDU_LENGTH) {
+   /* Missing lower byte is now available */
+   mpa_len = fpdu->fpdu_length | *mpa_data;
+   fpdu->fpdu_length = QED_IWARP_FPDU_LEN_WITH_PAD(mpa_len);
+   fpdu->mpa_frag_len = fpdu->fpdu_length;
+   /* one byte of hdr */
+   fpdu->incomplete_bytes = fpdu->fpdu_length - 1;
+   DP_VERBOSE(p_hwfn,
+  QED_MSG_RDMA,
+  "MPA_ALIGN: Partial header mpa_len=%x fpdu_length=%x 
incomplete_bytes=%x\n",
+  mpa_len, fpdu->fpdu_length, fpdu->incomplete_bytes);
+   }
+}
+
 static int
 qed_iwarp_send_fpdu(struct qed_hwfn *p_hwfn,
struct qed_iwarp_fpdu *fpdu,
@@ -1960,6 +1993,7 @@ enum qed_iwarp_mpa_pkt_type {
curr_pkt->first_mpa_offset += fpdu->fpdu_length;
break;
case QED_IWARP_MPA_PKT_UNALIGNED:
+   qed_iwarp_update_fpdu_length(p_hwfn, fpdu, mpa_data);
rc = qed_iwarp_send_fpdu(p_hwfn, fpdu, curr_pkt, buf,
 mpa_buf->tcp_payload_len,
 pkt_type);
diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.h 
b/drivers/net/ethernet/qlogic/qed/qed_iwarp.h
index 58db51a..c58793a 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.h
+++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.h
@@ -69,6 +69,12 @@ struct qed_iwarp_ll2_mpa_buf {
u8 placement_offset;
 };
 
+/* In some cases a fpdu will arrive with only one byte of the header, in this
+ * case the fpdu_length will be partial (contain only higher byte and
+ * incomplete bytes will contain the invalid value
+ */
+#define QED_IWARP_INVALID_INCOMPLETE_BYTES 0x
+
 struct qed_iwarp_fpdu {
struct qed_iwarp_ll2_buff *mpa_buf;
void *mpa_frag_virt;
-- 
1.8.3.1



[PATCH net-next 08/12] qed: Add mpa buffer descriptors for storing and processing mpa fpdus

2017-10-02 Thread Michal Kalderon
The mpa buff is a descriptor for iwarp ll2 buffers that contains
additional information required for aligining fpdu's.
In some cases, an additional packet will arrive which will complete
the alignment of a fpdu, but we won't be able to post the fpdu due to
insufficient place on the tx ring. In this case we can't loose the data
and require storing it for later. Processing is therefore done
in two places, during rx completion, where we initialize a mpa buffer
descriptor and add it to the pending list, and during tx-completion, since
we free up an entry in the tx chain we can process any pending mpa packets.
The mpa buff descriptors are pre-allocated since we have to ensure that
we won't reach a state where we can't store an incoming unaligned packet.
All packets received on the ll2 MUST be processed by the driver at some
stage. Since they are preallocated, we hold a free list.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed_iwarp.c | 116 
 drivers/net/ethernet/qlogic/qed/qed_iwarp.h |  11 +++
 2 files changed, 127 insertions(+)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c 
b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
index f413621..efd4861 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
@@ -1415,7 +1415,10 @@ int qed_iwarp_alloc(struct qed_hwfn *p_hwfn)
 
 void qed_iwarp_resc_free(struct qed_hwfn *p_hwfn)
 {
+   struct qed_iwarp_info *iwarp_info = _hwfn->p_rdma_info->iwarp;
+
qed_rdma_bmap_free(p_hwfn, _hwfn->p_rdma_info->tcp_cid_map, 1);
+   kfree(iwarp_info->mpa_bufs);
 }
 
 int qed_iwarp_accept(void *rdma_cxt, struct qed_iwarp_accept_in *iparams)
@@ -1716,12 +1719,103 @@ int qed_iwarp_reject(void *rdma_cxt, struct 
qed_iwarp_reject_in *iparams)
 /* fpdu can be fragmented over maximum 3 bds: header, partial mpa, unaligned */
 #define QED_IWARP_MAX_BDS_PER_FPDU 3
 static void
+qed_iwarp_mpa_get_data(struct qed_hwfn *p_hwfn,
+  struct unaligned_opaque_data *curr_pkt,
+  u32 opaque_data0, u32 opaque_data1)
+{
+   u64 opaque_data;
+
+   opaque_data = HILO_64(opaque_data1, opaque_data0);
+   *curr_pkt = *((struct unaligned_opaque_data *)_data);
+
+   curr_pkt->first_mpa_offset = curr_pkt->tcp_payload_offset +
+le16_to_cpu(curr_pkt->first_mpa_offset);
+   curr_pkt->cid = le32_to_cpu(curr_pkt->cid);
+}
+
+/* This function is called when an unaligned or incomplete MPA packet arrives
+ * driver needs to align the packet, perhaps using previous data and send
+ * it down to FW once it is aligned.
+ */
+static int
+qed_iwarp_process_mpa_pkt(struct qed_hwfn *p_hwfn,
+ struct qed_iwarp_ll2_mpa_buf *mpa_buf)
+{
+   struct qed_iwarp_ll2_buff *buf = mpa_buf->ll2_buf;
+   int rc = -EINVAL;
+
+   qed_iwarp_ll2_post_rx(p_hwfn,
+ buf,
+ p_hwfn->p_rdma_info->iwarp.ll2_mpa_handle);
+   return rc;
+}
+
+static void qed_iwarp_process_pending_pkts(struct qed_hwfn *p_hwfn)
+{
+   struct qed_iwarp_info *iwarp_info = _hwfn->p_rdma_info->iwarp;
+   struct qed_iwarp_ll2_mpa_buf *mpa_buf = NULL;
+   int rc;
+
+   while (!list_empty(_info->mpa_buf_pending_list)) {
+   mpa_buf = list_first_entry(_info->mpa_buf_pending_list,
+  struct qed_iwarp_ll2_mpa_buf,
+  list_entry);
+
+   rc = qed_iwarp_process_mpa_pkt(p_hwfn, mpa_buf);
+
+   /* busy means break and continue processing later, don't
+* remove the buf from the pending list.
+*/
+   if (rc == -EBUSY)
+   break;
+
+   list_del(_buf->list_entry);
+   list_add_tail(_buf->list_entry, _info->mpa_buf_list);
+
+   if (rc) {   /* different error, don't continue */
+   DP_NOTICE(p_hwfn, "process pkts failed rc=%d\n", rc);
+   break;
+   }
+   }
+}
+
+static void
 qed_iwarp_ll2_comp_mpa_pkt(void *cxt, struct qed_ll2_comp_rx_data *data)
 {
+   struct qed_iwarp_ll2_mpa_buf *mpa_buf;
struct qed_iwarp_info *iwarp_info;
struct qed_hwfn *p_hwfn = cxt;
 
iwarp_info = _hwfn->p_rdma_info->iwarp;
+   mpa_buf = list_first_entry(_info->mpa_buf_list,
+  struct qed_iwarp_ll2_mpa_buf, list_entry);
+   if (!mpa_buf) {
+   DP_ERR(p_hwfn, "No free mpa buf\n");
+   goto err;
+   }
+
+   list_del(_buf->list_entry);
+   qed_iwarp_mpa_get_data(p_hwfn, _buf->data,
+  data->opaque_data_

[PATCH net-next 09/12] qed: Add unaligned and packed packet processing

2017-10-02 Thread Michal Kalderon
The fpdu data structure is preallocated per connection.
Each connection stores the current status of the connection:
either nothing pending, or there is a partial fpdu that is waiting for
the rest of the fpdu (incomplete bytes != 0).
The same structure is also used for splitting a packet when there are
packed fpdus. The structure is initialized with all data required
for sending the fpdu back to the FW. A fpdu will always be spanned across
a maximum of 3 tx bds. One for the header, one for the partial fdpu
received and one for the remainder (unaligned) packet.
In case of packed fpdu's, two fragments are used, one for the header
and one for the data.
Corner cases are not handled in the patch for clarity, and will be added
as a separate patch.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed_iwarp.c | 257 
 drivers/net/ethernet/qlogic/qed/qed_iwarp.h |  13 ++
 2 files changed, 270 insertions(+)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c 
b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
index efd4861..83b147f 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
@@ -1419,6 +1419,7 @@ void qed_iwarp_resc_free(struct qed_hwfn *p_hwfn)
 
qed_rdma_bmap_free(p_hwfn, _hwfn->p_rdma_info->tcp_cid_map, 1);
kfree(iwarp_info->mpa_bufs);
+   kfree(iwarp_info->partial_fpdus);
 }
 
 int qed_iwarp_accept(void *rdma_cxt, struct qed_iwarp_accept_in *iparams)
@@ -1716,8 +1717,170 @@ int qed_iwarp_reject(void *rdma_cxt, struct 
qed_iwarp_reject_in *iparams)
return 0;
 }
 
+static struct qed_iwarp_fpdu *qed_iwarp_get_curr_fpdu(struct qed_hwfn *p_hwfn,
+ u16 cid)
+{
+   struct qed_iwarp_info *iwarp_info = _hwfn->p_rdma_info->iwarp;
+   struct qed_iwarp_fpdu *partial_fpdu;
+   u32 idx;
+
+   idx = cid - qed_cxt_get_proto_cid_start(p_hwfn, PROTOCOLID_IWARP);
+   if (idx >= iwarp_info->max_num_partial_fpdus) {
+   DP_ERR(p_hwfn, "Invalid cid %x max_num_partial_fpdus=%x\n", cid,
+  iwarp_info->max_num_partial_fpdus);
+   return NULL;
+   }
+
+   partial_fpdu = _info->partial_fpdus[idx];
+
+   return partial_fpdu;
+}
+
+enum qed_iwarp_mpa_pkt_type {
+   QED_IWARP_MPA_PKT_PACKED,
+   QED_IWARP_MPA_PKT_PARTIAL,
+   QED_IWARP_MPA_PKT_UNALIGNED
+};
+
+#define QED_IWARP_MPA_FPDU_LENGTH_SIZE (2)
+#define QED_IWARP_MPA_CRC32_DIGEST_SIZE (4)
+
+/* Pad to multiple of 4 */
+#define QED_IWARP_PDU_DATA_LEN_WITH_PAD(data_len) ALIGN(data_len, 4)
+#define QED_IWARP_FPDU_LEN_WITH_PAD(_mpa_len) \
+   (QED_IWARP_PDU_DATA_LEN_WITH_PAD((_mpa_len) +  \
+QED_IWARP_MPA_FPDU_LENGTH_SIZE) + \
+QED_IWARP_MPA_CRC32_DIGEST_SIZE)
+
 /* fpdu can be fragmented over maximum 3 bds: header, partial mpa, unaligned */
 #define QED_IWARP_MAX_BDS_PER_FPDU 3
+
+char *pkt_type_str[] = {
+   "QED_IWARP_MPA_PKT_PACKED",
+   "QED_IWARP_MPA_PKT_PARTIAL",
+   "QED_IWARP_MPA_PKT_UNALIGNED"
+};
+
+static enum qed_iwarp_mpa_pkt_type
+qed_iwarp_mpa_classify(struct qed_hwfn *p_hwfn,
+  struct qed_iwarp_fpdu *fpdu,
+  u16 tcp_payload_len, u8 *mpa_data)
+{
+   enum qed_iwarp_mpa_pkt_type pkt_type;
+   u16 mpa_len;
+
+   if (fpdu->incomplete_bytes) {
+   pkt_type = QED_IWARP_MPA_PKT_UNALIGNED;
+   goto out;
+   }
+
+   mpa_len = ntohs(*((u16 *)(mpa_data)));
+   fpdu->fpdu_length = QED_IWARP_FPDU_LEN_WITH_PAD(mpa_len);
+
+   if (fpdu->fpdu_length <= tcp_payload_len)
+   pkt_type = QED_IWARP_MPA_PKT_PACKED;
+   else
+   pkt_type = QED_IWARP_MPA_PKT_PARTIAL;
+
+out:
+   DP_VERBOSE(p_hwfn, QED_MSG_RDMA,
+  "MPA_ALIGN: %s: fpdu_length=0x%x tcp_payload_len:0x%x\n",
+  pkt_type_str[pkt_type], fpdu->fpdu_length, tcp_payload_len);
+
+   return pkt_type;
+}
+
+static void
+qed_iwarp_init_fpdu(struct qed_iwarp_ll2_buff *buf,
+   struct qed_iwarp_fpdu *fpdu,
+   struct unaligned_opaque_data *pkt_data,
+   u16 tcp_payload_size, u8 placement_offset)
+{
+   fpdu->mpa_buf = buf;
+   fpdu->pkt_hdr = buf->data_phys_addr + placement_offset;
+   fpdu->pkt_hdr_size = pkt_data->tcp_payload_offset;
+   fpdu->mpa_frag = buf->data_phys_addr + pkt_data->first_mpa_offset;
+   fpdu->mpa_frag_virt = (u8 *)(buf->data) + pkt_data->first_mpa_offset;
+
+   if (tcp_payload_size < fpdu->fpdu_length)
+   fpdu->incomplete_bytes = fpdu-

[PATCH net-next 12/12] qed: Add iWARP support for fpdu spanned over more than two tcp packets

2017-10-02 Thread Michal Kalderon
We continue to maintain a maximum of three buffers per fpdu, to ensure
that there are enough buffers for additional unaligned mpa packets.
To support this, if a fpdu is split over more than two tcp packets, we
use an intermediate buffer to copy the data to the previous buffer, then
we can release the data. We need an intermediate buffer as the initial
buffer partial packet could be located at the end of the packet, not
leaving room for additional data. This is a corner case, and will usually
not be the case.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed_iwarp.c | 193 
 drivers/net/ethernet/qlogic/qed/qed_iwarp.h |   1 +
 2 files changed, 194 insertions(+)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c 
b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
index 2994942..b2b1f87 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
@@ -1420,6 +1420,7 @@ void qed_iwarp_resc_free(struct qed_hwfn *p_hwfn)
qed_rdma_bmap_free(p_hwfn, _hwfn->p_rdma_info->tcp_cid_map, 1);
kfree(iwarp_info->mpa_bufs);
kfree(iwarp_info->partial_fpdus);
+   kfree(iwarp_info->mpa_intermediate_buf);
 }
 
 int qed_iwarp_accept(void *rdma_cxt, struct qed_iwarp_accept_in *iparams)
@@ -1762,6 +1763,11 @@ enum qed_iwarp_mpa_pkt_type {
"QED_IWARP_MPA_PKT_UNALIGNED"
 };
 
+static int
+qed_iwarp_recycle_pkt(struct qed_hwfn *p_hwfn,
+ struct qed_iwarp_fpdu *fpdu,
+ struct qed_iwarp_ll2_buff *buf);
+
 static enum qed_iwarp_mpa_pkt_type
 qed_iwarp_mpa_classify(struct qed_hwfn *p_hwfn,
   struct qed_iwarp_fpdu *fpdu,
@@ -1822,6 +1828,68 @@ enum qed_iwarp_mpa_pkt_type {
fpdu->mpa_frag_len = fpdu->fpdu_length - fpdu->incomplete_bytes;
 }
 
+static int
+qed_iwarp_cp_pkt(struct qed_hwfn *p_hwfn,
+struct qed_iwarp_fpdu *fpdu,
+struct unaligned_opaque_data *pkt_data,
+struct qed_iwarp_ll2_buff *buf, u16 tcp_payload_size)
+{
+   u8 *tmp_buf = p_hwfn->p_rdma_info->iwarp.mpa_intermediate_buf;
+   int rc;
+
+   /* need to copy the data from the partial packet stored in fpdu
+* to the new buf, for this we also need to move the data currently
+* placed on the buf. The assumption is that the buffer is big enough
+* since fpdu_length <= mss, we use an intermediate buffer since
+* we may need to copy the new data to an overlapping location
+*/
+   if ((fpdu->mpa_frag_len + tcp_payload_size) > (u16)buf->buff_size) {
+   DP_ERR(p_hwfn,
+  "MPA ALIGN: Unexpected: buffer is not large enough for 
split fpdu buff_size = %d mpa_frag_len = %d, tcp_payload_size = %d, 
incomplete_bytes = %d\n",
+  buf->buff_size, fpdu->mpa_frag_len,
+  tcp_payload_size, fpdu->incomplete_bytes);
+   return -EINVAL;
+   }
+
+   DP_VERBOSE(p_hwfn, QED_MSG_RDMA,
+  "MPA ALIGN Copying fpdu: [%p, %d] [%p, %d]\n",
+  fpdu->mpa_frag_virt, fpdu->mpa_frag_len,
+  (u8 *)(buf->data) + pkt_data->first_mpa_offset,
+  tcp_payload_size);
+
+   memcpy(tmp_buf, fpdu->mpa_frag_virt, fpdu->mpa_frag_len);
+   memcpy(tmp_buf + fpdu->mpa_frag_len,
+  (u8 *)(buf->data) + pkt_data->first_mpa_offset,
+  tcp_payload_size);
+
+   rc = qed_iwarp_recycle_pkt(p_hwfn, fpdu, fpdu->mpa_buf);
+   if (rc)
+   return rc;
+
+   /* If we managed to post the buffer copy the data to the new buffer
+* o/w this will occur in the next round...
+*/
+   memcpy((u8 *)(buf->data), tmp_buf,
+  fpdu->mpa_frag_len + tcp_payload_size);
+
+   fpdu->mpa_buf = buf;
+   /* fpdu->pkt_hdr remains as is */
+   /* fpdu->mpa_frag is overridden with new buf */
+   fpdu->mpa_frag = buf->data_phys_addr;
+   fpdu->mpa_frag_virt = buf->data;
+   fpdu->mpa_frag_len += tcp_payload_size;
+
+   fpdu->incomplete_bytes -= tcp_payload_size;
+
+   DP_VERBOSE(p_hwfn,
+  QED_MSG_RDMA,
+  "MPA ALIGN: split fpdu buff_size = %d mpa_frag_len = %d, 
tcp_payload_size = %d, incomplete_bytes = %d\n",
+  buf->buff_size, fpdu->mpa_frag_len, tcp_payload_size,
+  fpdu->incomplete_bytes);
+
+   return 0;
+}
+
 static void
 qed_iwarp_update_fpdu_length(struct qed_hwfn *p_hwfn,
 struct qed_iwarp_fpdu *fpdu, u8 *mpa_data)
@@ -1843,6 +1911,90 @@ enum qed_iwarp_mpa_pkt_type {
}
 }
 
+#define QED_IWARP_IS_RIGHT_EDGE(_curr_pkt) \
+   (GET_

[PATCH net-next 06/12] qed: Add LL2 slowpath handling

2017-10-02 Thread Michal Kalderon
For iWARP unaligned MPA flow, a slowpath event of flushing an
MPA connection that entered an unaligned state is required.
The flush ramrod is received on the ll2 queue, and a pre-registered
callback function is called to handle the flush event.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed_ll2.c | 40 +--
 include/linux/qed/qed_ll2_if.h|  5 
 2 files changed, 43 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.c 
b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
index dbcbf86..5fa7a20 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_ll2.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
@@ -423,6 +423,41 @@ static void qed_ll2_rxq_parse_reg(struct qed_hwfn *p_hwfn,
 }
 
 static int
+qed_ll2_handle_slowpath(struct qed_hwfn *p_hwfn,
+   struct qed_ll2_info *p_ll2_conn,
+   union core_rx_cqe_union *p_cqe,
+   unsigned long *p_lock_flags)
+{
+   struct qed_ll2_rx_queue *p_rx = _ll2_conn->rx_queue;
+   struct core_rx_slow_path_cqe *sp_cqe;
+
+   sp_cqe = _cqe->rx_cqe_sp;
+   if (sp_cqe->ramrod_cmd_id != CORE_RAMROD_RX_QUEUE_FLUSH) {
+   DP_NOTICE(p_hwfn,
+ "LL2 - unexpected Rx CQE slowpath ramrod_cmd_id:%d\n",
+ sp_cqe->ramrod_cmd_id);
+   return -EINVAL;
+   }
+
+   if (!p_ll2_conn->cbs.slowpath_cb) {
+   DP_NOTICE(p_hwfn,
+ "LL2 - received RX_QUEUE_FLUSH but no callback was 
provided\n");
+   return -EINVAL;
+   }
+
+   spin_unlock_irqrestore(_rx->lock, *p_lock_flags);
+
+   p_ll2_conn->cbs.slowpath_cb(p_ll2_conn->cbs.cookie,
+   p_ll2_conn->my_id,
+   le32_to_cpu(sp_cqe->opaque_data.data[0]),
+   le32_to_cpu(sp_cqe->opaque_data.data[1]));
+
+   spin_lock_irqsave(_rx->lock, *p_lock_flags);
+
+   return 0;
+}
+
+static int
 qed_ll2_rxq_handle_completion(struct qed_hwfn *p_hwfn,
  struct qed_ll2_info *p_ll2_conn,
  union core_rx_cqe_union *p_cqe,
@@ -495,8 +530,8 @@ static int qed_ll2_rxq_completion(struct qed_hwfn *p_hwfn, 
void *cookie)
 
switch (cqe->rx_cqe_sp.type) {
case CORE_RX_CQE_TYPE_SLOW_PATH:
-   DP_NOTICE(p_hwfn, "LL2 - unexpected Rx CQE slowpath\n");
-   rc = -EINVAL;
+   rc = qed_ll2_handle_slowpath(p_hwfn, p_ll2_conn,
+cqe, );
break;
case CORE_RX_CQE_TYPE_GSI_OFFLOAD:
case CORE_RX_CQE_TYPE_REGULAR:
@@ -1214,6 +1249,7 @@ static int qed_ll2_acquire_connection_tx(struct qed_hwfn 
*p_hwfn,
p_ll2_info->cbs.rx_release_cb = cbs->rx_release_cb;
p_ll2_info->cbs.tx_comp_cb = cbs->tx_comp_cb;
p_ll2_info->cbs.tx_release_cb = cbs->tx_release_cb;
+   p_ll2_info->cbs.slowpath_cb = cbs->slowpath_cb;
p_ll2_info->cbs.cookie = cbs->cookie;
 
return 0;
diff --git a/include/linux/qed/qed_ll2_if.h b/include/linux/qed/qed_ll2_if.h
index aa7cb3b..4c4d989 100644
--- a/include/linux/qed/qed_ll2_if.h
+++ b/include/linux/qed/qed_ll2_if.h
@@ -151,11 +151,16 @@ struct qed_ll2_comp_rx_data {
 dma_addr_t first_frag_addr,
 bool b_last_fragment, bool b_last_packet);
 
+typedef
+void (*qed_ll2_slowpath_cb)(void *cxt, u8 connection_handle,
+   u32 opaque_data_0, u32 opaque_data_1);
+
 struct qed_ll2_cbs {
qed_ll2_complete_rx_packet_cb rx_comp_cb;
qed_ll2_release_rx_packet_cb rx_release_cb;
qed_ll2_complete_tx_packet_cb tx_comp_cb;
qed_ll2_release_tx_packet_cb tx_release_cb;
+   qed_ll2_slowpath_cb slowpath_cb;
void *cookie;
 };
 
-- 
1.8.3.1



[PATCH net-next 07/12] qed: Add ll2 connection for processing unaligned MPA packets

2017-10-02 Thread Michal Kalderon
This patch adds only the establishment and termination of the
ll2 connection that handles unaligned MPA packets.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed_iwarp.c | 65 +
 drivers/net/ethernet/qlogic/qed/qed_iwarp.h |  1 +
 2 files changed, 66 insertions(+)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c 
b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
index 8fc9c811..f413621 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
@@ -1713,6 +1713,19 @@ int qed_iwarp_reject(void *rdma_cxt, struct 
qed_iwarp_reject_in *iparams)
return 0;
 }
 
+/* fpdu can be fragmented over maximum 3 bds: header, partial mpa, unaligned */
+#define QED_IWARP_MAX_BDS_PER_FPDU 3
+static void
+qed_iwarp_ll2_comp_mpa_pkt(void *cxt, struct qed_ll2_comp_rx_data *data)
+{
+   struct qed_iwarp_info *iwarp_info;
+   struct qed_hwfn *p_hwfn = cxt;
+
+   iwarp_info = _hwfn->p_rdma_info->iwarp;
+   qed_iwarp_ll2_post_rx(p_hwfn, data->cookie,
+ iwarp_info->ll2_mpa_handle);
+}
+
 static void
 qed_iwarp_ll2_comp_syn_pkt(void *cxt, struct qed_ll2_comp_rx_data *data)
 {
@@ -1877,6 +1890,13 @@ static void qed_iwarp_ll2_rel_tx_pkt(void *cxt, u8 
connection_handle,
kfree(buffer);
 }
 
+void
+qed_iwarp_ll2_slowpath(void *cxt,
+  u8 connection_handle,
+  u32 opaque_data_0, u32 opaque_data_1)
+{
+}
+
 static int qed_iwarp_ll2_stop(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
 {
struct qed_iwarp_info *iwarp_info = _hwfn->p_rdma_info->iwarp;
@@ -1902,6 +1922,16 @@ static int qed_iwarp_ll2_stop(struct qed_hwfn *p_hwfn, 
struct qed_ptt *p_ptt)
iwarp_info->ll2_ooo_handle = QED_IWARP_HANDLE_INVAL;
}
 
+   if (iwarp_info->ll2_mpa_handle != QED_IWARP_HANDLE_INVAL) {
+   rc = qed_ll2_terminate_connection(p_hwfn,
+ iwarp_info->ll2_mpa_handle);
+   if (rc)
+   DP_INFO(p_hwfn, "Failed to terminate mpa connection\n");
+
+   qed_ll2_release_connection(p_hwfn, iwarp_info->ll2_mpa_handle);
+   iwarp_info->ll2_mpa_handle = QED_IWARP_HANDLE_INVAL;
+   }
+
qed_llh_remove_mac_filter(p_hwfn,
  p_ptt, p_hwfn->p_rdma_info->iwarp.mac_addr);
return rc;
@@ -1953,12 +1983,14 @@ static int qed_iwarp_ll2_stop(struct qed_hwfn *p_hwfn, 
struct qed_ptt *p_ptt)
struct qed_iwarp_info *iwarp_info;
struct qed_ll2_acquire_data data;
struct qed_ll2_cbs cbs;
+   u32 mpa_buff_size;
u16 n_ooo_bufs;
int rc = 0;
 
iwarp_info = _hwfn->p_rdma_info->iwarp;
iwarp_info->ll2_syn_handle = QED_IWARP_HANDLE_INVAL;
iwarp_info->ll2_ooo_handle = QED_IWARP_HANDLE_INVAL;
+   iwarp_info->ll2_mpa_handle = QED_IWARP_HANDLE_INVAL;
 
iwarp_info->max_mtu = params->max_mtu;
 
@@ -2029,6 +2061,39 @@ static int qed_iwarp_ll2_stop(struct qed_hwfn *p_hwfn, 
struct qed_ptt *p_ptt)
if (rc)
goto err;
 
+   /* Start Unaligned MPA connection */
+   cbs.rx_comp_cb = qed_iwarp_ll2_comp_mpa_pkt;
+   cbs.slowpath_cb = qed_iwarp_ll2_slowpath;
+
+   memset(, 0, sizeof(data));
+   data.input.conn_type = QED_LL2_TYPE_IWARP;
+   data.input.mtu = params->max_mtu;
+   /* FW requires that once a packet arrives OOO, it must have at
+* least 2 rx buffers available on the unaligned connection
+* for handling the case that it is a partial fpdu.
+*/
+   data.input.rx_num_desc = n_ooo_bufs * 2;
+   data.input.tx_num_desc = data.input.rx_num_desc;
+   data.input.tx_max_bds_per_packet = QED_IWARP_MAX_BDS_PER_FPDU;
+   data.p_connection_handle = _info->ll2_mpa_handle;
+   data.input.secondary_queue = true;
+   data.cbs = 
+
+   rc = qed_ll2_acquire_connection(p_hwfn, );
+   if (rc)
+   goto err;
+
+   rc = qed_ll2_establish_connection(p_hwfn, iwarp_info->ll2_mpa_handle);
+   if (rc)
+   goto err;
+
+   mpa_buff_size = QED_IWARP_MAX_BUF_SIZE(params->max_mtu);
+   rc = qed_iwarp_ll2_alloc_buffers(p_hwfn,
+data.input.rx_num_desc,
+mpa_buff_size,
+iwarp_info->ll2_mpa_handle);
+   if (rc)
+   goto err;
return rc;
 err:
qed_iwarp_ll2_stop(p_hwfn, p_ptt);
diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.h 
b/drivers/net/ethernet/qlogic/qed/qed_iwarp.h
index 9e2bfde..9d33a1f 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.h
+++ b/drivers/net/ethernet/qlogic/qed/qed_

[PATCH net-next 03/12] qed: Add ll2 option for dropping a tx packet

2017-10-02 Thread Michal Kalderon
The option of sending a packet on the ll2 and dropping it exists in
hardware and was not used until now, thus not exposed.
The iWARP unaligned MPA flow requires this functionality for
flushing the tx queue.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed_ll2.c | 16 ++--
 include/linux/qed/qed_ll2_if.h|  1 +
 2 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.c 
b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
index 1dd0cca..49fcfda 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_ll2.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
@@ -1597,8 +1597,20 @@ static void qed_ll2_prepare_tx_packet_set(struct 
qed_hwfn *p_hwfn,
roce_flavor = (pkt->qed_roce_flavor == QED_LL2_ROCE) ? CORE_ROCE
 : CORE_RROCE;
 
-   tx_dest = (pkt->tx_dest == QED_LL2_TX_DEST_NW) ? CORE_TX_DEST_NW
-  : CORE_TX_DEST_LB;
+   switch (pkt->tx_dest) {
+   case QED_LL2_TX_DEST_NW:
+   tx_dest = CORE_TX_DEST_NW;
+   break;
+   case QED_LL2_TX_DEST_LB:
+   tx_dest = CORE_TX_DEST_LB;
+   break;
+   case QED_LL2_TX_DEST_DROP:
+   tx_dest = CORE_TX_DEST_DROP;
+   break;
+   default:
+   tx_dest = CORE_TX_DEST_LB;
+   break;
+   }
 
start_bd = (struct core_tx_bd *)qed_chain_produce(p_tx_chain);
start_bd->nw_vlan_or_lb_echo = cpu_to_le16(pkt->vlan);
diff --git a/include/linux/qed/qed_ll2_if.h b/include/linux/qed/qed_ll2_if.h
index 25153ff..aa7cb3b 100644
--- a/include/linux/qed/qed_ll2_if.h
+++ b/include/linux/qed/qed_ll2_if.h
@@ -64,6 +64,7 @@ enum qed_ll2_roce_flavor_type {
 enum qed_ll2_tx_dest {
QED_LL2_TX_DEST_NW, /* Light L2 TX Destination to the Network */
QED_LL2_TX_DEST_LB, /* Light L2 TX Destination to the Loopback */
+   QED_LL2_TX_DEST_DROP, /* Light L2 Drop the TX packet */
QED_LL2_TX_DEST_MAX
 };
 
-- 
1.8.3.1



[PATCH net-next 10/12] qed: Add support for freeing two ll2 buffers for corner cases

2017-10-02 Thread Michal Kalderon
When posting a packet on the ll2 tx, we can provide a cookie that
will be returned upon tx completion. This cookie is the ll2 iwarp buffer
which is then reposted to the rx ring. Part of the unaligned mpa flow
is determining when a buffer can be reposted. Each buffer needs to be
sent only once as a cookie for on the tx ring. In packed fpdu case, only
the last packet will be sent with the buffer, meaning we need to handle the
case that a cookie can be NULL on tx complete. In addition, when a fpdu
splits over two buffers, but there are no more fpdus on the second buffer,
two buffers need to be provided as a cookie. To avoid changing the ll2
interface to provide two cookies, we introduce a piggy buf pointer,
relevant for iWARP only, that holds a pointer to a second buffer that
needs to be released during tx completion.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed_iwarp.c | 25 +
 drivers/net/ethernet/qlogic/qed/qed_iwarp.h |  1 +
 2 files changed, 26 insertions(+)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c 
b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
index 83b147f..8b17369 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
@@ -1846,6 +1846,12 @@ enum qed_iwarp_mpa_pkt_type {
/* vlan overload with enum iwarp_ll2_tx_queues */
tx_pkt.vlan = IWARP_LL2_ALIGNED_TX_QUEUE;
 
+   /* special case of unaligned packet and not packed, need to send
+* both buffers as cookie to release.
+*/
+   if (tcp_payload_size == fpdu->incomplete_bytes)
+   fpdu->mpa_buf->piggy_buf = buf;
+
ll2_handle = p_hwfn->p_rdma_info->iwarp.ll2_mpa_handle;
 
/* Set first fragment to header */
@@ -2195,9 +2201,19 @@ static void qed_iwarp_ll2_comp_tx_pkt(void *cxt, u8 
connection_handle,
  bool b_last_fragment, bool b_last_packet)
 {
struct qed_iwarp_ll2_buff *buffer = cookie;
+   struct qed_iwarp_ll2_buff *piggy;
struct qed_hwfn *p_hwfn = cxt;
 
+   if (!buffer)/* can happen in packed mpa unaligned... */
+   return;
+
/* this was originally an rx packet, post it back */
+   piggy = buffer->piggy_buf;
+   if (piggy) {
+   buffer->piggy_buf = NULL;
+   qed_iwarp_ll2_post_rx(p_hwfn, piggy, connection_handle);
+   }
+
qed_iwarp_ll2_post_rx(p_hwfn, buffer, connection_handle);
 
if (connection_handle == p_hwfn->p_rdma_info->iwarp.ll2_mpa_handle)
@@ -2216,6 +2232,15 @@ static void qed_iwarp_ll2_rel_tx_pkt(void *cxt, u8 
connection_handle,
if (!buffer)
return;
 
+   if (buffer->piggy_buf) {
+   dma_free_coherent(_hwfn->cdev->pdev->dev,
+ buffer->piggy_buf->buff_size,
+ buffer->piggy_buf->data,
+ buffer->piggy_buf->data_phys_addr);
+
+   kfree(buffer->piggy_buf);
+   }
+
dma_free_coherent(_hwfn->cdev->pdev->dev, buffer->buff_size,
  buffer->data, buffer->data_phys_addr);
 
diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.h 
b/drivers/net/ethernet/qlogic/qed/qed_iwarp.h
index 858755c..58db51a 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.h
+++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.h
@@ -55,6 +55,7 @@ enum qed_iwarp_qp_state {
 #define QED_IWARP_HANDLE_INVAL (0xff)
 
 struct qed_iwarp_ll2_buff {
+   struct qed_iwarp_ll2_buff *piggy_buf;
void *data;
dma_addr_t data_phys_addr;
u32 buff_size;
-- 
1.8.3.1



[PATCH net-next 02/12] qed: Add ll2 ability of opening a secondary queue

2017-10-02 Thread Michal Kalderon
When more than one ll2 queue is opened ( that is not an OOO queue )
ll2 code does not have enough information to determine whether
the queue is the main one or not, so a new field is added to the
acquire input data to expose the control of determining whether
the queue is the main queue or a secondary queue.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed_ll2.c | 7 ++-
 drivers/net/ethernet/qlogic/qed/qed_ll2.h | 1 +
 include/linux/qed/qed_ll2_if.h| 1 +
 3 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.c 
b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
index 10e3a43..1dd0cca 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_ll2.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
@@ -894,7 +894,7 @@ static int qed_sp_ll2_rx_queue_start(struct qed_hwfn 
*p_hwfn,
p_ramrod->drop_ttl0_flg = p_ll2_conn->input.rx_drop_ttl0_flg;
p_ramrod->inner_vlan_removal_en = p_ll2_conn->input.rx_vlan_removal_en;
p_ramrod->queue_id = p_ll2_conn->queue_id;
-   p_ramrod->main_func_queue = (conn_type == QED_LL2_TYPE_OOO) ? 0 : 1;
+   p_ramrod->main_func_queue = p_ll2_conn->main_func_queue;
 
if ((IS_MF_DEFAULT(p_hwfn) || IS_MF_SI(p_hwfn)) &&
p_ramrod->main_func_queue && (conn_type != QED_LL2_TYPE_ROCE) &&
@@ -1265,6 +1265,11 @@ int qed_ll2_acquire_connection(void *cxt, struct 
qed_ll2_acquire_data *data)
 
p_ll2_info->tx_dest = (data->input.tx_dest == QED_LL2_TX_DEST_NW) ?
  CORE_TX_DEST_NW : CORE_TX_DEST_LB;
+   if (data->input.conn_type == QED_LL2_TYPE_OOO ||
+   data->input.secondary_queue)
+   p_ll2_info->main_func_queue = false;
+   else
+   p_ll2_info->main_func_queue = true;
 
/* Correct maximum number of Tx BDs */
p_tx_max = _ll2_info->input.tx_max_bds_per_packet;
diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.h 
b/drivers/net/ethernet/qlogic/qed/qed_ll2.h
index 8019336..346f3d3 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_ll2.h
+++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.h
@@ -121,6 +121,7 @@ struct qed_ll2_info {
bool b_active;
enum core_tx_dest tx_dest;
u8 tx_stats_en;
+   u8 main_func_queue;
struct qed_ll2_rx_queue rx_queue;
struct qed_ll2_tx_queue tx_queue;
struct qed_ll2_cbs cbs;
diff --git a/include/linux/qed/qed_ll2_if.h b/include/linux/qed/qed_ll2_if.h
index 89fa0bb..25153ff 100644
--- a/include/linux/qed/qed_ll2_if.h
+++ b/include/linux/qed/qed_ll2_if.h
@@ -171,6 +171,7 @@ struct qed_ll2_acquire_data_inputs {
enum qed_ll2_tx_dest tx_dest;
enum qed_ll2_error_handle ai_err_packet_too_big;
enum qed_ll2_error_handle ai_err_no_buf;
+   u8 secondary_queue;
u8 gsi_enable;
 };
 
-- 
1.8.3.1



[PATCH net-next 01/12] qed: Add ll2 option to limit the number of bds per packet

2017-10-02 Thread Michal Kalderon
iWARP uses 3 ll2 connections, the maximum number of bds is known
during connection setup. This patch modifies the static array in
the ll2_tx_packet descriptor to be a flexible array and
significantlly reduces memory size.

In addition, some redundant fields in the ll2_tx_packet were
removed, which also contributed to decreasing the descriptor size.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed_ll2.c | 25 +++--
 drivers/net/ethernet/qlogic/qed/qed_ll2.h |  7 ++-
 2 files changed, 21 insertions(+), 11 deletions(-)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.c 
b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
index 250afa5..10e3a43 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_ll2.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
@@ -1105,6 +1105,7 @@ static int qed_ll2_acquire_connection_tx(struct qed_hwfn 
*p_hwfn,
 struct qed_ll2_info *p_ll2_info)
 {
struct qed_ll2_tx_packet *p_descq;
+   u32 desc_size;
u32 capacity;
int rc = 0;
 
@@ -1122,8 +1123,12 @@ static int qed_ll2_acquire_connection_tx(struct qed_hwfn 
*p_hwfn,
goto out;
 
capacity = qed_chain_get_capacity(_ll2_info->tx_queue.txq_chain);
-   p_descq = kcalloc(capacity, sizeof(struct qed_ll2_tx_packet),
- GFP_KERNEL);
+   /* First element is part of the packet, rest are flexibly added */
+   desc_size = (sizeof(*p_descq) +
+(p_ll2_info->input.tx_max_bds_per_packet - 1) *
+sizeof(p_descq->bds_set));
+
+   p_descq = kcalloc(capacity, desc_size, GFP_KERNEL);
if (!p_descq) {
rc = -ENOMEM;
goto out;
@@ -1359,11 +1364,13 @@ int qed_ll2_establish_connection(void *cxt, u8 
connection_handle)
 {
struct qed_hwfn *p_hwfn = cxt;
struct qed_ll2_info *p_ll2_conn;
+   struct qed_ll2_tx_packet *p_pkt;
struct qed_ll2_rx_queue *p_rx;
struct qed_ll2_tx_queue *p_tx;
struct qed_ptt *p_ptt;
int rc = -EINVAL;
u32 i, capacity;
+   u32 desc_size;
u8 qid;
 
p_ptt = qed_ptt_acquire(p_hwfn);
@@ -1397,9 +1404,15 @@ int qed_ll2_establish_connection(void *cxt, u8 
connection_handle)
INIT_LIST_HEAD(_tx->sending_descq);
spin_lock_init(_tx->lock);
capacity = qed_chain_get_capacity(_tx->txq_chain);
-   for (i = 0; i < capacity; i++)
-   list_add_tail(_tx->descq_array[i].list_entry,
- _tx->free_descq);
+   /* First element is part of the packet, rest are flexibly added */
+   desc_size = (sizeof(*p_pkt) +
+(p_ll2_conn->input.tx_max_bds_per_packet - 1) *
+sizeof(p_pkt->bds_set));
+
+   for (i = 0; i < capacity; i++) {
+   p_pkt = (void *)((u8 *)p_tx->descq_array + desc_size * i);
+   list_add_tail(_pkt->list_entry, _tx->free_descq);
+   }
p_tx->cur_completing_bd_idx = 0;
p_tx->bds_idx = 0;
p_tx->b_completing_packet = false;
@@ -1698,7 +1711,7 @@ int qed_ll2_prepare_tx_packet(void *cxt,
p_tx = _ll2_conn->tx_queue;
p_tx_chain = _tx->txq_chain;
 
-   if (pkt->num_of_bds > CORE_LL2_TX_MAX_BDS_PER_PACKET)
+   if (pkt->num_of_bds > p_ll2_conn->input.tx_max_bds_per_packet)
return -EIO;
 
spin_lock_irqsave(_tx->lock, flags);
diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.h 
b/drivers/net/ethernet/qlogic/qed/qed_ll2.h
index a822528..8019336 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_ll2.h
+++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.h
@@ -63,17 +63,14 @@ struct qed_ll2_rx_packet {
 struct qed_ll2_tx_packet {
struct list_head list_entry;
u16 bd_used;
-   u16 vlan;
-   u16 l4_hdr_offset_w;
-   u8 bd_flags;
bool notify_fw;
void *cookie;
-
+   /* Flexible Array of bds_set determined by max_bds_per_packet */
struct {
struct core_tx_bd *txq_bd;
dma_addr_t tx_frag;
u16 frag_len;
-   } bds_set[ETH_TX_MAX_BDS_PER_NON_LSO_PACKET];
+   } bds_set[1];
 };
 
 struct qed_ll2_rx_queue {
-- 
1.8.3.1



[PATCH net-next 05/12] qed: Add the source of a packet sent on an iWARP ll2 connection

2017-10-02 Thread Michal Kalderon
When a packet is sent back to iWARP FW via the tx ll2 connection
the FW needs to know the source of the packet. Whether it is
OOO or unaligned MPA related. Since OOO is implemented entirely
inside the ll2 code (and shared with iSCSI), packets are marked
as IN_ORDER inside the ll2 code. For unaligned mpa the value
will be determined in the iWARP code and sent on the pkt->vlan
field.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed_ll2.c | 7 ++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.c 
b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
index 864132a..dbcbf86 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_ll2.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
@@ -1613,7 +1613,12 @@ static void qed_ll2_prepare_tx_packet_set(struct 
qed_hwfn *p_hwfn,
}
 
start_bd = (struct core_tx_bd *)qed_chain_produce(p_tx_chain);
-   start_bd->nw_vlan_or_lb_echo = cpu_to_le16(pkt->vlan);
+   if (QED_IS_IWARP_PERSONALITY(p_hwfn) &&
+   p_ll2->input.conn_type == QED_LL2_TYPE_OOO)
+   start_bd->nw_vlan_or_lb_echo =
+   cpu_to_le16(IWARP_LL2_IN_ORDER_TX_QUEUE);
+   else
+   start_bd->nw_vlan_or_lb_echo = cpu_to_le16(pkt->vlan);
SET_FIELD(start_bd->bitfield1, CORE_TX_BD_L4_HDR_OFFSET_W,
  cpu_to_le16(pkt->l4_hdr_offset_w));
SET_FIELD(start_bd->bitfield1, CORE_TX_BD_TX_DST, tx_dest);
-- 
1.8.3.1



[PATCH net-next 04/12] qed: Fix initialization of ll2 offload feature

2017-10-02 Thread Michal Kalderon
enable_ip_cksum, enable_l4_cksum, calc_ip_len were added in
commit stated below but not passed through to FW. This was OK
until now as it wasn't used, but is required for the iWARP
unaligned flow

Fixes:7c7973b2ae27 ("qed: LL2 to use packed information for tx")

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed_ll2.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.c 
b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
index 49fcfda..864132a 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_ll2.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
@@ -1621,6 +1621,9 @@ static void qed_ll2_prepare_tx_packet_set(struct qed_hwfn 
*p_hwfn,
SET_FIELD(bd_data, CORE_TX_BD_DATA_START_BD, 0x1);
SET_FIELD(bd_data, CORE_TX_BD_DATA_NBDS, pkt->num_of_bds);
SET_FIELD(bd_data, CORE_TX_BD_DATA_ROCE_FLAV, roce_flavor);
+   SET_FIELD(bd_data, CORE_TX_BD_DATA_IP_CSUM, !!(pkt->enable_ip_cksum));
+   SET_FIELD(bd_data, CORE_TX_BD_DATA_L4_CSUM, !!(pkt->enable_l4_cksum));
+   SET_FIELD(bd_data, CORE_TX_BD_DATA_IP_LEN, !!(pkt->calc_ip_len));
start_bd->bd_data.as_bitfield = cpu_to_le16(bd_data);
DMA_REGPAIR_LE(start_bd->addr, pkt->first_frag);
start_bd->nbytes = cpu_to_le16(pkt->first_frag_len);
-- 
1.8.3.1



[PATCH net-next 00/12] qed: Add iWARP support for unaligned MPA packets

2017-10-02 Thread Michal Kalderon
This patch series adds support for handling unaligned MPA packets.
(FPDUs split over more than one tcp packet).
When FW detects a packet is unaligned it fowards the packet to 
the driver via a light l2 dedicated connection. The driver then 
stores this packet until the remainder of the packet is received.
Once the driver reconstructs the full FPDU, it sends it down
to fw via the ll2 connection. Driver also breaks down any packed
PDUs into separate packets for FW. 

Patches 1-6 are all slight modifications to ll2 to support additional
requirements for the unaligned MPA ll2 client.

Patch 7 opens the additional ll2 connection for iWARP.
Patches 8-12 contain the algorithm for aligning packets.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>

Michal Kalderon (12):
  qed: Add ll2 option to limit the number of bds per packet
  qed: Add ll2 ability of opening a secondary queue
  qed: Add ll2 option for dropping a tx packet
  qed: Fix initialization of ll2 offload feature
  qed: Add the source of a packet sent on an iWARP ll2 connection
  qed: Add LL2 slowpath handling
  qed: Add ll2 connection for processing unaligned MPA packets
  qed: Add mpa buffer descriptors for storing and processing mpa fpdus
  qed: Add unaligned and packed packet processing
  qed: Add support for freeing two ll2 buffers for corner cases
  qed: Add support for MPA header being split over two tcp packets
  qed: Add iWARP support for fpdu spanned over more than two tcp packets

 drivers/net/ethernet/qlogic/qed/qed_iwarp.c | 690 
 drivers/net/ethernet/qlogic/qed/qed_iwarp.h |  33 ++
 drivers/net/ethernet/qlogic/qed/qed_ll2.c   |  98 +++-
 drivers/net/ethernet/qlogic/qed/qed_ll2.h   |   8 +-
 include/linux/qed/qed_ll2_if.h  |   7 +
 5 files changed, 819 insertions(+), 17 deletions(-)

-- 
1.8.3.1



[PATCH v2 net-next 1/4] qed: Add iWARP enablement support

2017-09-24 Thread Michal Kalderon
This patch is the last of the initial iWARP patch series. It
adds the possiblity to actually detect iWARP from the device and enable
it in the critical locations which basically make iWARP available.

It wasn't submitted until now as iWARP hadn't been accepted into
the rdma tree.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed_cxt.c |  6 ++
 drivers/net/ethernet/qlogic/qed/qed_mcp.c | 10 +-
 drivers/net/ethernet/qlogic/qed/qed_rdma.c|  5 -
 drivers/net/ethernet/qlogic/qed/qed_sp_commands.c |  1 +
 4 files changed, 16 insertions(+), 6 deletions(-)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_cxt.c 
b/drivers/net/ethernet/qlogic/qed/qed_cxt.c
index af106be..afd07ad 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_cxt.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_cxt.c
@@ -2069,6 +2069,12 @@ static void qed_rdma_set_pf_params(struct qed_hwfn 
*p_hwfn,
 
num_srqs = min_t(u32, 32 * 1024, p_params->num_srqs);
 
+   if (p_hwfn->mcp_info->func_info.protocol == QED_PCI_ETH_RDMA) {
+   DP_NOTICE(p_hwfn,
+ "Current day drivers don't support RoCE & iWARP 
simultaneously on the same PF. Default to RoCE-only\n");
+   p_hwfn->hw_info.personality = QED_PCI_ETH_ROCE;
+   }
+
switch (p_hwfn->hw_info.personality) {
case QED_PCI_ETH_IWARP:
/* Each QP requires one connection */
diff --git a/drivers/net/ethernet/qlogic/qed/qed_mcp.c 
b/drivers/net/ethernet/qlogic/qed/qed_mcp.c
index 376485d..8b99c7d 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_mcp.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_mcp.c
@@ -1691,12 +1691,12 @@ int qed_mcp_get_media_type(struct qed_dev *cdev, u32 
*p_media_type)
case FW_MB_PARAM_GET_PF_RDMA_ROCE:
*p_proto = QED_PCI_ETH_ROCE;
break;
-   case FW_MB_PARAM_GET_PF_RDMA_BOTH:
-   DP_NOTICE(p_hwfn,
- "Current day drivers don't support RoCE & iWARP. 
Default to RoCE-only\n");
-   *p_proto = QED_PCI_ETH_ROCE;
-   break;
case FW_MB_PARAM_GET_PF_RDMA_IWARP:
+   *p_proto = QED_PCI_ETH_IWARP;
+   break;
+   case FW_MB_PARAM_GET_PF_RDMA_BOTH:
+   *p_proto = QED_PCI_ETH_RDMA;
+   break;
default:
DP_NOTICE(p_hwfn,
  "MFW answers GET_PF_RDMA_PROTOCOL but param is 
%08x\n",
diff --git a/drivers/net/ethernet/qlogic/qed/qed_rdma.c 
b/drivers/net/ethernet/qlogic/qed/qed_rdma.c
index 6fb9951..06715f7 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_rdma.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_rdma.c
@@ -156,7 +156,10 @@ static int qed_rdma_alloc(struct qed_hwfn *p_hwfn,
return rc;
 
p_hwfn->p_rdma_info = p_rdma_info;
-   p_rdma_info->proto = PROTOCOLID_ROCE;
+   if (QED_IS_IWARP_PERSONALITY(p_hwfn))
+   p_rdma_info->proto = PROTOCOLID_IWARP;
+   else
+   p_rdma_info->proto = PROTOCOLID_ROCE;
 
num_cons = qed_cxt_get_proto_cid_count(p_hwfn, p_rdma_info->proto,
   NULL);
diff --git a/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c 
b/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c
index 46d0c3c..a1d33f3 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c
@@ -377,6 +377,7 @@ int qed_sp_pf_start(struct qed_hwfn *p_hwfn,
p_ramrod->personality = PERSONALITY_ISCSI;
break;
case QED_PCI_ETH_ROCE:
+   case QED_PCI_ETH_IWARP:
p_ramrod->personality = PERSONALITY_RDMA_AND_ETH;
break;
default:
-- 
1.8.3.1



[PATCH v2 net-next 0/4] qed: iWARP fixes and enhancements

2017-09-24 Thread Michal Kalderon
This patch series includes several fixes and enhancements
related to iWARP.

Patch #1 is actually the last of the initial iWARP submission.
It has been delayed until now as I wanted to make sure that qedr
supports iWARP prior to enabling iWARP device detection.

iWARP changes in RDMA tree have been accepted and targeted at
kernel 4.15, therefore, all iWARP fixes for this cycle are
submitted to net-next.

Changes from v1->v2 
  - Added "Fixes:" tag to commit message of patch #3

Signed-off by: michal.kalde...@cavium.com
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>

Michal Kalderon (4):
  qed: Add iWARP enablement support
  qed: Add iWARP out of order support
  qed: Fix maximum number of CQs for iWARP
  qed: iWARP - Add check for errors on a SYN packet

 drivers/net/ethernet/qlogic/qed/qed_cxt.c |  6 +++
 drivers/net/ethernet/qlogic/qed/qed_iwarp.c   | 52 +++
 drivers/net/ethernet/qlogic/qed/qed_iwarp.h   | 11 -
 drivers/net/ethernet/qlogic/qed/qed_ll2.c |  1 +
 drivers/net/ethernet/qlogic/qed/qed_mcp.c | 10 ++---
 drivers/net/ethernet/qlogic/qed/qed_rdma.c| 24 +++
 drivers/net/ethernet/qlogic/qed/qed_sp_commands.c |  1 +
 include/linux/qed/qed_ll2_if.h|  1 +
 8 files changed, 91 insertions(+), 15 deletions(-)

-- 
1.8.3.1



[PATCH v2 net-next 2/4] qed: Add iWARP out of order support

2017-09-24 Thread Michal Kalderon
iWARP requires OOO support which is already provided by the ll2
interface (until now was used only for iSCSI offload).
The changes mostly include opening a ll2 dedicated connection for
OOO and notifiying the FW about the handle id.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed_iwarp.c | 44 +
 drivers/net/ethernet/qlogic/qed/qed_iwarp.h | 11 +++-
 drivers/net/ethernet/qlogic/qed/qed_rdma.c  |  7 +++--
 3 files changed, 59 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c 
b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
index 9d989c9..568e985 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
@@ -41,6 +41,7 @@
 #include "qed_rdma.h"
 #include "qed_reg_addr.h"
 #include "qed_sp.h"
+#include "qed_ooo.h"
 
 #define QED_IWARP_ORD_DEFAULT  32
 #define QED_IWARP_IRD_DEFAULT  32
@@ -119,6 +120,13 @@ static void qed_iwarp_cid_cleaned(struct qed_hwfn *p_hwfn, 
u32 cid)
spin_unlock_bh(_hwfn->p_rdma_info->lock);
 }
 
+void qed_iwarp_init_fw_ramrod(struct qed_hwfn *p_hwfn,
+ struct iwarp_init_func_params *p_ramrod)
+{
+   p_ramrod->ll2_ooo_q_index = RESC_START(p_hwfn, QED_LL2_QUEUE) +
+   p_hwfn->p_rdma_info->iwarp.ll2_ooo_handle;
+}
+
 static int qed_iwarp_alloc_cid(struct qed_hwfn *p_hwfn, u32 *cid)
 {
int rc;
@@ -1876,6 +1884,16 @@ static int qed_iwarp_ll2_stop(struct qed_hwfn *p_hwfn, 
struct qed_ptt *p_ptt)
iwarp_info->ll2_syn_handle = QED_IWARP_HANDLE_INVAL;
}
 
+   if (iwarp_info->ll2_ooo_handle != QED_IWARP_HANDLE_INVAL) {
+   rc = qed_ll2_terminate_connection(p_hwfn,
+ iwarp_info->ll2_ooo_handle);
+   if (rc)
+   DP_INFO(p_hwfn, "Failed to terminate ooo connection\n");
+
+   qed_ll2_release_connection(p_hwfn, iwarp_info->ll2_ooo_handle);
+   iwarp_info->ll2_ooo_handle = QED_IWARP_HANDLE_INVAL;
+   }
+
qed_llh_remove_mac_filter(p_hwfn,
  p_ptt, p_hwfn->p_rdma_info->iwarp.mac_addr);
return rc;
@@ -1927,10 +1945,12 @@ static int qed_iwarp_ll2_stop(struct qed_hwfn *p_hwfn, 
struct qed_ptt *p_ptt)
struct qed_iwarp_info *iwarp_info;
struct qed_ll2_acquire_data data;
struct qed_ll2_cbs cbs;
+   u16 n_ooo_bufs;
int rc = 0;
 
iwarp_info = _hwfn->p_rdma_info->iwarp;
iwarp_info->ll2_syn_handle = QED_IWARP_HANDLE_INVAL;
+   iwarp_info->ll2_ooo_handle = QED_IWARP_HANDLE_INVAL;
 
iwarp_info->max_mtu = params->max_mtu;
 
@@ -1978,6 +1998,29 @@ static int qed_iwarp_ll2_stop(struct qed_hwfn *p_hwfn, 
struct qed_ptt *p_ptt)
if (rc)
goto err;
 
+   /* Start OOO connection */
+   data.input.conn_type = QED_LL2_TYPE_OOO;
+   data.input.mtu = params->max_mtu;
+
+   n_ooo_bufs = (QED_IWARP_MAX_OOO * QED_IWARP_RCV_WND_SIZE_DEF) /
+iwarp_info->max_mtu;
+   n_ooo_bufs = min_t(u32, n_ooo_bufs, QED_IWARP_LL2_OOO_MAX_RX_SIZE);
+
+   data.input.rx_num_desc = n_ooo_bufs;
+   data.input.rx_num_ooo_buffers = n_ooo_bufs;
+
+   data.input.tx_max_bds_per_packet = 1;   /* will never be fragmented */
+   data.input.tx_num_desc = QED_IWARP_LL2_OOO_DEF_TX_SIZE;
+   data.p_connection_handle = _info->ll2_ooo_handle;
+
+   rc = qed_ll2_acquire_connection(p_hwfn, );
+   if (rc)
+   goto err;
+
+   rc = qed_ll2_establish_connection(p_hwfn, iwarp_info->ll2_ooo_handle);
+   if (rc)
+   goto err;
+
return rc;
 err:
qed_iwarp_ll2_stop(p_hwfn, p_ptt);
@@ -2014,6 +2057,7 @@ int qed_iwarp_setup(struct qed_hwfn *p_hwfn, struct 
qed_ptt *p_ptt,
 
qed_spq_register_async_cb(p_hwfn, PROTOCOLID_IWARP,
  qed_iwarp_async_event);
+   qed_ooo_setup(p_hwfn);
 
return qed_iwarp_ll2_start(p_hwfn, params, p_ptt);
 }
diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.h 
b/drivers/net/ethernet/qlogic/qed/qed_iwarp.h
index 148ef3c..9e2bfde 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.h
+++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.h
@@ -47,7 +47,12 @@ enum qed_iwarp_qp_state {
 #define QED_IWARP_LL2_SYN_TX_SIZE   (128)
 #define QED_IWARP_LL2_SYN_RX_SIZE   (256)
 #define QED_IWARP_MAX_SYN_PKT_SIZE  (128)
-#define QED_IWARP_HANDLE_INVAL (0xff)
+
+#define QED_IWARP_LL2_OOO_DEF_TX_SIZE   (256)
+#define QED_IWARP_MAX_OOO  (16)
+#define QED_IWARP_LL2_OOO_MAX_RX_SIZE   (16384)
+
+#define QED_IWARP_HANDLE_INVAL (0xff)
 
 struc

[PATCH v2 net-next 4/4] qed: iWARP - Add check for errors on a SYN packet

2017-09-24 Thread Michal Kalderon
A SYN packet which arrives with errors from FW should be dropped.
This required adding an additional field to the ll2
rx completion data.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed_iwarp.c | 8 
 drivers/net/ethernet/qlogic/qed/qed_ll2.c   | 1 +
 include/linux/qed/qed_ll2_if.h  | 1 +
 3 files changed, 10 insertions(+)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c 
b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
index 568e985..8fc9c811 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
@@ -1733,6 +1733,14 @@ int qed_iwarp_reject(void *rdma_cxt, struct 
qed_iwarp_reject_in *iparams)
 
memset(_info, 0, sizeof(cm_info));
ll2_syn_handle = p_hwfn->p_rdma_info->iwarp.ll2_syn_handle;
+
+   /* Check if packet was received with errors... */
+   if (data->err_flags) {
+   DP_NOTICE(p_hwfn, "Error received on SYN packet: 0x%x\n",
+ data->err_flags);
+   goto err;
+   }
+
if (GET_FIELD(data->parse_flags,
  PARSING_AND_ERR_FLAGS_L4CHKSMWASCALCULATED) &&
GET_FIELD(data->parse_flags, PARSING_AND_ERR_FLAGS_L4CHKSMERROR)) {
diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.c 
b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
index c06ad4f..250afa5 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_ll2.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
@@ -413,6 +413,7 @@ static void qed_ll2_rxq_parse_reg(struct qed_hwfn *p_hwfn,
  struct qed_ll2_comp_rx_data *data)
 {
data->parse_flags = le16_to_cpu(p_cqe->rx_cqe_fp.parse_flags.flags);
+   data->err_flags = le16_to_cpu(p_cqe->rx_cqe_fp.err_flags.flags);
data->length.packet_length =
le16_to_cpu(p_cqe->rx_cqe_fp.packet_length);
data->vlan = le16_to_cpu(p_cqe->rx_cqe_fp.vlan);
diff --git a/include/linux/qed/qed_ll2_if.h b/include/linux/qed/qed_ll2_if.h
index dd7a3b8..89fa0bb 100644
--- a/include/linux/qed/qed_ll2_if.h
+++ b/include/linux/qed/qed_ll2_if.h
@@ -101,6 +101,7 @@ struct qed_ll2_comp_rx_data {
void *cookie;
dma_addr_t rx_buf_addr;
u16 parse_flags;
+   u16 err_flags;
u16 vlan;
bool b_last_packet;
u8 connection_handle;
-- 
1.8.3.1



[PATCH v2 net-next 3/4] qed: Fix maximum number of CQs for iWARP

2017-09-24 Thread Michal Kalderon
The maximum number of CQs supported is bound to the number
of connections supported, which differs between RoCE and iWARP.

This fixes a crash that occurred in iWARP when running 1000 sessions
using perftest.

Fixes: 67b40dccc45 ("qed: Implement iWARP initialization, teardown and qp 
operations")

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed_rdma.c | 12 ++--
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_rdma.c 
b/drivers/net/ethernet/qlogic/qed/qed_rdma.c
index 4f46f28..c8c4b39 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_rdma.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_rdma.c
@@ -209,11 +209,11 @@ static int qed_rdma_alloc(struct qed_hwfn *p_hwfn,
goto free_pd_map;
}
 
-   /* Allocate bitmap for cq's. The maximum number of CQs is bounded to
-* twice the number of QPs.
+   /* Allocate bitmap for cq's. The maximum number of CQs is bound to
+* the number of connections we support. (num_qps in iWARP or
+* num_qps/2 in RoCE).
 */
-   rc = qed_rdma_bmap_alloc(p_hwfn, _rdma_info->cq_map,
-p_rdma_info->num_qps * 2, "CQ");
+   rc = qed_rdma_bmap_alloc(p_hwfn, _rdma_info->cq_map, num_cons, "CQ");
if (rc) {
DP_VERBOSE(p_hwfn, QED_MSG_RDMA,
   "Failed to allocate cq bitmap, rc = %d\n", rc);
@@ -222,10 +222,10 @@ static int qed_rdma_alloc(struct qed_hwfn *p_hwfn,
 
/* Allocate bitmap for toggle bit for cq icids
 * We toggle the bit every time we create or resize cq for a given icid.
-* The maximum number of CQs is bounded to  twice the number of QPs.
+* Size needs to equal the size of the cq bmap.
 */
rc = qed_rdma_bmap_alloc(p_hwfn, _rdma_info->toggle_bits,
-p_rdma_info->num_qps * 2, "Toggle");
+num_cons, "Toggle");
if (rc) {
DP_VERBOSE(p_hwfn, QED_MSG_RDMA,
   "Failed to allocate toogle bits, rc = %d\n", rc);
-- 
1.8.3.1



[PATCH net-next 4/4] qed: iWARP - Add check for errors on a SYN packet

2017-09-19 Thread Michal Kalderon
A SYN packet which arrives with errors from FW should be dropped.
This required adding an additional field to the ll2
rx completion data.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed_iwarp.c | 8 
 drivers/net/ethernet/qlogic/qed/qed_ll2.c   | 1 +
 include/linux/qed/qed_ll2_if.h  | 1 +
 3 files changed, 10 insertions(+)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c 
b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
index 568e985..8fc9c811 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
@@ -1733,6 +1733,14 @@ int qed_iwarp_reject(void *rdma_cxt, struct 
qed_iwarp_reject_in *iparams)
 
memset(_info, 0, sizeof(cm_info));
ll2_syn_handle = p_hwfn->p_rdma_info->iwarp.ll2_syn_handle;
+
+   /* Check if packet was received with errors... */
+   if (data->err_flags) {
+   DP_NOTICE(p_hwfn, "Error received on SYN packet: 0x%x\n",
+ data->err_flags);
+   goto err;
+   }
+
if (GET_FIELD(data->parse_flags,
  PARSING_AND_ERR_FLAGS_L4CHKSMWASCALCULATED) &&
GET_FIELD(data->parse_flags, PARSING_AND_ERR_FLAGS_L4CHKSMERROR)) {
diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.c 
b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
index c06ad4f..250afa5 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_ll2.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
@@ -413,6 +413,7 @@ static void qed_ll2_rxq_parse_reg(struct qed_hwfn *p_hwfn,
  struct qed_ll2_comp_rx_data *data)
 {
data->parse_flags = le16_to_cpu(p_cqe->rx_cqe_fp.parse_flags.flags);
+   data->err_flags = le16_to_cpu(p_cqe->rx_cqe_fp.err_flags.flags);
data->length.packet_length =
le16_to_cpu(p_cqe->rx_cqe_fp.packet_length);
data->vlan = le16_to_cpu(p_cqe->rx_cqe_fp.vlan);
diff --git a/include/linux/qed/qed_ll2_if.h b/include/linux/qed/qed_ll2_if.h
index dd7a3b8..89fa0bb 100644
--- a/include/linux/qed/qed_ll2_if.h
+++ b/include/linux/qed/qed_ll2_if.h
@@ -101,6 +101,7 @@ struct qed_ll2_comp_rx_data {
void *cookie;
dma_addr_t rx_buf_addr;
u16 parse_flags;
+   u16 err_flags;
u16 vlan;
bool b_last_packet;
u8 connection_handle;
-- 
1.8.3.1



[PATCH net-next 3/4] qed: Fix maximum number of CQs for iWARP

2017-09-19 Thread Michal Kalderon
The maximum number of CQs supported is bound to the number
of connections supported, which differs between RoCE and iWARP.

This fixes a crash that occurred in iWARP when running 1000 sessions
using perftest.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed_rdma.c | 12 ++--
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_rdma.c 
b/drivers/net/ethernet/qlogic/qed/qed_rdma.c
index 4f46f28..c8c4b39 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_rdma.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_rdma.c
@@ -209,11 +209,11 @@ static int qed_rdma_alloc(struct qed_hwfn *p_hwfn,
goto free_pd_map;
}
 
-   /* Allocate bitmap for cq's. The maximum number of CQs is bounded to
-* twice the number of QPs.
+   /* Allocate bitmap for cq's. The maximum number of CQs is bound to
+* the number of connections we support. (num_qps in iWARP or
+* num_qps/2 in RoCE).
 */
-   rc = qed_rdma_bmap_alloc(p_hwfn, _rdma_info->cq_map,
-p_rdma_info->num_qps * 2, "CQ");
+   rc = qed_rdma_bmap_alloc(p_hwfn, _rdma_info->cq_map, num_cons, "CQ");
if (rc) {
DP_VERBOSE(p_hwfn, QED_MSG_RDMA,
   "Failed to allocate cq bitmap, rc = %d\n", rc);
@@ -222,10 +222,10 @@ static int qed_rdma_alloc(struct qed_hwfn *p_hwfn,
 
/* Allocate bitmap for toggle bit for cq icids
 * We toggle the bit every time we create or resize cq for a given icid.
-* The maximum number of CQs is bounded to  twice the number of QPs.
+* Size needs to equal the size of the cq bmap.
 */
rc = qed_rdma_bmap_alloc(p_hwfn, _rdma_info->toggle_bits,
-p_rdma_info->num_qps * 2, "Toggle");
+num_cons, "Toggle");
if (rc) {
DP_VERBOSE(p_hwfn, QED_MSG_RDMA,
   "Failed to allocate toogle bits, rc = %d\n", rc);
-- 
1.8.3.1



[PATCH net-next 1/4] qed: Add iWARP enablement support

2017-09-19 Thread Michal Kalderon
This patch is the last of the initial iWARP patch series. It
adds the possiblity to actually detect iWARP from the device and enable
it in the critical locations which basically make iWARP available.

It wasn't submitted until now as iWARP hadn't been accepted into
the rdma tree.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed_cxt.c |  6 ++
 drivers/net/ethernet/qlogic/qed/qed_mcp.c | 10 +-
 drivers/net/ethernet/qlogic/qed/qed_rdma.c|  5 -
 drivers/net/ethernet/qlogic/qed/qed_sp_commands.c |  1 +
 4 files changed, 16 insertions(+), 6 deletions(-)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_cxt.c 
b/drivers/net/ethernet/qlogic/qed/qed_cxt.c
index af106be..afd07ad 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_cxt.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_cxt.c
@@ -2069,6 +2069,12 @@ static void qed_rdma_set_pf_params(struct qed_hwfn 
*p_hwfn,
 
num_srqs = min_t(u32, 32 * 1024, p_params->num_srqs);
 
+   if (p_hwfn->mcp_info->func_info.protocol == QED_PCI_ETH_RDMA) {
+   DP_NOTICE(p_hwfn,
+ "Current day drivers don't support RoCE & iWARP 
simultaneously on the same PF. Default to RoCE-only\n");
+   p_hwfn->hw_info.personality = QED_PCI_ETH_ROCE;
+   }
+
switch (p_hwfn->hw_info.personality) {
case QED_PCI_ETH_IWARP:
/* Each QP requires one connection */
diff --git a/drivers/net/ethernet/qlogic/qed/qed_mcp.c 
b/drivers/net/ethernet/qlogic/qed/qed_mcp.c
index 376485d..8b99c7d 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_mcp.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_mcp.c
@@ -1691,12 +1691,12 @@ int qed_mcp_get_media_type(struct qed_dev *cdev, u32 
*p_media_type)
case FW_MB_PARAM_GET_PF_RDMA_ROCE:
*p_proto = QED_PCI_ETH_ROCE;
break;
-   case FW_MB_PARAM_GET_PF_RDMA_BOTH:
-   DP_NOTICE(p_hwfn,
- "Current day drivers don't support RoCE & iWARP. 
Default to RoCE-only\n");
-   *p_proto = QED_PCI_ETH_ROCE;
-   break;
case FW_MB_PARAM_GET_PF_RDMA_IWARP:
+   *p_proto = QED_PCI_ETH_IWARP;
+   break;
+   case FW_MB_PARAM_GET_PF_RDMA_BOTH:
+   *p_proto = QED_PCI_ETH_RDMA;
+   break;
default:
DP_NOTICE(p_hwfn,
  "MFW answers GET_PF_RDMA_PROTOCOL but param is 
%08x\n",
diff --git a/drivers/net/ethernet/qlogic/qed/qed_rdma.c 
b/drivers/net/ethernet/qlogic/qed/qed_rdma.c
index 6fb9951..06715f7 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_rdma.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_rdma.c
@@ -156,7 +156,10 @@ static int qed_rdma_alloc(struct qed_hwfn *p_hwfn,
return rc;
 
p_hwfn->p_rdma_info = p_rdma_info;
-   p_rdma_info->proto = PROTOCOLID_ROCE;
+   if (QED_IS_IWARP_PERSONALITY(p_hwfn))
+   p_rdma_info->proto = PROTOCOLID_IWARP;
+   else
+   p_rdma_info->proto = PROTOCOLID_ROCE;
 
num_cons = qed_cxt_get_proto_cid_count(p_hwfn, p_rdma_info->proto,
   NULL);
diff --git a/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c 
b/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c
index 46d0c3c..a1d33f3 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c
@@ -377,6 +377,7 @@ int qed_sp_pf_start(struct qed_hwfn *p_hwfn,
p_ramrod->personality = PERSONALITY_ISCSI;
break;
case QED_PCI_ETH_ROCE:
+   case QED_PCI_ETH_IWARP:
p_ramrod->personality = PERSONALITY_RDMA_AND_ETH;
break;
default:
-- 
1.8.3.1



[PATCH net-next 2/4] qed: Add iWARP out of order support

2017-09-19 Thread Michal Kalderon
iWARP requires OOO support which is already provided by the ll2
interface (until now was used only for iSCSI offload).
The changes mostly include opening a ll2 dedicated connection for
OOO and notifiying the FW about the handle id.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed_iwarp.c | 44 +
 drivers/net/ethernet/qlogic/qed/qed_iwarp.h | 11 +++-
 drivers/net/ethernet/qlogic/qed/qed_rdma.c  |  7 +++--
 3 files changed, 59 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c 
b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
index 9d989c9..568e985 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
@@ -41,6 +41,7 @@
 #include "qed_rdma.h"
 #include "qed_reg_addr.h"
 #include "qed_sp.h"
+#include "qed_ooo.h"
 
 #define QED_IWARP_ORD_DEFAULT  32
 #define QED_IWARP_IRD_DEFAULT  32
@@ -119,6 +120,13 @@ static void qed_iwarp_cid_cleaned(struct qed_hwfn *p_hwfn, 
u32 cid)
spin_unlock_bh(_hwfn->p_rdma_info->lock);
 }
 
+void qed_iwarp_init_fw_ramrod(struct qed_hwfn *p_hwfn,
+ struct iwarp_init_func_params *p_ramrod)
+{
+   p_ramrod->ll2_ooo_q_index = RESC_START(p_hwfn, QED_LL2_QUEUE) +
+   p_hwfn->p_rdma_info->iwarp.ll2_ooo_handle;
+}
+
 static int qed_iwarp_alloc_cid(struct qed_hwfn *p_hwfn, u32 *cid)
 {
int rc;
@@ -1876,6 +1884,16 @@ static int qed_iwarp_ll2_stop(struct qed_hwfn *p_hwfn, 
struct qed_ptt *p_ptt)
iwarp_info->ll2_syn_handle = QED_IWARP_HANDLE_INVAL;
}
 
+   if (iwarp_info->ll2_ooo_handle != QED_IWARP_HANDLE_INVAL) {
+   rc = qed_ll2_terminate_connection(p_hwfn,
+ iwarp_info->ll2_ooo_handle);
+   if (rc)
+   DP_INFO(p_hwfn, "Failed to terminate ooo connection\n");
+
+   qed_ll2_release_connection(p_hwfn, iwarp_info->ll2_ooo_handle);
+   iwarp_info->ll2_ooo_handle = QED_IWARP_HANDLE_INVAL;
+   }
+
qed_llh_remove_mac_filter(p_hwfn,
  p_ptt, p_hwfn->p_rdma_info->iwarp.mac_addr);
return rc;
@@ -1927,10 +1945,12 @@ static int qed_iwarp_ll2_stop(struct qed_hwfn *p_hwfn, 
struct qed_ptt *p_ptt)
struct qed_iwarp_info *iwarp_info;
struct qed_ll2_acquire_data data;
struct qed_ll2_cbs cbs;
+   u16 n_ooo_bufs;
int rc = 0;
 
iwarp_info = _hwfn->p_rdma_info->iwarp;
iwarp_info->ll2_syn_handle = QED_IWARP_HANDLE_INVAL;
+   iwarp_info->ll2_ooo_handle = QED_IWARP_HANDLE_INVAL;
 
iwarp_info->max_mtu = params->max_mtu;
 
@@ -1978,6 +1998,29 @@ static int qed_iwarp_ll2_stop(struct qed_hwfn *p_hwfn, 
struct qed_ptt *p_ptt)
if (rc)
goto err;
 
+   /* Start OOO connection */
+   data.input.conn_type = QED_LL2_TYPE_OOO;
+   data.input.mtu = params->max_mtu;
+
+   n_ooo_bufs = (QED_IWARP_MAX_OOO * QED_IWARP_RCV_WND_SIZE_DEF) /
+iwarp_info->max_mtu;
+   n_ooo_bufs = min_t(u32, n_ooo_bufs, QED_IWARP_LL2_OOO_MAX_RX_SIZE);
+
+   data.input.rx_num_desc = n_ooo_bufs;
+   data.input.rx_num_ooo_buffers = n_ooo_bufs;
+
+   data.input.tx_max_bds_per_packet = 1;   /* will never be fragmented */
+   data.input.tx_num_desc = QED_IWARP_LL2_OOO_DEF_TX_SIZE;
+   data.p_connection_handle = _info->ll2_ooo_handle;
+
+   rc = qed_ll2_acquire_connection(p_hwfn, );
+   if (rc)
+   goto err;
+
+   rc = qed_ll2_establish_connection(p_hwfn, iwarp_info->ll2_ooo_handle);
+   if (rc)
+   goto err;
+
return rc;
 err:
qed_iwarp_ll2_stop(p_hwfn, p_ptt);
@@ -2014,6 +2057,7 @@ int qed_iwarp_setup(struct qed_hwfn *p_hwfn, struct 
qed_ptt *p_ptt,
 
qed_spq_register_async_cb(p_hwfn, PROTOCOLID_IWARP,
  qed_iwarp_async_event);
+   qed_ooo_setup(p_hwfn);
 
return qed_iwarp_ll2_start(p_hwfn, params, p_ptt);
 }
diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.h 
b/drivers/net/ethernet/qlogic/qed/qed_iwarp.h
index 148ef3c..9e2bfde 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.h
+++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.h
@@ -47,7 +47,12 @@ enum qed_iwarp_qp_state {
 #define QED_IWARP_LL2_SYN_TX_SIZE   (128)
 #define QED_IWARP_LL2_SYN_RX_SIZE   (256)
 #define QED_IWARP_MAX_SYN_PKT_SIZE  (128)
-#define QED_IWARP_HANDLE_INVAL (0xff)
+
+#define QED_IWARP_LL2_OOO_DEF_TX_SIZE   (256)
+#define QED_IWARP_MAX_OOO  (16)
+#define QED_IWARP_LL2_OOO_MAX_RX_SIZE   (16384)
+
+#define QED_IWARP_HANDLE_INVAL (0xff)
 
 struc

[PATCH net-next 0/4] qed: iWARP fixes and enhancements

2017-09-19 Thread Michal Kalderon
This patch series includes several fixes and enhancements
related to iWARP.

Patch #1 is actually the last of the initial iWARP submission.
It has been delayed until now as I wanted to make sure that qedr
supports iWARP prior to enabling iWARP device detection.

iWARP changes in RDMA tree have been accepted and targeted at
kernel 4.15, therefore, all iWARP fixes for this cycle are
submitted to net-next.

Signed-off by: michal.kalde...@cavium.com
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>

Michal Kalderon (4):
  qed: Add iWARP enablement support
  qed: Add iWARP out of order support
  qed: Fix maximum number of CQs for iWARP
  qed: iWARP - Add check for errors on a SYN packet

 drivers/net/ethernet/qlogic/qed/qed_cxt.c |  6 +++
 drivers/net/ethernet/qlogic/qed/qed_iwarp.c   | 52 +++
 drivers/net/ethernet/qlogic/qed/qed_iwarp.h   | 11 -
 drivers/net/ethernet/qlogic/qed/qed_ll2.c |  1 +
 drivers/net/ethernet/qlogic/qed/qed_mcp.c | 10 ++---
 drivers/net/ethernet/qlogic/qed/qed_rdma.c| 24 +++
 drivers/net/ethernet/qlogic/qed/qed_sp_commands.c |  1 +
 include/linux/qed/qed_ll2_if.h|  1 +
 8 files changed, 91 insertions(+), 15 deletions(-)

-- 
1.8.3.1



[PATCH net] qed: Fix printk option passed when printing ipv6 addresses

2017-07-09 Thread Michal Kalderon
The option "h" (host order ) exists for ipv4 only.
Remove the h when printing ipv6 addresses.

Lead to the following smatch warning:

drivers/net/ethernet/qlogic/qed/qed_iwarp.c:585 qed_iwarp_print_tcp_ramrod()
warn: '%pI6' can only be followed by c
drivers/net/ethernet/qlogic/qed/qed_iwarp.c:1521 qed_iwarp_print_cm_info()
warn: '%pI6' can only be followed by c

Fixes commit 456a584947d5 ("qed: iWARP CM add passive side connect")

Reported-by: Dan Carpenter <dan.carpen...@oracle.com>
Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Yuval Mintz <yuval.mi...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed_iwarp.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c 
b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
index b251eba..9d989c9 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
@@ -575,7 +575,7 @@ int qed_iwarp_destroy_qp(struct qed_hwfn *p_hwfn, struct 
qed_rdma_qp *qp)
 
if (p_tcp_ramrod->tcp.ip_version == TCP_IPV4) {
DP_VERBOSE(p_hwfn, QED_MSG_RDMA,
-  "local_ip=%pI4h:%x, remote_ip=%pI4h%x, vlan=%x\n",
+  "local_ip=%pI4h:%x, remote_ip=%pI4h:%x, vlan=%x\n",
   p_tcp_ramrod->tcp.local_ip,
   p_tcp_ramrod->tcp.local_port,
   p_tcp_ramrod->tcp.remote_ip,
@@ -583,7 +583,7 @@ int qed_iwarp_destroy_qp(struct qed_hwfn *p_hwfn, struct 
qed_rdma_qp *qp)
   p_tcp_ramrod->tcp.vlan_id);
} else {
DP_VERBOSE(p_hwfn, QED_MSG_RDMA,
-  "local_ip=%pI6h:%x, remote_ip=%pI6h:%x, vlan=%x\n",
+  "local_ip=%pI6:%x, remote_ip=%pI6:%x, vlan=%x\n",
   p_tcp_ramrod->tcp.local_ip,
   p_tcp_ramrod->tcp.local_port,
   p_tcp_ramrod->tcp.remote_ip,
@@ -1519,7 +1519,7 @@ int qed_iwarp_reject(void *rdma_cxt, struct 
qed_iwarp_reject_in *iparams)
   cm_info->vlan);
else
DP_VERBOSE(p_hwfn, QED_MSG_RDMA,
-  "remote_ip %pI6h:%x, local_ip %pI6h:%x vlan=%x\n",
+  "remote_ip %pI6:%x, local_ip %pI6:%x vlan=%x\n",
   cm_info->remote_ip, cm_info->remote_port,
   cm_info->local_ip, cm_info->local_port,
   cm_info->vlan);
-- 
1.8.3.1



[PATCH net-next] qed: initialize ll2_syn_handle at start of function

2017-07-03 Thread Michal Kalderon
Fix compilation warning
qed_iwarp.c:1721:5: warning: ll2_syn_handle may be used
uninitialized in this function

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed_iwarp.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c 
b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
index 5cd20da..b251eba 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
@@ -1724,7 +1724,7 @@ int qed_iwarp_reject(void *rdma_cxt, struct 
qed_iwarp_reject_in *iparams)
int rc;
 
memset(_info, 0, sizeof(cm_info));
-
+   ll2_syn_handle = p_hwfn->p_rdma_info->iwarp.ll2_syn_handle;
if (GET_FIELD(data->parse_flags,
  PARSING_AND_ERR_FLAGS_L4CHKSMWASCALCULATED) &&
GET_FIELD(data->parse_flags, PARSING_AND_ERR_FLAGS_L4CHKSMERROR)) {
@@ -1740,7 +1740,6 @@ int qed_iwarp_reject(void *rdma_cxt, struct 
qed_iwarp_reject_in *iparams)
goto err;
 
/* Check if there is a listener for this 4-tuple+vlan */
-   ll2_syn_handle = p_hwfn->p_rdma_info->iwarp.ll2_syn_handle;
listener = qed_iwarp_get_listener(p_hwfn, _info);
if (!listener) {
DP_VERBOSE(p_hwfn,
-- 
1.8.3.1



[PATCH net-next 12/12] qed: Add iWARP support for physical queue allocation

2017-07-02 Thread Michal Kalderon
iWARP has different physical queue requirements than RoCE

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Yuval Mintz <yuval.mi...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed_dev.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c 
b/drivers/net/ethernet/qlogic/qed/qed_dev.c
index 4060a6a..6c87bed 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_dev.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c
@@ -216,6 +216,10 @@ static u32 qed_get_pq_flags(struct qed_hwfn *p_hwfn)
case QED_PCI_ETH_ROCE:
flags |= PQ_FLAGS_MCOS | PQ_FLAGS_OFLD | PQ_FLAGS_LLT;
break;
+   case QED_PCI_ETH_IWARP:
+   flags |= PQ_FLAGS_MCOS | PQ_FLAGS_ACK | PQ_FLAGS_OOO |
+   PQ_FLAGS_OFLD;
+   break;
default:
DP_ERR(p_hwfn,
   "unknown personality %d\n", p_hwfn->hw_info.personality);
-- 
1.8.3.1



[PATCH net-next 11/12] qed: Add iWARP protocol support in context allocation

2017-07-02 Thread Michal Kalderon
When computing how much memory is required for the different hw clients
iWARP protocol should be taken into account

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Yuval Mintz <yuval.mi...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed_cxt.c | 13 +++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_cxt.c 
b/drivers/net/ethernet/qlogic/qed/qed_cxt.c
index 38716f7..af106be 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_cxt.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_cxt.c
@@ -246,14 +246,16 @@ struct qed_cxt_mngr {
 static bool src_proto(enum protocol_type type)
 {
return type == PROTOCOLID_ISCSI ||
-  type == PROTOCOLID_FCOE;
+  type == PROTOCOLID_FCOE ||
+  type == PROTOCOLID_IWARP;
 }
 
 static bool tm_cid_proto(enum protocol_type type)
 {
return type == PROTOCOLID_ISCSI ||
   type == PROTOCOLID_FCOE ||
-  type == PROTOCOLID_ROCE;
+  type == PROTOCOLID_ROCE ||
+  type == PROTOCOLID_IWARP;
 }
 
 static bool tm_tid_proto(enum protocol_type type)
@@ -2068,6 +2070,11 @@ static void qed_rdma_set_pf_params(struct qed_hwfn 
*p_hwfn,
num_srqs = min_t(u32, 32 * 1024, p_params->num_srqs);
 
switch (p_hwfn->hw_info.personality) {
+   case QED_PCI_ETH_IWARP:
+   /* Each QP requires one connection */
+   num_cons = min_t(u32, IWARP_MAX_QPS, p_params->num_qps);
+   proto = PROTOCOLID_IWARP;
+   break;
case QED_PCI_ETH_ROCE:
num_qps = min_t(u32, ROCE_MAX_QPS, p_params->num_qps);
num_cons = num_qps * 2; /* each QP requires two connections */
@@ -2103,6 +2110,8 @@ int qed_cxt_set_pf_params(struct qed_hwfn *p_hwfn, u32 
rdma_tasks)
qed_cxt_set_proto_cid_count(p_hwfn, PROTOCOLID_CORE, core_cids, 0);
 
switch (p_hwfn->hw_info.personality) {
+   case QED_PCI_ETH_RDMA:
+   case QED_PCI_ETH_IWARP:
case QED_PCI_ETH_ROCE:
{
qed_rdma_set_pf_params(p_hwfn,
-- 
1.8.3.1



[PATCH net-next 10/12] qed: iWARP CM add error handling

2017-07-02 Thread Michal Kalderon
This patch introduces error handling for errors that occurred during
connection establishment.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Yuval Mintz <yuval.mi...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed_iwarp.c | 183 +++-
 include/linux/qed/qed_rdma_if.h |   9 ++
 2 files changed, 190 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c 
b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
index 84bcda3..5cd20da 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
@@ -1001,12 +1001,75 @@ int qed_iwarp_destroy_qp(struct qed_hwfn *p_hwfn, 
struct qed_rdma_qp *qp)
ep->state = QED_IWARP_EP_ESTABLISHED;
params.status = 0;
break;
+   case IWARP_CONN_ERROR_MPA_TIMEOUT:
+   DP_NOTICE(p_hwfn, "%s(0x%x) MPA timeout\n",
+ QED_IWARP_CONNECT_MODE_STRING(ep), ep->cid);
+   params.status = -EBUSY;
+   break;
+   case IWARP_CONN_ERROR_MPA_ERROR_REJECT:
+   DP_NOTICE(p_hwfn, "%s(0x%x) MPA Reject\n",
+ QED_IWARP_CONNECT_MODE_STRING(ep), ep->cid);
+   params.status = -ECONNREFUSED;
+   break;
+   case IWARP_CONN_ERROR_MPA_RST:
+   DP_NOTICE(p_hwfn, "%s(0x%x) MPA reset(tcp cid: 0x%x)\n",
+ QED_IWARP_CONNECT_MODE_STRING(ep), ep->cid,
+ ep->tcp_cid);
+   params.status = -ECONNRESET;
+   break;
+   case IWARP_CONN_ERROR_MPA_FIN:
+   DP_NOTICE(p_hwfn, "%s(0x%x) MPA received FIN\n",
+ QED_IWARP_CONNECT_MODE_STRING(ep), ep->cid);
+   params.status = -ECONNREFUSED;
+   break;
+   case IWARP_CONN_ERROR_MPA_INSUF_IRD:
+   DP_NOTICE(p_hwfn, "%s(0x%x) MPA insufficient ird\n",
+ QED_IWARP_CONNECT_MODE_STRING(ep), ep->cid);
+   params.status = -ECONNREFUSED;
+   break;
+   case IWARP_CONN_ERROR_MPA_RTR_MISMATCH:
+   DP_NOTICE(p_hwfn, "%s(0x%x) MPA RTR MISMATCH\n",
+ QED_IWARP_CONNECT_MODE_STRING(ep), ep->cid);
+   params.status = -ECONNREFUSED;
+   break;
+   case IWARP_CONN_ERROR_MPA_INVALID_PACKET:
+   DP_NOTICE(p_hwfn, "%s(0x%x) MPA Invalid Packet\n",
+ QED_IWARP_CONNECT_MODE_STRING(ep), ep->cid);
+   params.status = -ECONNREFUSED;
+   break;
+   case IWARP_CONN_ERROR_MPA_LOCAL_ERROR:
+   DP_NOTICE(p_hwfn, "%s(0x%x) MPA Local Error\n",
+ QED_IWARP_CONNECT_MODE_STRING(ep), ep->cid);
+   params.status = -ECONNREFUSED;
+   break;
+   case IWARP_CONN_ERROR_MPA_TERMINATE:
+   DP_NOTICE(p_hwfn, "%s(0x%x) MPA TERMINATE\n",
+ QED_IWARP_CONNECT_MODE_STRING(ep), ep->cid);
+   params.status = -ECONNREFUSED;
+   break;
default:
params.status = -ECONNRESET;
break;
}
 
ep->event_cb(ep->cb_context, );
+
+   /* on passive side, if there is no associated QP (REJECT) we need to
+* return the ep to the pool, (in the regular case we add an element
+* in accept instead of this one.
+* In both cases we need to remove it from the ep_list.
+*/
+   if (fw_return_code != RDMA_RETURN_OK) {
+   ep->tcp_cid = QED_IWARP_INVALID_TCP_CID;
+   if ((ep->connect_mode == TCP_CONNECT_PASSIVE) &&
+   (!ep->qp)) {/* Rejected */
+   qed_iwarp_return_ep(p_hwfn, ep);
+   } else {
+   spin_lock_bh(_hwfn->p_rdma_info->iwarp.iw_lock);
+   list_del(>list_entry);
+   spin_unlock_bh(_hwfn->p_rdma_info->iwarp.iw_lock);
+   }
+   }
 }
 
 static void
@@ -2011,6 +2074,42 @@ void qed_iwarp_exception_received(struct qed_hwfn 
*p_hwfn,
params.event = QED_IWARP_EVENT_DISCONNECT;
event_cb = true;
break;
+   case IWARP_EXCEPTION_DETECTED_RQ_EMPTY:
+   params.event = QED_IWARP_EVENT_RQ_EMPTY;
+   event_cb = true;
+   break;
+   case IWARP_EXCEPTION_DETECTED_IRQ_FULL:
+   params.event = QED_IWARP_EVENT_IRQ_FULL;
+   event_cb = true;
+   break;
+   case IWARP_EXCEPTION_DETECTED_LLP_TIMEOUT:
+   params.event = QED_IWARP_EVENT_LLP_TIMEOUT;
+   event_cb = true;
+ 

[PATCH net-next 09/12] qed: iWARP implement disconnect flows

2017-07-02 Thread Michal Kalderon
This patch takes care of active/passive disconnect flows.
Disconnect flows can be initiated remotely, in which case a async event
will arrive from peer and indicated to qedr driver. These
are referred to as exceptions. When a QP is destroyed, it needs to check
that it's associated ep has been closed.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Yuval Mintz <yuval.mi...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed_iwarp.c | 90 -
 include/linux/qed/qed_rdma_if.h |  2 +
 2 files changed, 91 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c 
b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
index a5da9fc..84bcda3 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
@@ -496,6 +496,8 @@ static void qed_iwarp_destroy_ep(struct qed_hwfn *p_hwfn,
 
 int qed_iwarp_destroy_qp(struct qed_hwfn *p_hwfn, struct qed_rdma_qp *qp)
 {
+   struct qed_iwarp_ep *ep = qp->ep;
+   int wait_count = 0;
int rc = 0;
 
if (qp->iwarp_state != QED_IWARP_QP_STATE_ERROR) {
@@ -505,6 +507,18 @@ int qed_iwarp_destroy_qp(struct qed_hwfn *p_hwfn, struct 
qed_rdma_qp *qp)
return rc;
}
 
+   /* Make sure ep is closed before returning and freeing memory. */
+   if (ep) {
+   while (ep->state != QED_IWARP_EP_CLOSED && wait_count++ < 200)
+   msleep(100);
+
+   if (ep->state != QED_IWARP_EP_CLOSED)
+   DP_NOTICE(p_hwfn, "ep state close timeout state=%x\n",
+ ep->state);
+
+   qed_iwarp_destroy_ep(p_hwfn, ep, false);
+   }
+
rc = qed_iwarp_fw_destroy(p_hwfn, qp);
 
if (qp->shared_queue)
@@ -1956,6 +1970,61 @@ int qed_iwarp_stop(struct qed_hwfn *p_hwfn, struct 
qed_ptt *p_ptt)
return qed_iwarp_ll2_stop(p_hwfn, p_ptt);
 }
 
+void qed_iwarp_qp_in_error(struct qed_hwfn *p_hwfn,
+  struct qed_iwarp_ep *ep, u8 fw_return_code)
+{
+   struct qed_iwarp_cm_event_params params;
+
+   qed_iwarp_modify_qp(p_hwfn, ep->qp, QED_IWARP_QP_STATE_ERROR, true);
+
+   params.event = QED_IWARP_EVENT_CLOSE;
+   params.ep_context = ep;
+   params.cm_info = >cm_info;
+   params.status = (fw_return_code == IWARP_QP_IN_ERROR_GOOD_CLOSE) ?
+0 : -ECONNRESET;
+
+   ep->state = QED_IWARP_EP_CLOSED;
+   spin_lock_bh(_hwfn->p_rdma_info->iwarp.iw_lock);
+   list_del(>list_entry);
+   spin_unlock_bh(_hwfn->p_rdma_info->iwarp.iw_lock);
+
+   ep->event_cb(ep->cb_context, );
+}
+
+void qed_iwarp_exception_received(struct qed_hwfn *p_hwfn,
+ struct qed_iwarp_ep *ep, int fw_ret_code)
+{
+   struct qed_iwarp_cm_event_params params;
+   bool event_cb = false;
+
+   DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "EP(0x%x) fw_ret_code=%d\n",
+  ep->cid, fw_ret_code);
+
+   switch (fw_ret_code) {
+   case IWARP_EXCEPTION_DETECTED_LLP_CLOSED:
+   params.status = 0;
+   params.event = QED_IWARP_EVENT_DISCONNECT;
+   event_cb = true;
+   break;
+   case IWARP_EXCEPTION_DETECTED_LLP_RESET:
+   params.status = -ECONNRESET;
+   params.event = QED_IWARP_EVENT_DISCONNECT;
+   event_cb = true;
+   break;
+   default:
+   DP_VERBOSE(p_hwfn, QED_MSG_RDMA,
+  "Unhandled exception received...fw_ret_code=%d\n",
+  fw_ret_code);
+   break;
+   }
+
+   if (event_cb) {
+   params.ep_context = ep;
+   params.cm_info = >cm_info;
+   ep->event_cb(ep->cb_context, );
+   }
+}
+
 void
 qed_iwarp_connect_complete(struct qed_hwfn *p_hwfn,
   struct qed_iwarp_ep *ep, u8 fw_return_code)
@@ -2009,8 +2078,27 @@ static int qed_iwarp_async_event(struct qed_hwfn *p_hwfn,
   ep->tcp_cid, fw_return_code);
qed_iwarp_connect_complete(p_hwfn, ep, fw_return_code);
break;
-   /* Async event for active side only */
+   case IWARP_EVENT_TYPE_ASYNC_EXCEPTION_DETECTED:
+   if (!qed_iwarp_check_ep_ok(p_hwfn, ep))
+   return -EINVAL;
+   DP_VERBOSE(p_hwfn,
+  QED_MSG_RDMA,
+  "QP(0x%x) IWARP_EVENT_TYPE_ASYNC_EXCEPTION_DETECTED 
fw_ret_code=%d\n",
+  ep->cid, fw_return_code);
+   qed_iwarp_exception_received(p_hwfn, ep, fw_return_code);
+   break;
+   case IWARP_EVENT_TYPE_ASYNC_QP_I

[PATCH net-next 08/12] qed: iWARP CM add active side connect

2017-07-02 Thread Michal Kalderon
This patch implements the active side connect.
Offload a connection, process MPA reply and send RTR.
In some of the common passive/active functions, the active side
will work in blocking mode.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Yuval Mintz <yuval.mi...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed_iwarp.c | 240 ++--
 drivers/net/ethernet/qlogic/qed/qed_iwarp.h |   7 +
 drivers/net/ethernet/qlogic/qed/qed_rdma.c  |   4 +
 include/linux/qed/qed_rdma_if.h |  26 +++
 4 files changed, 265 insertions(+), 12 deletions(-)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c 
b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
index a6dadae..a5da9fc 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
@@ -611,7 +611,10 @@ int qed_iwarp_destroy_qp(struct qed_hwfn *p_hwfn, struct 
qed_rdma_qp *qp)
memset(_data, 0, sizeof(init_data));
init_data.cid = ep->tcp_cid;
init_data.opaque_fid = p_hwfn->hw_info.opaque_fid;
-   init_data.comp_mode = QED_SPQ_MODE_CB;
+   if (ep->connect_mode == TCP_CONNECT_PASSIVE)
+   init_data.comp_mode = QED_SPQ_MODE_CB;
+   else
+   init_data.comp_mode = QED_SPQ_MODE_EBLOCK;
 
rc = qed_sp_init_request(p_hwfn, _ent,
 IWARP_RAMROD_CMD_ID_TCP_OFFLOAD,
@@ -711,7 +714,7 @@ int qed_iwarp_destroy_qp(struct qed_hwfn *p_hwfn, struct 
qed_rdma_qp *qp)
DP_VERBOSE(p_hwfn, QED_MSG_RDMA,
   "private_data_len=%x handshake_mode=%x private_data=(%x)\n",
   async_data->mpa_request.ulp_data_len,
-  mpa_rev, *((u32 *)((u8 *)ep->ep_buffer_virt->in_pdata)));
+  mpa_rev, *((u32 *)(ep->ep_buffer_virt->in_pdata)));
 
if (mpa_rev == MPA_NEGOTIATION_TYPE_ENHANCED) {
/* Read ord/ird values from private data buffer */
@@ -801,7 +804,10 @@ int qed_iwarp_destroy_qp(struct qed_hwfn *p_hwfn, struct 
qed_rdma_qp *qp)
init_data.cid = reject ? ep->tcp_cid : qp->icid;
init_data.opaque_fid = p_hwfn->hw_info.opaque_fid;
 
-   init_data.comp_mode = QED_SPQ_MODE_EBLOCK;
+   if (ep->connect_mode == TCP_CONNECT_ACTIVE)
+   init_data.comp_mode = QED_SPQ_MODE_CB;
+   else
+   init_data.comp_mode = QED_SPQ_MODE_EBLOCK;
 
rc = qed_sp_init_request(p_hwfn, _ent,
 IWARP_RAMROD_CMD_ID_MPA_OFFLOAD,
@@ -890,6 +896,59 @@ int qed_iwarp_destroy_qp(struct qed_hwfn *p_hwfn, struct 
qed_rdma_qp *qp)
spin_unlock_bh(_hwfn->p_rdma_info->iwarp.iw_lock);
 }
 
+void
+qed_iwarp_parse_private_data(struct qed_hwfn *p_hwfn, struct qed_iwarp_ep *ep)
+{
+   struct mpa_v2_hdr *mpa_v2_params;
+   union async_output *async_data;
+   u16 mpa_ird, mpa_ord;
+   u8 mpa_data_size = 0;
+
+   if (MPA_REV2(p_hwfn->p_rdma_info->iwarp.mpa_rev)) {
+   mpa_v2_params =
+   (struct mpa_v2_hdr *)(ep->ep_buffer_virt->in_pdata);
+   mpa_data_size = sizeof(*mpa_v2_params);
+   mpa_ird = ntohs(mpa_v2_params->ird);
+   mpa_ord = ntohs(mpa_v2_params->ord);
+
+   ep->cm_info.ird = (u8)(mpa_ord & MPA_V2_IRD_ORD_MASK);
+   ep->cm_info.ord = (u8)(mpa_ird & MPA_V2_IRD_ORD_MASK);
+   }
+   async_data = >ep_buffer_virt->async_output;
+
+   ep->cm_info.private_data = ep->ep_buffer_virt->in_pdata + mpa_data_size;
+   ep->cm_info.private_data_len = async_data->mpa_response.ulp_data_len -
+  mpa_data_size;
+}
+
+void
+qed_iwarp_mpa_reply_arrived(struct qed_hwfn *p_hwfn, struct qed_iwarp_ep *ep)
+{
+   struct qed_iwarp_cm_event_params params;
+
+   if (ep->connect_mode == TCP_CONNECT_PASSIVE) {
+   DP_NOTICE(p_hwfn,
+ "MPA reply event not expected on passive side!\n");
+   return;
+   }
+
+   params.event = QED_IWARP_EVENT_ACTIVE_MPA_REPLY;
+
+   qed_iwarp_parse_private_data(p_hwfn, ep);
+
+   DP_VERBOSE(p_hwfn, QED_MSG_RDMA,
+  "MPA_NEGOTIATE (v%d): ORD: 0x%x IRD: 0x%x\n",
+  ep->mpa_rev, ep->cm_info.ord, ep->cm_info.ird);
+
+   params.cm_info = >cm_info;
+   params.ep_context = ep;
+   params.status = 0;
+
+   ep->mpa_reply_processed = true;
+
+   ep->event_cb(ep->cb_context, );
+}
+
 #define QED_IWARP_CONNECT_MODE_STRING(ep) \
((ep)->connect_mode == TCP_CONNECT_PASSIVE) ? "Passive" : "Active"
 
@@ -902,7 +961,13 @@ int qed_iwarp_destroy_qp(struct qed_hwfn *p_hwfn, struct 
qed_rdma_qp *qp)
 {
struct qed_iwarp_cm_event_params param

[PATCH net-next 07/12] qed: iWARP CM add passive side connect

2017-07-02 Thread Michal Kalderon
This patch implements the passive side connect.
It addresses pre-allocating resources, creating a connection
element upon valid SYN packet received. Calling upper layer and
implementation of the accept/reject calls.

Error handling is not part of this patch.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Yuval Mintz <yuval.mi...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed.h   |   2 +
 drivers/net/ethernet/qlogic/qed/qed_dev.c   |  11 +
 drivers/net/ethernet/qlogic/qed/qed_iwarp.c | 939 +++-
 drivers/net/ethernet/qlogic/qed/qed_iwarp.h |  62 ++
 drivers/net/ethernet/qlogic/qed/qed_l2.c|  13 -
 drivers/net/ethernet/qlogic/qed/qed_rdma.h  |   2 +
 drivers/net/ethernet/qlogic/qed/qed_sp.h|   2 +
 include/linux/qed/common_hsi.h  |   2 +
 include/linux/qed/qed_rdma_if.h |  26 +-
 9 files changed, 1039 insertions(+), 20 deletions(-)

diff --git a/drivers/net/ethernet/qlogic/qed/qed.h 
b/drivers/net/ethernet/qlogic/qed/qed.h
index fd8cd5e..91003bc 100644
--- a/drivers/net/ethernet/qlogic/qed/qed.h
+++ b/drivers/net/ethernet/qlogic/qed/qed.h
@@ -789,6 +789,8 @@ void qed_configure_vp_wfq_on_link_change(struct qed_dev 
*cdev,
 void qed_clean_wfq_db(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt);
 int qed_device_num_engines(struct qed_dev *cdev);
 int qed_device_get_port_id(struct qed_dev *cdev);
+void qed_set_fw_mac_addr(__le16 *fw_msb,
+__le16 *fw_mid, __le16 *fw_lsb, u8 *mac);
 
 #define QED_LEADING_HWFN(dev)   (>hwfns[0])
 
diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c 
b/drivers/net/ethernet/qlogic/qed/qed_dev.c
index 6c8505d..4060a6a 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_dev.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c
@@ -4127,3 +4127,14 @@ int qed_device_get_port_id(struct qed_dev *cdev)
 {
return (QED_LEADING_HWFN(cdev)->abs_pf_id) % qed_device_num_ports(cdev);
 }
+
+void qed_set_fw_mac_addr(__le16 *fw_msb,
+__le16 *fw_mid, __le16 *fw_lsb, u8 *mac)
+{
+   ((u8 *)fw_msb)[0] = mac[1];
+   ((u8 *)fw_msb)[1] = mac[0];
+   ((u8 *)fw_mid)[0] = mac[3];
+   ((u8 *)fw_mid)[1] = mac[2];
+   ((u8 *)fw_lsb)[0] = mac[5];
+   ((u8 *)fw_lsb)[1] = mac[4];
+}
diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c 
b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
index 2bab57c..a6dadae 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
@@ -44,9 +44,30 @@
 
 #define QED_IWARP_ORD_DEFAULT  32
 #define QED_IWARP_IRD_DEFAULT  32
+#define QED_IWARP_MAX_FW_MSS   4120
+
+#define QED_EP_SIG 0xecabcdef
+
+struct mpa_v2_hdr {
+   __be16 ird;
+   __be16 ord;
+};
+
+#define MPA_V2_PEER2PEER_MODEL  0x8000
+#define MPA_V2_SEND_RTR 0x4000 /* on ird */
+#define MPA_V2_READ_RTR 0x4000 /* on ord */
+#define MPA_V2_WRITE_RTR0x8000
+#define MPA_V2_IRD_ORD_MASK 0x3FFF
+
+#define MPA_REV2(_mpa_rev) ((_mpa_rev) == MPA_NEGOTIATION_TYPE_ENHANCED)
+
+#define QED_IWARP_INVALID_TCP_CID  0x
 #define QED_IWARP_RCV_WND_SIZE_DEF (256 * 1024)
 #define QED_IWARP_RCV_WND_SIZE_MIN (64 * 1024)
+#define TIMESTAMP_HEADER_SIZE  (12)
+
 #define QED_IWARP_TS_ENBIT(0)
+#define QED_IWARP_DA_ENBIT(1)
 #define QED_IWARP_PARAM_CRC_NEEDED (1)
 #define QED_IWARP_PARAM_P2P(1)
 
@@ -63,7 +84,8 @@ void qed_iwarp_init_devinfo(struct qed_hwfn *p_hwfn)
dev->max_inline = IWARP_REQ_MAX_INLINE_DATA_SIZE;
dev->max_qp = min_t(u32,
IWARP_MAX_QPS,
-   p_hwfn->p_rdma_info->num_qps);
+   p_hwfn->p_rdma_info->num_qps) -
+ QED_IWARP_PREALLOC_CNT;
 
dev->max_cq = dev->max_qp;
 
@@ -78,12 +100,22 @@ void qed_iwarp_init_hw(struct qed_hwfn *p_hwfn, struct 
qed_ptt *p_ptt)
p_hwfn->b_rdma_enabled_in_prs = true;
 }
 
+/* We have two cid maps, one for tcp which should be used only from passive
+ * syn processing and replacing a pre-allocated ep in the list. The second
+ * for active tcp and for QPs.
+ */
 static void qed_iwarp_cid_cleaned(struct qed_hwfn *p_hwfn, u32 cid)
 {
cid -= qed_cxt_get_proto_cid_start(p_hwfn, p_hwfn->p_rdma_info->proto);
 
spin_lock_bh(_hwfn->p_rdma_info->lock);
-   qed_bmap_release_id(p_hwfn, _hwfn->p_rdma_info->cid_map, cid);
+
+   if (cid < QED_IWARP_PREALLOC_CNT)
+   qed_bmap_release_id(p_hwfn, _hwfn->p_rdma_info->tcp_cid_map,
+   cid);
+   else
+   qed_bmap_release_id(p_hwfn, _hwfn->p_rdma_info->cid_map, cid);
+
spin_unlock_bh(_hwfn->p_rdma_info->lock);
 }
 
@@ -107,6 +139,45 @@ static int qe

[PATCH net-next 05/12] qed: iWARP CM - setup a ll2 connection for handling SYN packets

2017-07-02 Thread Michal Kalderon
iWARP handles incoming SYN packets using the ll2 interface. This patch
implements ll2 setup and teardown. Additional ll2 connections will
be used in the future which are not part of this patch series.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Yuval Mintz <yuval.mi...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed_iwarp.c | 211 +++-
 drivers/net/ethernet/qlogic/qed/qed_iwarp.h |  12 ++
 2 files changed, 220 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c 
b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
index a8bd5f8..f3b4b32 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
@@ -29,8 +29,11 @@
  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
  */
+#include 
+#include 
 #include "qed_cxt.h"
 #include "qed_hw.h"
+#include "qed_ll2.h"
 #include "qed_rdma.h"
 #include "qed_reg_addr.h"
 #include "qed_sp.h"
@@ -474,12 +477,214 @@ void qed_iwarp_resc_free(struct qed_hwfn *p_hwfn)
 {
 }
 
+static int
+qed_iwarp_ll2_post_rx(struct qed_hwfn *p_hwfn,
+ struct qed_iwarp_ll2_buff *buf, u8 handle)
+{
+   int rc;
+
+   rc = qed_ll2_post_rx_buffer(p_hwfn, handle, buf->data_phys_addr,
+   (u16)buf->buff_size, buf, 1);
+   if (rc) {
+   DP_NOTICE(p_hwfn,
+ "Failed to repost rx buffer to ll2 rc = %d, 
handle=%d\n",
+ rc, handle);
+   dma_free_coherent(_hwfn->cdev->pdev->dev, buf->buff_size,
+ buf->data, buf->data_phys_addr);
+   kfree(buf);
+   }
+
+   return rc;
+}
+
+static void
+qed_iwarp_ll2_comp_syn_pkt(void *cxt, struct qed_ll2_comp_rx_data *data)
+{
+   struct qed_iwarp_ll2_buff *buf = data->cookie;
+   struct qed_hwfn *p_hwfn = cxt;
+
+   if (GET_FIELD(data->parse_flags,
+ PARSING_AND_ERR_FLAGS_L4CHKSMWASCALCULATED) &&
+   GET_FIELD(data->parse_flags, PARSING_AND_ERR_FLAGS_L4CHKSMERROR)) {
+   DP_NOTICE(p_hwfn, "Syn packet received with checksum error\n");
+   goto err;
+   }
+
+   /* Process SYN packet - added later on in series */
+
+err:
+   qed_iwarp_ll2_post_rx(p_hwfn, buf,
+ p_hwfn->p_rdma_info->iwarp.ll2_syn_handle);
+}
+
+static void qed_iwarp_ll2_rel_rx_pkt(void *cxt, u8 connection_handle,
+void *cookie, dma_addr_t rx_buf_addr,
+bool b_last_packet)
+{
+   struct qed_iwarp_ll2_buff *buffer = cookie;
+   struct qed_hwfn *p_hwfn = cxt;
+
+   dma_free_coherent(_hwfn->cdev->pdev->dev, buffer->buff_size,
+ buffer->data, buffer->data_phys_addr);
+   kfree(buffer);
+}
+
+static void qed_iwarp_ll2_comp_tx_pkt(void *cxt, u8 connection_handle,
+ void *cookie, dma_addr_t first_frag_addr,
+ bool b_last_fragment, bool b_last_packet)
+{
+   struct qed_iwarp_ll2_buff *buffer = cookie;
+   struct qed_hwfn *p_hwfn = cxt;
+
+   /* this was originally an rx packet, post it back */
+   qed_iwarp_ll2_post_rx(p_hwfn, buffer, connection_handle);
+}
+
+static void qed_iwarp_ll2_rel_tx_pkt(void *cxt, u8 connection_handle,
+void *cookie, dma_addr_t first_frag_addr,
+bool b_last_fragment, bool b_last_packet)
+{
+   struct qed_iwarp_ll2_buff *buffer = cookie;
+   struct qed_hwfn *p_hwfn = cxt;
+
+   if (!buffer)
+   return;
+
+   dma_free_coherent(_hwfn->cdev->pdev->dev, buffer->buff_size,
+ buffer->data, buffer->data_phys_addr);
+
+   kfree(buffer);
+}
+
+static int qed_iwarp_ll2_stop(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
+{
+   struct qed_iwarp_info *iwarp_info = _hwfn->p_rdma_info->iwarp;
+   int rc = 0;
+
+   if (iwarp_info->ll2_syn_handle != QED_IWARP_HANDLE_INVAL) {
+   rc = qed_ll2_terminate_connection(p_hwfn,
+ iwarp_info->ll2_syn_handle);
+   if (rc)
+   DP_INFO(p_hwfn, "Failed to terminate syn connection\n");
+
+   qed_ll2_release_connection(p_hwfn, iwarp_info->ll2_syn_handle);
+   iwarp_info->ll2_syn_handle = QED_IWARP_HANDLE_INVAL;
+   }
+
+   qed_llh_remove_mac_filter(p_hwfn,
+ p_ptt, p_hwfn->p_rdma_info->iwarp.mac_addr);
+   return rc;
+}
+
+static int
+qed_iwarp_ll2_alloc_buffers(str

[PATCH net-next 06/12] qed: iWARP CM add listener functions and initial SYN processing

2017-07-02 Thread Michal Kalderon
This patch adds the ability to add and remove listeners and identify
whether the SYN packet received is intended for iWARP or not. If
a listener is not found the SYN packet is posted back to the chip.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Yuval Mintz <yuval.mi...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed_iwarp.c | 269 +++-
 drivers/net/ethernet/qlogic/qed/qed_iwarp.h |  23 +++
 drivers/net/ethernet/qlogic/qed/qed_rdma.c  |   2 +
 include/linux/qed/qed_rdma_if.h |  52 ++
 4 files changed, 343 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c 
b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
index f3b4b32..2bab57c 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
@@ -31,6 +31,10 @@
  */
 #include 
 #include 
+#include 
+#include 
+#include 
+#include 
 #include "qed_cxt.h"
 #include "qed_hw.h"
 #include "qed_ll2.h"
@@ -477,6 +481,31 @@ void qed_iwarp_resc_free(struct qed_hwfn *p_hwfn)
 {
 }
 
+static void
+qed_iwarp_print_cm_info(struct qed_hwfn *p_hwfn,
+   struct qed_iwarp_cm_info *cm_info)
+{
+   DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "ip_version = %d\n",
+  cm_info->ip_version);
+
+   if (cm_info->ip_version == QED_TCP_IPV4)
+   DP_VERBOSE(p_hwfn, QED_MSG_RDMA,
+  "remote_ip %pI4h:%x, local_ip %pI4h:%x vlan=%x\n",
+  cm_info->remote_ip, cm_info->remote_port,
+  cm_info->local_ip, cm_info->local_port,
+  cm_info->vlan);
+   else
+   DP_VERBOSE(p_hwfn, QED_MSG_RDMA,
+  "remote_ip %pI6h:%x, local_ip %pI6h:%x vlan=%x\n",
+  cm_info->remote_ip, cm_info->remote_port,
+  cm_info->local_ip, cm_info->local_port,
+  cm_info->vlan);
+
+   DP_VERBOSE(p_hwfn, QED_MSG_RDMA,
+  "private_data_len = %x ord = %d, ird = %d\n",
+  cm_info->private_data_len, cm_info->ord, cm_info->ird);
+}
+
 static int
 qed_iwarp_ll2_post_rx(struct qed_hwfn *p_hwfn,
  struct qed_iwarp_ll2_buff *buf, u8 handle)
@@ -497,11 +526,147 @@ void qed_iwarp_resc_free(struct qed_hwfn *p_hwfn)
return rc;
 }
 
+static struct qed_iwarp_listener *
+qed_iwarp_get_listener(struct qed_hwfn *p_hwfn,
+  struct qed_iwarp_cm_info *cm_info)
+{
+   struct qed_iwarp_listener *listener = NULL;
+   static const u32 ip_zero[4] = { 0, 0, 0, 0 };
+   bool found = false;
+
+   qed_iwarp_print_cm_info(p_hwfn, cm_info);
+
+   list_for_each_entry(listener,
+   _hwfn->p_rdma_info->iwarp.listen_list,
+   list_entry) {
+   if (listener->port == cm_info->local_port) {
+   if (!memcmp(listener->ip_addr,
+   ip_zero, sizeof(ip_zero))) {
+   found = true;
+   break;
+   }
+
+   if (!memcmp(listener->ip_addr,
+   cm_info->local_ip,
+   sizeof(cm_info->local_ip)) &&
+   (listener->vlan == cm_info->vlan)) {
+   found = true;
+   break;
+   }
+   }
+   }
+
+   if (found) {
+   DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "listener found = %p\n",
+  listener);
+   return listener;
+   }
+
+   DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "listener not found\n");
+   return NULL;
+}
+
+static int
+qed_iwarp_parse_rx_pkt(struct qed_hwfn *p_hwfn,
+  struct qed_iwarp_cm_info *cm_info,
+  void *buf,
+  u8 *remote_mac_addr,
+  u8 *local_mac_addr,
+  int *payload_len, int *tcp_start_offset)
+{
+   struct vlan_ethhdr *vethh;
+   bool vlan_valid = false;
+   struct ipv6hdr *ip6h;
+   struct ethhdr *ethh;
+   struct tcphdr *tcph;
+   struct iphdr *iph;
+   int eth_hlen;
+   int ip_hlen;
+   int eth_type;
+   int i;
+
+   ethh = buf;
+   eth_type = ntohs(ethh->h_proto);
+   if (eth_type == ETH_P_8021Q) {
+   vlan_valid = true;
+   vethh = (struct vlan_ethhdr *)ethh;
+   cm_info->vlan = ntohs(vethh->h_vlan_TCI) & VLAN_VID_MASK;
+   eth_type = ntohs(vethh->h_vlan_encapsulated_proto);
+ 

[PATCH net-next 04/12] qed: Add iWARP support in ll2 connections

2017-07-02 Thread Michal Kalderon
Add a new connection type for iWARP ll2 connections for setting
correct ll2 filters and connection type to FW.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Yuval Mintz <yuval.mi...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed_ll2.c | 13 +++--
 include/linux/qed/qed_ll2_if.h|  1 +
 2 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.c 
b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
index e235fb2..c06ad4f 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_ll2.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
@@ -896,7 +896,8 @@ static int qed_sp_ll2_rx_queue_start(struct qed_hwfn 
*p_hwfn,
p_ramrod->main_func_queue = (conn_type == QED_LL2_TYPE_OOO) ? 0 : 1;
 
if ((IS_MF_DEFAULT(p_hwfn) || IS_MF_SI(p_hwfn)) &&
-   p_ramrod->main_func_queue && (conn_type != QED_LL2_TYPE_ROCE)) {
+   p_ramrod->main_func_queue && (conn_type != QED_LL2_TYPE_ROCE) &&
+   (conn_type != QED_LL2_TYPE_IWARP)) {
p_ramrod->mf_si_bcast_accept_all = 1;
p_ramrod->mf_si_mcast_accept_all = 1;
} else {
@@ -972,12 +973,20 @@ static int qed_sp_ll2_tx_queue_start(struct qed_hwfn 
*p_hwfn,
p_ramrod->conn_type = PROTOCOLID_FCOE;
break;
case QED_LL2_TYPE_ISCSI:
-   case QED_LL2_TYPE_OOO:
p_ramrod->conn_type = PROTOCOLID_ISCSI;
break;
case QED_LL2_TYPE_ROCE:
p_ramrod->conn_type = PROTOCOLID_ROCE;
break;
+   case QED_LL2_TYPE_IWARP:
+   p_ramrod->conn_type = PROTOCOLID_IWARP;
+   break;
+   case QED_LL2_TYPE_OOO:
+   if (p_hwfn->hw_info.personality == QED_PCI_ISCSI)
+   p_ramrod->conn_type = PROTOCOLID_ISCSI;
+   else
+   p_ramrod->conn_type = PROTOCOLID_IWARP;
+   break;
default:
p_ramrod->conn_type = PROTOCOLID_ETH;
DP_NOTICE(p_hwfn, "Unknown connection type: %d\n", conn_type);
diff --git a/include/linux/qed/qed_ll2_if.h b/include/linux/qed/qed_ll2_if.h
index c9c56bc..dd7a3b8 100644
--- a/include/linux/qed/qed_ll2_if.h
+++ b/include/linux/qed/qed_ll2_if.h
@@ -50,6 +50,7 @@ enum qed_ll2_conn_type {
QED_LL2_TYPE_OOO,
QED_LL2_TYPE_RESERVED2,
QED_LL2_TYPE_ROCE,
+   QED_LL2_TYPE_IWARP,
QED_LL2_TYPE_RESERVED3,
MAX_QED_LL2_RX_CONN_TYPE
 };
-- 
1.8.3.1



[PATCH net-next 03/12] qed: Rename some ll2 related defines

2017-07-02 Thread Michal Kalderon
Make some names more generic as they will be used by iWARP too.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Yuval Mintz <yuval.mi...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed.h |  2 +-
 drivers/net/ethernet/qlogic/qed/qed_ll2.c | 29 ++---
 include/linux/qed/qed_ll2_if.h|  2 +-
 3 files changed, 16 insertions(+), 17 deletions(-)

diff --git a/drivers/net/ethernet/qlogic/qed/qed.h 
b/drivers/net/ethernet/qlogic/qed/qed.h
index 22e1171..fd8cd5e 100644
--- a/drivers/net/ethernet/qlogic/qed/qed.h
+++ b/drivers/net/ethernet/qlogic/qed/qed.h
@@ -779,7 +779,7 @@ static inline u8 qed_concrete_to_sw_fid(struct qed_dev 
*cdev,
 }
 
 #define PURE_LB_TC 8
-#define OOO_LB_TC 9
+#define PKT_LB_TC 9
 
 int qed_configure_vport_wfq(struct qed_dev *cdev, u16 vp_id, u32 rate);
 void qed_configure_vp_wfq_on_link_change(struct qed_dev *cdev,
diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.c 
b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
index be66f19..e235fb2 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_ll2.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
@@ -309,7 +309,7 @@ static void qed_ll2_txq_flush(struct qed_hwfn *p_hwfn, u8 
connection_handle)
list_del(_pkt->list_entry);
b_last_packet = list_empty(_tx->active_descq);
list_add_tail(_pkt->list_entry, _tx->free_descq);
-   if (p_ll2_conn->input.conn_type == QED_LL2_TYPE_ISCSI_OOO) {
+   if (p_ll2_conn->input.conn_type == QED_LL2_TYPE_OOO) {
struct qed_ooo_buffer *p_buffer;
 
p_buffer = (struct qed_ooo_buffer *)p_pkt->cookie;
@@ -532,7 +532,7 @@ static void qed_ll2_rxq_flush(struct qed_hwfn *p_hwfn, u8 
connection_handle)
 
list_move_tail(_pkt->list_entry, _rx->free_descq);
 
-   if (p_ll2_conn->input.conn_type == QED_LL2_TYPE_ISCSI_OOO) {
+   if (p_ll2_conn->input.conn_type == QED_LL2_TYPE_OOO) {
struct qed_ooo_buffer *p_buffer;
 
p_buffer = (struct qed_ooo_buffer *)p_pkt->cookie;
@@ -893,8 +893,7 @@ static int qed_sp_ll2_rx_queue_start(struct qed_hwfn 
*p_hwfn,
p_ramrod->drop_ttl0_flg = p_ll2_conn->input.rx_drop_ttl0_flg;
p_ramrod->inner_vlan_removal_en = p_ll2_conn->input.rx_vlan_removal_en;
p_ramrod->queue_id = p_ll2_conn->queue_id;
-   p_ramrod->main_func_queue = (conn_type == QED_LL2_TYPE_ISCSI_OOO) ? 0
- : 1;
+   p_ramrod->main_func_queue = (conn_type == QED_LL2_TYPE_OOO) ? 0 : 1;
 
if ((IS_MF_DEFAULT(p_hwfn) || IS_MF_SI(p_hwfn)) &&
p_ramrod->main_func_queue && (conn_type != QED_LL2_TYPE_ROCE)) {
@@ -924,7 +923,7 @@ static int qed_sp_ll2_tx_queue_start(struct qed_hwfn 
*p_hwfn,
if (!QED_LL2_TX_REGISTERED(p_ll2_conn))
return 0;
 
-   if (p_ll2_conn->input.conn_type == QED_LL2_TYPE_ISCSI_OOO)
+   if (p_ll2_conn->input.conn_type == QED_LL2_TYPE_OOO)
p_ll2_conn->tx_stats_en = 0;
else
p_ll2_conn->tx_stats_en = 1;
@@ -955,10 +954,10 @@ static int qed_sp_ll2_tx_queue_start(struct qed_hwfn 
*p_hwfn,
p_ramrod->pbl_size = cpu_to_le16(pbl_size);
 
switch (p_ll2_conn->input.tx_tc) {
-   case LB_TC:
+   case PURE_LB_TC:
pq_id = qed_get_cm_pq_idx(p_hwfn, PQ_FLAGS_LB);
break;
-   case OOO_LB_TC:
+   case PKT_LB_TC:
pq_id = qed_get_cm_pq_idx(p_hwfn, PQ_FLAGS_OOO);
break;
default:
@@ -973,7 +972,7 @@ static int qed_sp_ll2_tx_queue_start(struct qed_hwfn 
*p_hwfn,
p_ramrod->conn_type = PROTOCOLID_FCOE;
break;
case QED_LL2_TYPE_ISCSI:
-   case QED_LL2_TYPE_ISCSI_OOO:
+   case QED_LL2_TYPE_OOO:
p_ramrod->conn_type = PROTOCOLID_ISCSI;
break;
case QED_LL2_TYPE_ROCE:
@@ -1142,7 +1141,7 @@ static int qed_ll2_acquire_connection_tx(struct qed_hwfn 
*p_hwfn,
u16 buf_idx;
int rc = 0;
 
-   if (p_ll2_info->input.conn_type != QED_LL2_TYPE_ISCSI_OOO)
+   if (p_ll2_info->input.conn_type != QED_LL2_TYPE_OOO)
return rc;
 
/* Correct number of requested OOO buffers if needed */
@@ -1280,7 +1279,7 @@ int qed_ll2_acquire_connection(void *cxt, struct 
qed_ll2_acquire_data *data)
goto q_allocate_fail;
 
/* Register callbacks for the Rx/Tx queues */
-   if (data->input.conn_type == QED_LL2_TYPE_ISCSI_OOO) {
+   if (data->input.conn_type == QED_LL2_TYPE_OOO) {
comp_rx_cb = qed_ll2_lb_rxq_completion;
comp_tx_cb = 

[PATCH net-next 02/12] qed: Implement iWARP initialization, teardown and qp operations

2017-07-02 Thread Michal Kalderon
This patch adds iWARP support for flows that have common code
between RoCE and iWARP, such as initialization, teardown and
qp setup verbs: create, destroy, modify, query.
It introduces the iWARP specific files qed_iwarp.[ch] and
iwarp_common.h

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Yuval Mintz <yuval.mi...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/Makefile|   2 +-
 drivers/net/ethernet/qlogic/qed/qed_dev.c   |   9 +-
 drivers/net/ethernet/qlogic/qed/qed_hsi.h   |   1 +
 drivers/net/ethernet/qlogic/qed/qed_iwarp.c | 531 
 drivers/net/ethernet/qlogic/qed/qed_iwarp.h |  85 +
 drivers/net/ethernet/qlogic/qed/qed_rdma.c  | 133 +--
 drivers/net/ethernet/qlogic/qed/qed_rdma.h  |   3 +
 drivers/net/ethernet/qlogic/qed/qed_roce.c  |  20 ++
 drivers/net/ethernet/qlogic/qed/qed_sp.h|   5 +-
 include/linux/qed/iwarp_common.h|  53 +++
 include/linux/qed/qed_rdma_if.h |   1 +
 11 files changed, 803 insertions(+), 40 deletions(-)
 create mode 100644 drivers/net/ethernet/qlogic/qed/qed_iwarp.c
 create mode 100644 drivers/net/ethernet/qlogic/qed/qed_iwarp.h
 create mode 100644 include/linux/qed/iwarp_common.h

diff --git a/drivers/net/ethernet/qlogic/qed/Makefile 
b/drivers/net/ethernet/qlogic/qed/Makefile
index 6745238..82dd470 100644
--- a/drivers/net/ethernet/qlogic/qed/Makefile
+++ b/drivers/net/ethernet/qlogic/qed/Makefile
@@ -5,6 +5,6 @@ qed-y := qed_cxt.o qed_dev.o qed_hw.o qed_init_fw_funcs.o 
qed_init_ops.o \
 qed_selftest.o qed_dcbx.o qed_debug.o qed_ptp.o
 qed-$(CONFIG_QED_SRIOV) += qed_sriov.o qed_vf.o
 qed-$(CONFIG_QED_LL2) += qed_ll2.o
-qed-$(CONFIG_QED_RDMA) += qed_roce.o qed_rdma.o
+qed-$(CONFIG_QED_RDMA) += qed_roce.o qed_rdma.o qed_iwarp.o
 qed-$(CONFIG_QED_ISCSI) += qed_iscsi.o qed_ooo.o
 qed-$(CONFIG_QED_FCOE) += qed_fcoe.o
diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c 
b/drivers/net/ethernet/qlogic/qed/qed_dev.c
index 68e6182..6c8505d 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_dev.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c
@@ -937,8 +937,15 @@ int qed_resc_alloc(struct qed_dev *cdev)
/* EQ */
n_eqes = qed_chain_get_capacity(_hwfn->p_spq->chain);
if (QED_IS_RDMA_PERSONALITY(p_hwfn)) {
+   enum protocol_type rdma_proto;
+
+   if (QED_IS_ROCE_PERSONALITY(p_hwfn))
+   rdma_proto = PROTOCOLID_ROCE;
+   else
+   rdma_proto = PROTOCOLID_IWARP;
+
num_cons = qed_cxt_get_proto_cid_count(p_hwfn,
-  PROTOCOLID_ROCE,
+  rdma_proto,
   NULL) * 2;
n_eqes += num_cons + 2 * MAX_NUM_VFS_BB;
} else if (p_hwfn->hw_info.personality == QED_PCI_ISCSI) {
diff --git a/drivers/net/ethernet/qlogic/qed/qed_hsi.h 
b/drivers/net/ethernet/qlogic/qed/qed_hsi.h
index 3bf3614..31fb0bf 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_hsi.h
+++ b/drivers/net/ethernet/qlogic/qed/qed_hsi.h
@@ -46,6 +46,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c 
b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
new file mode 100644
index 000..a8bd5f8
--- /dev/null
+++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
@@ -0,0 +1,531 @@
+/* QLogic qed NIC Driver
+ * Copyright (c) 2015-2017  QLogic Corporation
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ *  - Redistributions of source code must retain the above
+ *copyright notice, this list of conditions and the following
+ *disclaimer.
+ *
+ *  - Redistributions in binary form must reproduce the above
+ *copyright notice, this list of conditions and the following
+ *disclaimer in the documentation and /or other materials
+ *provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONT

[PATCH net-next 01/12] qed: Introduce iWARP personality

2017-07-02 Thread Michal Kalderon
iWARP personality introduced the need for differentiating in several
places in the code whether we are RoCE, iWARP or either. This
leads to introducing new macros for querying the personality.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Yuval Mintz <yuval.mi...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed.h  | 26 +++---
 drivers/net/ethernet/qlogic/qed/qed_cxt.c  |  8 
 drivers/net/ethernet/qlogic/qed/qed_dev.c  | 12 +---
 drivers/net/ethernet/qlogic/qed/qed_l2.c   |  3 +--
 drivers/net/ethernet/qlogic/qed/qed_ll2.c  |  2 +-
 drivers/net/ethernet/qlogic/qed/qed_main.c | 17 -
 include/linux/qed/common_hsi.h |  2 +-
 7 files changed, 43 insertions(+), 27 deletions(-)

diff --git a/drivers/net/ethernet/qlogic/qed/qed.h 
b/drivers/net/ethernet/qlogic/qed/qed.h
index 14b08ee..22e1171 100644
--- a/drivers/net/ethernet/qlogic/qed/qed.h
+++ b/drivers/net/ethernet/qlogic/qed/qed.h
@@ -210,14 +210,16 @@ struct qed_tunn_update_params {
 
 /* The PCI personality is not quite synonymous to protocol ID:
  * 1. All personalities need CORE connections
- * 2. The Ethernet personality may support also the RoCE protocol
+ * 2. The Ethernet personality may support also the RoCE/iWARP protocol
  */
 enum qed_pci_personality {
QED_PCI_ETH,
QED_PCI_FCOE,
QED_PCI_ISCSI,
QED_PCI_ETH_ROCE,
-   QED_PCI_DEFAULT /* default in shmem */
+   QED_PCI_ETH_IWARP,
+   QED_PCI_ETH_RDMA,
+   QED_PCI_DEFAULT, /* default in shmem */
 };
 
 /* All VFs are symmetric, all counters are PF + all VFs */
@@ -277,6 +279,7 @@ enum qed_dev_cap {
QED_DEV_CAP_FCOE,
QED_DEV_CAP_ISCSI,
QED_DEV_CAP_ROCE,
+   QED_DEV_CAP_IWARP,
 };
 
 enum qed_wol_support {
@@ -286,7 +289,24 @@ enum qed_wol_support {
 
 struct qed_hw_info {
/* PCI personality */
-   enum qed_pci_personalitypersonality;
+   enum qed_pci_personality personality;
+#define QED_IS_RDMA_PERSONALITY(dev)   \
+   ((dev)->hw_info.personality == QED_PCI_ETH_ROCE ||  \
+(dev)->hw_info.personality == QED_PCI_ETH_IWARP || \
+(dev)->hw_info.personality == QED_PCI_ETH_RDMA)
+#define QED_IS_ROCE_PERSONALITY(dev)  \
+   ((dev)->hw_info.personality == QED_PCI_ETH_ROCE || \
+(dev)->hw_info.personality == QED_PCI_ETH_RDMA)
+#define QED_IS_IWARP_PERSONALITY(dev)  \
+   ((dev)->hw_info.personality == QED_PCI_ETH_IWARP || \
+(dev)->hw_info.personality == QED_PCI_ETH_RDMA)
+#define QED_IS_L2_PERSONALITY(dev)   \
+   ((dev)->hw_info.personality == QED_PCI_ETH || \
+QED_IS_RDMA_PERSONALITY(dev))
+#define QED_IS_FCOE_PERSONALITY(dev) \
+   ((dev)->hw_info.personality == QED_PCI_FCOE)
+#define QED_IS_ISCSI_PERSONALITY(dev) \
+   ((dev)->hw_info.personality == QED_PCI_ISCSI)
 
/* Resource Allocation scheme results */
u32 resc_start[QED_MAX_RESC];
diff --git a/drivers/net/ethernet/qlogic/qed/qed_cxt.c 
b/drivers/net/ethernet/qlogic/qed/qed_cxt.c
index e201214..38716f7 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_cxt.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_cxt.c
@@ -853,7 +853,7 @@ u32 qed_cxt_cfg_ilt_compute_excess(struct qed_hwfn *p_hwfn, 
u32 used_lines)
if (!excess_lines)
return 0;
 
-   if (p_hwfn->hw_info.personality != QED_PCI_ETH_ROCE)
+   if (!QED_IS_RDMA_PERSONALITY(p_hwfn))
return 0;
 
p_mngr = p_hwfn->p_cxt_mngr;
@@ -1033,7 +1033,7 @@ static int qed_ilt_blk_alloc(struct qed_hwfn *p_hwfn,
u32 lines, line, sz_left, lines_to_skip = 0;
 
/* Special handling for RoCE that supports dynamic allocation */
-   if ((p_hwfn->hw_info.personality == QED_PCI_ETH_ROCE) &&
+   if (QED_IS_RDMA_PERSONALITY(p_hwfn) &&
((ilt_client == ILT_CLI_CDUT) || ilt_client == ILT_CLI_TSDM))
return 0;
 
@@ -1833,7 +1833,7 @@ static void qed_tm_init_pf(struct qed_hwfn *p_hwfn)
tm_offset += tm_iids.pf_tids[i];
}
 
-   if (p_hwfn->hw_info.personality == QED_PCI_ETH_ROCE)
+   if (QED_IS_RDMA_PERSONALITY(p_hwfn))
active_seg_mask = 0;
 
STORE_RT_REG(p_hwfn, TM_REG_PF_ENABLE_TASK_RT_OFFSET, active_seg_mask);
@@ -2344,7 +2344,7 @@ int qed_cxt_get_tid_mem_info(struct qed_hwfn *p_hwfn,
   last_cid_allocated - 1);
 
if (!p_hwfn->b_rdma_enabled_in_prs) {
-   /* Enable RoCE search */
+   /* Enable RDMA search */
qed_wr(p_hwfn, p_ptt, p_hwfn->rdma_prs_search_reg, 1);
p_hwfn->b_rdma_enabled_in_prs = true;
}
diff --git a/drivers

[PATCH net-next 00/12] qed: Add iWARP support for QL4xxxx

2017-07-02 Thread Michal Kalderon
This patch series adds iWARP support to our QL4 networking adapters.
The code changes span across qed and qedr drivers, but this series contains
changes to qed only. Once the series is accepted, the qedr series will
be submitted to the rdma tree.
There is one additional qed patch which enables the iWARP, this patch is
delayed until the qedr series will be accepted. 

The patches were previously sent as an RFC, and these are the first 12
patches in the RFC series:
https://www.spinics.net/lists/linux-rdma/msg51416.html

This series was tested and built against net-next.

MAINTAINERS file is not updated in this PATCH as there is a pending patch
for qedr driver update https://patchwork.kernel.org/patch/9752761.

Michal Kalderon (12):
  qed: Introduce iWARP personality
  qed: Implement iWARP initialization, teardown and qp operations
  qed: Rename some ll2 related defines
  qed: Add iWARP support in ll2 connections
  qed: iWARP CM - setup a ll2 connection for handling SYN packets
  qed: iWARP CM add listener functions and initial SYN processing
  qed: iWARP CM add passive side connect
  qed: iWARP CM add active side connect
  qed: iWARP implement disconnect flows
  qed: iWARP CM add error handling
  qed: Add iWARP protocol support in context allocation
  qed: Add iWARP support for physical queue allocation

 drivers/net/ethernet/qlogic/qed/Makefile|2 +-
 drivers/net/ethernet/qlogic/qed/qed.h   |   30 +-
 drivers/net/ethernet/qlogic/qed/qed_cxt.c   |   21 +-
 drivers/net/ethernet/qlogic/qed/qed_dev.c   |   36 +-
 drivers/net/ethernet/qlogic/qed/qed_hsi.h   |1 +
 drivers/net/ethernet/qlogic/qed/qed_iwarp.c | 2409 +++
 drivers/net/ethernet/qlogic/qed/qed_iwarp.h |  189 +++
 drivers/net/ethernet/qlogic/qed/qed_l2.c|   16 +-
 drivers/net/ethernet/qlogic/qed/qed_ll2.c   |   42 +-
 drivers/net/ethernet/qlogic/qed/qed_main.c  |   17 +-
 drivers/net/ethernet/qlogic/qed/qed_rdma.c  |  139 +-
 drivers/net/ethernet/qlogic/qed/qed_rdma.h  |5 +
 drivers/net/ethernet/qlogic/qed/qed_roce.c  |   20 +
 drivers/net/ethernet/qlogic/qed/qed_sp.h|7 +-
 include/linux/qed/common_hsi.h  |4 +-
 include/linux/qed/iwarp_common.h|   53 +
 include/linux/qed/qed_ll2_if.h  |3 +-
 include/linux/qed/qed_rdma_if.h |  114 ++
 18 files changed, 3008 insertions(+), 100 deletions(-)
 create mode 100644 drivers/net/ethernet/qlogic/qed/qed_iwarp.c
 create mode 100644 drivers/net/ethernet/qlogic/qed/qed_iwarp.h
 create mode 100644 include/linux/qed/iwarp_common.h

-- 
1.8.3.1



[RFC 19/19] qed*: Add iWARP enablement support

2017-06-26 Thread Michal Kalderon
This patch is the last of the initial iWARP patch series. It
adds the possiblity to actually detect iWARP from the device and enable
it in the critical locations which basically make iWARP available.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Yuval Mintz <yuval.mi...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>

---
 drivers/infiniband/hw/qedr/main.c |  2 ++
 drivers/net/ethernet/qlogic/qed/qed_cxt.c |  6 ++
 drivers/net/ethernet/qlogic/qed/qed_mcp.c | 10 +-
 drivers/net/ethernet/qlogic/qed/qed_rdma.c|  5 -
 drivers/net/ethernet/qlogic/qed/qed_sp_commands.c |  2 ++
 5 files changed, 19 insertions(+), 6 deletions(-)

diff --git a/drivers/infiniband/hw/qedr/main.c 
b/drivers/infiniband/hw/qedr/main.c
index c594b11..3357053 100644
--- a/drivers/infiniband/hw/qedr/main.c
+++ b/drivers/infiniband/hw/qedr/main.c
@@ -871,6 +871,8 @@ static struct qedr_dev *qedr_add(struct qed_dev *cdev, 
struct pci_dev *pdev,
if (rc)
goto init_err;
 
+   dev->rdma_type = dev_info.rdma_type;
+
dev->num_hwfns = dev_info.common.num_hwfns;
dev->rdma_ctx = dev->ops->rdma_get_rdma_ctx(cdev);
 
diff --git a/drivers/net/ethernet/qlogic/qed/qed_cxt.c 
b/drivers/net/ethernet/qlogic/qed/qed_cxt.c
index af106be..32bed84 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_cxt.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_cxt.c
@@ -2069,6 +2069,12 @@ static void qed_rdma_set_pf_params(struct qed_hwfn 
*p_hwfn,
 
num_srqs = min_t(u32, 32 * 1024, p_params->num_srqs);
 
+   if (p_hwfn->mcp_info->func_info.protocol == QED_PCI_ETH_RDMA) {
+   DP_NOTICE(p_hwfn,
+ "Current day drivers don't support RoCE & iWARP. 
Default to RoCE-only\n");
+   p_hwfn->hw_info.personality = QED_PCI_ETH_ROCE;
+   }
+
switch (p_hwfn->hw_info.personality) {
case QED_PCI_ETH_IWARP:
/* Each QP requires one connection */
diff --git a/drivers/net/ethernet/qlogic/qed/qed_mcp.c 
b/drivers/net/ethernet/qlogic/qed/qed_mcp.c
index 9da9104..8645099 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_mcp.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_mcp.c
@@ -1650,12 +1650,12 @@ int qed_mcp_get_media_type(struct qed_dev *cdev, u32 
*p_media_type)
case FW_MB_PARAM_GET_PF_RDMA_ROCE:
*p_proto = QED_PCI_ETH_ROCE;
break;
-   case FW_MB_PARAM_GET_PF_RDMA_BOTH:
-   DP_NOTICE(p_hwfn,
- "Current day drivers don't support RoCE & iWARP. 
Default to RoCE-only\n");
-   *p_proto = QED_PCI_ETH_ROCE;
-   break;
case FW_MB_PARAM_GET_PF_RDMA_IWARP:
+   *p_proto = QED_PCI_ETH_IWARP;
+   break;
+   case FW_MB_PARAM_GET_PF_RDMA_BOTH:
+   *p_proto = QED_PCI_ETH_RDMA;
+   break;
default:
DP_NOTICE(p_hwfn,
  "MFW answers GET_PF_RDMA_PROTOCOL but param is 
%08x\n",
diff --git a/drivers/net/ethernet/qlogic/qed/qed_rdma.c 
b/drivers/net/ethernet/qlogic/qed/qed_rdma.c
index 6fb9951..06715f7 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_rdma.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_rdma.c
@@ -156,7 +156,10 @@ static int qed_rdma_alloc(struct qed_hwfn *p_hwfn,
return rc;
 
p_hwfn->p_rdma_info = p_rdma_info;
-   p_rdma_info->proto = PROTOCOLID_ROCE;
+   if (QED_IS_IWARP_PERSONALITY(p_hwfn))
+   p_rdma_info->proto = PROTOCOLID_IWARP;
+   else
+   p_rdma_info->proto = PROTOCOLID_ROCE;
 
num_cons = qed_cxt_get_proto_cid_count(p_hwfn, p_rdma_info->proto,
   NULL);
diff --git a/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c 
b/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c
index 46d0c3c..3503b43 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c
@@ -376,7 +376,9 @@ int qed_sp_pf_start(struct qed_hwfn *p_hwfn,
case QED_PCI_ISCSI:
p_ramrod->personality = PERSONALITY_ISCSI;
break;
+   case QED_PCI_ETH_IWARP:
case QED_PCI_ETH_ROCE:
+   case QED_PCI_ETH_RDMA:
p_ramrod->personality = PERSONALITY_RDMA_AND_ETH;
break;
default:
-- 
1.8.3.1



[RFC 18/19] RDMA/qedr: Add iWARP connection management functions

2017-06-26 Thread Michal Kalderon
Implements the iWARP connection management functions:
connect, accept, create listener and destroy listener

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Ram Amrani <ram.amr...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>

---
 drivers/infiniband/hw/qedr/main.c   |  11 +
 drivers/infiniband/hw/qedr/qedr.h   |  21 +-
 drivers/infiniband/hw/qedr/qedr_iw_cm.c | 689 
 drivers/infiniband/hw/qedr/qedr_iw_cm.h |  12 +
 drivers/infiniband/hw/qedr/verbs.c  |  17 +
 5 files changed, 749 insertions(+), 1 deletion(-)

diff --git a/drivers/infiniband/hw/qedr/main.c 
b/drivers/infiniband/hw/qedr/main.c
index ebac63f..c594b11 100644
--- a/drivers/infiniband/hw/qedr/main.c
+++ b/drivers/infiniband/hw/qedr/main.c
@@ -145,6 +145,12 @@ int qedr_iw_register_device(struct qedr_dev *dev)
dev->ibdev.iwcm = kzalloc(sizeof(*dev->ibdev.iwcm), GFP_KERNEL);
if (!dev->ibdev.iwcm)
return -ENOMEM;
+
+   dev->ibdev.iwcm->connect = qedr_iw_connect;
+   dev->ibdev.iwcm->accept = qedr_iw_accept;
+   dev->ibdev.iwcm->reject = qedr_iw_reject;
+   dev->ibdev.iwcm->create_listen = qedr_iw_create_listen;
+   dev->ibdev.iwcm->destroy_listen = qedr_iw_destroy_listen;
dev->ibdev.iwcm->add_ref = qedr_iw_qp_add_ref;
dev->ibdev.iwcm->rem_ref = qedr_iw_qp_rem_ref;
dev->ibdev.iwcm->get_qp = qedr_iw_get_qp;
@@ -296,6 +302,9 @@ static void qedr_free_resources(struct qedr_dev *dev)
 {
int i;
 
+   if (IS_IWARP(dev))
+   destroy_workqueue(dev->iwarp_wq);
+
for (i = 0; i < dev->num_cnq; i++) {
qedr_free_mem_sb(dev, >sb_array[i], dev->sb_start + i);
dev->ops->common->chain_free(dev->cdev, >cnq_array[i].pbl);
@@ -323,6 +332,7 @@ static int qedr_alloc_resources(struct qedr_dev *dev)
if (IS_IWARP(dev)) {
spin_lock_init(>idr_lock);
idr_init(>qpidr);
+   dev->iwarp_wq = create_singlethread_workqueue("qedr_iwarpq");
}
 
/* Allocate Status blocks for CNQ */
@@ -800,6 +810,7 @@ static int qedr_init_hw(struct qedr_dev *dev)
in_params->events = 
in_params->cq_mode = QED_RDMA_CQ_MODE_32_BITS;
in_params->max_mtu = dev->ndev->mtu;
+   dev->iwarp_max_mtu = dev->ndev->mtu;
ether_addr_copy(_params->mac_addr[0], dev->ndev->dev_addr);
 
rc = dev->ops->rdma_init(dev->cdev, in_params);
diff --git a/drivers/infiniband/hw/qedr/qedr.h 
b/drivers/infiniband/hw/qedr/qedr.h
index 5dd82d1..7c7183a 100644
--- a/drivers/infiniband/hw/qedr/qedr.h
+++ b/drivers/infiniband/hw/qedr/qedr.h
@@ -60,6 +60,7 @@
 #define QEDR_MSG_SQ   "  SQ"
 #define QEDR_MSG_QP   "  QP"
 #define QEDR_MSG_GSI  " GSI"
+#define QEDR_MSG_IWARP  " IW"
 
 #define QEDR_CQ_MAGIC_NUMBER   (0x11223344)
 
@@ -167,6 +168,8 @@ struct qedr_dev {
enum qed_rdma_type  rdma_type;
spinlock_t  idr_lock; /* Protect qpidr data-structure */
struct idr  qpidr;
+   struct workqueue_struct *iwarp_wq;
+   u16 iwarp_max_mtu;
unsigned long enet_state;
 };
 
@@ -344,7 +347,7 @@ enum qedr_qp_err_bitmap {
 struct qedr_qp {
struct ib_qp ibqp;  /* must be first */
struct qedr_dev *dev;
-
+   struct qedr_iw_ep *ep;
struct qedr_qp_hwq_info sq;
struct qedr_qp_hwq_info rq;
 
@@ -402,6 +405,7 @@ struct qedr_qp {
struct qedr_userq usq;
struct qedr_userq urq;
atomic_t refcnt;
+   bool destroyed;
 };
 
 struct qedr_ah {
@@ -482,6 +486,21 @@ static inline int qedr_get_dmac(struct qedr_dev *dev,
return 0;
 }
 
+struct qedr_iw_listener {
+   struct qedr_dev *dev;
+   struct iw_cm_id *cm_id;
+   int backlog;
+   void*qed_handle;
+};
+
+struct qedr_iw_ep {
+   struct qedr_dev *dev;
+   struct iw_cm_id *cm_id;
+   struct qedr_qp  *qp;
+   void*qed_context;
+   u8  during_connect;
+};
+
 static inline
 struct qedr_ucontext *get_qedr_ucontext(struct ib_ucontext *ibucontext)
 {
diff --git a/drivers/infiniband/hw/qedr/qedr_iw_cm.c 
b/drivers/infiniband/hw/qedr/qedr_iw_cm.c
index 8811dbc..fe9b2b6 100644
--- a/drivers/infiniband/hw/qedr/qedr_iw_cm.c
+++ b/drivers/infiniband/hw/qedr/qedr_iw_cm.c
@@ -29,7 +29,696 @@
  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
  */
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
 #include "qedr.h"
+#include "qedr_iw_cm.h"
+
+static inline void
+qedr_fill_sockaddr4(const struct qed_iwarp_cm_info *cm_info,
+   struct iw_cm_event *event)
+{
+   

[RFC 17/19] RDMA/qedr: Add iWARP connection management qp related callbacks

2017-06-26 Thread Michal Kalderon
This patch implements the following iWARP callbacks:
qp_add_ref
qp_rem_ref
get_qp

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Ram Amrani <ram.amr...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>

---
 drivers/infiniband/hw/qedr/Makefile |  2 +-
 drivers/infiniband/hw/qedr/main.c   | 10 ++
 drivers/infiniband/hw/qedr/qedr.h   |  5 ++-
 drivers/infiniband/hw/qedr/qedr_iw_cm.c | 57 +
 drivers/infiniband/hw/qedr/qedr_iw_cm.h | 37 +
 drivers/infiniband/hw/qedr/verbs.c  | 38 --
 6 files changed, 145 insertions(+), 4 deletions(-)
 create mode 100644 drivers/infiniband/hw/qedr/qedr_iw_cm.c
 create mode 100644 drivers/infiniband/hw/qedr/qedr_iw_cm.h

diff --git a/drivers/infiniband/hw/qedr/Makefile 
b/drivers/infiniband/hw/qedr/Makefile
index 331a361..1c0bc4f 100644
--- a/drivers/infiniband/hw/qedr/Makefile
+++ b/drivers/infiniband/hw/qedr/Makefile
@@ -1,3 +1,3 @@
 obj-$(CONFIG_INFINIBAND_QEDR) := qedr.o
 
-qedr-y := main.o verbs.o qedr_roce_cm.o
+qedr-y := main.o verbs.o qedr_roce_cm.o qedr_iw_cm.o
diff --git a/drivers/infiniband/hw/qedr/main.c 
b/drivers/infiniband/hw/qedr/main.c
index ad227b5..ebac63f 100644
--- a/drivers/infiniband/hw/qedr/main.c
+++ b/drivers/infiniband/hw/qedr/main.c
@@ -39,12 +39,14 @@
 #include 
 #include 
 #include 
+#include 
 
 #include 
 #include 
 #include "qedr.h"
 #include "verbs.h"
 #include 
+#include "qedr_iw_cm.h"
 
 MODULE_DESCRIPTION("QLogic 40G/100G ROCE Driver");
 MODULE_AUTHOR("QLogic Corporation");
@@ -143,6 +145,9 @@ int qedr_iw_register_device(struct qedr_dev *dev)
dev->ibdev.iwcm = kzalloc(sizeof(*dev->ibdev.iwcm), GFP_KERNEL);
if (!dev->ibdev.iwcm)
return -ENOMEM;
+   dev->ibdev.iwcm->add_ref = qedr_iw_qp_add_ref;
+   dev->ibdev.iwcm->rem_ref = qedr_iw_qp_rem_ref;
+   dev->ibdev.iwcm->get_qp = qedr_iw_get_qp;
 
memcpy(dev->ibdev.iwcm->ifname,
   dev->ndev->name, sizeof(dev->ibdev.iwcm->ifname));
@@ -315,6 +320,11 @@ static int qedr_alloc_resources(struct qedr_dev *dev)
 
spin_lock_init(>sgid_lock);
 
+   if (IS_IWARP(dev)) {
+   spin_lock_init(>idr_lock);
+   idr_init(>qpidr);
+   }
+
/* Allocate Status blocks for CNQ */
dev->sb_array = kcalloc(dev->num_cnq, sizeof(*dev->sb_array),
GFP_KERNEL);
diff --git a/drivers/infiniband/hw/qedr/qedr.h 
b/drivers/infiniband/hw/qedr/qedr.h
index 0c0a39a..5dd82d1 100644
--- a/drivers/infiniband/hw/qedr/qedr.h
+++ b/drivers/infiniband/hw/qedr/qedr.h
@@ -33,6 +33,7 @@
 #define __QEDR_H__
 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -164,7 +165,8 @@ struct qedr_dev {
struct qedr_cq  *gsi_rqcq;
struct qedr_qp  *gsi_qp;
enum qed_rdma_type  rdma_type;
-
+   spinlock_t  idr_lock; /* Protect qpidr data-structure */
+   struct idr  qpidr;
unsigned long enet_state;
 };
 
@@ -399,6 +401,7 @@ struct qedr_qp {
/* Relevant to qps created from user space only (applications) */
struct qedr_userq usq;
struct qedr_userq urq;
+   atomic_t refcnt;
 };
 
 struct qedr_ah {
diff --git a/drivers/infiniband/hw/qedr/qedr_iw_cm.c 
b/drivers/infiniband/hw/qedr/qedr_iw_cm.c
new file mode 100644
index 000..8811dbc
--- /dev/null
+++ b/drivers/infiniband/hw/qedr/qedr_iw_cm.c
@@ -0,0 +1,57 @@
+/* QLogic qedr NIC Driver
+ * Copyright (c) 2015-2017  QLogic Corporation
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ *  - Redistributions of source code must retain the above
+ *copyright notice, this list of conditions and the following
+ *disclaimer.
+ *
+ *  - Redistributions in binary form must reproduce the above
+ *copyright notice, this list of conditions and the following
+ *disclaimer in the documentation and /or other materials
+ *provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TO

[RFC 16/19] RDMA/qedr: Add support for read with invalidate, supported in iWARP

2017-06-26 Thread Michal Kalderon
iWARP supports read with invalidate. There is an assumption
that read with invalidate will only be called on an iWARP device

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Ram Amrani <ram.amr...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>

---
 drivers/infiniband/hw/qedr/qedr_hsi_rdma.h | 6 --
 drivers/infiniband/hw/qedr/verbs.c | 8 +++-
 2 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/drivers/infiniband/hw/qedr/qedr_hsi_rdma.h 
b/drivers/infiniband/hw/qedr/qedr_hsi_rdma.h
index 5c98d20..b7587f1 100644
--- a/drivers/infiniband/hw/qedr/qedr_hsi_rdma.h
+++ b/drivers/infiniband/hw/qedr/qedr_hsi_rdma.h
@@ -655,8 +655,10 @@ struct rdma_sq_rdma_wqe_1st {
 #define RDMA_SQ_RDMA_WQE_1ST_INLINE_FLG_SHIFT  4
 #define RDMA_SQ_RDMA_WQE_1ST_DIF_ON_HOST_FLG_MASK  0x1
 #define RDMA_SQ_RDMA_WQE_1ST_DIF_ON_HOST_FLG_SHIFT 5
-#define RDMA_SQ_RDMA_WQE_1ST_RESERVED0_MASK0x3
-#define RDMA_SQ_RDMA_WQE_1ST_RESERVED0_SHIFT   6
+#define RDMA_SQ_RDMA_WQE_1ST_READ_INV_FLG_MASK 0x1
+#define RDMA_SQ_RDMA_WQE_1ST_READ_INV_FLG_SHIFT6
+#define RDMA_SQ_RDMA_WQE_1ST_RESERVED0_MASK0x1
+#define RDMA_SQ_RDMA_WQE_1ST_RESERVED0_SHIFT   7
u8 wqe_size;
u8 prev_wqe_size;
 };
diff --git a/drivers/infiniband/hw/qedr/verbs.c 
b/drivers/infiniband/hw/qedr/verbs.c
index 7fef9b3..fc9ff13 100644
--- a/drivers/infiniband/hw/qedr/verbs.c
+++ b/drivers/infiniband/hw/qedr/verbs.c
@@ -2837,6 +2837,7 @@ static enum ib_wc_opcode qedr_ib_to_wc_opcode(enum 
ib_wr_opcode opcode)
case IB_WR_SEND_WITH_INV:
return IB_WC_SEND;
case IB_WR_RDMA_READ:
+   case IB_WR_RDMA_READ_WITH_INV:
return IB_WC_RDMA_READ;
case IB_WR_ATOMIC_CMP_AND_SWP:
return IB_WC_COMP_SWAP;
@@ -2997,11 +2998,8 @@ static int __qedr_post_send(struct ib_qp *ibqp, struct 
ib_send_wr *wr,
qp->wqe_wr_id[qp->sq.prod].bytes_len = rwqe->length;
break;
case IB_WR_RDMA_READ_WITH_INV:
-   DP_ERR(dev,
-  "RDMA READ WITH INVALIDATE not supported\n");
-   *bad_wr = wr;
-   rc = -EINVAL;
-   break;
+   SET_FIELD2(wqe->flags, RDMA_SQ_RDMA_WQE_1ST_READ_INV_FLG, 1);
+   /* fallthrough... same is identical to RDMA READ */
 
case IB_WR_RDMA_READ:
wqe->req_type = RDMA_SQ_REQ_TYPE_RDMA_RD;
-- 
1.8.3.1



[RFC 15/19] RDMA/qedr: Add iWARP support in existing verbs.

2017-06-26 Thread Michal Kalderon
Make slight modifications to common RoCE/iWARP code.
Add additional doorbell for iWARP post_send.
iWARP QP pbl is allocated in qed and not in qedr.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Ram Amrani <ram.amr...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>

---
 drivers/infiniband/hw/qedr/qedr.h  |   3 +
 drivers/infiniband/hw/qedr/verbs.c | 171 +
 2 files changed, 139 insertions(+), 35 deletions(-)

diff --git a/drivers/infiniband/hw/qedr/qedr.h 
b/drivers/infiniband/hw/qedr/qedr.h
index c52fde0..0c0a39a 100644
--- a/drivers/infiniband/hw/qedr/qedr.h
+++ b/drivers/infiniband/hw/qedr/qedr.h
@@ -319,6 +319,9 @@ struct qedr_qp_hwq_info {
/* DB */
void __iomem *db;
union db_prod32 db_data;
+
+   void __iomem *iwarp_db2;
+   union db_prod32 iwarp_db2_data;
 };
 
 #define QEDR_INC_SW_IDX(p_info, index) \
diff --git a/drivers/infiniband/hw/qedr/verbs.c 
b/drivers/infiniband/hw/qedr/verbs.c
index 9b74015..7fef9b3 100644
--- a/drivers/infiniband/hw/qedr/verbs.c
+++ b/drivers/infiniband/hw/qedr/verbs.c
@@ -269,8 +269,13 @@ int qedr_query_port(struct ib_device *ibdev, u8 port, 
struct ib_port_attr *attr)
attr->sm_lid = 0;
attr->sm_sl = 0;
attr->port_cap_flags = IB_PORT_IP_BASED_GIDS;
-   attr->gid_tbl_len = QEDR_MAX_SGID;
-   attr->pkey_tbl_len = QEDR_ROCE_PKEY_TABLE_LEN;
+   if (IS_IWARP(dev)) {
+   attr->gid_tbl_len = 1;
+   attr->pkey_tbl_len = 1;
+   } else {
+   attr->gid_tbl_len = QEDR_MAX_SGID;
+   attr->pkey_tbl_len = QEDR_ROCE_PKEY_TABLE_LEN;
+   }
attr->bad_pkey_cntr = rdma_port->pkey_bad_counter;
attr->qkey_viol_cntr = 0;
get_link_speed_and_width(rdma_port->link_speed,
@@ -1422,6 +1427,21 @@ static int qedr_create_user_qp(struct qedr_dev *dev,
return rc;
 }
 
+static void qedr_set_iwarp_db_info(struct qedr_dev *dev, struct qedr_qp *qp)
+{
+   qp->sq.db = dev->db_addr +
+   DB_ADDR_SHIFT(DQ_PWM_OFFSET_XCM_RDMA_SQ_PROD);
+   qp->sq.db_data.data.icid = qp->icid;
+
+   qp->rq.db = dev->db_addr +
+   DB_ADDR_SHIFT(DQ_PWM_OFFSET_TCM_IWARP_RQ_PROD);
+   qp->rq.db_data.data.icid = qp->icid;
+   qp->rq.iwarp_db2 = dev->db_addr +
+  DB_ADDR_SHIFT(DQ_PWM_OFFSET_TCM_FLAGS);
+   qp->rq.iwarp_db2_data.data.icid = qp->icid;
+   qp->rq.iwarp_db2_data.data.value = DQ_TCM_IWARP_POST_RQ_CF_CMD;
+}
+
 static int
 qedr_roce_create_kernel_qp(struct qedr_dev *dev,
   struct qedr_qp *qp,
@@ -1468,8 +1488,71 @@ static int qedr_create_user_qp(struct qedr_dev *dev,
qp->icid = out_params.icid;
 
qedr_set_roce_db_info(dev, qp);
+   return rc;
+}
 
-   return 0;
+static int
+qedr_iwarp_create_kernel_qp(struct qedr_dev *dev,
+   struct qedr_qp *qp,
+   struct qed_rdma_create_qp_in_params *in_params,
+   u32 n_sq_elems, u32 n_rq_elems)
+{
+   struct qed_rdma_create_qp_out_params out_params;
+   struct qed_chain_ext_pbl ext_pbl;
+   int rc;
+
+   in_params->sq_num_pages = QED_CHAIN_PAGE_CNT(n_sq_elems,
+QEDR_SQE_ELEMENT_SIZE,
+QED_CHAIN_MODE_PBL);
+   in_params->rq_num_pages = QED_CHAIN_PAGE_CNT(n_rq_elems,
+QEDR_RQE_ELEMENT_SIZE,
+QED_CHAIN_MODE_PBL);
+
+   qp->qed_qp = dev->ops->rdma_create_qp(dev->rdma_ctx,
+ in_params, _params);
+
+   if (!qp->qed_qp)
+   return -EINVAL;
+
+   /* Now we allocate the chain */
+   ext_pbl.p_pbl_virt = out_params.sq_pbl_virt;
+   ext_pbl.p_pbl_phys = out_params.sq_pbl_phys;
+
+   rc = dev->ops->common->chain_alloc(dev->cdev,
+  QED_CHAIN_USE_TO_PRODUCE,
+  QED_CHAIN_MODE_PBL,
+  QED_CHAIN_CNT_TYPE_U32,
+  n_sq_elems,
+  QEDR_SQE_ELEMENT_SIZE,
+  >sq.pbl, _pbl);
+
+   if (rc)
+   goto err;
+
+   ext_pbl.p_pbl_virt = out_params.rq_pbl_virt;
+   ext_pbl.p_pbl_phys = out_params.rq_pbl_phys;
+
+   rc = dev->ops->common->chain_alloc(dev->cdev,
+  QED_CHAIN_USE_TO_CONSUME_PRODUCE,
+  QED_CHAIN_MODE_PBL,
+  

[RFC 14/19] RDMA/qedr: Add support for registering an iWARP device

2017-06-26 Thread Michal Kalderon
There are slight differences between iWARP and RoCE in the ibdev
registration. This patch handles the changes.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Ram Amrani <ram.amr...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>

---
 drivers/infiniband/hw/qedr/main.c  | 84 +++---
 drivers/infiniband/hw/qedr/qedr.h  |  3 ++
 drivers/infiniband/hw/qedr/verbs.c | 34 +++
 drivers/infiniband/hw/qedr/verbs.h |  2 +
 4 files changed, 97 insertions(+), 26 deletions(-)

diff --git a/drivers/infiniband/hw/qedr/main.c 
b/drivers/infiniband/hw/qedr/main.c
index b5851fd..ad227b5 100644
--- a/drivers/infiniband/hw/qedr/main.c
+++ b/drivers/infiniband/hw/qedr/main.c
@@ -33,6 +33,8 @@
 #include 
 #include 
 #include 
+#include 
+#include 
 #include 
 #include 
 #include 
@@ -94,8 +96,75 @@ static struct net_device *qedr_get_netdev(struct ib_device 
*dev, u8 port_num)
return qdev->ndev;
 }
 
+int qedr_roce_port_immutable(struct ib_device *ibdev, u8 port_num,
+struct ib_port_immutable *immutable)
+{
+   struct ib_port_attr attr;
+   int err;
+
+   err = qedr_query_port(ibdev, port_num, );
+   if (err)
+   return err;
+
+   immutable->pkey_tbl_len = attr.pkey_tbl_len;
+   immutable->gid_tbl_len = attr.gid_tbl_len;
+   immutable->core_cap_flags = RDMA_CORE_PORT_IBA_ROCE |
+   RDMA_CORE_PORT_IBA_ROCE_UDP_ENCAP;
+   immutable->max_mad_size = IB_MGMT_MAD_SIZE;
+
+   return 0;
+}
+
+int qedr_iw_port_immutable(struct ib_device *ibdev, u8 port_num,
+  struct ib_port_immutable *immutable)
+{
+   struct ib_port_attr attr;
+   int err;
+
+   err = qedr_query_port(ibdev, port_num, );
+   if (err)
+   return err;
+
+   immutable->pkey_tbl_len = 1;
+   immutable->gid_tbl_len = 1;
+   immutable->core_cap_flags = RDMA_CORE_PORT_IWARP;
+   immutable->max_mad_size = 0;
+
+   return 0;
+}
+
+int qedr_iw_register_device(struct qedr_dev *dev)
+{
+   dev->ibdev.node_type = RDMA_NODE_RNIC;
+   dev->ibdev.query_gid = qedr_iw_query_gid;
+
+   dev->ibdev.get_port_immutable = qedr_iw_port_immutable;
+
+   dev->ibdev.iwcm = kzalloc(sizeof(*dev->ibdev.iwcm), GFP_KERNEL);
+   if (!dev->ibdev.iwcm)
+   return -ENOMEM;
+
+   memcpy(dev->ibdev.iwcm->ifname,
+  dev->ndev->name, sizeof(dev->ibdev.iwcm->ifname));
+
+   return 0;
+}
+
+void qedr_roce_register_device(struct qedr_dev *dev)
+{
+   dev->ibdev.node_type = RDMA_NODE_IB_CA;
+   dev->ibdev.query_gid = qedr_query_gid;
+
+   dev->ibdev.add_gid = qedr_add_gid;
+   dev->ibdev.del_gid = qedr_del_gid;
+
+   dev->ibdev.get_port_immutable = qedr_roce_port_immutable;
+}
+
 static int qedr_register_device(struct qedr_dev *dev)
 {
+   int rc;
+
strlcpy(dev->ibdev.name, "qedr%d", IB_DEVICE_NAME_MAX);
 
dev->ibdev.node_guid = dev->attr.node_guid;
@@ -123,18 +192,21 @@ static int qedr_register_device(struct qedr_dev *dev)
 QEDR_UVERBS(POST_SEND) |
 QEDR_UVERBS(POST_RECV);
 
+   if (IS_IWARP(dev)) {
+   rc = qedr_iw_register_device(dev);
+   if (rc)
+   return rc;
+   } else {
+   qedr_roce_register_device(dev);
+   }
+
dev->ibdev.phys_port_cnt = 1;
dev->ibdev.num_comp_vectors = dev->num_cnq;
-   dev->ibdev.node_type = RDMA_NODE_IB_CA;
 
dev->ibdev.query_device = qedr_query_device;
dev->ibdev.query_port = qedr_query_port;
dev->ibdev.modify_port = qedr_modify_port;
 
-   dev->ibdev.query_gid = qedr_query_gid;
-   dev->ibdev.add_gid = qedr_add_gid;
-   dev->ibdev.del_gid = qedr_del_gid;
-
dev->ibdev.alloc_ucontext = qedr_alloc_ucontext;
dev->ibdev.dealloc_ucontext = qedr_dealloc_ucontext;
dev->ibdev.mmap = qedr_mmap;
@@ -168,7 +240,7 @@ static int qedr_register_device(struct qedr_dev *dev)
dev->ibdev.post_recv = qedr_post_recv;
 
dev->ibdev.process_mad = qedr_process_mad;
-   dev->ibdev.get_port_immutable = qedr_port_immutable;
+
dev->ibdev.get_netdev = qedr_get_netdev;
 
dev->ibdev.dev.parent = >pdev->dev;
diff --git a/drivers/infiniband/hw/qedr/qedr.h 
b/drivers/infiniband/hw/qedr/qedr.h
index ab7784b..c52fde0 100644
--- a/drivers/infiniband/hw/qedr/qedr.h
+++ b/drivers/infiniband/hw/qedr/qedr.h
@@ -44,6 +44,8 @@
 #define QEDR_MODULE_VERSION"8.10.10.0"
 #define QEDR_NODE_DESC "QLogic 579xx RoCE HCA"
 #define DP_NAME(dev) ((dev)->ibdev.name)
+#define IS_IWARP(_dev) ((_dev)->rdma_type == QED_RDMA_T

[RFC 11/19] qed: Add iWARP protocol support in context allocation

2017-06-26 Thread Michal Kalderon
When computing how much memory is required for the different hw clients
iWARP protocol should be taken into account

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Yuval Mintz <yuval.mi...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>

---
 drivers/net/ethernet/qlogic/qed/qed_cxt.c | 13 +++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_cxt.c 
b/drivers/net/ethernet/qlogic/qed/qed_cxt.c
index 38716f7..af106be 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_cxt.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_cxt.c
@@ -246,14 +246,16 @@ struct qed_cxt_mngr {
 static bool src_proto(enum protocol_type type)
 {
return type == PROTOCOLID_ISCSI ||
-  type == PROTOCOLID_FCOE;
+  type == PROTOCOLID_FCOE ||
+  type == PROTOCOLID_IWARP;
 }
 
 static bool tm_cid_proto(enum protocol_type type)
 {
return type == PROTOCOLID_ISCSI ||
   type == PROTOCOLID_FCOE ||
-  type == PROTOCOLID_ROCE;
+  type == PROTOCOLID_ROCE ||
+  type == PROTOCOLID_IWARP;
 }
 
 static bool tm_tid_proto(enum protocol_type type)
@@ -2068,6 +2070,11 @@ static void qed_rdma_set_pf_params(struct qed_hwfn 
*p_hwfn,
num_srqs = min_t(u32, 32 * 1024, p_params->num_srqs);
 
switch (p_hwfn->hw_info.personality) {
+   case QED_PCI_ETH_IWARP:
+   /* Each QP requires one connection */
+   num_cons = min_t(u32, IWARP_MAX_QPS, p_params->num_qps);
+   proto = PROTOCOLID_IWARP;
+   break;
case QED_PCI_ETH_ROCE:
num_qps = min_t(u32, ROCE_MAX_QPS, p_params->num_qps);
num_cons = num_qps * 2; /* each QP requires two connections */
@@ -2103,6 +2110,8 @@ int qed_cxt_set_pf_params(struct qed_hwfn *p_hwfn, u32 
rdma_tasks)
qed_cxt_set_proto_cid_count(p_hwfn, PROTOCOLID_CORE, core_cids, 0);
 
switch (p_hwfn->hw_info.personality) {
+   case QED_PCI_ETH_RDMA:
+   case QED_PCI_ETH_IWARP:
case QED_PCI_ETH_ROCE:
{
qed_rdma_set_pf_params(p_hwfn,
-- 
1.8.3.1



[RFC 12/19] qed: Add iWARP support for physical queue allocation

2017-06-26 Thread Michal Kalderon
iWARP has different physical queue requirements than RoCE

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Yuval Mintz <yuval.mi...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>

---
 drivers/net/ethernet/qlogic/qed/qed_dev.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c 
b/drivers/net/ethernet/qlogic/qed/qed_dev.c
index 4060a6a..6c87bed 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_dev.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c
@@ -216,6 +216,10 @@ static u32 qed_get_pq_flags(struct qed_hwfn *p_hwfn)
case QED_PCI_ETH_ROCE:
flags |= PQ_FLAGS_MCOS | PQ_FLAGS_OFLD | PQ_FLAGS_LLT;
break;
+   case QED_PCI_ETH_IWARP:
+   flags |= PQ_FLAGS_MCOS | PQ_FLAGS_ACK | PQ_FLAGS_OOO |
+   PQ_FLAGS_OFLD;
+   break;
default:
DP_ERR(p_hwfn,
   "unknown personality %d\n", p_hwfn->hw_info.personality);
-- 
1.8.3.1



[RFC 13/19] RDMA/qedr: Rename the qedr_cm file as a preparation for iWARP support

2017-06-26 Thread Michal Kalderon
The main differences between iWARP and RoCE lay in the communication
 management functions. These will be placed in separate files.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Ram Amrani <ram.amr...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>

---
 drivers/infiniband/hw/qedr/Makefile  | 2 +-
 drivers/infiniband/hw/qedr/{qedr_cm.c => qedr_roce_cm.c} | 2 +-
 drivers/infiniband/hw/qedr/{qedr_cm.h => qedr_roce_cm.h} | 0
 drivers/infiniband/hw/qedr/verbs.c   | 2 +-
 4 files changed, 3 insertions(+), 3 deletions(-)
 rename drivers/infiniband/hw/qedr/{qedr_cm.c => qedr_roce_cm.c} (99%)
 rename drivers/infiniband/hw/qedr/{qedr_cm.h => qedr_roce_cm.h} (100%)

diff --git a/drivers/infiniband/hw/qedr/Makefile 
b/drivers/infiniband/hw/qedr/Makefile
index ba7067c..331a361 100644
--- a/drivers/infiniband/hw/qedr/Makefile
+++ b/drivers/infiniband/hw/qedr/Makefile
@@ -1,3 +1,3 @@
 obj-$(CONFIG_INFINIBAND_QEDR) := qedr.o
 
-qedr-y := main.o verbs.o qedr_cm.o
+qedr-y := main.o verbs.o qedr_roce_cm.o
diff --git a/drivers/infiniband/hw/qedr/qedr_cm.c 
b/drivers/infiniband/hw/qedr/qedr_roce_cm.c
similarity index 99%
rename from drivers/infiniband/hw/qedr/qedr_cm.c
rename to drivers/infiniband/hw/qedr/qedr_roce_cm.c
index 4689e80..c3c249b 100644
--- a/drivers/infiniband/hw/qedr/qedr_cm.c
+++ b/drivers/infiniband/hw/qedr/qedr_roce_cm.c
@@ -48,7 +48,7 @@
 #include "qedr.h"
 #include "verbs.h"
 #include 
-#include "qedr_cm.h"
+#include "qedr_roce_cm.h"
 
 void qedr_inc_sw_gsi_cons(struct qedr_qp_hwq_info *info)
 {
diff --git a/drivers/infiniband/hw/qedr/qedr_cm.h 
b/drivers/infiniband/hw/qedr/qedr_roce_cm.h
similarity index 100%
rename from drivers/infiniband/hw/qedr/qedr_cm.h
rename to drivers/infiniband/hw/qedr/qedr_roce_cm.h
diff --git a/drivers/infiniband/hw/qedr/verbs.c 
b/drivers/infiniband/hw/qedr/verbs.c
index 548e4d1..16637ec 100644
--- a/drivers/infiniband/hw/qedr/verbs.c
+++ b/drivers/infiniband/hw/qedr/verbs.c
@@ -49,7 +49,7 @@
 #include "qedr.h"
 #include "verbs.h"
 #include 
-#include "qedr_cm.h"
+#include "qedr_roce_cm.h"
 
 #define DB_ADDR_SHIFT(addr)((addr) << DB_PWM_ADDR_OFFSET_SHIFT)
 
-- 
1.8.3.1



[RFC 10/19] qed: iWARP CM add error handling

2017-06-26 Thread Michal Kalderon
This patch introduces error handling for errors that occurred during
connection establishment.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Yuval Mintz <yuval.mi...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>

---
 drivers/net/ethernet/qlogic/qed/qed_iwarp.c | 183 +++-
 include/linux/qed/qed_rdma_if.h |   9 ++
 2 files changed, 190 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c 
b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
index 84bcda3..5cd20da 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
@@ -1001,12 +1001,75 @@ int qed_iwarp_destroy_qp(struct qed_hwfn *p_hwfn, 
struct qed_rdma_qp *qp)
ep->state = QED_IWARP_EP_ESTABLISHED;
params.status = 0;
break;
+   case IWARP_CONN_ERROR_MPA_TIMEOUT:
+   DP_NOTICE(p_hwfn, "%s(0x%x) MPA timeout\n",
+ QED_IWARP_CONNECT_MODE_STRING(ep), ep->cid);
+   params.status = -EBUSY;
+   break;
+   case IWARP_CONN_ERROR_MPA_ERROR_REJECT:
+   DP_NOTICE(p_hwfn, "%s(0x%x) MPA Reject\n",
+ QED_IWARP_CONNECT_MODE_STRING(ep), ep->cid);
+   params.status = -ECONNREFUSED;
+   break;
+   case IWARP_CONN_ERROR_MPA_RST:
+   DP_NOTICE(p_hwfn, "%s(0x%x) MPA reset(tcp cid: 0x%x)\n",
+ QED_IWARP_CONNECT_MODE_STRING(ep), ep->cid,
+ ep->tcp_cid);
+   params.status = -ECONNRESET;
+   break;
+   case IWARP_CONN_ERROR_MPA_FIN:
+   DP_NOTICE(p_hwfn, "%s(0x%x) MPA received FIN\n",
+ QED_IWARP_CONNECT_MODE_STRING(ep), ep->cid);
+   params.status = -ECONNREFUSED;
+   break;
+   case IWARP_CONN_ERROR_MPA_INSUF_IRD:
+   DP_NOTICE(p_hwfn, "%s(0x%x) MPA insufficient ird\n",
+ QED_IWARP_CONNECT_MODE_STRING(ep), ep->cid);
+   params.status = -ECONNREFUSED;
+   break;
+   case IWARP_CONN_ERROR_MPA_RTR_MISMATCH:
+   DP_NOTICE(p_hwfn, "%s(0x%x) MPA RTR MISMATCH\n",
+ QED_IWARP_CONNECT_MODE_STRING(ep), ep->cid);
+   params.status = -ECONNREFUSED;
+   break;
+   case IWARP_CONN_ERROR_MPA_INVALID_PACKET:
+   DP_NOTICE(p_hwfn, "%s(0x%x) MPA Invalid Packet\n",
+ QED_IWARP_CONNECT_MODE_STRING(ep), ep->cid);
+   params.status = -ECONNREFUSED;
+   break;
+   case IWARP_CONN_ERROR_MPA_LOCAL_ERROR:
+   DP_NOTICE(p_hwfn, "%s(0x%x) MPA Local Error\n",
+ QED_IWARP_CONNECT_MODE_STRING(ep), ep->cid);
+   params.status = -ECONNREFUSED;
+   break;
+   case IWARP_CONN_ERROR_MPA_TERMINATE:
+   DP_NOTICE(p_hwfn, "%s(0x%x) MPA TERMINATE\n",
+ QED_IWARP_CONNECT_MODE_STRING(ep), ep->cid);
+   params.status = -ECONNREFUSED;
+   break;
default:
params.status = -ECONNRESET;
break;
}
 
ep->event_cb(ep->cb_context, );
+
+   /* on passive side, if there is no associated QP (REJECT) we need to
+* return the ep to the pool, (in the regular case we add an element
+* in accept instead of this one.
+* In both cases we need to remove it from the ep_list.
+*/
+   if (fw_return_code != RDMA_RETURN_OK) {
+   ep->tcp_cid = QED_IWARP_INVALID_TCP_CID;
+   if ((ep->connect_mode == TCP_CONNECT_PASSIVE) &&
+   (!ep->qp)) {/* Rejected */
+   qed_iwarp_return_ep(p_hwfn, ep);
+   } else {
+   spin_lock_bh(_hwfn->p_rdma_info->iwarp.iw_lock);
+   list_del(>list_entry);
+   spin_unlock_bh(_hwfn->p_rdma_info->iwarp.iw_lock);
+   }
+   }
 }
 
 static void
@@ -2011,6 +2074,42 @@ void qed_iwarp_exception_received(struct qed_hwfn 
*p_hwfn,
params.event = QED_IWARP_EVENT_DISCONNECT;
event_cb = true;
break;
+   case IWARP_EXCEPTION_DETECTED_RQ_EMPTY:
+   params.event = QED_IWARP_EVENT_RQ_EMPTY;
+   event_cb = true;
+   break;
+   case IWARP_EXCEPTION_DETECTED_IRQ_FULL:
+   params.event = QED_IWARP_EVENT_IRQ_FULL;
+   event_cb = true;
+   break;
+   case IWARP_EXCEPTION_DETECTED_LLP_TIMEOUT:
+   params.event = QED_IWARP_EVENT_LLP_TIMEOUT;
+   event_cb = true;
+ 

[RFC 08/19] qed: iWARP CM add active side connect

2017-06-26 Thread Michal Kalderon
This patch implements the active side connect.
Offload a connection, process MPA reply and send RTR.
In some of the common passive/active functions, the active side
will work in blocking mode.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Yuval Mintz <yuval.mi...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>

---
 drivers/net/ethernet/qlogic/qed/qed_iwarp.c | 240 ++--
 drivers/net/ethernet/qlogic/qed/qed_iwarp.h |   7 +
 drivers/net/ethernet/qlogic/qed/qed_rdma.c  |   4 +
 include/linux/qed/qed_rdma_if.h |  26 +++
 4 files changed, 265 insertions(+), 12 deletions(-)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c 
b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
index a6dadae..a5da9fc 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
@@ -611,7 +611,10 @@ int qed_iwarp_destroy_qp(struct qed_hwfn *p_hwfn, struct 
qed_rdma_qp *qp)
memset(_data, 0, sizeof(init_data));
init_data.cid = ep->tcp_cid;
init_data.opaque_fid = p_hwfn->hw_info.opaque_fid;
-   init_data.comp_mode = QED_SPQ_MODE_CB;
+   if (ep->connect_mode == TCP_CONNECT_PASSIVE)
+   init_data.comp_mode = QED_SPQ_MODE_CB;
+   else
+   init_data.comp_mode = QED_SPQ_MODE_EBLOCK;
 
rc = qed_sp_init_request(p_hwfn, _ent,
 IWARP_RAMROD_CMD_ID_TCP_OFFLOAD,
@@ -711,7 +714,7 @@ int qed_iwarp_destroy_qp(struct qed_hwfn *p_hwfn, struct 
qed_rdma_qp *qp)
DP_VERBOSE(p_hwfn, QED_MSG_RDMA,
   "private_data_len=%x handshake_mode=%x private_data=(%x)\n",
   async_data->mpa_request.ulp_data_len,
-  mpa_rev, *((u32 *)((u8 *)ep->ep_buffer_virt->in_pdata)));
+  mpa_rev, *((u32 *)(ep->ep_buffer_virt->in_pdata)));
 
if (mpa_rev == MPA_NEGOTIATION_TYPE_ENHANCED) {
/* Read ord/ird values from private data buffer */
@@ -801,7 +804,10 @@ int qed_iwarp_destroy_qp(struct qed_hwfn *p_hwfn, struct 
qed_rdma_qp *qp)
init_data.cid = reject ? ep->tcp_cid : qp->icid;
init_data.opaque_fid = p_hwfn->hw_info.opaque_fid;
 
-   init_data.comp_mode = QED_SPQ_MODE_EBLOCK;
+   if (ep->connect_mode == TCP_CONNECT_ACTIVE)
+   init_data.comp_mode = QED_SPQ_MODE_CB;
+   else
+   init_data.comp_mode = QED_SPQ_MODE_EBLOCK;
 
rc = qed_sp_init_request(p_hwfn, _ent,
 IWARP_RAMROD_CMD_ID_MPA_OFFLOAD,
@@ -890,6 +896,59 @@ int qed_iwarp_destroy_qp(struct qed_hwfn *p_hwfn, struct 
qed_rdma_qp *qp)
spin_unlock_bh(_hwfn->p_rdma_info->iwarp.iw_lock);
 }
 
+void
+qed_iwarp_parse_private_data(struct qed_hwfn *p_hwfn, struct qed_iwarp_ep *ep)
+{
+   struct mpa_v2_hdr *mpa_v2_params;
+   union async_output *async_data;
+   u16 mpa_ird, mpa_ord;
+   u8 mpa_data_size = 0;
+
+   if (MPA_REV2(p_hwfn->p_rdma_info->iwarp.mpa_rev)) {
+   mpa_v2_params =
+   (struct mpa_v2_hdr *)(ep->ep_buffer_virt->in_pdata);
+   mpa_data_size = sizeof(*mpa_v2_params);
+   mpa_ird = ntohs(mpa_v2_params->ird);
+   mpa_ord = ntohs(mpa_v2_params->ord);
+
+   ep->cm_info.ird = (u8)(mpa_ord & MPA_V2_IRD_ORD_MASK);
+   ep->cm_info.ord = (u8)(mpa_ird & MPA_V2_IRD_ORD_MASK);
+   }
+   async_data = >ep_buffer_virt->async_output;
+
+   ep->cm_info.private_data = ep->ep_buffer_virt->in_pdata + mpa_data_size;
+   ep->cm_info.private_data_len = async_data->mpa_response.ulp_data_len -
+  mpa_data_size;
+}
+
+void
+qed_iwarp_mpa_reply_arrived(struct qed_hwfn *p_hwfn, struct qed_iwarp_ep *ep)
+{
+   struct qed_iwarp_cm_event_params params;
+
+   if (ep->connect_mode == TCP_CONNECT_PASSIVE) {
+   DP_NOTICE(p_hwfn,
+ "MPA reply event not expected on passive side!\n");
+   return;
+   }
+
+   params.event = QED_IWARP_EVENT_ACTIVE_MPA_REPLY;
+
+   qed_iwarp_parse_private_data(p_hwfn, ep);
+
+   DP_VERBOSE(p_hwfn, QED_MSG_RDMA,
+  "MPA_NEGOTIATE (v%d): ORD: 0x%x IRD: 0x%x\n",
+  ep->mpa_rev, ep->cm_info.ord, ep->cm_info.ird);
+
+   params.cm_info = >cm_info;
+   params.ep_context = ep;
+   params.status = 0;
+
+   ep->mpa_reply_processed = true;
+
+   ep->event_cb(ep->cb_context, );
+}
+
 #define QED_IWARP_CONNECT_MODE_STRING(ep) \
((ep)->connect_mode == TCP_CONNECT_PASSIVE) ? "Passive" : "Active"
 
@@ -902,7 +961,13 @@ int qed_iwarp_destroy_qp(struct qed_hwfn *p_hwfn, struct 
qed_rdma_qp *qp)
 {
struct qed_iwarp_cm_event_params param

[RFC 09/19] qed: iWARP implement disconnect flows

2017-06-26 Thread Michal Kalderon
This patch takes care of active/passive disconnect flows.
Disconnect flows can be initiated remotely, in which case a async event
will arrive from peer and indicated to qedr driver. These
are referred to as exceptions. When a QP is destroyed, it needs to check
that it's associated ep has been closed.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Yuval Mintz <yuval.mi...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>

---
 drivers/net/ethernet/qlogic/qed/qed_iwarp.c | 90 -
 include/linux/qed/qed_rdma_if.h |  2 +
 2 files changed, 91 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c 
b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
index a5da9fc..84bcda3 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
@@ -496,6 +496,8 @@ static void qed_iwarp_destroy_ep(struct qed_hwfn *p_hwfn,
 
 int qed_iwarp_destroy_qp(struct qed_hwfn *p_hwfn, struct qed_rdma_qp *qp)
 {
+   struct qed_iwarp_ep *ep = qp->ep;
+   int wait_count = 0;
int rc = 0;
 
if (qp->iwarp_state != QED_IWARP_QP_STATE_ERROR) {
@@ -505,6 +507,18 @@ int qed_iwarp_destroy_qp(struct qed_hwfn *p_hwfn, struct 
qed_rdma_qp *qp)
return rc;
}
 
+   /* Make sure ep is closed before returning and freeing memory. */
+   if (ep) {
+   while (ep->state != QED_IWARP_EP_CLOSED && wait_count++ < 200)
+   msleep(100);
+
+   if (ep->state != QED_IWARP_EP_CLOSED)
+   DP_NOTICE(p_hwfn, "ep state close timeout state=%x\n",
+ ep->state);
+
+   qed_iwarp_destroy_ep(p_hwfn, ep, false);
+   }
+
rc = qed_iwarp_fw_destroy(p_hwfn, qp);
 
if (qp->shared_queue)
@@ -1956,6 +1970,61 @@ int qed_iwarp_stop(struct qed_hwfn *p_hwfn, struct 
qed_ptt *p_ptt)
return qed_iwarp_ll2_stop(p_hwfn, p_ptt);
 }
 
+void qed_iwarp_qp_in_error(struct qed_hwfn *p_hwfn,
+  struct qed_iwarp_ep *ep, u8 fw_return_code)
+{
+   struct qed_iwarp_cm_event_params params;
+
+   qed_iwarp_modify_qp(p_hwfn, ep->qp, QED_IWARP_QP_STATE_ERROR, true);
+
+   params.event = QED_IWARP_EVENT_CLOSE;
+   params.ep_context = ep;
+   params.cm_info = >cm_info;
+   params.status = (fw_return_code == IWARP_QP_IN_ERROR_GOOD_CLOSE) ?
+0 : -ECONNRESET;
+
+   ep->state = QED_IWARP_EP_CLOSED;
+   spin_lock_bh(_hwfn->p_rdma_info->iwarp.iw_lock);
+   list_del(>list_entry);
+   spin_unlock_bh(_hwfn->p_rdma_info->iwarp.iw_lock);
+
+   ep->event_cb(ep->cb_context, );
+}
+
+void qed_iwarp_exception_received(struct qed_hwfn *p_hwfn,
+ struct qed_iwarp_ep *ep, int fw_ret_code)
+{
+   struct qed_iwarp_cm_event_params params;
+   bool event_cb = false;
+
+   DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "EP(0x%x) fw_ret_code=%d\n",
+  ep->cid, fw_ret_code);
+
+   switch (fw_ret_code) {
+   case IWARP_EXCEPTION_DETECTED_LLP_CLOSED:
+   params.status = 0;
+   params.event = QED_IWARP_EVENT_DISCONNECT;
+   event_cb = true;
+   break;
+   case IWARP_EXCEPTION_DETECTED_LLP_RESET:
+   params.status = -ECONNRESET;
+   params.event = QED_IWARP_EVENT_DISCONNECT;
+   event_cb = true;
+   break;
+   default:
+   DP_VERBOSE(p_hwfn, QED_MSG_RDMA,
+  "Unhandled exception received...fw_ret_code=%d\n",
+  fw_ret_code);
+   break;
+   }
+
+   if (event_cb) {
+   params.ep_context = ep;
+   params.cm_info = >cm_info;
+   ep->event_cb(ep->cb_context, );
+   }
+}
+
 void
 qed_iwarp_connect_complete(struct qed_hwfn *p_hwfn,
   struct qed_iwarp_ep *ep, u8 fw_return_code)
@@ -2009,8 +2078,27 @@ static int qed_iwarp_async_event(struct qed_hwfn *p_hwfn,
   ep->tcp_cid, fw_return_code);
qed_iwarp_connect_complete(p_hwfn, ep, fw_return_code);
break;
-   /* Async event for active side only */
+   case IWARP_EVENT_TYPE_ASYNC_EXCEPTION_DETECTED:
+   if (!qed_iwarp_check_ep_ok(p_hwfn, ep))
+   return -EINVAL;
+   DP_VERBOSE(p_hwfn,
+  QED_MSG_RDMA,
+  "QP(0x%x) IWARP_EVENT_TYPE_ASYNC_EXCEPTION_DETECTED 
fw_ret_code=%d\n",
+  ep->cid, fw_return_code);
+   qed_iwarp_exception_received(p_hwfn, ep, fw_return_code);
+   break;
+   case IWARP_EVENT_TYPE_ASYNC_QP_I

[RFC 07/19] qed: iWARP CM add passive side connect

2017-06-26 Thread Michal Kalderon
This patch implements the passive side connect.
It addresses pre-allocating resources, creating a connection
element upon valid SYN packet received. Calling upper layer and
implementation of the accept/reject calls.

Error handling is not part of this patch.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Yuval Mintz <yuval.mi...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>

---
 drivers/net/ethernet/qlogic/qed/qed.h   |   2 +
 drivers/net/ethernet/qlogic/qed/qed_dev.c   |  11 +
 drivers/net/ethernet/qlogic/qed/qed_iwarp.c | 939 +++-
 drivers/net/ethernet/qlogic/qed/qed_iwarp.h |  62 ++
 drivers/net/ethernet/qlogic/qed/qed_l2.c|  13 -
 drivers/net/ethernet/qlogic/qed/qed_rdma.h  |   2 +
 drivers/net/ethernet/qlogic/qed/qed_sp.h|   2 +
 include/linux/qed/common_hsi.h  |   2 +
 include/linux/qed/qed_rdma_if.h |  26 +-
 9 files changed, 1039 insertions(+), 20 deletions(-)

diff --git a/drivers/net/ethernet/qlogic/qed/qed.h 
b/drivers/net/ethernet/qlogic/qed/qed.h
index fd8cd5e..91003bc 100644
--- a/drivers/net/ethernet/qlogic/qed/qed.h
+++ b/drivers/net/ethernet/qlogic/qed/qed.h
@@ -789,6 +789,8 @@ void qed_configure_vp_wfq_on_link_change(struct qed_dev 
*cdev,
 void qed_clean_wfq_db(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt);
 int qed_device_num_engines(struct qed_dev *cdev);
 int qed_device_get_port_id(struct qed_dev *cdev);
+void qed_set_fw_mac_addr(__le16 *fw_msb,
+__le16 *fw_mid, __le16 *fw_lsb, u8 *mac);
 
 #define QED_LEADING_HWFN(dev)   (>hwfns[0])
 
diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c 
b/drivers/net/ethernet/qlogic/qed/qed_dev.c
index 6c8505d..4060a6a 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_dev.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c
@@ -4127,3 +4127,14 @@ int qed_device_get_port_id(struct qed_dev *cdev)
 {
return (QED_LEADING_HWFN(cdev)->abs_pf_id) % qed_device_num_ports(cdev);
 }
+
+void qed_set_fw_mac_addr(__le16 *fw_msb,
+__le16 *fw_mid, __le16 *fw_lsb, u8 *mac)
+{
+   ((u8 *)fw_msb)[0] = mac[1];
+   ((u8 *)fw_msb)[1] = mac[0];
+   ((u8 *)fw_mid)[0] = mac[3];
+   ((u8 *)fw_mid)[1] = mac[2];
+   ((u8 *)fw_lsb)[0] = mac[5];
+   ((u8 *)fw_lsb)[1] = mac[4];
+}
diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c 
b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
index 2bab57c..a6dadae 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
@@ -44,9 +44,30 @@
 
 #define QED_IWARP_ORD_DEFAULT  32
 #define QED_IWARP_IRD_DEFAULT  32
+#define QED_IWARP_MAX_FW_MSS   4120
+
+#define QED_EP_SIG 0xecabcdef
+
+struct mpa_v2_hdr {
+   __be16 ird;
+   __be16 ord;
+};
+
+#define MPA_V2_PEER2PEER_MODEL  0x8000
+#define MPA_V2_SEND_RTR 0x4000 /* on ird */
+#define MPA_V2_READ_RTR 0x4000 /* on ord */
+#define MPA_V2_WRITE_RTR0x8000
+#define MPA_V2_IRD_ORD_MASK 0x3FFF
+
+#define MPA_REV2(_mpa_rev) ((_mpa_rev) == MPA_NEGOTIATION_TYPE_ENHANCED)
+
+#define QED_IWARP_INVALID_TCP_CID  0x
 #define QED_IWARP_RCV_WND_SIZE_DEF (256 * 1024)
 #define QED_IWARP_RCV_WND_SIZE_MIN (64 * 1024)
+#define TIMESTAMP_HEADER_SIZE  (12)
+
 #define QED_IWARP_TS_ENBIT(0)
+#define QED_IWARP_DA_ENBIT(1)
 #define QED_IWARP_PARAM_CRC_NEEDED (1)
 #define QED_IWARP_PARAM_P2P(1)
 
@@ -63,7 +84,8 @@ void qed_iwarp_init_devinfo(struct qed_hwfn *p_hwfn)
dev->max_inline = IWARP_REQ_MAX_INLINE_DATA_SIZE;
dev->max_qp = min_t(u32,
IWARP_MAX_QPS,
-   p_hwfn->p_rdma_info->num_qps);
+   p_hwfn->p_rdma_info->num_qps) -
+ QED_IWARP_PREALLOC_CNT;
 
dev->max_cq = dev->max_qp;
 
@@ -78,12 +100,22 @@ void qed_iwarp_init_hw(struct qed_hwfn *p_hwfn, struct 
qed_ptt *p_ptt)
p_hwfn->b_rdma_enabled_in_prs = true;
 }
 
+/* We have two cid maps, one for tcp which should be used only from passive
+ * syn processing and replacing a pre-allocated ep in the list. The second
+ * for active tcp and for QPs.
+ */
 static void qed_iwarp_cid_cleaned(struct qed_hwfn *p_hwfn, u32 cid)
 {
cid -= qed_cxt_get_proto_cid_start(p_hwfn, p_hwfn->p_rdma_info->proto);
 
spin_lock_bh(_hwfn->p_rdma_info->lock);
-   qed_bmap_release_id(p_hwfn, _hwfn->p_rdma_info->cid_map, cid);
+
+   if (cid < QED_IWARP_PREALLOC_CNT)
+   qed_bmap_release_id(p_hwfn, _hwfn->p_rdma_info->tcp_cid_map,
+   cid);
+   else
+   qed_bmap_release_id(p_hwfn, _hwfn->p_rdma_info->cid_map, cid);
+
spin_unlock_bh(_hwfn->p_rdma_info->lock);
 }
 
@@ -107,6 +139,45 @@ static int qe

[RFC 04/19] qed: Add iWARP support in ll2 connections

2017-06-26 Thread Michal Kalderon
Add a new connection type for iWARP ll2 connections for setting
correct ll2 filters and connection type to FW.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Yuval Mintz <yuval.mi...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>

---
 drivers/net/ethernet/qlogic/qed/qed_ll2.c | 13 +++--
 include/linux/qed/qed_ll2_if.h|  1 +
 2 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.c 
b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
index e235fb2..c06ad4f 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_ll2.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
@@ -896,7 +896,8 @@ static int qed_sp_ll2_rx_queue_start(struct qed_hwfn 
*p_hwfn,
p_ramrod->main_func_queue = (conn_type == QED_LL2_TYPE_OOO) ? 0 : 1;
 
if ((IS_MF_DEFAULT(p_hwfn) || IS_MF_SI(p_hwfn)) &&
-   p_ramrod->main_func_queue && (conn_type != QED_LL2_TYPE_ROCE)) {
+   p_ramrod->main_func_queue && (conn_type != QED_LL2_TYPE_ROCE) &&
+   (conn_type != QED_LL2_TYPE_IWARP)) {
p_ramrod->mf_si_bcast_accept_all = 1;
p_ramrod->mf_si_mcast_accept_all = 1;
} else {
@@ -972,12 +973,20 @@ static int qed_sp_ll2_tx_queue_start(struct qed_hwfn 
*p_hwfn,
p_ramrod->conn_type = PROTOCOLID_FCOE;
break;
case QED_LL2_TYPE_ISCSI:
-   case QED_LL2_TYPE_OOO:
p_ramrod->conn_type = PROTOCOLID_ISCSI;
break;
case QED_LL2_TYPE_ROCE:
p_ramrod->conn_type = PROTOCOLID_ROCE;
break;
+   case QED_LL2_TYPE_IWARP:
+   p_ramrod->conn_type = PROTOCOLID_IWARP;
+   break;
+   case QED_LL2_TYPE_OOO:
+   if (p_hwfn->hw_info.personality == QED_PCI_ISCSI)
+   p_ramrod->conn_type = PROTOCOLID_ISCSI;
+   else
+   p_ramrod->conn_type = PROTOCOLID_IWARP;
+   break;
default:
p_ramrod->conn_type = PROTOCOLID_ETH;
DP_NOTICE(p_hwfn, "Unknown connection type: %d\n", conn_type);
diff --git a/include/linux/qed/qed_ll2_if.h b/include/linux/qed/qed_ll2_if.h
index c9c56bc..dd7a3b8 100644
--- a/include/linux/qed/qed_ll2_if.h
+++ b/include/linux/qed/qed_ll2_if.h
@@ -50,6 +50,7 @@ enum qed_ll2_conn_type {
QED_LL2_TYPE_OOO,
QED_LL2_TYPE_RESERVED2,
QED_LL2_TYPE_ROCE,
+   QED_LL2_TYPE_IWARP,
QED_LL2_TYPE_RESERVED3,
MAX_QED_LL2_RX_CONN_TYPE
 };
-- 
1.8.3.1



[RFC 06/19] qed: iWARP CM add listener functions and initial SYN processing

2017-06-26 Thread Michal Kalderon
This patch adds the ability to add and remove listeners and identify
whether the SYN packet received is intended for iWARP or not. If
a listener is not found the SYN packet is posted back to the chip.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Yuval Mintz <yuval.mi...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>

---
 drivers/net/ethernet/qlogic/qed/qed_iwarp.c | 269 +++-
 drivers/net/ethernet/qlogic/qed/qed_iwarp.h |  23 +++
 drivers/net/ethernet/qlogic/qed/qed_rdma.c  |   2 +
 include/linux/qed/qed_rdma_if.h |  52 ++
 4 files changed, 343 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c 
b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
index f3b4b32..2bab57c 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
@@ -31,6 +31,10 @@
  */
 #include 
 #include 
+#include 
+#include 
+#include 
+#include 
 #include "qed_cxt.h"
 #include "qed_hw.h"
 #include "qed_ll2.h"
@@ -477,6 +481,31 @@ void qed_iwarp_resc_free(struct qed_hwfn *p_hwfn)
 {
 }
 
+static void
+qed_iwarp_print_cm_info(struct qed_hwfn *p_hwfn,
+   struct qed_iwarp_cm_info *cm_info)
+{
+   DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "ip_version = %d\n",
+  cm_info->ip_version);
+
+   if (cm_info->ip_version == QED_TCP_IPV4)
+   DP_VERBOSE(p_hwfn, QED_MSG_RDMA,
+  "remote_ip %pI4h:%x, local_ip %pI4h:%x vlan=%x\n",
+  cm_info->remote_ip, cm_info->remote_port,
+  cm_info->local_ip, cm_info->local_port,
+  cm_info->vlan);
+   else
+   DP_VERBOSE(p_hwfn, QED_MSG_RDMA,
+  "remote_ip %pI6h:%x, local_ip %pI6h:%x vlan=%x\n",
+  cm_info->remote_ip, cm_info->remote_port,
+  cm_info->local_ip, cm_info->local_port,
+  cm_info->vlan);
+
+   DP_VERBOSE(p_hwfn, QED_MSG_RDMA,
+  "private_data_len = %x ord = %d, ird = %d\n",
+  cm_info->private_data_len, cm_info->ord, cm_info->ird);
+}
+
 static int
 qed_iwarp_ll2_post_rx(struct qed_hwfn *p_hwfn,
  struct qed_iwarp_ll2_buff *buf, u8 handle)
@@ -497,11 +526,147 @@ void qed_iwarp_resc_free(struct qed_hwfn *p_hwfn)
return rc;
 }
 
+static struct qed_iwarp_listener *
+qed_iwarp_get_listener(struct qed_hwfn *p_hwfn,
+  struct qed_iwarp_cm_info *cm_info)
+{
+   struct qed_iwarp_listener *listener = NULL;
+   static const u32 ip_zero[4] = { 0, 0, 0, 0 };
+   bool found = false;
+
+   qed_iwarp_print_cm_info(p_hwfn, cm_info);
+
+   list_for_each_entry(listener,
+   _hwfn->p_rdma_info->iwarp.listen_list,
+   list_entry) {
+   if (listener->port == cm_info->local_port) {
+   if (!memcmp(listener->ip_addr,
+   ip_zero, sizeof(ip_zero))) {
+   found = true;
+   break;
+   }
+
+   if (!memcmp(listener->ip_addr,
+   cm_info->local_ip,
+   sizeof(cm_info->local_ip)) &&
+   (listener->vlan == cm_info->vlan)) {
+   found = true;
+   break;
+   }
+   }
+   }
+
+   if (found) {
+   DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "listener found = %p\n",
+  listener);
+   return listener;
+   }
+
+   DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "listener not found\n");
+   return NULL;
+}
+
+static int
+qed_iwarp_parse_rx_pkt(struct qed_hwfn *p_hwfn,
+  struct qed_iwarp_cm_info *cm_info,
+  void *buf,
+  u8 *remote_mac_addr,
+  u8 *local_mac_addr,
+  int *payload_len, int *tcp_start_offset)
+{
+   struct vlan_ethhdr *vethh;
+   bool vlan_valid = false;
+   struct ipv6hdr *ip6h;
+   struct ethhdr *ethh;
+   struct tcphdr *tcph;
+   struct iphdr *iph;
+   int eth_hlen;
+   int ip_hlen;
+   int eth_type;
+   int i;
+
+   ethh = buf;
+   eth_type = ntohs(ethh->h_proto);
+   if (eth_type == ETH_P_8021Q) {
+   vlan_valid = true;
+   vethh = (struct vlan_ethhdr *)ethh;
+   cm_info->vlan = ntohs(vethh->h_vlan_TCI) & VLAN_VID_MASK;
+   eth_type = ntohs(vethh->h_vlan_encapsulated_proto);
+ 

[RFC 05/19] qed: iWARP CM - setup a ll2 connection for handling SYN packets

2017-06-26 Thread Michal Kalderon
iWARP handles incoming SYN packets using the ll2 interface. This patch
implements ll2 setup and teardown. Additional ll2 connections will
be used in the future which are not part of this patch series.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Yuval Mintz <yuval.mi...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>

---
 drivers/net/ethernet/qlogic/qed/qed_iwarp.c | 211 +++-
 drivers/net/ethernet/qlogic/qed/qed_iwarp.h |  12 ++
 2 files changed, 220 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c 
b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
index a8bd5f8..f3b4b32 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_iwarp.c
@@ -29,8 +29,11 @@
  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
  */
+#include 
+#include 
 #include "qed_cxt.h"
 #include "qed_hw.h"
+#include "qed_ll2.h"
 #include "qed_rdma.h"
 #include "qed_reg_addr.h"
 #include "qed_sp.h"
@@ -474,12 +477,214 @@ void qed_iwarp_resc_free(struct qed_hwfn *p_hwfn)
 {
 }
 
+static int
+qed_iwarp_ll2_post_rx(struct qed_hwfn *p_hwfn,
+ struct qed_iwarp_ll2_buff *buf, u8 handle)
+{
+   int rc;
+
+   rc = qed_ll2_post_rx_buffer(p_hwfn, handle, buf->data_phys_addr,
+   (u16)buf->buff_size, buf, 1);
+   if (rc) {
+   DP_NOTICE(p_hwfn,
+ "Failed to repost rx buffer to ll2 rc = %d, 
handle=%d\n",
+ rc, handle);
+   dma_free_coherent(_hwfn->cdev->pdev->dev, buf->buff_size,
+ buf->data, buf->data_phys_addr);
+   kfree(buf);
+   }
+
+   return rc;
+}
+
+static void
+qed_iwarp_ll2_comp_syn_pkt(void *cxt, struct qed_ll2_comp_rx_data *data)
+{
+   struct qed_iwarp_ll2_buff *buf = data->cookie;
+   struct qed_hwfn *p_hwfn = cxt;
+
+   if (GET_FIELD(data->parse_flags,
+ PARSING_AND_ERR_FLAGS_L4CHKSMWASCALCULATED) &&
+   GET_FIELD(data->parse_flags, PARSING_AND_ERR_FLAGS_L4CHKSMERROR)) {
+   DP_NOTICE(p_hwfn, "Syn packet received with checksum error\n");
+   goto err;
+   }
+
+   /* Process SYN packet - added later on in series */
+
+err:
+   qed_iwarp_ll2_post_rx(p_hwfn, buf,
+ p_hwfn->p_rdma_info->iwarp.ll2_syn_handle);
+}
+
+static void qed_iwarp_ll2_rel_rx_pkt(void *cxt, u8 connection_handle,
+void *cookie, dma_addr_t rx_buf_addr,
+bool b_last_packet)
+{
+   struct qed_iwarp_ll2_buff *buffer = cookie;
+   struct qed_hwfn *p_hwfn = cxt;
+
+   dma_free_coherent(_hwfn->cdev->pdev->dev, buffer->buff_size,
+ buffer->data, buffer->data_phys_addr);
+   kfree(buffer);
+}
+
+static void qed_iwarp_ll2_comp_tx_pkt(void *cxt, u8 connection_handle,
+ void *cookie, dma_addr_t first_frag_addr,
+ bool b_last_fragment, bool b_last_packet)
+{
+   struct qed_iwarp_ll2_buff *buffer = cookie;
+   struct qed_hwfn *p_hwfn = cxt;
+
+   /* this was originally an rx packet, post it back */
+   qed_iwarp_ll2_post_rx(p_hwfn, buffer, connection_handle);
+}
+
+static void qed_iwarp_ll2_rel_tx_pkt(void *cxt, u8 connection_handle,
+void *cookie, dma_addr_t first_frag_addr,
+bool b_last_fragment, bool b_last_packet)
+{
+   struct qed_iwarp_ll2_buff *buffer = cookie;
+   struct qed_hwfn *p_hwfn = cxt;
+
+   if (!buffer)
+   return;
+
+   dma_free_coherent(_hwfn->cdev->pdev->dev, buffer->buff_size,
+ buffer->data, buffer->data_phys_addr);
+
+   kfree(buffer);
+}
+
+static int qed_iwarp_ll2_stop(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
+{
+   struct qed_iwarp_info *iwarp_info = _hwfn->p_rdma_info->iwarp;
+   int rc = 0;
+
+   if (iwarp_info->ll2_syn_handle != QED_IWARP_HANDLE_INVAL) {
+   rc = qed_ll2_terminate_connection(p_hwfn,
+ iwarp_info->ll2_syn_handle);
+   if (rc)
+   DP_INFO(p_hwfn, "Failed to terminate syn connection\n");
+
+   qed_ll2_release_connection(p_hwfn, iwarp_info->ll2_syn_handle);
+   iwarp_info->ll2_syn_handle = QED_IWARP_HANDLE_INVAL;
+   }
+
+   qed_llh_remove_mac_filter(p_hwfn,
+ p_ptt, p_hwfn->p_rdma_info->iwarp.mac_addr);
+   return rc;
+}
+
+static int
+qed_iwarp_ll2_alloc_buffers(str

[RFC 03/19] qed: Rename some ll2 related defines

2017-06-26 Thread Michal Kalderon
Make some names more generic as they will be used by iWARP too.

Signed-off-by: Michal Kalderon <michal.kalde...@cavium.com>
Signed-off-by: Yuval Mintz <yuval.mi...@cavium.com>
Signed-off-by: Ariel Elior <ariel.el...@cavium.com>

---
 drivers/net/ethernet/qlogic/qed/qed.h |  2 +-
 drivers/net/ethernet/qlogic/qed/qed_ll2.c | 29 ++---
 include/linux/qed/qed_ll2_if.h|  2 +-
 3 files changed, 16 insertions(+), 17 deletions(-)

diff --git a/drivers/net/ethernet/qlogic/qed/qed.h 
b/drivers/net/ethernet/qlogic/qed/qed.h
index 22e1171..fd8cd5e 100644
--- a/drivers/net/ethernet/qlogic/qed/qed.h
+++ b/drivers/net/ethernet/qlogic/qed/qed.h
@@ -779,7 +779,7 @@ static inline u8 qed_concrete_to_sw_fid(struct qed_dev 
*cdev,
 }
 
 #define PURE_LB_TC 8
-#define OOO_LB_TC 9
+#define PKT_LB_TC 9
 
 int qed_configure_vport_wfq(struct qed_dev *cdev, u16 vp_id, u32 rate);
 void qed_configure_vp_wfq_on_link_change(struct qed_dev *cdev,
diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.c 
b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
index be66f19..e235fb2 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_ll2.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
@@ -309,7 +309,7 @@ static void qed_ll2_txq_flush(struct qed_hwfn *p_hwfn, u8 
connection_handle)
list_del(_pkt->list_entry);
b_last_packet = list_empty(_tx->active_descq);
list_add_tail(_pkt->list_entry, _tx->free_descq);
-   if (p_ll2_conn->input.conn_type == QED_LL2_TYPE_ISCSI_OOO) {
+   if (p_ll2_conn->input.conn_type == QED_LL2_TYPE_OOO) {
struct qed_ooo_buffer *p_buffer;
 
p_buffer = (struct qed_ooo_buffer *)p_pkt->cookie;
@@ -532,7 +532,7 @@ static void qed_ll2_rxq_flush(struct qed_hwfn *p_hwfn, u8 
connection_handle)
 
list_move_tail(_pkt->list_entry, _rx->free_descq);
 
-   if (p_ll2_conn->input.conn_type == QED_LL2_TYPE_ISCSI_OOO) {
+   if (p_ll2_conn->input.conn_type == QED_LL2_TYPE_OOO) {
struct qed_ooo_buffer *p_buffer;
 
p_buffer = (struct qed_ooo_buffer *)p_pkt->cookie;
@@ -893,8 +893,7 @@ static int qed_sp_ll2_rx_queue_start(struct qed_hwfn 
*p_hwfn,
p_ramrod->drop_ttl0_flg = p_ll2_conn->input.rx_drop_ttl0_flg;
p_ramrod->inner_vlan_removal_en = p_ll2_conn->input.rx_vlan_removal_en;
p_ramrod->queue_id = p_ll2_conn->queue_id;
-   p_ramrod->main_func_queue = (conn_type == QED_LL2_TYPE_ISCSI_OOO) ? 0
- : 1;
+   p_ramrod->main_func_queue = (conn_type == QED_LL2_TYPE_OOO) ? 0 : 1;
 
if ((IS_MF_DEFAULT(p_hwfn) || IS_MF_SI(p_hwfn)) &&
p_ramrod->main_func_queue && (conn_type != QED_LL2_TYPE_ROCE)) {
@@ -924,7 +923,7 @@ static int qed_sp_ll2_tx_queue_start(struct qed_hwfn 
*p_hwfn,
if (!QED_LL2_TX_REGISTERED(p_ll2_conn))
return 0;
 
-   if (p_ll2_conn->input.conn_type == QED_LL2_TYPE_ISCSI_OOO)
+   if (p_ll2_conn->input.conn_type == QED_LL2_TYPE_OOO)
p_ll2_conn->tx_stats_en = 0;
else
p_ll2_conn->tx_stats_en = 1;
@@ -955,10 +954,10 @@ static int qed_sp_ll2_tx_queue_start(struct qed_hwfn 
*p_hwfn,
p_ramrod->pbl_size = cpu_to_le16(pbl_size);
 
switch (p_ll2_conn->input.tx_tc) {
-   case LB_TC:
+   case PURE_LB_TC:
pq_id = qed_get_cm_pq_idx(p_hwfn, PQ_FLAGS_LB);
break;
-   case OOO_LB_TC:
+   case PKT_LB_TC:
pq_id = qed_get_cm_pq_idx(p_hwfn, PQ_FLAGS_OOO);
break;
default:
@@ -973,7 +972,7 @@ static int qed_sp_ll2_tx_queue_start(struct qed_hwfn 
*p_hwfn,
p_ramrod->conn_type = PROTOCOLID_FCOE;
break;
case QED_LL2_TYPE_ISCSI:
-   case QED_LL2_TYPE_ISCSI_OOO:
+   case QED_LL2_TYPE_OOO:
p_ramrod->conn_type = PROTOCOLID_ISCSI;
break;
case QED_LL2_TYPE_ROCE:
@@ -1142,7 +1141,7 @@ static int qed_ll2_acquire_connection_tx(struct qed_hwfn 
*p_hwfn,
u16 buf_idx;
int rc = 0;
 
-   if (p_ll2_info->input.conn_type != QED_LL2_TYPE_ISCSI_OOO)
+   if (p_ll2_info->input.conn_type != QED_LL2_TYPE_OOO)
return rc;
 
/* Correct number of requested OOO buffers if needed */
@@ -1280,7 +1279,7 @@ int qed_ll2_acquire_connection(void *cxt, struct 
qed_ll2_acquire_data *data)
goto q_allocate_fail;
 
/* Register callbacks for the Rx/Tx queues */
-   if (data->input.conn_type == QED_LL2_TYPE_ISCSI_OOO) {
+   if (data->input.conn_type == QED_LL2_TYPE_OOO) {
comp_rx_cb = qed_ll2_lb_rxq_completion;
comp_tx_cb = 

  1   2   >