netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH net-next v2 0/4] cxgb4: add FCoE DDP and RSS
@ 2015-04-13 14:04 Varun Prakash
  2015-04-13 14:04 ` [PATCH net-next v2 1/4] cxgb4/iw_cxgb4/cxgb4i: remove duplicate definitions Varun Prakash
                   ` (3 more replies)
  0 siblings, 4 replies; 10+ messages in thread
From: Varun Prakash @ 2015-04-13 14:04 UTC (permalink / raw)
  To: netdev, linux-scsi, linux-rdma
  Cc: davem, JBottomley, roland, leedom, anish, hariprasad, swise, kxie,
	praveenm, kumaras, varun

This patch series enables RSS for FCoE frames and adds
DDP support for FCoE target.

v2: add patch 1/4 to fix build error "redefinition of 
    struct ulptx_idata".

Varun Prakash (4):
  cxgb4/iw_cxgb4/cxgb4i: remove duplicate definitions
  cxgb4: add structure and macro definitions for FCoE DDP
  cxgb4: add DDP support for FCoE target
  cxgb4: enable RSS for FCoE frames

 drivers/infiniband/hw/cxgb4/t4fw_ri_api.h       |    9 -
 drivers/net/ethernet/chelsio/cxgb4/cxgb4.h      |    1 +
 drivers/net/ethernet/chelsio/cxgb4/cxgb4_fcoe.c |  600 +++++++++++++++++++++++
 drivers/net/ethernet/chelsio/cxgb4/cxgb4_fcoe.h |   54 ++-
 drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c |   47 ++-
 drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h  |    7 +
 drivers/net/ethernet/chelsio/cxgb4/sge.c        |  328 ++++++++++++-
 drivers/net/ethernet/chelsio/cxgb4/t4_hw.c      |    1 +
 drivers/net/ethernet/chelsio/cxgb4/t4_hw.h      |   29 ++
 drivers/net/ethernet/chelsio/cxgb4/t4_msg.h     |   64 +++
 drivers/net/ethernet/chelsio/cxgb4/t4_regs.h    |    8 +
 drivers/net/ethernet/chelsio/cxgb4/t4_tcb.h     |   90 ++++
 drivers/net/ethernet/chelsio/cxgb4/t4_values.h  |    3 +
 drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h   |    9 +
 drivers/scsi/cxgbi/cxgb4i/cxgb4i.h              |    5 -
 15 files changed, 1234 insertions(+), 21 deletions(-)
 create mode 100644 drivers/net/ethernet/chelsio/cxgb4/t4_tcb.h

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH net-next v2 1/4] cxgb4/iw_cxgb4/cxgb4i: remove duplicate definitions
  2015-04-13 14:04 [PATCH net-next v2 0/4] cxgb4: add FCoE DDP and RSS Varun Prakash
@ 2015-04-13 14:04 ` Varun Prakash
  2015-04-13 16:38   ` Jason Gunthorpe
       [not found]   ` <6358f849b5a1a3727879f4f2f5c855e3a5b95ab4.1428930614.git.varun-ut6Up61K2wZBDgjK7y7TUQ@public.gmane.org>
  2015-04-13 14:04 ` [PATCH net-next v2 2/4] cxgb4: add structure and macro definitions for FCoE DDP Varun Prakash
                   ` (2 subsequent siblings)
  3 siblings, 2 replies; 10+ messages in thread
From: Varun Prakash @ 2015-04-13 14:04 UTC (permalink / raw)
  To: netdev, linux-scsi, linux-rdma
  Cc: davem, JBottomley, roland, leedom, anish, hariprasad, swise, kxie,
	praveenm, kumaras, varun

define struct ulptx_idata in common header file t4_msg.h
to remove duplicate definitions.

Signed-off-by: Varun Prakash <varun@chelsio.com>
---
 drivers/infiniband/hw/cxgb4/t4fw_ri_api.h   |    9 ---------
 drivers/net/ethernet/chelsio/cxgb4/t4_msg.h |    5 +++++
 drivers/scsi/cxgbi/cxgb4i/cxgb4i.h          |    5 -----
 3 files changed, 5 insertions(+), 14 deletions(-)

diff --git a/drivers/infiniband/hw/cxgb4/t4fw_ri_api.h b/drivers/infiniband/hw/cxgb4/t4fw_ri_api.h
index 5e53327..210f04a 100644
--- a/drivers/infiniband/hw/cxgb4/t4fw_ri_api.h
+++ b/drivers/infiniband/hw/cxgb4/t4fw_ri_api.h
@@ -818,15 +818,6 @@ struct cpl_pass_accept_req {
 #define SYN_INTF_V(x) ((x) << SYN_INTF_S)
 #define SYN_INTF_G(x) (((x) >> SYN_INTF_S) & SYN_INTF_M)
 
-struct ulptx_idata {
-	__be32 cmd_more;
-	__be32 len;
-};
-
-#define ULPTX_NSGE_S    0
-#define ULPTX_NSGE_M    0xFFFF
-#define ULPTX_NSGE_V(x) ((x) << ULPTX_NSGE_S)
-
 #define RX_DACK_MODE_S    29
 #define RX_DACK_MODE_M    0x3
 #define RX_DACK_MODE_V(x) ((x) << RX_DACK_MODE_S)
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h b/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h
index 30a2f56..7e2137d 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h
@@ -1054,6 +1054,11 @@ struct ulptx_sgl {
 	struct ulptx_sge_pair sge[0];
 };
 
+struct ulptx_idata {
+	__be32 cmd_more;
+	__be32 len;
+};
+
 #define ULPTX_NSGE_S    0
 #define ULPTX_NSGE_V(x) ((x) << ULPTX_NSGE_S)
 
diff --git a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.h b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.h
index 1096026..342263b 100644
--- a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.h
+++ b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.h
@@ -23,11 +23,6 @@
 #define CXGB4I_TX_HEADER_LEN \
 	(sizeof(struct fw_ofld_tx_data_wr) + sizeof(struct sge_opaque_hdr))
 
-struct ulptx_idata {
-	__be32 cmd_more;
-	__be32 len;
-};
-
 struct cpl_rx_data_ddp {
 	union opcode_tid ot;
 	__be16 urg;
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH net-next v2 2/4] cxgb4: add structure and macro definitions for FCoE DDP
  2015-04-13 14:04 [PATCH net-next v2 0/4] cxgb4: add FCoE DDP and RSS Varun Prakash
  2015-04-13 14:04 ` [PATCH net-next v2 1/4] cxgb4/iw_cxgb4/cxgb4i: remove duplicate definitions Varun Prakash
