|
@@ -278,6 +278,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_tx_packet *p_pkt = NULL;
|
|
struct qed_ll2_info *p_ll2_conn;
|
|
struct qed_ll2_info *p_ll2_conn;
|
|
struct qed_ll2_tx_queue *p_tx;
|
|
struct qed_ll2_tx_queue *p_tx;
|
|
|
|
+ dma_addr_t tx_frag;
|
|
|
|
|
|
p_ll2_conn = qed_ll2_handle_sanity_inactive(p_hwfn, connection_handle);
|
|
p_ll2_conn = qed_ll2_handle_sanity_inactive(p_hwfn, connection_handle);
|
|
if (!p_ll2_conn)
|
|
if (!p_ll2_conn)
|
|
@@ -297,11 +298,22 @@ static void qed_ll2_txq_flush(struct qed_hwfn *p_hwfn, u8 connection_handle)
|
|
p_tx->cur_completing_packet = *p_pkt;
|
|
p_tx->cur_completing_packet = *p_pkt;
|
|
p_tx->cur_completing_bd_idx = 1;
|
|
p_tx->cur_completing_bd_idx = 1;
|
|
b_last_frag = p_tx->cur_completing_bd_idx == p_pkt->bd_used;
|
|
b_last_frag = p_tx->cur_completing_bd_idx == p_pkt->bd_used;
|
|
|
|
+ tx_frag = p_pkt->bds_set[0].tx_frag;
|
|
|
|
+ if (p_ll2_conn->gsi_enable)
|
|
|
|
+ qed_ll2b_release_tx_gsi_packet(p_hwfn,
|
|
|
|
+ p_ll2_conn->my_id,
|
|
|
|
+ p_pkt->cookie,
|
|
|
|
+ tx_frag,
|
|
|
|
+ b_last_frag,
|
|
|
|
+ b_last_packet);
|
|
|
|
+ else
|
|
|
|
+ qed_ll2b_complete_tx_packet(p_hwfn,
|
|
|
|
+ p_ll2_conn->my_id,
|
|
|
|
+ p_pkt->cookie,
|
|
|
|
+ tx_frag,
|
|
|
|
+ b_last_frag,
|
|
|
|
+ b_last_packet);
|
|
|
|
|
|
- qed_ll2b_complete_tx_packet(p_hwfn, p_ll2_conn->my_id,
|
|
|
|
- p_pkt->cookie,
|
|
|
|
- p_pkt->bds_set[0].tx_frag,
|
|
|
|
- b_last_frag, b_last_packet);
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -313,6 +325,7 @@ static int qed_ll2_txq_completion(struct qed_hwfn *p_hwfn, void *p_cookie)
|
|
struct qed_ll2_tx_packet *p_pkt;
|
|
struct qed_ll2_tx_packet *p_pkt;
|
|
bool b_last_frag = false;
|
|
bool b_last_frag = false;
|
|
unsigned long flags;
|
|
unsigned long flags;
|
|
|
|
+ dma_addr_t tx_frag;
|
|
int rc = -EINVAL;
|
|
int rc = -EINVAL;
|
|
|
|
|
|
spin_lock_irqsave(&p_tx->lock, flags);
|
|
spin_lock_irqsave(&p_tx->lock, flags);
|
|
@@ -353,11 +366,19 @@ static int qed_ll2_txq_completion(struct qed_hwfn *p_hwfn, void *p_cookie)
|
|
list_add_tail(&p_pkt->list_entry, &p_tx->free_descq);
|
|
list_add_tail(&p_pkt->list_entry, &p_tx->free_descq);
|
|
|
|
|
|
spin_unlock_irqrestore(&p_tx->lock, flags);
|
|
spin_unlock_irqrestore(&p_tx->lock, flags);
|
|
- qed_ll2b_complete_tx_packet(p_hwfn,
|
|
|
|
- p_ll2_conn->my_id,
|
|
|
|
- p_pkt->cookie,
|
|
|
|
- p_pkt->bds_set[0].tx_frag,
|
|
|
|
- b_last_frag, !num_bds);
|
|
|
|
|
|
+ tx_frag = p_pkt->bds_set[0].tx_frag;
|
|
|
|
+ if (p_ll2_conn->gsi_enable)
|
|
|
|
+ qed_ll2b_complete_tx_gsi_packet(p_hwfn,
|
|
|
|
+ p_ll2_conn->my_id,
|
|
|
|
+ p_pkt->cookie,
|
|
|
|
+ tx_frag,
|
|
|
|
+ b_last_frag, !num_bds);
|
|
|
|
+ else
|
|
|
|
+ qed_ll2b_complete_tx_packet(p_hwfn,
|
|
|
|
+ p_ll2_conn->my_id,
|
|
|
|
+ p_pkt->cookie,
|
|
|
|
+ tx_frag,
|
|
|
|
+ b_last_frag, !num_bds);
|
|
spin_lock_irqsave(&p_tx->lock, flags);
|
|
spin_lock_irqsave(&p_tx->lock, flags);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -368,6 +389,54 @@ out:
|
|
return rc;
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static int
|
|
|
|
+qed_ll2_rxq_completion_gsi(struct qed_hwfn *p_hwfn,
|
|
|
|
+ struct qed_ll2_info *p_ll2_info,
|
|
|
|
+ union core_rx_cqe_union *p_cqe,
|
|
|
|
+ unsigned long lock_flags, bool b_last_cqe)
|
|
|
|
+{
|
|
|
|
+ struct qed_ll2_rx_queue *p_rx = &p_ll2_info->rx_queue;
|
|
|
|
+ struct qed_ll2_rx_packet *p_pkt = NULL;
|
|
|
|
+ u16 packet_length, parse_flags, vlan;
|
|
|
|
+ u32 src_mac_addrhi;
|
|
|
|
+ u16 src_mac_addrlo;
|
|
|
|
+
|
|
|
|
+ if (!list_empty(&p_rx->active_descq))
|
|
|
|
+ p_pkt = list_first_entry(&p_rx->active_descq,
|
|
|
|
+ struct qed_ll2_rx_packet, list_entry);
|
|
|
|
+ if (!p_pkt) {
|
|
|
|
+ DP_NOTICE(p_hwfn,
|
|
|
|
+ "GSI Rx completion but active_descq is empty\n");
|
|
|
|
+ return -EIO;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ list_del(&p_pkt->list_entry);
|
|
|
|
+ parse_flags = le16_to_cpu(p_cqe->rx_cqe_gsi.parse_flags.flags);
|
|
|
|
+ packet_length = le16_to_cpu(p_cqe->rx_cqe_gsi.data_length);
|
|
|
|
+ vlan = le16_to_cpu(p_cqe->rx_cqe_gsi.vlan);
|
|
|
|
+ src_mac_addrhi = le32_to_cpu(p_cqe->rx_cqe_gsi.src_mac_addrhi);
|
|
|
|
+ src_mac_addrlo = le16_to_cpu(p_cqe->rx_cqe_gsi.src_mac_addrlo);
|
|
|
|
+ if (qed_chain_consume(&p_rx->rxq_chain) != p_pkt->rxq_bd)
|
|
|
|
+ DP_NOTICE(p_hwfn,
|
|
|
|
+ "Mismatch between active_descq and the LL2 Rx chain\n");
|
|
|
|
+ list_add_tail(&p_pkt->list_entry, &p_rx->free_descq);
|
|
|
|
+
|
|
|
|
+ spin_unlock_irqrestore(&p_rx->lock, lock_flags);
|
|
|
|
+ qed_ll2b_complete_rx_gsi_packet(p_hwfn,
|
|
|
|
+ p_ll2_info->my_id,
|
|
|
|
+ p_pkt->cookie,
|
|
|
|
+ p_pkt->rx_buf_addr,
|
|
|
|
+ packet_length,
|
|
|
|
+ p_cqe->rx_cqe_gsi.data_length_error,
|
|
|
|
+ parse_flags,
|
|
|
|
+ vlan,
|
|
|
|
+ src_mac_addrhi,
|
|
|
|
+ src_mac_addrlo, b_last_cqe);
|
|
|
|
+ spin_lock_irqsave(&p_rx->lock, lock_flags);
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
static int qed_ll2_rxq_completion_reg(struct qed_hwfn *p_hwfn,
|
|
static int qed_ll2_rxq_completion_reg(struct qed_hwfn *p_hwfn,
|
|
struct qed_ll2_info *p_ll2_conn,
|
|
struct qed_ll2_info *p_ll2_conn,
|
|
union core_rx_cqe_union *p_cqe,
|
|
union core_rx_cqe_union *p_cqe,
|
|
@@ -429,6 +498,10 @@ static int qed_ll2_rxq_completion(struct qed_hwfn *p_hwfn, void *cookie)
|
|
DP_NOTICE(p_hwfn, "LL2 - unexpected Rx CQE slowpath\n");
|
|
DP_NOTICE(p_hwfn, "LL2 - unexpected Rx CQE slowpath\n");
|
|
rc = -EINVAL;
|
|
rc = -EINVAL;
|
|
break;
|
|
break;
|
|
|
|
+ case CORE_RX_CQE_TYPE_GSI_OFFLOAD:
|
|
|
|
+ rc = qed_ll2_rxq_completion_gsi(p_hwfn, p_ll2_conn,
|
|
|
|
+ cqe, flags, b_last_cqe);
|
|
|
|
+ break;
|
|
case CORE_RX_CQE_TYPE_REGULAR:
|
|
case CORE_RX_CQE_TYPE_REGULAR:
|
|
rc = qed_ll2_rxq_completion_reg(p_hwfn, p_ll2_conn,
|
|
rc = qed_ll2_rxq_completion_reg(p_hwfn, p_ll2_conn,
|
|
cqe, flags, b_last_cqe);
|
|
cqe, flags, b_last_cqe);
|
|
@@ -527,6 +600,7 @@ static int qed_sp_ll2_rx_queue_start(struct qed_hwfn *p_hwfn,
|
|
}
|
|
}
|
|
|
|
|
|
p_ramrod->action_on_error.error_type = action_on_error;
|
|
p_ramrod->action_on_error.error_type = action_on_error;
|
|
|
|
+ p_ramrod->gsi_offload_flag = p_ll2_conn->gsi_enable;
|
|
return qed_spq_post(p_hwfn, p_ent, NULL);
|
|
return qed_spq_post(p_hwfn, p_ent, NULL);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -589,6 +663,7 @@ static int qed_sp_ll2_tx_queue_start(struct qed_hwfn *p_hwfn,
|
|
DP_NOTICE(p_hwfn, "Unknown connection type: %d\n", conn_type);
|
|
DP_NOTICE(p_hwfn, "Unknown connection type: %d\n", conn_type);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ p_ramrod->gsi_offload_flag = p_ll2_conn->gsi_enable;
|
|
return qed_spq_post(p_hwfn, p_ent, NULL);
|
|
return qed_spq_post(p_hwfn, p_ent, NULL);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -775,6 +850,7 @@ int qed_ll2_acquire_connection(struct qed_hwfn *p_hwfn,
|
|
p_ll2_info->tx_dest = p_params->tx_dest;
|
|
p_ll2_info->tx_dest = p_params->tx_dest;
|
|
p_ll2_info->ai_err_packet_too_big = p_params->ai_err_packet_too_big;
|
|
p_ll2_info->ai_err_packet_too_big = p_params->ai_err_packet_too_big;
|
|
p_ll2_info->ai_err_no_buf = p_params->ai_err_no_buf;
|
|
p_ll2_info->ai_err_no_buf = p_params->ai_err_no_buf;
|
|
|
|
+ p_ll2_info->gsi_enable = p_params->gsi_enable;
|
|
|
|
|
|
rc = qed_ll2_acquire_connection_rx(p_hwfn, p_ll2_info, rx_num_desc);
|
|
rc = qed_ll2_acquire_connection_rx(p_hwfn, p_ll2_info, rx_num_desc);
|
|
if (rc)
|
|
if (rc)
|
|
@@ -1026,6 +1102,7 @@ static void qed_ll2_prepare_tx_packet_set_bd(struct qed_hwfn *p_hwfn,
|
|
u16 vlan,
|
|
u16 vlan,
|
|
u8 bd_flags,
|
|
u8 bd_flags,
|
|
u16 l4_hdr_offset_w,
|
|
u16 l4_hdr_offset_w,
|
|
|
|
+ enum core_roce_flavor_type type,
|
|
dma_addr_t first_frag,
|
|
dma_addr_t first_frag,
|
|
u16 first_frag_len)
|
|
u16 first_frag_len)
|
|
{
|
|
{
|
|
@@ -1046,6 +1123,9 @@ static void qed_ll2_prepare_tx_packet_set_bd(struct qed_hwfn *p_hwfn,
|
|
DMA_REGPAIR_LE(start_bd->addr, first_frag);
|
|
DMA_REGPAIR_LE(start_bd->addr, first_frag);
|
|
start_bd->nbytes = cpu_to_le16(first_frag_len);
|
|
start_bd->nbytes = cpu_to_le16(first_frag_len);
|
|
|
|
|
|
|
|
+ SET_FIELD(start_bd->bd_flags.as_bitfield, CORE_TX_BD_FLAGS_ROCE_FLAV,
|
|
|
|
+ type);
|
|
|
|
+
|
|
DP_VERBOSE(p_hwfn,
|
|
DP_VERBOSE(p_hwfn,
|
|
(NETIF_MSG_TX_QUEUED | QED_MSG_LL2),
|
|
(NETIF_MSG_TX_QUEUED | QED_MSG_LL2),
|
|
"LL2 [q 0x%02x cid 0x%08x type 0x%08x] Tx Producer at [0x%04x] - set with a %04x bytes %02x BDs buffer at %08x:%08x\n",
|
|
"LL2 [q 0x%02x cid 0x%08x type 0x%08x] Tx Producer at [0x%04x] - set with a %04x bytes %02x BDs buffer at %08x:%08x\n",
|
|
@@ -1137,11 +1217,13 @@ int qed_ll2_prepare_tx_packet(struct qed_hwfn *p_hwfn,
|
|
u16 vlan,
|
|
u16 vlan,
|
|
u8 bd_flags,
|
|
u8 bd_flags,
|
|
u16 l4_hdr_offset_w,
|
|
u16 l4_hdr_offset_w,
|
|
|
|
+ enum qed_ll2_roce_flavor_type qed_roce_flavor,
|
|
dma_addr_t first_frag,
|
|
dma_addr_t first_frag,
|
|
u16 first_frag_len, void *cookie, u8 notify_fw)
|
|
u16 first_frag_len, void *cookie, u8 notify_fw)
|
|
{
|
|
{
|
|
struct qed_ll2_tx_packet *p_curp = NULL;
|
|
struct qed_ll2_tx_packet *p_curp = NULL;
|
|
struct qed_ll2_info *p_ll2_conn = NULL;
|
|
struct qed_ll2_info *p_ll2_conn = NULL;
|
|
|
|
+ enum core_roce_flavor_type roce_flavor;
|
|
struct qed_ll2_tx_queue *p_tx;
|
|
struct qed_ll2_tx_queue *p_tx;
|
|
struct qed_chain *p_tx_chain;
|
|
struct qed_chain *p_tx_chain;
|
|
unsigned long flags;
|
|
unsigned long flags;
|
|
@@ -1174,6 +1256,15 @@ int qed_ll2_prepare_tx_packet(struct qed_hwfn *p_hwfn,
|
|
goto out;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ if (qed_roce_flavor == QED_LL2_ROCE) {
|
|
|
|
+ roce_flavor = CORE_ROCE;
|
|
|
|
+ } else if (qed_roce_flavor == QED_LL2_RROCE) {
|
|
|
|
+ roce_flavor = CORE_RROCE;
|
|
|
|
+ } else {
|
|
|
|
+ rc = -EINVAL;
|
|
|
|
+ goto out;
|
|
|
|
+ }
|
|
|
|
+
|
|
/* Prepare packet and BD, and perhaps send a doorbell to FW */
|
|
/* Prepare packet and BD, and perhaps send a doorbell to FW */
|
|
qed_ll2_prepare_tx_packet_set(p_hwfn, p_tx, p_curp,
|
|
qed_ll2_prepare_tx_packet_set(p_hwfn, p_tx, p_curp,
|
|
num_of_bds, first_frag,
|
|
num_of_bds, first_frag,
|
|
@@ -1181,6 +1272,7 @@ int qed_ll2_prepare_tx_packet(struct qed_hwfn *p_hwfn,
|
|
qed_ll2_prepare_tx_packet_set_bd(p_hwfn, p_ll2_conn, p_curp,
|
|
qed_ll2_prepare_tx_packet_set_bd(p_hwfn, p_ll2_conn, p_curp,
|
|
num_of_bds, CORE_TX_DEST_NW,
|
|
num_of_bds, CORE_TX_DEST_NW,
|
|
vlan, bd_flags, l4_hdr_offset_w,
|
|
vlan, bd_flags, l4_hdr_offset_w,
|
|
|
|
+ roce_flavor,
|
|
first_frag, first_frag_len);
|
|
first_frag, first_frag_len);
|
|
|
|
|
|
qed_ll2_tx_packet_notify(p_hwfn, p_ll2_conn);
|
|
qed_ll2_tx_packet_notify(p_hwfn, p_ll2_conn);
|
|
@@ -1476,6 +1568,7 @@ static int qed_ll2_start(struct qed_dev *cdev, struct qed_ll2_params *params)
|
|
ll2_info.rx_vlan_removal_en = params->rx_vlan_stripping;
|
|
ll2_info.rx_vlan_removal_en = params->rx_vlan_stripping;
|
|
ll2_info.tx_tc = 0;
|
|
ll2_info.tx_tc = 0;
|
|
ll2_info.tx_dest = CORE_TX_DEST_NW;
|
|
ll2_info.tx_dest = CORE_TX_DEST_NW;
|
|
|
|
+ ll2_info.gsi_enable = 1;
|
|
|
|
|
|
rc = qed_ll2_acquire_connection(QED_LEADING_HWFN(cdev), &ll2_info,
|
|
rc = qed_ll2_acquire_connection(QED_LEADING_HWFN(cdev), &ll2_info,
|
|
QED_LL2_RX_SIZE, QED_LL2_TX_SIZE,
|
|
QED_LL2_RX_SIZE, QED_LL2_TX_SIZE,
|
|
@@ -1625,8 +1718,8 @@ static int qed_ll2_start_xmit(struct qed_dev *cdev, struct sk_buff *skb)
|
|
rc = qed_ll2_prepare_tx_packet(QED_LEADING_HWFN(cdev),
|
|
rc = qed_ll2_prepare_tx_packet(QED_LEADING_HWFN(cdev),
|
|
cdev->ll2->handle,
|
|
cdev->ll2->handle,
|
|
1 + skb_shinfo(skb)->nr_frags,
|
|
1 + skb_shinfo(skb)->nr_frags,
|
|
- vlan, flags, 0, mapping,
|
|
|
|
- skb->len, skb, 1);
|
|
|
|
|
|
+ vlan, flags, 0, 0 /* RoCE FLAVOR */,
|
|
|
|
+ mapping, skb->len, skb, 1);
|
|
if (rc)
|
|
if (rc)
|
|
goto err;
|
|
goto err;
|
|
|
|
|