@ 2015-04-13 14:04 ` Varun Prakash
  2015-04-13 14:04 ` [PATCH net-next v2 3/4] cxgb4: add DDP support for FCoE target Varun Prakash
  2015-04-13 14:04 ` [PATCH net-next v2 4/4] cxgb4: enable RSS for FCoE frames Varun Prakash
  3 siblings, 0 replies; 10+ messages in thread
From: Varun Prakash @ 2015-04-13 14:04 UTC (permalink / raw)
  To: netdev, linux-scsi, linux-rdma
  Cc: davem, JBottomley, roland, leedom, anish, hariprasad, swise, kxie,
	praveenm, kumaras, varun

This patch adds new header file t4_tcb.h and
structure, macro definitions for FCoE DDP
support in cxgb4 driver.

Signed-off-by: Varun Prakash <varun@chelsio.com>
---
 drivers/net/ethernet/chelsio/cxgb4/cxgb4_fcoe.h |   54 +++++++++++++-
 drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h  |    7 ++
 drivers/net/ethernet/chelsio/cxgb4/t4_hw.h      |   29 +++++++
 drivers/net/ethernet/chelsio/cxgb4/t4_msg.h     |   59 +++++++++++++++
 drivers/net/ethernet/chelsio/cxgb4/t4_tcb.h     |   90 +++++++++++++++++++++++
 drivers/net/ethernet/chelsio/cxgb4/t4_values.h  |    3 +
 drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h   |    9 ++
 7 files changed, 250 insertions(+), 1 deletions(-)
 create mode 100644 drivers/net/ethernet/chelsio/cxgb4/t4_tcb.h

diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_fcoe.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_fcoe.h
index bf9258a..458c696 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_fcoe.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_fcoe.h
@@ -40,18 +40,70 @@
 #define CXGB_FCOE_TXPKT_CSUM_START	28
 #define CXGB_FCOE_TXPKT_CSUM_END	8
 
+#define CXGB_FCOE_ATID		13
+#define CXGB_FCOE_GET_XID(x)	((x) & 0x3FF)
+
+#define CXGB_FCOE_SHIFT_PORTID	11
+#define CXGB_FCOE_MASK_PORTID	0x3
+#define CXGB_FCOE_GET_PORTID(x)	\
+	(((x) >> CXGB_FCOE_SHIFT_PORTID) & CXGB_FCOE_MASK_PORTID)
+
+/* # of sentinel invalid page pods at the end of a group of valid page pods */
+#define CXGB_FCOE_NUM_SENTINEL_PPODS	0
+
+#define CXGB_FCOE_PPOD_SIZE		sizeof(struct pagepod)
+
+#define CXGB_FCOE_MAX_XCHGS_PORT	1024	/* Per netdev */
+#define CXGB_FCOE_MAX_PAGE_CNT		((10485760) / PAGE_SIZE)
+
+/* ddp flags */
+enum {
+	CXGB_FCOE_DDP_ERROR     = (1 << 0),
+	CXGB_FCOE_DDP_TID_VALID = (1 << 1),
+};
+
+struct cxgb_fcoe_ddp {
+	u8 h_source[ETH_ALEN];
+	u8 h_dest[ETH_ALEN];
+	unsigned int sgc;
+	struct scatterlist *sgl;
+	int ddp_len;
+	unsigned int tid;
+	unsigned int nppods;
+	unsigned int npages;
+	unsigned int ppod_tag;
+	unsigned int first_pg_off;
+	unsigned int xfer_len;
+	u16 vlan_tci;
+	u16 xid;
+	u8 d_id[3];
+	u8 flags;
+	dma_addr_t *ppod_gl;
+};
+
 /* fcoe flags */
 enum {
 	CXGB_FCOE_ENABLED     = (1 << 0),
 };
 
 struct cxgb_fcoe {
-	u8	flags;
+	u8 flags;
+	struct completion *cmpl;
+	struct cxgb_fcoe_ddp ddp[CXGB_FCOE_MAX_XCHGS_PORT];
 };
 
 int cxgb_fcoe_enable(struct net_device *);
 int cxgb_fcoe_disable(struct net_device *);
 bool cxgb_fcoe_sof_eof_supported(struct adapter *, struct sk_buff *);
 
+void cxgb_fcoe_init_ddp(struct adapter *);
+void cxgb_fcoe_exit_ddp(struct adapter *);
+void cxgb_fcoe_cpl_act_open_rpl(struct adapter *, unsigned int,
+				unsigned int, unsigned int);
+int cxgb_fcoe_rx_handler(struct sge_rspq *, const __be64 *);
+void cxgb_fcoe_free_ppods(struct adapter *, unsigned int, unsigned int);
+int cxgb_fcoe_ddp_setup(struct net_device *, u16,
+			struct scatterlist *, unsigned int);
+int cxgb_fcoe_ddp_done(struct net_device *, u16);
 #endif /* CONFIG_CHELSIO_T4_FCOE */
 #endif /* __CXGB4_FCOE_H__ */
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h
index 78ab4d4..412a740 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h
@@ -218,6 +218,13 @@ struct cxgb4_virt_res {                      /* virtualized HW resources */
 	struct cxgb4_range qp;
 	struct cxgb4_range cq;
 	struct cxgb4_range ocq;
+#ifdef CONFIG_CHELSIO_T4_FCOE
+	u8 *ppod_map;
+	u16 *tid2xid;
+	unsigned int toe_nppods;
+	unsigned int fcoe_nppods;
+	spinlock_t ppod_map_lock;	/* page pod map lock */
+#endif /* CONFIG_CHELSIO_T4_FCOE */
 };
 
 #define OCQ_WIN_OFFSET(pdev, vres) \
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h
index 380b15c..133e776 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h
@@ -164,6 +164,35 @@ struct rsp_ctrl {
 #define QINTR_TIMER_IDX(x) ((x) << 1)
 #define QINTR_TIMER_IDX_GET(x) (((x) >> 1) & 0x7)
 
+/* # of pages a pagepod can hold without needing another pagepod */
+#define PPOD_PAGES 4U
+
+struct pagepod {
+	__be64 vld_tid_pgsz_tag_color;
+	__be64 len_offset;
+	__be64 rsvd;
+	__be64 addr[PPOD_PAGES + 1];
+};
+
+#define PPOD_COLOR_S    0
+#define PPOD_COLOR_V(x) ((x) << PPOD_COLOR_S)
+
+#define PPOD_TAG_S    6
+#define PPOD_TAG_V(x) ((x) << PPOD_TAG_S)
+
+#define PPOD_TID_S    32
+#define PPOD_TID_V(x) ((__u64)(x) << PPOD_TID_S)
+
+#define PPOD_VALID_S    56
+#define PPOD_VALID_V(x) ((__u64)(x) << PPOD_VALID_S)
+#define PPOD_VALID_F    PPOD_VALID_V(1ULL)
+
+#define PPOD_LEN_S    32
+#define PPOD_LEN_V(x) ((__u64)(x) << PPOD_LEN_S)
+
+#define PPOD_OFST_S    0
+#define PPOD_OFST_V(x) ((x) << PPOD_OFST_S)
+
 /*
  * Flash layout.
  */
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h b/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h
index 7e2137d..8142d4e 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h
@@ -74,6 +74,8 @@ enum {
 	CPL_PASS_ESTABLISH    = 0x41,
 	CPL_RX_DATA_DDP       = 0x42,
 	CPL_PASS_ACCEPT_REQ   = 0x44,
+	CPL_RX_FCOE_DDP       = 0x46,
+	CPL_FCOE_HDR          = 0x47,
 	CPL_TRACE_PKT_T5      = 0x48,
 	CPL_RX_ISCSI_DDP      = 0x49,
 
@@ -88,6 +90,7 @@ enum {
 
 	CPL_TRACE_PKT         = 0xB0,
 	CPL_ISCSI_DATA	      = 0xB2,
+	CPL_FCOE_DATA         = 0xB3,
 
 	CPL_FW4_MSG           = 0xC0,
 	CPL_FW4_PLD           = 0xC1,
@@ -227,6 +230,10 @@ struct work_request_hdr {
 #define TX_CHAN_S    2
 #define TX_CHAN_V(x) ((x) << TX_CHAN_S)
 
+#define NON_OFFLOAD_S    7
+#define NON_OFFLOAD_V(x) ((x) << NON_OFFLOAD_S)
+#define NON_OFFLOAD_F    NON_OFFLOAD_V(1U)
+
 #define ULP_MODE_S    8
 #define ULP_MODE_V(x) ((x) << ULP_MODE_S)
 
@@ -417,6 +424,11 @@ struct cpl_t5_act_open_req {
 	__be64 params;
 };
 
+/* cpl_t5_act_open_req.params field */
+#define AOPEN_FCOEMASK_S	0
+#define AOPEN_FCOEMASK_V(x)	((x) << AOPEN_FCOEMASK_S)
+#define AOPEN_FCOEMASK_F	AOPEN_FCOEMASK_V(1U)
+
 struct cpl_act_open_req6 {
 	WR_HDR;
 	union opcode_tid ot;
@@ -734,6 +746,44 @@ struct cpl_iscsi_hdr {
 #define ISCSI_DDP_V(x) ((x) << ISCSI_DDP_S)
 #define ISCSI_DDP_F    ISCSI_DDP_V(1U)
 
+struct cpl_fcoe_hdr {
+	struct rss_header rsshdr;
+	union opcode_tid ot;
+	__be16 oxid;
+	__be16 len;
+	__be32 rctl_fctl;
+	__u8 cs_ctl;
+	__u8 df_ctl;
+	__u8 sof;
+	__u8 eof;
+	__be16 seq_cnt;
+	__u8 seq_id;
+	__u8 type;
+	__be32 param;
+};
+
+/* cpl_fcoe_hdr.rctl_fctl fields */
+#define FCOE_FCHDR_RCTL_S	24
+#define FCOE_FCHDR_RCTL_M	0xff
+#define FCOE_FCHDR_RCTL_G(x)	\
+	(((x) >> FCOE_FCHDR_RCTL_S) & FCOE_FCHDR_RCTL_M)
+
+#define FCOE_FCHDR_FCTL_S	0
+#define FCOE_FCHDR_FCTL_M	0xffffff
+#define G_FCOE_FCHDR_FCTL(x)	\
+	(((x) >> FCOE_FCHDR_FCTL_S) & FCOE_FCHDR_FCTL_M)
+
+struct cpl_rx_fcoe_ddp {
+	struct rss_header rsshdr;
+	union opcode_tid ot;
+	__be16 rsvd;
+	__be16 len;
+	__be32 seq;
+	__be32 ddp_report;
+	__be32 ulp_crc;
+	__be32 ddpvld;
+};
+
 struct cpl_rx_data {
 	union opcode_tid ot;
 	__be16 rsvd;
@@ -1099,4 +1149,13 @@ struct ulp_mem_io {
 #define ULP_MEMIO_DATA_LEN_S    0
 #define ULP_MEMIO_DATA_LEN_V(x) ((x) << ULP_MEMIO_DATA_LEN_S)
 
+struct ulp_txpkt {
+	__be32 cmd_dest;
+	__be32 len;
+};
+
+/* ulp_txpkt.cmd_dest fields */
+#define ULP_TXPKT_DEST_S    16
+#define ULP_TXPKT_DEST_V(x) ((x) << ULP_TXPKT_DEST_S)
+
 #endif  /* __T4_MSG_H */
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_tcb.h b/drivers/net/ethernet/chelsio/cxgb4/t4_tcb.h
new file mode 100644
index 0000000..1ccd7f3
--- /dev/null
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4_tcb.h
@@ -0,0 +1,90 @@
+/*
+ * This file is part of the Chelsio T4 Ethernet driver for Linux.
+ *
+ * Copyright (c) 2015 Chelsio Communications, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _T4_TCB_DEFS_H
+#define _T4_TCB_DEFS_H
+
+/* 95:32 */
+#define TCB_T_FLAGS_W    1
+
+/* 105:96 */
+#define TCB_RSS_INFO_S    0
+#define TCB_RSS_INFO_M    0x3ffULL
+#define TCB_RSS_INFO_V(x) ((x) << TCB_RSS_INFO_S)
+
+/* 115:112 */
+#define TCB_T_STATE_W    3
+#define TCB_T_STATE_S    16
+#define TCB_T_STATE_M    0xfULL
+#define TCB_T_STATE_V(x) ((x) << TCB_T_STATE_S)
+
+/* 855:832 */
+#define TCB_RX_DDP_BUF0_OFFSET_W    26
+#define TCB_RX_DDP_BUF0_OFFSET_S    0
+#define TCB_RX_DDP_BUF0_OFFSET_M    0xffffffULL
+#define TCB_RX_DDP_BUF0_OFFSET_V(x) ((x) << TCB_RX_DDP_BUF0_OFFSET_S)
+
+/* 879:856 */
+#define TCB_RX_DDP_BUF0_LEN_S    24
+#define TCB_RX_DDP_BUF0_LEN_M    0xffffffULL
+#define TCB_RX_DDP_BUF0_LEN_V(x) ((__u64)(x) << TCB_RX_DDP_BUF0_LEN_S)
+
+/* 903:880 */
+#define TCB_RX_DDP_FLAGS_W    27
+
+/* 991:960 */
+#define TCB_RX_DDP_BUF0_TAG_W    30
+#define TCB_RX_DDP_BUF0_TAG_S    0
+#define TCB_RX_DDP_BUF0_TAG_M    0xffffffffULL
+#define TCB_RX_DDP_BUF0_TAG_V(x) ((x) << TCB_RX_DDP_BUF0_TAG_S)
+
+#define TF_NON_OFFLOAD_S    1
+#define TF_NON_OFFLOAD_V(x) ((x) << TF_NON_OFFLOAD_S)
+
+#define TF_DDP_INDICATE_OUT_S    16
+#define TF_DDP_INDICATE_OUT_V(x) ((x) << TF_DDP_INDICATE_OUT_S)
+
+#define TF_DDP_OFF_S    18
+#define TF_DDP_OFF_V(x) ((x) << TF_DDP_OFF_S)
+
+#define TF_DDP_BUF_INF_S    20
+#define TF_DDP_BUF_INF_V(x) ((x) << TF_DDP_BUF_INF_S)
+
+#define TF_DDP_BUF0_VALID_S    24
+#define TF_DDP_BUF0_VALID_V(x) ((x) << TF_DDP_BUF0_VALID_S)
+
+#define TF_DDP_BUF0_INDICATE_S    25
+#define TF_DDP_BUF0_INDICATE_V(x) ((x) << TF_DDP_BUF0_INDICATE_S)
+
+#endif /* _T4_TCB_DEFS_H */
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_values.h b/drivers/net/ethernet/chelsio/cxgb4/t4_values.h
index 19b2dcf..28a8d36 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4_values.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4_values.h
@@ -61,6 +61,9 @@
 #define SGE_TIMERREGS			6
 #define TIMERREG_COUNTER0_X		0
 
+/* Egress Context field values */
+#define IDXSIZE_UNIT_X			64
+
 /* T5 and later support a new BAR2-based doorbell mechanism for Egress Queues.
  * The User Doorbells are each 128 bytes in length with a Simple Doorbell at
  * offsets 8x and a Write Combining single 64-byte Egress Queue Unit
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
index 03fbfd1..0babf8e 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
@@ -101,6 +101,7 @@ enum fw_wr_opcodes {
 	FW_RI_BIND_MW_WR               = 0x18,
 	FW_RI_FR_NSMR_WR               = 0x19,
 	FW_RI_INV_LSTAG_WR             = 0x1a,
+	FW_POFCOE_ULPTX_WR	       = 0x43,
 	FW_LASTC2E_WR                  = 0x70
 };
 
@@ -631,6 +632,12 @@ struct fw_eth_tx_pkt_vm_wr {
 	__be16 vlantci;
 };
 
+struct fw_pofcoe_ulptx_wr {
+	__be32 op_pkd;
+	__be32 equiq_to_len16;
+	__u64  cookie;
+};
+
 #define FW_CMD_MAX_TIMEOUT 10000
 
 /*
@@ -985,6 +992,8 @@ enum fw_caps_config_fcoe {
 	FW_CAPS_CONFIG_FCOE_INITIATOR	= 0x00000001,
 	FW_CAPS_CONFIG_FCOE_TARGET	= 0x00000002,
 	FW_CAPS_CONFIG_FCOE_CTRL_OFLD	= 0x00000004,
+	FW_CAPS_CONFIG_POFCOE_INITIATOR = 0x00000008,
+	FW_CAPS_CONFIG_POFCOE_TARGET    = 0x00000010,
 };
 
 enum fw_memtype_cf {
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH net-next v2 3/4] cxgb4: add DDP support for FCoE target
  2015-04-13 14:04 [PATCH net-next v2 0/4] cxgb4: add FCoE DDP and RSS Varun Prakash
  2015-04-13 14:04 ` [PATCH net-next v2 1/4] cxgb4/iw_cxgb4/cxgb4i: remove duplicate definitions Varun Prakash
  2015-04-13 14:04 ` [PATCH net-next v2 2/4] cxgb4: add structure and macro definitions for FCoE DDP Varun Prakash
@ 2015-04-13 14:04 ` Varun Prakash
  2015-04-13 17:12   ` David Miller
  2015-04-13 14:04 ` [PATCH net-next v2 4/4] cxgb4: enable RSS for FCoE frames Varun Prakash
  3 siblings, 1 reply; 10+ messages in thread
From: Varun Prakash @ 2015-04-13 14:04 UTC (permalink / raw)
  To: netdev, linux-scsi, linux-rdma
  Cc: davem, JBottomley, roland, leedom, anish, hariprasad, swise, kxie,
	praveenm, kumaras, varun

This patch adds code for ndo_fcoe_ddp_target and
ndo_fcoe_ddp_done.

Signed-off-by: Varun Prakash <varun@chelsio.com>
---
 drivers/net/ethernet/chelsio/cxgb4/cxgb4.h      |    1 +
 drivers/net/ethernet/chelsio/cxgb4/cxgb4_fcoe.c |  600 +++++++++++++++++++++++
 drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c |   39 ++-
 drivers/net/ethernet/chelsio/cxgb4/sge.c        |  328 ++++++++++++-
 drivers/net/ethernet/chelsio/cxgb4/t4_hw.c      |    1 +
 5 files changed, 963 insertions(+), 6 deletions(-)

diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
index 524d110..8cc53f9 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
@@ -247,6 +247,7 @@ struct tp_params {
 	 * places we store their offsets here, or a -1 if the field isn't
 	 * present.
 	 */
+	int fcoe_shift;
 	int vlan_shift;
 	int vnic_shift;
 	int port_shift;
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_fcoe.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_fcoe.c
index 6c8a62e..f78d632 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_fcoe.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_fcoe.c
@@ -34,8 +34,10 @@
 
 #ifdef CONFIG_CHELSIO_T4_FCOE
 
+#include <linux/if_vlan.h>
 #include <scsi/fc/fc_fs.h>
 #include <scsi/libfcoe.h>
+#include "t4_msg.h"
 #include "cxgb4.h"
 
 bool cxgb_fcoe_sof_eof_supported(struct adapter *adap, struct sk_buff *skb)
@@ -59,6 +61,528 @@ bool cxgb_fcoe_sof_eof_supported(struct adapter *adap, struct sk_buff *skb)
 	return true;
 }
 
+static inline struct cxgb_fcoe_ddp *
+cxgb_fcoe_lookup_ddp(struct port_info *pi, unsigned int tid)
+{
+	struct adapter *adap = pi->adapter;
+	struct cxgb_fcoe *fcoe = &pi->fcoe;
+	struct cxgb_fcoe_ddp *ddp;
+	u16 xid;
+
+	if (tid >= adap->tids.ntids) {
+		dev_err(adap->pdev_dev, "tid %x out of bounds\n", tid);
+		return NULL;
+	}
+
+	xid = adap->vres.tid2xid[tid];
+
+	if (xid >= CXGB_FCOE_MAX_XCHGS_PORT) {
+		dev_err(adap->pdev_dev, "xid %x out of bounds, tid:%x\n",
+			xid, tid);
+		return NULL;
+	}
+
+	ddp = &fcoe->ddp[xid];
+
+	if ((fcoe->flags & CXGB_FCOE_ENABLED) && (ddp->tid == tid) && ddp->sgl)
+		return ddp;
+
+	return NULL;
+}
+
+static inline struct sk_buff *
+cxgb_fcoe_init_skb(struct adapter *adapter, u16 xid, struct port_info *pi,
+		   struct cxgb_fcoe_ddp *ddp, struct cpl_fcoe_hdr *cfcoe_hdr,
+		   struct sge_eth_rxq *rxq)
+{
+	struct sk_buff *skb;
+	struct ethhdr *eh;
+	struct fcoe_crc_eof *cp;
+	struct fc_frame_header *fh;
+	unsigned int hlen;		/* fcoe header length */
+	unsigned int tlen;		/* fcoe trailer length */
+	unsigned int elen;		/* eth header excluding vlan */
+	unsigned int fclen;		/* fc header len */
+	u8 rctl;
+	struct fcoe_hdr *hp;
+
+	elen = sizeof(struct ethhdr);
+	hlen = sizeof(struct fcoe_hdr);
+	fclen = sizeof(struct fc_frame_header);
+	tlen = sizeof(struct fcoe_crc_eof);
+
+	skb = dev_alloc_skb(elen + hlen + fclen + tlen);
+	if (!skb)
+		return NULL;
+
+	rctl = FCOE_FCHDR_RCTL_G(be32_to_cpu(cfcoe_hdr->rctl_fctl));
+
+	skb->ip_summed = CHECKSUM_UNNECESSARY;
+	skb->protocol = htons(ETH_P_FCOE);
+	skb->dev = adapter->port[pi->port_id];
+
+	eh = (struct ethhdr *)skb_put(skb, elen);
+	ether_addr_copy(eh->h_source, ddp->h_dest);
+	ether_addr_copy(eh->h_dest, ddp->h_source);
+	eh->h_proto = htons(ETH_P_FCOE);
+
+	hp = (struct fcoe_hdr *)skb_put(skb, hlen);
+	memset(hp, 0, sizeof(*hp));
+	if (FC_FCOE_VER)
+		FC_FCOE_ENCAPS_VER(hp, FC_FCOE_VER);
+	hp->fcoe_sof = cfcoe_hdr->sof;
+
+	fh = (struct fc_frame_header *)skb_put(skb, fclen);
+	fh->fh_r_ctl = rctl;
+	memcpy(fh->fh_d_id, &ddp->h_source[3], 3);
+	memcpy(fh->fh_s_id, ddp->d_id, 3);
+
+	fh->fh_cs_ctl = cfcoe_hdr->cs_ctl;
+	fh->fh_type = cfcoe_hdr->type;
+	memcpy(fh->fh_f_ctl, ((char *)&cfcoe_hdr->rctl_fctl) + 1, 3);
+	fh->fh_seq_id = cfcoe_hdr->seq_id;
+	fh->fh_df_ctl = cfcoe_hdr->df_ctl;
+	fh->fh_seq_cnt = cfcoe_hdr->seq_cnt;
+	fh->fh_ox_id = cfcoe_hdr->oxid;
+	fh->fh_rx_id = htons(xid);
+	fh->fh_parm_offset = cfcoe_hdr->param;
+
+	cp = (struct fcoe_crc_eof *)skb_put(skb, tlen);
+
+	memset(cp, 0, sizeof(*cp));
+	cp->fcoe_eof = cfcoe_hdr->eof;
+
+	skb_reset_mac_header(skb);
+	skb_set_network_header(skb, sizeof(*eh));
+	__skb_pull(skb, sizeof(*eh));
+	skb_record_rx_queue(skb, rxq->rspq.idx);
+
+	return skb;
+}
+
+static inline void
+cxgb_fcoe_cpl_fcoe_hdr(struct port_info *pi, struct sge_rspq *q,
+		       struct cpl_fcoe_hdr *cfcoe_hdr)
+{
+	struct adapter *adap = pi->adapter;
+	struct sk_buff *skb;
+	struct cxgb_fcoe_ddp *ddp;
+	struct sge_eth_rxq *rxq = container_of(q, struct sge_eth_rxq, rspq);
+	unsigned int tid = GET_TID(cfcoe_hdr);
+	u32 fctl;
+
+	ddp = cxgb_fcoe_lookup_ddp(pi, tid);
+	if (!ddp)
+		return;
+
+	if (ddp->flags & CXGB_FCOE_DDP_ERROR)
+		return;
+
+	fctl = G_FCOE_FCHDR_FCTL(be32_to_cpu(cfcoe_hdr->rctl_fctl));
+
+	ddp->ddp_len += ntohs(cfcoe_hdr->len);
+
+	/* Send skb only on transfer of sequence initiative (last frame) */
+	if ((fctl & (FC_FC_SEQ_INIT | FC_FC_END_SEQ)) !=
+					(FC_FC_SEQ_INIT | FC_FC_END_SEQ))
+		return;
+
+	/* Synth a skb */
+	skb = cxgb_fcoe_init_skb(adap, ddp->xid, pi, ddp, cfcoe_hdr, rxq);
+	if (unlikely(!skb)) {
+		ddp->flags |= CXGB_FCOE_DDP_ERROR;
+		return;
+	}
+
+	if (ddp->vlan_tci)
+		__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), ddp->vlan_tci);
+
+	netif_receive_skb(skb);
+}
+
+static void cxgb_fcoe_cpl_rx_fcoe_ddp(struct port_info *pi,
+				      struct cpl_rx_fcoe_ddp *cfcoe_ddp)
+{
+	struct adapter *adap = pi->adapter;
+	struct cxgb_fcoe_ddp *ddp;
+	unsigned int tid = GET_TID(cfcoe_ddp);
+
+	ddp = cxgb_fcoe_lookup_ddp(pi, tid);
+	if (!ddp)
+		return;
+
+	dev_warn(adap->pdev_dev, "DDP Error, xid:%x tid:%x report:%x"
+		 " vld:%x\n", ddp->xid, tid,
+		 be32_to_cpu(cfcoe_ddp->ddp_report),
+		 be32_to_cpu(cfcoe_ddp->ddpvld));
+
+	ddp->flags |= CXGB_FCOE_DDP_ERROR;
+}
+
+int cxgb_fcoe_rx_handler(struct sge_rspq *q, const __be64 *rsp)
+{
+	struct port_info *pi = netdev_priv(q->netdev);
+
+	switch (*(u8 *)rsp) {
+	case CPL_FCOE_HDR:
+		cxgb_fcoe_cpl_fcoe_hdr(pi, q,
+				       (struct cpl_fcoe_hdr *)&rsp[1]);
+		break;
+	case CPL_RX_FCOE_DDP:
+		cxgb_fcoe_cpl_rx_fcoe_ddp(pi,
+					  (struct cpl_rx_fcoe_ddp *)&rsp[1]);
+		break;
+	case CPL_FCOE_DATA:
+		break;
+	default:
+		return 0;
+	}
+
+	return 1;
+}
+
+/**
+ * cxgb_fcoe_alloc_ppods - Allocate page pods
+ * @adap: adapter
+ * @n: number of page pods to allocate
+ *
+ * Returns -1 on failure or the page pod tag
+ */
+static inline int
+cxgb_fcoe_alloc_ppods(struct adapter *adap, unsigned int n)
+{
+	unsigned int i, j;
+	struct cxgb4_virt_res *vres = &adap->vres;
+
+	if (unlikely(!vres->ppod_map))
+		return -1;
+
+	spin_lock_bh(&vres->ppod_map_lock);
+
+	/* Look for n consecutive available page pods.
+	 * Make sure to guard from scanning beyond the table.
+	 */
+	for (i = 0; i + n - 1 < vres->fcoe_nppods; ) {
+		for (j = 0; j < n; ++j)		/* scan ppod_map[i..i+n-1] */
+			if (vres->ppod_map[i + j]) {
+				i = i + j + 1;
+				goto next;
+			}
+
+		memset(&vres->ppod_map[i], 1, n);   /* allocate range */
+		spin_unlock_bh(&vres->ppod_map_lock);
+		return i;
+next:
+		continue;
+	}
+
+	spin_unlock_bh(&vres->ppod_map_lock);
+	return -1;
+}
+
+void
+cxgb_fcoe_free_ppods(struct adapter *adap, unsigned int tag, unsigned int n)
+{
+	struct cxgb4_virt_res *vres = &adap->vres;
+
+	spin_lock_bh(&vres->ppod_map_lock);
+	memset(&vres->ppod_map[tag], 0, n);
+	spin_unlock_bh(&vres->ppod_map_lock);
+}
+
+static inline void cxgb_fcoe_clear_ddp(struct cxgb_fcoe_ddp *ddp)
+{
+	ddp->sgl = NULL;
+	ddp->sgc = 0;
+	ddp->first_pg_off = 0;
+	ddp->nppods = 0;
+	ddp->ppod_tag = 0;
+	ddp->xfer_len = 0;
+	ddp->ddp_len = 0;
+	ddp->npages = 0;
+	ddp->flags = 0;
+}
+
+void cxgb_fcoe_cpl_act_open_rpl(struct adapter *adap, unsigned int atid,
+				unsigned int tid, unsigned int status)
+{
+	u16 xid = CXGB_FCOE_GET_XID(atid);
+	u8 port_id = CXGB_FCOE_GET_PORTID(atid);
+	struct port_info *pi = adap2pinfo(adap, port_id);
+	struct cxgb_fcoe *fcoe = &pi->fcoe;
+	struct cxgb_fcoe_ddp *ddp = &fcoe->ddp[xid];
+
+	if ((status == CPL_ERR_NONE) &&
+	    (tid < adap->tids.ntids)) {
+		ddp->tid = tid;
+		ddp->flags |= CXGB_FCOE_DDP_TID_VALID;
+		adap->vres.tid2xid[tid] = xid;
+	} else
+		dev_err(adap->pdev_dev, "tid allocation failed xid 0x%x status 0x%x\n",
+			xid, status);
+
+	complete(fcoe->cmpl);
+}
+
+static int cxgb_fcoe_alloc_tid(struct port_info *pi, u16 xid)
+{
+	struct adapter *adap = pi->adapter;
+	struct cxgb_fcoe *fcoe = &pi->fcoe;
+	struct cxgb_fcoe_ddp *ddp = &fcoe->ddp[xid];
+	struct tp_params *tp = &adap->params.tp;
+	struct cpl_t5_act_open_req *req;
+	struct sk_buff *skb;
+	unsigned int qid_atid = xid;
+
+	skb = alloc_skb(sizeof(*req), GFP_KERNEL);
+	if (!skb)
+		return 1;
+
+	qid_atid |= BIT(CXGB_FCOE_ATID);
+	qid_atid |= (pi->port_id << CXGB_FCOE_SHIFT_PORTID);
+	qid_atid |= (adap->sge.fw_evtq.abs_id << 14);
+
+	req = (struct cpl_t5_act_open_req *)__skb_put(skb, sizeof(*req));
+	memset(req, 0, sizeof(*req));
+
+	INIT_TP_WR(req, 0);
+	OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_ACT_OPEN_REQ, qid_atid));
+
+	req->peer_port = cpu_to_be16(xid);
+	req->opt0 = cpu_to_be64(ULP_MODE_V(ULP_MODE_FCOE) |
+			NON_OFFLOAD_F | NO_CONG_F | TX_CHAN_V(pi->tx_chan) |
+			RCV_BUFSIZ_V(RCV_BUFSIZ_M) | L2T_IDX_V(0));
+
+	req->params = cpu_to_be64(FILTER_TUPLE_V(
+				(pi->port_id << tp->port_shift) |
+				(1 << tp->fcoe_shift)) | AOPEN_FCOEMASK_F);
+
+	if (t4_mgmt_tx(adap, skb) == NET_XMIT_DROP)
+		return 1;
+
+	wait_for_completion(fcoe->cmpl);
+
+	reinit_completion(fcoe->cmpl);
+
+	if (!(ddp->flags & CXGB_FCOE_DDP_TID_VALID))
+		return 1;
+
+	return 0;
+}
+
+static void cxgb_fcoe_free_tid(struct port_info *pi, u16 xid)
+{
+	struct adapter *adap = pi->adapter;
+	struct cxgb_fcoe *fcoe = &pi->fcoe;
+	struct cxgb_fcoe_ddp *ddp = &fcoe->ddp[xid];
+	struct cpl_tid_release *req;
+	struct sk_buff *skb;
+	unsigned int len = ALIGN(sizeof(*req), 16);
+
+	skb = alloc_skb(len, GFP_KERNEL);
+	if (!skb)
+		return;
+
+	req = (struct cpl_tid_release *)__skb_put(skb, len);
+	memset(req, 0, len);
+
+	INIT_TP_WR(req, 0);
+	OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_TID_RELEASE, ddp->tid));
+
+	t4_mgmt_tx(adap, skb);
+}
+
+static void cxgb_fcoe_free_ddp(struct port_info *pi, u16 xid)
+{
+	struct cxgb_fcoe *fcoe = &pi->fcoe;
+	struct cxgb_fcoe_ddp *ddp;
+	u16 i;
+
+	for (i = 0; i < xid; i++) {
+		ddp = &fcoe->ddp[i];
+		kfree(ddp->ppod_gl);
+		cxgb_fcoe_free_tid(pi, i);
+	}
+}
+
+/* Return the # of page pods needed to accommodate a # of pages.
+ */
+static inline unsigned int pages2ppods(unsigned int pages)
+{
+	return (pages + PPOD_PAGES - 1) / PPOD_PAGES +
+			CXGB_FCOE_NUM_SENTINEL_PPODS;
+}
+
+/**
+ * cxgb_fcoe_ddp_setup - setup ddp in target mode
+ * @netdev: net device
+ * @xid: exchange id
+ * @sgl: scatterlist
+ * @sgc: number of scatterlist elements
+ *
+ * Returns 1 on success or 0 on failure.
+ */
+int cxgb_fcoe_ddp_setup(struct net_device *netdev, u16 xid,
+			struct scatterlist *sgl, unsigned int sgc)
+{
+	struct port_info *pi;
+	struct adapter *adap;
+	struct cxgb_fcoe *fcoe;
+	struct cxgb_fcoe_ddp *ddp;
+	struct scatterlist *sg;
+	unsigned int nsge, i, j, len, nppods;
+	static const unsigned int bufflen = PAGE_SIZE;
+	unsigned int firstoff = 0;
+	unsigned int thisoff = 0;
+	unsigned int thislen = 0;
+	unsigned int totlen = 0;
+	int tag;
+	dma_addr_t addr;
+
+	if (!netdev || !sgl)
+		return 0;
+
+	pi = netdev_priv(netdev);
+	adap = pi->adapter;
+
+	if (xid >= CXGB_FCOE_MAX_XCHGS_PORT) {
+		dev_warn(adap->pdev_dev, "xid=0x%x out-of-range\n", xid);
+		return 0;
+	}
+
+	fcoe = &pi->fcoe;
+	ddp = &fcoe->ddp[xid];
+	if (ddp->sgl) {
+		dev_err(adap->pdev_dev, "xid 0x%x w/ non-null sgl%p nents=%d\n",
+			xid, ddp->sgl, ddp->sgc);
+		return 0;
+	}
+
+	cxgb_fcoe_clear_ddp(ddp);
+
+	nsge = pci_map_sg(adap->pdev, sgl, sgc, DMA_FROM_DEVICE);
+	if (nsge == 0) {
+		dev_err(adap->pdev_dev, "xid 0x%x DMA map error\n", xid);
+		return 0;
+	}
+
+	j = 0;
+	for_each_sg(sgl, sg, nsge, i) {
+		addr = sg_dma_address(sg);
+		len = sg_dma_len(sg);
+		totlen += len;
+		while (len) {
+			/* max number of pages allowed in one DDP transfer */
+			if (j >= CXGB_FCOE_MAX_PAGE_CNT) {
+				dev_err(adap->pdev_dev,
+					"xid=%x:%d,%d,%d:addr=%llx "
+					"not enough descriptors\n",
+					xid, i, j, nsge, (u64)addr);
+				goto out_noddp;
+			}
+
+			/* get the offset of length of current buffer */
+			thisoff = addr & ((dma_addr_t)bufflen - 1);
+			thislen = min((bufflen - thisoff), len);
+
+			/* all but the 1st buffer (j == 0)
+			 * must be aligned on bufflen
+			 */
+			if ((j != 0) && (thisoff))
+				goto out_noddp;
+			/* all but the last buffer
+			 * ((i == (nsge - 1)) && (thislen == len))
+			 * must end at bufflen
+			 */
+			if (((i != (nsge - 1)) || (thislen != len)) &&
+			    ((thislen + thisoff) != bufflen))
+				goto out_noddp;
+
+			ddp->ppod_gl[j] = (dma_addr_t)(addr - thisoff);
+
+			/* only the first buffer may have none-zero offset */
+			if (j == 0)
+				firstoff = thisoff;
+			len -= thislen;
+			addr += thislen;
+			j++;
+		}
+	}
+
+	nppods = pages2ppods(j);
+	tag = cxgb_fcoe_alloc_ppods(adap, nppods);
+	if (tag < 0) {
+		dev_err(adap->pdev_dev, "Failed to allocate %d ppods"
+					" xid:0x%x\n", nppods, xid);
+		goto out_noddp;
+	}
+
+	/* Should be offset by TOE's ppods */
+	tag += adap->vres.toe_nppods;
+
+	ddp->sgl = sgl;
+	ddp->sgc = sgc;
+	ddp->xfer_len = totlen;
+	ddp->first_pg_off = firstoff;
+	ddp->nppods = nppods;
+	ddp->npages = j;
+	ddp->ppod_tag = tag;
+
+	return 1;
+
+out_noddp:
+	pci_unmap_sg(adap->pdev, sgl, sgc, DMA_FROM_DEVICE);
+	return 0;
+}
+
+/**
+ * cxgb_fcoe_ddp_done - complete DDP
+ * @netdev: net device
+ * @xid: exchange id
+ *
+ * Returns length of data directly placed in bytes.
+ */
+int cxgb_fcoe_ddp_done(struct net_device *netdev, u16 xid)
+{
+	struct port_info *pi;
+	struct adapter *adap;
+	struct cxgb_fcoe *fcoe;
+	struct cxgb_fcoe_ddp *ddp;
+	int len = 0;
+
+	if (!netdev)
+		return 0;
+
+	pi = netdev_priv(netdev);
+	adap = pi->adapter;
+
+	if (xid >= CXGB_FCOE_MAX_XCHGS_PORT) {
+		dev_warn(adap->pdev_dev, "ddp_done: xid%x out-of-range\n", xid);
+		return 0;
+	}
+
+	fcoe = &pi->fcoe;
+	ddp = &fcoe->ddp[xid];
+	if (!ddp->sgl) {
+		dev_err(adap->pdev_dev, "ddp_done: xid %x with null sgl\n",
+			xid);
+		return 0;
+	}
+
+	if (!(ddp->flags & CXGB_FCOE_DDP_ERROR))
+		len = ddp->ddp_len;
+
+	cxgb_fcoe_free_ppods(adap, ddp->ppod_tag - adap->vres.toe_nppods,
+			     ddp->nppods);
+
+	if (ddp->sgl)
+		pci_unmap_sg(adap->pdev, ddp->sgl, ddp->sgc, DMA_FROM_DEVICE);
+
+	cxgb_fcoe_clear_ddp(ddp);
+
+	return len;
+}
+
 /**
  * cxgb_fcoe_enable - enable FCoE offload features
  * @netdev: net device
@@ -70,6 +594,10 @@ int cxgb_fcoe_enable(struct net_device *netdev)
 	struct port_info *pi = netdev_priv(netdev);
 	struct adapter *adap = pi->adapter;
 	struct cxgb_fcoe *fcoe = &pi->fcoe;
+	struct tp_params *tp = &adap->params.tp;
+	struct cxgb_fcoe_ddp *ddp;
+	struct completion cmpl;
+	u16 xid;
 
 	if (is_t4(adap->params.chip))
 		return -EINVAL;
@@ -77,12 +605,48 @@ int cxgb_fcoe_enable(struct net_device *netdev)
 	if (!(adap->flags & FULL_INIT_DONE))
 		return -EINVAL;
 
+	if (adap->tids.natids > 8192)
+		return -EINVAL;
+
+	if ((tp->port_shift < 0) || (tp->fcoe_shift < 0))
+		return -EINVAL;
+
+	if (!adap->vres.ppod_map || !adap->vres.tid2xid) {
+		dev_warn(adap->pdev_dev, "FCoE Offload resources "
+			 " unavailable\n");
+		return -EINVAL;
+	}
+
 	dev_info(adap->pdev_dev, "Enabling FCoE offload features\n");
 
+	init_completion(&cmpl);
+	fcoe->cmpl = &cmpl;
+	memset(fcoe->ddp, 0, sizeof(*ddp) * CXGB_FCOE_MAX_XCHGS_PORT);
+
+	for (xid = 0; xid < CXGB_FCOE_MAX_XCHGS_PORT; xid++) {
+		ddp = &fcoe->ddp[xid];
+		ddp->xid = xid;
+		ddp->ppod_gl = kcalloc(CXGB_FCOE_MAX_PAGE_CNT,
+					sizeof(dma_addr_t), GFP_KERNEL);
+		if (!ddp->ppod_gl) {
+			cxgb_fcoe_free_ddp(pi, xid);
+			return -EINVAL;
+		}
+
+		if (cxgb_fcoe_alloc_tid(pi, xid)) {
+			dev_warn(adap->pdev_dev, "Unable to allocate "
+				 "tid xid 0x%x\n", xid);
+			kfree(ddp->ppod_gl);
+			cxgb_fcoe_free_ddp(pi, xid);
+			return -EINVAL;
+		}
+	}
+
 	netdev->features |= NETIF_F_FCOE_CRC;
 	netdev->vlan_features |= NETIF_F_FCOE_CRC;
 	netdev->features |= NETIF_F_FCOE_MTU;
 	netdev->vlan_features |= NETIF_F_FCOE_MTU;
+	netdev->fcoe_ddp_xid = CXGB_FCOE_MAX_XCHGS_PORT - 1;
 
 	netdev_features_change(netdev);
 
@@ -114,9 +678,45 @@ int cxgb_fcoe_disable(struct net_device *netdev)
 	netdev->vlan_features &= ~NETIF_F_FCOE_CRC;
 	netdev->features &= ~NETIF_F_FCOE_MTU;
 	netdev->vlan_features &= ~NETIF_F_FCOE_MTU;
+	netdev->fcoe_ddp_xid = 0;
 
 	netdev_features_change(netdev);
 
+	cxgb_fcoe_free_ddp(pi, CXGB_FCOE_MAX_XCHGS_PORT);
+
 	return 0;
 }
+
+void cxgb_fcoe_init_ddp(struct adapter *adap)
+{
+	u32 tot_ppods = adap->vres.ddp.size / CXGB_FCOE_PPOD_SIZE;
+	u32 fcoe_ddp_size, fcoe_ddp_start;
+
+	adap->vres.fcoe_nppods = tot_ppods / 2;
+	adap->vres.toe_nppods = tot_ppods - adap->vres.fcoe_nppods;
+
+	adap->vres.ddp.size = adap->vres.toe_nppods * CXGB_FCOE_PPOD_SIZE;
+	fcoe_ddp_size = adap->vres.fcoe_nppods * CXGB_FCOE_PPOD_SIZE;
+	fcoe_ddp_start = adap->vres.ddp.start + adap->vres.ddp.size;
+
+	dev_info(adap->pdev_dev, "TOE ddp start:0x%x size:%d"
+		 " nppods:%d\n", adap->vres.ddp.start,
+		 adap->vres.ddp.size, adap->vres.toe_nppods);
+	dev_info(adap->pdev_dev, "FCoE ddp start:0x%x size:%d"
+		 " nppods:%d tids:%d\n",
+		 fcoe_ddp_start, fcoe_ddp_size,
+		 adap->vres.fcoe_nppods, adap->tids.ntids);
+
+	spin_lock_init(&adap->vres.ppod_map_lock);
+
+	adap->vres.ppod_map = kzalloc(adap->vres.fcoe_nppods, GFP_KERNEL);
+	adap->vres.tid2xid = kcalloc(adap->tids.ntids, sizeof(u16),
+				GFP_KERNEL);
+}
+
+void cxgb_fcoe_exit_ddp(struct adapter *adap)
+{
+	kfree(adap->vres.ppod_map);
+	kfree(adap->vres.tid2xid);
+}
 #endif /* CONFIG_CHELSIO_T4_FCOE */
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
index 24e10ea..95e7527 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
@@ -544,6 +544,23 @@ static void clear_filter(struct adapter *adap, struct filter_entry *f)
 	memset(f, 0, sizeof(*f));
 }
 
+#ifdef CONFIG_CHELSIO_T4_FCOE
+static void hash_filter_rpl(struct adapter *adap,
+			    const struct cpl_act_open_rpl *rpl)
+{
+	unsigned int tid = GET_TID(rpl);
+	unsigned int ftid = TID_TID_G(AOPEN_ATID_G(ntohl(rpl->atid_status)));
+	unsigned int status  = AOPEN_STATUS_G(ntohl(rpl->atid_status));
+
+	/* ATID is 14 bit value [0..13], MAX_ATIDS is 8192
+	 * ATID needs max 13 bits [0..12], using 13th bit in
+	 * ATID for FCoE CPL_ACT_OPEN_REQ.
+	 */
+	if (ftid & BIT(CXGB_FCOE_ATID))
+		cxgb_fcoe_cpl_act_open_rpl(adap, ftid, tid, status);
+}
+#endif /* CONFIG_CHELSIO_T4_FCOE */
+
 /* Handle a filter write/deletion reply.
  */
 static void filter_rpl(struct adapter *adap, const struct cpl_set_tcb_rpl *rpl)
@@ -661,7 +678,15 @@ static int fwevtq_handler(struct sge_rspq *q, const __be64 *rsp,
 		const struct cpl_set_tcb_rpl *p = (void *)rsp;
 
 		filter_rpl(q->adap, p);
-	} else
+	}
+#ifdef CONFIG_CHELSIO_T4_FCOE
+	else if (opcode == CPL_ACT_OPEN_RPL) {
+		const struct cpl_act_open_rpl *p = (void *)rsp;
+
+		hash_filter_rpl(q->adap, p);
+	}
+#endif /* CONFIG_CHELSIO_T4_FCOE */
+	else
 		dev_err(q->adap->pdev_dev,
 			"unexpected CPL %#x on FW event queue\n", opcode);
 out:
@@ -3010,6 +3035,8 @@ static const struct net_device_ops cxgb4_netdev_ops = {
 #ifdef CONFIG_CHELSIO_T4_FCOE
 	.ndo_fcoe_enable      = cxgb_fcoe_enable,
 	.ndo_fcoe_disable     = cxgb_fcoe_disable,
+	.ndo_fcoe_ddp_target  = cxgb_fcoe_ddp_setup,
+	.ndo_fcoe_ddp_done    = cxgb_fcoe_ddp_done,
 #endif /* CONFIG_CHELSIO_T4_FCOE */
 #ifdef CONFIG_NET_RX_BUSY_POLL
 	.ndo_busy_poll        = cxgb_busy_poll,
@@ -3845,6 +3872,10 @@ static int adap_init0(struct adapter *adap)
 		adap->vres.ddp.start = val[3];
 		adap->vres.ddp.size = val[4] - val[3] + 1;
 		adap->params.ofldq_wr_cred = val[5];
+#ifdef CONFIG_CHELSIO_T4_FCOE
+		if (ntohs(caps_cmd.fcoecaps) & FW_CAPS_CONFIG_POFCOE_TARGET)
+			cxgb_fcoe_init_ddp(adap);
+#endif /* CONFIG_CHELSIO_T4_FCOE */
 
 		adap->params.offload = 1;
 	}
@@ -3965,6 +3996,9 @@ bye:
 	kfree(adap->sge.txq_maperr);
 	if (ret != -ETIMEDOUT && ret != -EIO)
 		t4_fw_bye(adap, adap->mbox);
+#ifdef CONFIG_CHELSIO_T4_FCOE
+	cxgb_fcoe_exit_ddp(adap);
+#endif /* CONFIG_CHELSIO_T4_FCOE */
 	return ret;
 }
 
@@ -4757,6 +4791,9 @@ static void remove_one(struct pci_dev *pdev)
 		iounmap(adapter->regs);
 		if (!is_t4(adapter->params.chip))
 			iounmap(adapter->bar2);
+#ifdef CONFIG_CHELSIO_T4_FCOE
+		cxgb_fcoe_exit_ddp(adapter);
+#endif /* CONFIG_CHELSIO_T4_FCOE */
 		pci_disable_pcie_error_reporting(pdev);
 		if ((adapter->flags & DEV_ENABLED)) {
 			pci_disable_device(pdev);
diff --git a/drivers/net/ethernet/chelsio/cxgb4/sge.c b/drivers/net/ethernet/chelsio/cxgb4/sge.c
index e622214..05e8c93 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/sge.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/sge.c
@@ -48,6 +48,8 @@
 #endif /* CONFIG_NET_RX_BUSY_POLL */
 #ifdef CONFIG_CHELSIO_T4_FCOE
 #include <scsi/fc/fc_fcoe.h>
+#include <scsi/libfcoe.h>
+#include "t4_tcb.h"
 #endif /* CONFIG_CHELSIO_T4_FCOE */
 #include "cxgb4.h"
 #include "t4_regs.h"
@@ -1048,11 +1050,260 @@ static inline void txq_advance(struct sge_txq *q, unsigned int n)
 }
 
 #ifdef CONFIG_CHELSIO_T4_FCOE
+
+#define CXGB_FCOE_NUM_IMM_PPODS		4
+
+#define CXGB_FCOE_NUM_IMM_PPOD_BYTES	\
+	(CXGB_FCOE_NUM_IMM_PPODS * CXGB_FCOE_PPOD_SIZE)
+
+#define WR_LEN_MAX_PPODS	\
+	(sizeof(struct ulp_mem_io) + \
+	sizeof(struct ulptx_idata) + \
+	CXGB_FCOE_NUM_IMM_PPOD_BYTES)
+
+#define WR_CRED_MAX_PPODS	(DIV_ROUND_UP(WR_LEN_MAX_PPODS, IDXSIZE_UNIT_X))
+
+#define WR_LEN_SET_TCBS \
+	(sizeof(struct fw_pofcoe_ulptx_wr) + \
+	 (5 * ALIGN(sizeof(struct cpl_set_tcb_field), 16)))
+
+#define WR_LEN16_SET_TCBS DIV_ROUND_UP(WR_LEN_SET_TCBS, 16)
+
+#define WR_NDESC_SET_TCBS DIV_ROUND_UP(WR_LEN_SET_TCBS, IDXSIZE_UNIT_X)
+
+static inline int calc_ddp_credits(struct sk_buff *skb, unsigned int nppods)
+{
+	unsigned int n_full = (nppods / CXGB_FCOE_NUM_IMM_PPODS);
+	int credits = n_full * WR_CRED_MAX_PPODS;
+	unsigned int last_ppod_len = (nppods % CXGB_FCOE_NUM_IMM_PPODS) *
+					CXGB_FCOE_PPOD_SIZE;
+	unsigned int last_len;
+	unsigned int flits;
+
+	if (last_ppod_len) {
+		last_len = sizeof(struct ulp_mem_io) +
+				sizeof(struct ulptx_idata) + last_ppod_len;
+		credits += DIV_ROUND_UP(last_len, IDXSIZE_UNIT_X);
+	}
+
+	credits += WR_NDESC_SET_TCBS;
+
+	flits = calc_tx_flits(skb);
+	credits += flits_to_desc(flits);
+
+	return credits;
+}
+
+static inline void
+cxgb_fcoe_set_tcb_field(struct cpl_set_tcb_field *req, unsigned int tid,
+			unsigned int word, u64 mask, u64 val)
+{
+	struct ulp_txpkt *txpkt = (struct ulp_txpkt *)req;
+	struct ulptx_idata *sc = (struct ulptx_idata *)(txpkt + 1);
+
+	txpkt->cmd_dest = htonl(ULPTX_CMD_V(ULP_TX_PKT) | ULP_TXPKT_DEST_V(0));
+	txpkt->len = htonl((tid << 8) | DIV_ROUND_UP(sizeof(*req), 16));
+	sc->cmd_more = htonl(ULPTX_CMD_V(ULP_TX_SC_IMM));
+	sc->len = htonl(sizeof(*req) - sizeof(struct work_request_hdr));
+	OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, tid));
+	req->reply_ctrl = htons(NO_REPLY_V(1) | REPLY_CHAN_V(0) |
+				QUEUENO_V(0));
+	req->word_cookie = htons(TCB_WORD(word) | TCB_COOKIE_V(0));
+	req->mask = cpu_to_be64(mask);
+	req->val = cpu_to_be64(val);
+	sc = (struct ulptx_idata *)(req + 1);
+	sc->cmd_more = htonl(ULPTX_CMD_V(ULP_TX_SC_NOOP));
+	sc->len = htonl(0);
+}
+
+static inline void
+cxgb_fcoe_set_tcbs(struct adapter *adap, const struct port_info *pi,
+		   struct sge_eth_txq *q,
+		   struct cxgb_fcoe_ddp *ddp, u16 iqid)
+{
+	struct cpl_set_tcb_field *req;
+	struct fw_pofcoe_ulptx_wr *wr;
+	u8 buf[WR_LEN_SET_TCBS] = {0};
+	u8 *end, *wrp = (u8 *)&q->q.desc[q->q.pidx];
+	unsigned int len = ALIGN(sizeof(struct cpl_set_tcb_field), 16);
+
+	end = wrp + WR_LEN_SET_TCBS;
+	wr = (struct fw_pofcoe_ulptx_wr *)
+		((u8 *)end > (u8 *)q->q.stat ? buf : wrp);
+
+	wr->op_pkd = htonl(FW_WR_OP_V(FW_POFCOE_ULPTX_WR));
+	wr->equiq_to_len16 = htonl(FW_WR_LEN16_V(WR_LEN16_SET_TCBS));
+
+	req = (struct cpl_set_tcb_field *)(wr + 1);
+	cxgb_fcoe_set_tcb_field(req, ddp->tid, TCB_RX_DDP_BUF0_TAG_W,
+				TCB_RX_DDP_BUF0_TAG_V(TCB_RX_DDP_BUF0_TAG_M),
+				TCB_RX_DDP_BUF0_TAG_V(
+					PPOD_TAG_V(ddp->ppod_tag)));
+
+	req = (struct cpl_set_tcb_field *)((u8 *)req + len);
+	cxgb_fcoe_set_tcb_field(req, ddp->tid, TCB_RX_DDP_BUF0_OFFSET_W,
+				TCB_RX_DDP_BUF0_OFFSET_V(
+					TCB_RX_DDP_BUF0_OFFSET_M) |
+				TCB_RX_DDP_BUF0_LEN_V(TCB_RX_DDP_BUF0_LEN_M),
+				TCB_RX_DDP_BUF0_OFFSET_V(0) |
+				TCB_RX_DDP_BUF0_LEN_V(ddp->xfer_len));
+
+	req = (struct cpl_set_tcb_field *)((u8 *)req + len);
+	cxgb_fcoe_set_tcb_field(req, ddp->tid, TCB_T_STATE_W,
+				TCB_T_STATE_V(TCB_T_STATE_M) |
+				TCB_RSS_INFO_V(TCB_RSS_INFO_M),
+				TCB_T_STATE_V(0x4) |
+				TCB_RSS_INFO_V(iqid));
+
+	req = (struct cpl_set_tcb_field *)((u8 *)req + len);
+	cxgb_fcoe_set_tcb_field(req, ddp->tid, TCB_T_FLAGS_W,
+				TF_NON_OFFLOAD_V(1), 0);
+
+	req = (struct cpl_set_tcb_field *)((u8 *)req + len);
+	cxgb_fcoe_set_tcb_field(req, ddp->tid, TCB_RX_DDP_FLAGS_W,
+				TF_DDP_BUF_INF_V(1) |
+				TF_DDP_INDICATE_OUT_V(1) |
+				TF_DDP_BUF0_INDICATE_V(1) |
+				TF_DDP_BUF0_VALID_V(1) |
+				TF_DDP_OFF_V(1),
+				TF_DDP_BUF_INF_V(1) |
+				TF_DDP_INDICATE_OUT_V(1) |
+				TF_DDP_BUF0_INDICATE_V(1) |
+				TF_DDP_BUF0_VALID_V(1) |
+				TF_DDP_OFF_V(0));
+
+	if (unlikely((u8 *)end > (u8 *)q->q.stat)) {
+		unsigned int part0 = (u8 *)q->q.stat - (u8 *)wrp, part1;
+
+		if (likely(part0))
+			memcpy(wrp, buf, part0);
+		part1 = (u8 *)end - (u8 *)q->q.stat;
+		memcpy(q->q.desc, (u8 *)buf + part0, part1);
+		end = (void *)q->q.desc + part1;
+	}
+
+	if ((uintptr_t)end & 8)		/* 0-pad to multiple of 16 */
+		*(u64 *)end = 0;
+
+	/* Post this WR */
+	txq_advance(&q->q, WR_NDESC_SET_TCBS);
+	ring_tx_db(adap, &q->q, WR_NDESC_SET_TCBS);
+}
+
+static inline void
+cxgb_setup_ppods(struct adapter *adap, const struct port_info *pi,
+		 struct sge_eth_txq *q, struct cxgb_fcoe_ddp *ddp)
+{
+	unsigned int i, j, pidx;
+	struct pagepod *p;
+	u8 *wrp = (u8 *)&q->q.desc[q->q.pidx];
+	struct fw_pofcoe_ulptx_wr *mwr;
+	struct ulp_mem_io *wr;
+	struct ulptx_idata *sc;
+	unsigned int tid = ddp->tid;
+	unsigned int color = 0;
+	unsigned int nppods = ddp->nppods;
+	unsigned int tag = ddp->ppod_tag;
+	unsigned int maxoff = ddp->xfer_len;
+	unsigned int pg_off = ddp->first_pg_off;
+	unsigned int ppod_addr = tag * CXGB_FCOE_PPOD_SIZE +
+					adap->vres.ddp.start;
+	unsigned int len, podchunk, ndesc;
+	u8 buf[WR_LEN_MAX_PPODS];
+	u8 *end, *to;
+	__be32 cmd = htonl(ULPTX_CMD_V(ULP_TX_MEM_WRITE));
+
+	if (is_t4(adap->params.chip))
+		cmd |= htonl(ULP_MEMIO_ORDER_V(1));
+	else
+		cmd |= htonl(T5_ULP_MEMIO_IMM_V(1));
+
+	for (i = 0; i < nppods; ppod_addr += podchunk) {
+		unsigned int ppodout = 0;
+
+		podchunk = ((nppods - i) >= CXGB_FCOE_NUM_IMM_PPODS) ?
+				CXGB_FCOE_NUM_IMM_PPODS : (nppods - i);
+		podchunk *= CXGB_FCOE_PPOD_SIZE;
+
+		len = roundup(sizeof(*wr) + sizeof(*sc) + podchunk, 16);
+		end = wrp + len;
+		to = (u8 *)end > (u8 *)q->q.stat ? buf : wrp;
+
+		mwr = (struct fw_pofcoe_ulptx_wr *)to;
+		mwr->op_pkd = htonl(FW_WR_OP_V(FW_POFCOE_ULPTX_WR));
+		mwr->equiq_to_len16 = htonl(FW_WR_LEN16_V(
+						DIV_ROUND_UP(len, 16)));
+		wr = (struct ulp_mem_io *)to;
+		wr->cmd = cmd;
+		wr->dlen = htonl(ULP_MEMIO_DATA_LEN_V(podchunk / 32));
+		wr->len16 = htonl((ddp->tid << 8) |
+					DIV_ROUND_UP(len - sizeof(wr->wr), 16));
+		wr->lock_addr = htonl(ULP_MEMIO_ADDR_V(ppod_addr >> 5));
+		sc = (struct ulptx_idata *)(wr + 1);
+		sc->cmd_more = htonl(ULPTX_CMD_V(ULP_TX_SC_IMM));
+		sc->len = htonl(podchunk);
+		p = (struct pagepod *)(sc + 1);
+
+		do {
+			pidx = 4 * i;
+			if (likely(i < nppods - CXGB_FCOE_NUM_SENTINEL_PPODS)) {
+				p->vld_tid_pgsz_tag_color =
+					cpu_to_be64(PPOD_VALID_F |
+							PPOD_TID_V(tid) |
+							PPOD_TAG_V(tag) |
+							PPOD_COLOR_V(color));
+				p->len_offset = cpu_to_be64(PPOD_LEN_V(maxoff) |
+							PPOD_OFST_V(pg_off));
+				p->rsvd = 0;
+				for (j = 0; j < 5; ++j, ++pidx)
+					p->addr[j] = pidx < ddp->npages ?
+					    cpu_to_be64(ddp->ppod_gl[pidx]) : 0;
+			} else {
+				/* mark sentinel page pods invalid */
+				p->vld_tid_pgsz_tag_color = 0;
+			}
+			p++;
+			ppodout += CXGB_FCOE_PPOD_SIZE;
+			i++;
+
+		} while (ppodout < podchunk);
+
+		if (unlikely((u8 *)end > (u8 *)q->q.stat)) {
+			unsigned int part0 = (u8 *)q->q.stat - (u8 *)wrp, part1;
+
+			if (likely(part0))
+				memcpy(wrp, buf, part0);
+			part1 = (u8 *)end - (u8 *)q->q.stat;
+			memcpy(q->q.desc, (u8 *)buf + part0, part1);
+			end = (void *)q->q.desc + part1;
+		}
+
+		if ((uintptr_t)end & 8)		/* 0-pad to multiple of 16 */
+			*(u64 *)end = 0;
+
+		/* Post this WR */
+		ndesc = DIV_ROUND_UP(len, IDXSIZE_UNIT_X);
+		txq_advance(&q->q, ndesc);
+		ring_tx_db(adap, &q->q, ndesc);
+
+		wrp = (u8 *)&q->q.desc[q->q.pidx];
+	} /* for all pagepod chunks */
+}
+
 static inline int
-cxgb_fcoe_offload(struct sk_buff *skb, struct adapter *adap,
-		  const struct port_info *pi, u64 *cntrl)
+cxgb_fcoe_offload(struct sk_buff *skb, struct net_device *dev,
+		  struct adapter *adap, const struct port_info *pi,
+		  struct sge_eth_txq *q, u64 *cntrl)
 {
 	const struct cxgb_fcoe *fcoe = &pi->fcoe;
+	struct cxgb_fcoe_ddp *ddp;
+	struct ethhdr *eh;
+	struct fc_frame_header *fh;
+	struct sge_eth_rxq *rxq;
+	unsigned int ndesc;
+	int qidx, credits;
+	u16 xid, vlan_tci = 0;
+	u32 fctl;
 
 	if (!(fcoe->flags & CXGB_FCOE_ENABLED))
 		return 0;
@@ -1075,6 +1326,64 @@ cxgb_fcoe_offload(struct sk_buff *skb, struct adapter *adap,
 		     TXPKT_CSUM_START(CXGB_FCOE_TXPKT_CSUM_START) |
 		     TXPKT_CSUM_END(CXGB_FCOE_TXPKT_CSUM_END) |
 		     TXPKT_CSUM_LOC(CXGB_FCOE_TXPKT_CSUM_END);
+
+	if (skb_vlan_tag_present(skb)) {
+		vlan_tci = skb_vlan_tag_get(skb);
+		vlan_tci |= ((skb->priority & 0x7) << VLAN_PRIO_SHIFT);
+	}
+
+	fh = (struct fc_frame_header *)(skb_transport_header(skb));
+
+	/* Program DDP for XFER_RDY frames only */
+	if (fh->fh_r_ctl != FC_RCTL_DD_DATA_DESC)
+		return 0;
+
+	fctl = ntoh24(fh->fh_f_ctl);
+	if (!(fctl & FC_FC_EX_CTX))
+		return 0;
+
+	xid = be16_to_cpu(fh->fh_rx_id);
+
+	if (xid >= CXGB_FCOE_MAX_XCHGS_PORT)
+		return 0;
+
+	ddp = (struct cxgb_fcoe_ddp *)&fcoe->ddp[xid];
+
+	/* Upper layer may not have requested for ddp_setup */
+	if (!ddp->sgl)
+		return 0;
+
+	eh = (struct ethhdr *)skb_mac_header(skb);
+	/* Save d_id, smac, dmac, vlan */
+	ether_addr_copy(ddp->h_source, eh->h_source);
+	ether_addr_copy(ddp->h_dest, eh->h_dest);
+	memcpy(ddp->d_id, fh->fh_d_id, 3);
+	ddp->vlan_tci = vlan_tci;
+
+	/* program ppods on the card. They should already have been
+	 * allocated in cxgb_fcoe_ddp_setup
+	 */
+
+	/* Calculate number credits required for ddp */
+	ndesc = calc_ddp_credits(skb, ddp->nppods);
+
+	credits = txq_avail(&q->q) - ndesc;
+
+	if (unlikely(credits < 0))
+		return -EBUSY;
+
+	/* Get an associated iqid */
+	qidx = skb_get_queue_mapping(skb);
+	rxq = &adap->sge.ethrxq[qidx + pi->first_qset];
+
+	cxgb_fcoe_set_tcbs(adap, pi, q, ddp, rxq->rspq.abs_id);
+
+	cxgb_setup_ppods(adap, pi, q, ddp);
+
+	dev->trans_start = jiffies;
+
+	reclaim_completed_tx(adap, &q->q, true);
+
 	return 0;
 }
 #endif /* CONFIG_CHELSIO_T4_FCOE */
@@ -1123,9 +1432,16 @@ out_free:	dev_kfree_skb_any(skb);
 	cntrl = TXPKT_L4CSUM_DIS | TXPKT_IPCSUM_DIS;
 
 #ifdef CONFIG_CHELSIO_T4_FCOE
-	err = cxgb_fcoe_offload(skb, adap, pi, &cntrl);
-	if (unlikely(err == -ENOTSUPP))
-		goto out_free;
+	err = cxgb_fcoe_offload(skb, dev, adap, pi, q, &cntrl);
+	if (unlikely(err == -EBUSY)) {
+		eth_txq_stop(q);
+		dev_err(adap->pdev_dev,
+			"%s: (fcoe) Tx ring %u full while queue awake!\n",
+			dev->name, qidx);
+		return NETDEV_TX_BUSY;
+	} else if (unlikely(err == -ENOTSUPP)) {
+			goto out_free;
+	}
 #endif /* CONFIG_CHELSIO_T4_FCOE */
 
 	flits = calc_tx_flits(skb);
@@ -1810,6 +2126,8 @@ int t4_ethrx_handler(struct sge_rspq *q, const __be64 *rsp,
 			    CPL_TRACE_PKT : CPL_TRACE_PKT_T5;
 #ifdef CONFIG_CHELSIO_T4_FCOE
 	struct port_info *pi;
+	if (cxgb_fcoe_rx_handler(q, rsp))
+		return 0;
 #endif
 
 	if (unlikely(*(u8 *)rsp == cpl_trace_pkt))
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
index 5959e3a..bcb0567 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
@@ -5303,6 +5303,7 @@ int t4_init_tp_params(struct adapter *adap)
 	 * shift positions of several elements of the Compressed Filter Tuple
 	 * for this adapter which we need frequently ...
 	 */
+	adap->params.tp.fcoe_shift = t4_filter_field_shift(adap, FCOE_F);
 	adap->params.tp.vlan_shift = t4_filter_field_shift(adap, VLAN_F);
 	adap->params.tp.vnic_shift = t4_filter_field_shift(adap, VNIC_ID_F);
 	adap->params.tp.port_shift = t4_filter_field_shift(adap, PORT_F);
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH net-next v2 4/4] cxgb4: enable RSS for FCoE frames
  2015-04-13 14:04 [PATCH net-next v2 0/4] cxgb4: add FCoE DDP and RSS Varun Prakash
                   ` (2 preceding siblings ...)
  2015-04-13 14:04 ` [PATCH net-next v2 3/4] cxgb4: add DDP support for FCoE target Varun Prakash
@ 2015-04-13 14:04 ` Varun Prakash
  3 siblings, 0 replies; 10+ messages in thread
From: Varun Prakash @ 2015-04-13 14:04 UTC (permalink / raw)
  To: netdev, linux-scsi, linux-rdma
  Cc: davem, JBottomley, roland, leedom, anish, hariprasad, swise, kxie,
	praveenm, kumaras, varun

Signed-off-by: Varun Prakash <varun@chelsio.com>
---
 drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c |    8 ++++++++
 drivers/net/ethernet/chelsio/cxgb4/t4_regs.h    |    8 ++++++++
 2 files changed, 16 insertions(+), 0 deletions(-)

diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
index 95e7527..606aa5a 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
@@ -910,6 +910,9 @@ int cxgb4_write_rss(const struct port_info *pi, const u16 *queues)
 static int setup_rss(struct adapter *adap)
 {
 	int i, err;
+#ifdef CONFIG_CHELSIO_T4_FCOE
+	u32 rss_config;
+#endif
 
 	for_each_port(adap, i) {
 		const struct port_info *pi = adap2pinfo(adap, i);
@@ -918,6 +921,11 @@ static int setup_rss(struct adapter *adap)
 		if (err)
 			return err;
 	}
+#ifdef CONFIG_CHELSIO_T4_FCOE
+	rss_config = t4_read_reg(adap, TP_RSS_CONFIG_A);
+	rss_config |= TNLFCOEEN_F | TNLFCOEMODE_F;
+	t4_write_reg(adap, TP_RSS_CONFIG_A, rss_config);
+#endif
 	return 0;
 }
 
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
index 326674b..3e10c99 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
@@ -1856,6 +1856,14 @@
 #define DISABLE_V(x) ((x) << DISABLE_S)
 #define DISABLE_F    DISABLE_V(1U)
 
+#define TNLFCOEMODE_S    23
+#define TNLFCOEMODE_V(x) ((x) << TNLFCOEMODE_S)
+#define TNLFCOEMODE_F    TNLFCOEMODE_V(1U)
+
+#define TNLFCOEEN_S    21
+#define TNLFCOEEN_V(x) ((x) << TNLFCOEEN_S)
+#define TNLFCOEEN_F    TNLFCOEEN_V(1U)
+
 #define TP_RSS_CONFIG_TNL_A 0x7df4
 
 #define MASKSIZE_S    28
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH net-next v2 1/4] cxgb4/iw_cxgb4/cxgb4i: remove duplicate definitions
  2015-04-13 14:04 ` [PATCH net-next v2 1/4] cxgb4/iw_cxgb4/cxgb4i: remove duplicate definitions Varun Prakash
@ 2015-04-13 16:38   ` Jason Gunthorpe
       [not found]     ` <20150413163808.GA17521-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/@public.gmane.org>
       [not found]   ` <6358f849b5a1a3727879f4f2f5c855e3a5b95ab4.1428930614.git.varun-ut6Up61K2wZBDgjK7y7TUQ@public.gmane.org>
  1 sibling, 1 reply; 10+ messages in thread
From: Jason Gunthorpe @ 2015-04-13 16:38 UTC (permalink / raw)
  To: Varun Prakash
  Cc: netdev, linux-scsi, linux-rdma, davem, JBottomley, roland, leedom,
	anish, hariprasad, swise, kxie, praveenm, kumaras

On Mon, Apr 13, 2015 at 07:34:23PM +0530, Varun Prakash wrote:
> define struct ulptx_idata in common header file t4_msg.h
> to remove duplicate definitions.

The Infiniband side of this patch looks OK.

Reviewed-By: Jason Gunthorpe <jgunthorpe@obsidianresearch.com>

Just some random thoughts on the other patches:
 - Try and use 'if (IS_ENABLED(CONFIG_XX))' over #ifdef 
   to improve compile test coverage. This would drop a fair number
   of ifdefs.
 - Some of the commit message are short, or non existant (ie #4)
 - Generally, no need for 'static inline' in a .c file, the compiler knows
   what to do.

Regards,
Jason

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH net-next v2 3/4] cxgb4: add DDP support for FCoE target
  2015-04-13 14:04 ` [PATCH net-next v2 3/4] cxgb4: add DDP support for FCoE target Varun Prakash
@ 2015-04-13 17:12   ` David Miller
  0 siblings, 0 replies; 10+ messages in thread
From: David Miller @ 2015-04-13 17:12 UTC (permalink / raw)
  To: varun
  Cc: netdev, linux-scsi, linux-rdma, JBottomley, roland, leedom, anish,
	hariprasad, swise, kxie, praveenm, kumaras

From: Varun Prakash <varun@chelsio.com>
Date: Mon, 13 Apr 2015 19:34:25 +0530

> diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_fcoe.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_fcoe.c
> index 6c8a62e..f78d632 100644
> --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_fcoe.c
> +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_fcoe.c
...
> + */
> +static inline unsigned int pages2ppods(unsigned int pages)
> +{
> +	return (pages + PPOD_PAGES - 1) / PPOD_PAGES +

Please do not ever use inline in foo.c file function definitions.  Let
the compiler decide on it's own.

Thanks.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH net-next v2 1/4] cxgb4/iw_cxgb4/cxgb4i: remove duplicate definitions
       [not found]   ` <6358f849b5a1a3727879f4f2f5c855e3a5b95ab4.1428930614.git.varun-ut6Up61K2wZBDgjK7y7TUQ@public.gmane.org>
@ 2015-04-13 18:13     ` Steve Wise
  0 siblings, 0 replies; 10+ messages in thread
From: Steve Wise @ 2015-04-13 18:13 UTC (permalink / raw)
  To: Varun Prakash, netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-scsi-u79uwXL29TY76Z2rM5mHXA,
	linux-rdma-u79uwXL29TY76Z2rM5mHXA
  Cc: davem-fT/PcQaiUtIeIZ0/mPfg9Q, JBottomley-bzQdu9zFT3WakBO8gow8eQ,
	roland-BHEL68pLQRGGvPXPguhicg, leedom-ut6Up61K2wZBDgjK7y7TUQ,
	anish-ut6Up61K2wZBDgjK7y7TUQ, hariprasad-ut6Up61K2wZBDgjK7y7TUQ,
	kxie-ut6Up61K2wZBDgjK7y7TUQ, praveenm-ut6Up61K2wZBDgjK7y7TUQ,
	kumaras-ut6Up61K2wZBDgjK7y7TUQ

Acked-by: Steve Wise <swise-7bPotxP6k4+P2YhJcF5u+vpXobYPEAuW@public.gmane.org>
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH net-next v2 1/4] cxgb4/iw_cxgb4/cxgb4i: remove duplicate definitions
       [not found]     ` <20150413163808.GA17521-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/@public.gmane.org>
@ 2015-04-15 13:04       ` Varun Prakash
  2015-04-15 16:12         ` Jason Gunthorpe
  0 siblings, 1 reply; 10+ messages in thread
From: Varun Prakash @ 2015-04-15 13:04 UTC (permalink / raw)
  To: Jason Gunthorpe
  Cc: netdev-u79uwXL29TY76Z2rM5mHXA, linux-scsi-u79uwXL29TY76Z2rM5mHXA,
	linux-rdma-u79uwXL29TY76Z2rM5mHXA, davem-fT/PcQaiUtIeIZ0/mPfg9Q,
	JBottomley-bzQdu9zFT3WakBO8gow8eQ, roland-BHEL68pLQRGGvPXPguhicg,
	leedom-ut6Up61K2wZBDgjK7y7TUQ, anish-ut6Up61K2wZBDgjK7y7TUQ,
	hariprasad-ut6Up61K2wZBDgjK7y7TUQ,
	swise-7bPotxP6k4+P2YhJcF5u+vpXobYPEAuW,
	kxie-ut6Up61K2wZBDgjK7y7TUQ, praveenm-ut6Up61K2wZBDgjK7y7TUQ,
	kumaras-ut6Up61K2wZBDgjK7y7TUQ

On Mon, Apr 13, 2015 at 10:38:08AM -0600, Jason Gunthorpe wrote:
> On Mon, Apr 13, 2015 at 07:34:23PM +0530, Varun Prakash wrote:
> > define struct ulptx_idata in common header file t4_msg.h
> > to remove duplicate definitions.
> 
> The Infiniband side of this patch looks OK.
> 
> Reviewed-By: Jason Gunthorpe <jgunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/@public.gmane.org>
> 
> Just some random thoughts on the other patches:
>  - Try and use 'if (IS_ENABLED(CONFIG_XX))' over #ifdef 
>    to improve compile test coverage. This would drop a fair number
>    of ifdefs.

FCoE specific structures and functions are defined only if 
CONFIG_CHELSIO_T4_FCOE is enabled.

#ifdef CONFIG_CHELSIO_T4_FCOE
void cxgb_fcoe_init_ddp(struct adapter *adap)
{
	...
}
#endif

If CONFIG_CHELSIO_T4_FCOE is disabled then following code will
result in build error "implicit declaration of function cxgb_fcoe_init_ddp"

if (IS_ENABLED(CONFIG_CHELSIO_T4_FCOE))
	cxgb_fcoe_init_ddp(adap);

>  - Some of the commit message are short, or non existant (ie #4)
>  - Generally, no need for 'static inline' in a .c file, the compiler knows
>    what to do.
> 
> Regards,
> Jason
>
Thanks 
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH net-next v2 1/4] cxgb4/iw_cxgb4/cxgb4i: remove duplicate definitions
  2015-04-15 13:04       ` Varun Prakash
@ 2015-04-15 16:12         ` Jason Gunthorpe
  0 siblings, 0 replies; 10+ messages in thread
From: Jason Gunthorpe @ 2015-04-15 16:12 UTC (permalink / raw)
  To: Varun Prakash
  Cc: netdev, linux-scsi, linux-rdma, davem, JBottomley, roland, leedom,
	anish, hariprasad, swise, kxie, praveenm, kumaras

On Wed, Apr 15, 2015 at 06:34:27PM +0530, Varun Prakash wrote:
> On Mon, Apr 13, 2015 at 10:38:08AM -0600, Jason Gunthorpe wrote:
> > On Mon, Apr 13, 2015 at 07:34:23PM +0530, Varun Prakash wrote:
> > > define struct ulptx_idata in common header file t4_msg.h
> > > to remove duplicate definitions.
> > 
> > The Infiniband side of this patch looks OK.
> > 
> > Reviewed-By: Jason Gunthorpe <jgunthorpe@obsidianresearch.com>
> > 
> > Just some random thoughts on the other patches:
> >  - Try and use 'if (IS_ENABLED(CONFIG_XX))' over #ifdef 
> >    to improve compile test coverage. This would drop a fair number
> >    of ifdefs.
> 
> FCoE specific structures and functions are defined only if 
> CONFIG_CHELSIO_T4_FCOE is enabled.

I saw a number of places that could be switched, you should look
through.

> #ifdef CONFIG_CHELSIO_T4_FCOE
> void cxgb_fcoe_init_ddp(struct adapter *adap)
> {
> 	...
> }
> #endif
> 
> If CONFIG_CHELSIO_T4_FCOE is disabled then following code will
> result in build error "implicit declaration of function cxgb_fcoe_init_ddp"
>
> if (IS_ENABLED(CONFIG_CHELSIO_T4_FCOE))
> 	cxgb_fcoe_init_ddp(adap);

Commonly the ifdef would be moved to the function header and a static
inline cxgb_fcoe_init_ddp(..) {} declared for the ifndef case. For the
case of static function calls, just drop the ifdefing entirely. The
compiler will silently drop unused static functions. Think carefully
about ifdefing out structure members - I don't think saving a few bytes of
heap in a driver like cxgb4 is worthwhile.

I also just noticed that

drivers/net/ethernet/chelsio/cxgb4/cxgb4_fcoe.c

Is wrapped in a whole file #ifdef CONFIG_CHELSIO_T4_FCOE - please use
the makefile instead for this.

Jason

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2015-04-15 16:12 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-04-13 14:04 [PATCH net-next v2 0/4] cxgb4: add FCoE DDP and RSS Varun Prakash
2015-04-13 14:04 ` [PATCH net-next v2 1/4] cxgb4/iw_cxgb4/cxgb4i: remove duplicate definitions Varun Prakash
2015-04-13 16:38   ` Jason Gunthorpe
     [not found]     ` <20150413163808.GA17521-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/@public.gmane.org>
2015-04-15 13:04       ` Varun Prakash
2015-04-15 16:12         ` Jason Gunthorpe
     [not found]   ` <6358f849b5a1a3727879f4f2f5c855e3a5b95ab4.1428930614.git.varun-ut6Up61K2wZBDgjK7y7TUQ@public.gmane.org>
2015-04-13 18:13     ` Steve Wise
2015-04-13 14:04 ` [PATCH net-next v2 2/4] cxgb4: add structure and macro definitions for FCoE DDP Varun Prakash
2015-04-13 14:04 ` [PATCH net-next v2 3/4] cxgb4: add DDP support for FCoE target Varun Prakash
2015-04-13 17:12   ` David Miller
2015-04-13 14:04 ` [PATCH net-next v2 4/4] cxgb4: enable RSS for FCoE frames Varun Prakash

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).