Commit cb6aeb07 authored by Mintz, Yuval's avatar Mintz, Yuval Committed by David S. Miller

qede: Add support for XDP_TX

Add support for forwarding via XDP. Once the eBPF is attached,
driver would allocate & configure a designated transmission queue
meant solely for forwarding packets. Said queue would share the
receive-queue's interrupt line, and would have it's own Tx statistics.

Infrastructure changes required for this [spread-out through the code]:
 - Determine the DMA direction of the receive buffers based on the presence
of the eBPF program.
 - Turn the sw Tx ring into a union, as regular/XDP queues have different
needs for releasing resources after completion [regular requires the SKB,
XDP requires the transmitted page].
Signed-off-by: default avatarYuval Mintz <Yuval.Mintz@cavium.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 496e0517
...@@ -258,6 +258,7 @@ struct qede_rx_queue { ...@@ -258,6 +258,7 @@ struct qede_rx_queue {
u16 sw_rx_prod; u16 sw_rx_prod;
u16 num_rx_buffers; /* Slowpath */ u16 num_rx_buffers; /* Slowpath */
u8 data_direction;
u8 rxq_id; u8 rxq_id;
u32 rx_buf_size; u32 rx_buf_size;
...@@ -294,6 +295,7 @@ struct sw_tx_bd { ...@@ -294,6 +295,7 @@ struct sw_tx_bd {
}; };
struct qede_tx_queue { struct qede_tx_queue {
u8 is_xdp;
bool is_legacy; bool is_legacy;
u16 sw_tx_cons; u16 sw_tx_cons;
u16 sw_tx_prod; u16 sw_tx_prod;
...@@ -310,8 +312,18 @@ struct qede_tx_queue { ...@@ -310,8 +312,18 @@ struct qede_tx_queue {
void __iomem *doorbell_addr; void __iomem *doorbell_addr;
union db_prod tx_db; union db_prod tx_db;
int index; /* Slowpath only */ int index; /* Slowpath only */
#define QEDE_TXQ_XDP_TO_IDX(edev, txq) ((txq)->index - \
QEDE_MAX_TSS_CNT(edev))
#define QEDE_TXQ_IDX_TO_XDP(edev, idx) ((idx) + QEDE_MAX_TSS_CNT(edev))
/* Regular Tx requires skb + metadata for release purpose,
* while XDP requires only the pages themselves.
*/
union {
struct sw_tx_bd *skbs;
struct page **pages;
} sw_tx_ring;
struct sw_tx_bd *sw_tx_ring;
struct qed_chain tx_pbl; struct qed_chain tx_pbl;
/* Slowpath; Should be kept in end [unless missing padding] */ /* Slowpath; Should be kept in end [unless missing padding] */
...@@ -336,10 +348,12 @@ struct qede_fastpath { ...@@ -336,10 +348,12 @@ struct qede_fastpath {
#define QEDE_FASTPATH_COMBINED (QEDE_FASTPATH_TX | QEDE_FASTPATH_RX) #define QEDE_FASTPATH_COMBINED (QEDE_FASTPATH_TX | QEDE_FASTPATH_RX)
u8 type; u8 type;
u8 id; u8 id;
u8 xdp_xmit;
struct napi_struct napi; struct napi_struct napi;
struct qed_sb_info *sb_info; struct qed_sb_info *sb_info;
struct qede_rx_queue *rxq; struct qede_rx_queue *rxq;
struct qede_tx_queue *txq; struct qede_tx_queue *txq;
struct qede_tx_queue *xdp_tx;
#define VEC_NAME_SIZE (sizeof(((struct net_device *)0)->name) + 8) #define VEC_NAME_SIZE (sizeof(((struct net_device *)0)->name) + 8)
char name[VEC_NAME_SIZE]; char name[VEC_NAME_SIZE];
......
...@@ -165,8 +165,13 @@ static void qede_get_strings_stats_txq(struct qede_dev *edev, ...@@ -165,8 +165,13 @@ static void qede_get_strings_stats_txq(struct qede_dev *edev,
int i; int i;
for (i = 0; i < QEDE_NUM_TQSTATS; i++) { for (i = 0; i < QEDE_NUM_TQSTATS; i++) {
sprintf(*buf, "%d: %s", txq->index, if (txq->is_xdp)
qede_tqstats_arr[i].string); sprintf(*buf, "%d [XDP]: %s",
QEDE_TXQ_XDP_TO_IDX(edev, txq),
qede_tqstats_arr[i].string);
else
sprintf(*buf, "%d: %s", txq->index,
qede_tqstats_arr[i].string);
*buf += ETH_GSTRING_LEN; *buf += ETH_GSTRING_LEN;
} }
} }
...@@ -195,6 +200,9 @@ static void qede_get_strings_stats(struct qede_dev *edev, u8 *buf) ...@@ -195,6 +200,9 @@ static void qede_get_strings_stats(struct qede_dev *edev, u8 *buf)
if (fp->type & QEDE_FASTPATH_RX) if (fp->type & QEDE_FASTPATH_RX)
qede_get_strings_stats_rxq(edev, fp->rxq, &buf); qede_get_strings_stats_rxq(edev, fp->rxq, &buf);
if (fp->type & QEDE_FASTPATH_XDP)
qede_get_strings_stats_txq(edev, fp->xdp_tx, &buf);
if (fp->type & QEDE_FASTPATH_TX) if (fp->type & QEDE_FASTPATH_TX)
qede_get_strings_stats_txq(edev, fp->txq, &buf); qede_get_strings_stats_txq(edev, fp->txq, &buf);
} }
...@@ -268,6 +276,9 @@ static void qede_get_ethtool_stats(struct net_device *dev, ...@@ -268,6 +276,9 @@ static void qede_get_ethtool_stats(struct net_device *dev,
if (fp->type & QEDE_FASTPATH_RX) if (fp->type & QEDE_FASTPATH_RX)
qede_get_ethtool_stats_rxq(fp->rxq, &buf); qede_get_ethtool_stats_rxq(fp->rxq, &buf);
if (fp->type & QEDE_FASTPATH_XDP)
qede_get_ethtool_stats_txq(fp->xdp_tx, &buf);
if (fp->type & QEDE_FASTPATH_TX) if (fp->type & QEDE_FASTPATH_TX)
qede_get_ethtool_stats_txq(fp->txq, &buf); qede_get_ethtool_stats_txq(fp->txq, &buf);
} }
...@@ -305,6 +316,9 @@ static int qede_get_sset_count(struct net_device *dev, int stringset) ...@@ -305,6 +316,9 @@ static int qede_get_sset_count(struct net_device *dev, int stringset)
/* Account for the Regular Rx statistics */ /* Account for the Regular Rx statistics */
num_stats += QEDE_RSS_COUNT(edev) * QEDE_NUM_RQSTATS; num_stats += QEDE_RSS_COUNT(edev) * QEDE_NUM_RQSTATS;
/* Account for XDP statistics [if needed] */
if (edev->xdp_prog)
num_stats += QEDE_RSS_COUNT(edev) * QEDE_NUM_TQSTATS;
return num_stats; return num_stats;
case ETH_SS_PRIV_FLAGS: case ETH_SS_PRIV_FLAGS:
...@@ -1216,7 +1230,7 @@ static int qede_selftest_transmit_traffic(struct qede_dev *edev, ...@@ -1216,7 +1230,7 @@ static int qede_selftest_transmit_traffic(struct qede_dev *edev,
/* Fill the entry in the SW ring and the BDs in the FW ring */ /* Fill the entry in the SW ring and the BDs in the FW ring */
idx = txq->sw_tx_prod & NUM_TX_BDS_MAX; idx = txq->sw_tx_prod & NUM_TX_BDS_MAX;
txq->sw_tx_ring[idx].skb = skb; txq->sw_tx_ring.skbs[idx].skb = skb;
first_bd = qed_chain_produce(&txq->tx_pbl); first_bd = qed_chain_produce(&txq->tx_pbl);
memset(first_bd, 0, sizeof(*first_bd)); memset(first_bd, 0, sizeof(*first_bd));
val = 1 << ETH_TX_1ST_BD_FLAGS_START_BD_SHIFT; val = 1 << ETH_TX_1ST_BD_FLAGS_START_BD_SHIFT;
...@@ -1270,7 +1284,7 @@ static int qede_selftest_transmit_traffic(struct qede_dev *edev, ...@@ -1270,7 +1284,7 @@ static int qede_selftest_transmit_traffic(struct qede_dev *edev,
dma_unmap_single(&edev->pdev->dev, BD_UNMAP_ADDR(first_bd), dma_unmap_single(&edev->pdev->dev, BD_UNMAP_ADDR(first_bd),
BD_UNMAP_LEN(first_bd), DMA_TO_DEVICE); BD_UNMAP_LEN(first_bd), DMA_TO_DEVICE);
txq->sw_tx_cons++; txq->sw_tx_cons++;
txq->sw_tx_ring[idx].skb = NULL; txq->sw_tx_ring.skbs[idx].skb = NULL;
return 0; return 0;
} }
......
...@@ -94,6 +94,9 @@ static int qede_probe(struct pci_dev *pdev, const struct pci_device_id *id); ...@@ -94,6 +94,9 @@ static int qede_probe(struct pci_dev *pdev, const struct pci_device_id *id);
#define TX_TIMEOUT (5 * HZ) #define TX_TIMEOUT (5 * HZ)
/* Utilize last protocol index for XDP */
#define XDP_PI 11
static void qede_remove(struct pci_dev *pdev); static void qede_remove(struct pci_dev *pdev);
static void qede_shutdown(struct pci_dev *pdev); static void qede_shutdown(struct pci_dev *pdev);
static void qede_link_update(void *dev, struct qed_link_output *link); static void qede_link_update(void *dev, struct qed_link_output *link);
...@@ -301,12 +304,12 @@ static int qede_free_tx_pkt(struct qede_dev *edev, ...@@ -301,12 +304,12 @@ static int qede_free_tx_pkt(struct qede_dev *edev,
struct qede_tx_queue *txq, int *len) struct qede_tx_queue *txq, int *len)
{ {
u16 idx = txq->sw_tx_cons & NUM_TX_BDS_MAX; u16 idx = txq->sw_tx_cons & NUM_TX_BDS_MAX;
struct sk_buff *skb = txq->sw_tx_ring[idx].skb; struct sk_buff *skb = txq->sw_tx_ring.skbs[idx].skb;
struct eth_tx_1st_bd *first_bd; struct eth_tx_1st_bd *first_bd;
struct eth_tx_bd *tx_data_bd; struct eth_tx_bd *tx_data_bd;
int bds_consumed = 0; int bds_consumed = 0;
int nbds; int nbds;
bool data_split = txq->sw_tx_ring[idx].flags & QEDE_TSO_SPLIT_BD; bool data_split = txq->sw_tx_ring.skbs[idx].flags & QEDE_TSO_SPLIT_BD;
int i, split_bd_len = 0; int i, split_bd_len = 0;
if (unlikely(!skb)) { if (unlikely(!skb)) {
...@@ -346,8 +349,8 @@ static int qede_free_tx_pkt(struct qede_dev *edev, ...@@ -346,8 +349,8 @@ static int qede_free_tx_pkt(struct qede_dev *edev,
/* Free skb */ /* Free skb */
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
txq->sw_tx_ring[idx].skb = NULL; txq->sw_tx_ring.skbs[idx].skb = NULL;
txq->sw_tx_ring[idx].flags = 0; txq->sw_tx_ring.skbs[idx].flags = 0;
return 0; return 0;
} }
...@@ -358,7 +361,7 @@ static void qede_free_failed_tx_pkt(struct qede_tx_queue *txq, ...@@ -358,7 +361,7 @@ static void qede_free_failed_tx_pkt(struct qede_tx_queue *txq,
int nbd, bool data_split) int nbd, bool data_split)
{ {
u16 idx = txq->sw_tx_prod & NUM_TX_BDS_MAX; u16 idx = txq->sw_tx_prod & NUM_TX_BDS_MAX;
struct sk_buff *skb = txq->sw_tx_ring[idx].skb; struct sk_buff *skb = txq->sw_tx_ring.skbs[idx].skb;
struct eth_tx_bd *tx_data_bd; struct eth_tx_bd *tx_data_bd;
int i, split_bd_len = 0; int i, split_bd_len = 0;
...@@ -394,8 +397,8 @@ static void qede_free_failed_tx_pkt(struct qede_tx_queue *txq, ...@@ -394,8 +397,8 @@ static void qede_free_failed_tx_pkt(struct qede_tx_queue *txq,
/* Free skb */ /* Free skb */
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
txq->sw_tx_ring[idx].skb = NULL; txq->sw_tx_ring.skbs[idx].skb = NULL;
txq->sw_tx_ring[idx].flags = 0; txq->sw_tx_ring.skbs[idx].flags = 0;
} }
static u32 qede_xmit_type(struct sk_buff *skb, int *ipv6_ext) static u32 qede_xmit_type(struct sk_buff *skb, int *ipv6_ext)
...@@ -530,6 +533,47 @@ static inline void qede_update_tx_producer(struct qede_tx_queue *txq) ...@@ -530,6 +533,47 @@ static inline void qede_update_tx_producer(struct qede_tx_queue *txq)
mmiowb(); mmiowb();
} }
static int qede_xdp_xmit(struct qede_dev *edev, struct qede_fastpath *fp,
struct sw_rx_data *metadata, u16 padding, u16 length)
{
struct qede_tx_queue *txq = fp->xdp_tx;
u16 idx = txq->sw_tx_prod & NUM_TX_BDS_MAX;
struct eth_tx_1st_bd *first_bd;
if (!qed_chain_get_elem_left(&txq->tx_pbl)) {
txq->stopped_cnt++;
return -ENOMEM;
}
first_bd = (struct eth_tx_1st_bd *)qed_chain_produce(&txq->tx_pbl);
memset(first_bd, 0, sizeof(*first_bd));
first_bd->data.bd_flags.bitfields =
BIT(ETH_TX_1ST_BD_FLAGS_START_BD_SHIFT);
first_bd->data.bitfields |=
(length & ETH_TX_DATA_1ST_BD_PKT_LEN_MASK) <<
ETH_TX_DATA_1ST_BD_PKT_LEN_SHIFT;
first_bd->data.nbds = 1;
/* We can safely ignore the offset, as it's 0 for XDP */
BD_SET_UNMAP_ADDR_LEN(first_bd, metadata->mapping + padding, length);
/* Synchronize the buffer back to device, as program [probably]
* has changed it.
*/
dma_sync_single_for_device(&edev->pdev->dev,
metadata->mapping + padding,
length, PCI_DMA_TODEVICE);
txq->sw_tx_ring.pages[idx] = metadata->data;
txq->sw_tx_prod++;
/* Mark the fastpath for future XDP doorbell */
fp->xdp_xmit = 1;
return 0;
}
/* Main transmit function */ /* Main transmit function */
static netdev_tx_t qede_start_xmit(struct sk_buff *skb, static netdev_tx_t qede_start_xmit(struct sk_buff *skb,
struct net_device *ndev) struct net_device *ndev)
...@@ -573,7 +617,7 @@ static netdev_tx_t qede_start_xmit(struct sk_buff *skb, ...@@ -573,7 +617,7 @@ static netdev_tx_t qede_start_xmit(struct sk_buff *skb,
/* Fill the entry in the SW ring and the BDs in the FW ring */ /* Fill the entry in the SW ring and the BDs in the FW ring */
idx = txq->sw_tx_prod & NUM_TX_BDS_MAX; idx = txq->sw_tx_prod & NUM_TX_BDS_MAX;
txq->sw_tx_ring[idx].skb = skb; txq->sw_tx_ring.skbs[idx].skb = skb;
first_bd = (struct eth_tx_1st_bd *) first_bd = (struct eth_tx_1st_bd *)
qed_chain_produce(&txq->tx_pbl); qed_chain_produce(&txq->tx_pbl);
memset(first_bd, 0, sizeof(*first_bd)); memset(first_bd, 0, sizeof(*first_bd));
...@@ -693,7 +737,7 @@ static netdev_tx_t qede_start_xmit(struct sk_buff *skb, ...@@ -693,7 +737,7 @@ static netdev_tx_t qede_start_xmit(struct sk_buff *skb,
/* this marks the BD as one that has no /* this marks the BD as one that has no
* individual mapping * individual mapping
*/ */
txq->sw_tx_ring[idx].flags |= QEDE_TSO_SPLIT_BD; txq->sw_tx_ring.skbs[idx].flags |= QEDE_TSO_SPLIT_BD;
first_bd->nbytes = cpu_to_le16(hlen); first_bd->nbytes = cpu_to_le16(hlen);
...@@ -802,6 +846,27 @@ int qede_txq_has_work(struct qede_tx_queue *txq) ...@@ -802,6 +846,27 @@ int qede_txq_has_work(struct qede_tx_queue *txq)
return hw_bd_cons != qed_chain_get_cons_idx(&txq->tx_pbl); return hw_bd_cons != qed_chain_get_cons_idx(&txq->tx_pbl);
} }
static void qede_xdp_tx_int(struct qede_dev *edev, struct qede_tx_queue *txq)
{
struct eth_tx_1st_bd *bd;
u16 hw_bd_cons;
hw_bd_cons = le16_to_cpu(*txq->hw_cons_ptr);
barrier();
while (hw_bd_cons != qed_chain_get_cons_idx(&txq->tx_pbl)) {
bd = (struct eth_tx_1st_bd *)qed_chain_consume(&txq->tx_pbl);
dma_unmap_single(&edev->pdev->dev, BD_UNMAP_ADDR(bd),
PAGE_SIZE, DMA_BIDIRECTIONAL);
__free_page(txq->sw_tx_ring.pages[txq->sw_tx_cons &
NUM_TX_BDS_MAX]);
txq->sw_tx_cons++;
txq->xmit_pkts++;
}
}
static int qede_tx_int(struct qede_dev *edev, struct qede_tx_queue *txq) static int qede_tx_int(struct qede_dev *edev, struct qede_tx_queue *txq)
{ {
struct netdev_queue *netdev_txq; struct netdev_queue *netdev_txq;
...@@ -942,7 +1007,7 @@ static int qede_alloc_rx_buffer(struct qede_rx_queue *rxq) ...@@ -942,7 +1007,7 @@ static int qede_alloc_rx_buffer(struct qede_rx_queue *rxq)
* for multiple RX buffer segment size mapping. * for multiple RX buffer segment size mapping.
*/ */
mapping = dma_map_page(rxq->dev, data, 0, mapping = dma_map_page(rxq->dev, data, 0,
PAGE_SIZE, DMA_FROM_DEVICE); PAGE_SIZE, rxq->data_direction);
if (unlikely(dma_mapping_error(rxq->dev, mapping))) { if (unlikely(dma_mapping_error(rxq->dev, mapping))) {
__free_page(data); __free_page(data);
return -ENOMEM; return -ENOMEM;
...@@ -981,7 +1046,7 @@ static inline int qede_realloc_rx_buffer(struct qede_rx_queue *rxq, ...@@ -981,7 +1046,7 @@ static inline int qede_realloc_rx_buffer(struct qede_rx_queue *rxq,
} }
dma_unmap_page(rxq->dev, curr_cons->mapping, dma_unmap_page(rxq->dev, curr_cons->mapping,
PAGE_SIZE, DMA_FROM_DEVICE); PAGE_SIZE, rxq->data_direction);
} else { } else {
/* Increment refcount of the page as we don't want /* Increment refcount of the page as we don't want
* network stack to take the ownership of the page * network stack to take the ownership of the page
...@@ -1441,6 +1506,26 @@ static bool qede_rx_xdp(struct qede_dev *edev, ...@@ -1441,6 +1506,26 @@ static bool qede_rx_xdp(struct qede_dev *edev,
rxq->xdp_no_pass++; rxq->xdp_no_pass++;
switch (act) { switch (act) {
case XDP_TX:
/* We need the replacement buffer before transmit. */
if (qede_alloc_rx_buffer(rxq)) {
qede_recycle_rx_bd_ring(rxq, 1);
return false;
}
/* Now if there's a transmission problem, we'd still have to
* throw current buffer, as replacement was already allocated.
*/
if (qede_xdp_xmit(edev, fp, bd, cqe->placement_offset, len)) {
dma_unmap_page(rxq->dev, bd->mapping,
PAGE_SIZE, DMA_BIDIRECTIONAL);
__free_page(bd->data);
}
/* Regardless, we've consumed an Rx BD */
qede_rx_bd_ring_consume(rxq);
return false;
default: default:
bpf_warn_invalid_xdp_action(act); bpf_warn_invalid_xdp_action(act);
case XDP_ABORTED: case XDP_ABORTED:
...@@ -1740,6 +1825,10 @@ static bool qede_poll_is_more_work(struct qede_fastpath *fp) ...@@ -1740,6 +1825,10 @@ static bool qede_poll_is_more_work(struct qede_fastpath *fp)
if (qede_has_rx_work(fp->rxq)) if (qede_has_rx_work(fp->rxq))
return true; return true;
if (fp->type & QEDE_FASTPATH_XDP)
if (qede_txq_has_work(fp->xdp_tx))
return true;
if (likely(fp->type & QEDE_FASTPATH_TX)) if (likely(fp->type & QEDE_FASTPATH_TX))
if (qede_txq_has_work(fp->txq)) if (qede_txq_has_work(fp->txq))
return true; return true;
...@@ -1757,6 +1846,9 @@ static int qede_poll(struct napi_struct *napi, int budget) ...@@ -1757,6 +1846,9 @@ static int qede_poll(struct napi_struct *napi, int budget)
if (likely(fp->type & QEDE_FASTPATH_TX) && qede_txq_has_work(fp->txq)) if (likely(fp->type & QEDE_FASTPATH_TX) && qede_txq_has_work(fp->txq))
qede_tx_int(edev, fp->txq); qede_tx_int(edev, fp->txq);
if ((fp->type & QEDE_FASTPATH_XDP) && qede_txq_has_work(fp->xdp_tx))
qede_xdp_tx_int(edev, fp->xdp_tx);
rx_work_done = (likely(fp->type & QEDE_FASTPATH_RX) && rx_work_done = (likely(fp->type & QEDE_FASTPATH_RX) &&
qede_has_rx_work(fp->rxq)) ? qede_has_rx_work(fp->rxq)) ?
qede_rx_int(fp, budget) : 0; qede_rx_int(fp, budget) : 0;
...@@ -1771,6 +1863,14 @@ static int qede_poll(struct napi_struct *napi, int budget) ...@@ -1771,6 +1863,14 @@ static int qede_poll(struct napi_struct *napi, int budget)
} }
} }
if (fp->xdp_xmit) {
u16 xdp_prod = qed_chain_get_prod_idx(&fp->xdp_tx->tx_pbl);
fp->xdp_xmit = 0;
fp->xdp_tx->tx_db.data.bd_prod = cpu_to_le16(xdp_prod);
qede_update_tx_producer(fp->xdp_tx);
}
return rx_work_done; return rx_work_done;
} }
...@@ -2586,6 +2686,7 @@ static void qede_free_fp_array(struct qede_dev *edev) ...@@ -2586,6 +2686,7 @@ static void qede_free_fp_array(struct qede_dev *edev)
kfree(fp->sb_info); kfree(fp->sb_info);
kfree(fp->rxq); kfree(fp->rxq);
kfree(fp->xdp_tx);
kfree(fp->txq); kfree(fp->txq);
} }
kfree(edev->fp_array); kfree(edev->fp_array);
...@@ -2646,8 +2747,13 @@ static int qede_alloc_fp_array(struct qede_dev *edev) ...@@ -2646,8 +2747,13 @@ static int qede_alloc_fp_array(struct qede_dev *edev)
if (!fp->rxq) if (!fp->rxq)
goto err; goto err;
if (edev->xdp_prog) if (edev->xdp_prog) {
fp->xdp_tx = kzalloc(sizeof(*fp->xdp_tx),
GFP_KERNEL);
if (!fp->xdp_tx)
goto err;
fp->type |= QEDE_FASTPATH_XDP; fp->type |= QEDE_FASTPATH_XDP;
}
} }
} }
...@@ -2694,9 +2800,9 @@ static void qede_update_pf_params(struct qed_dev *cdev) ...@@ -2694,9 +2800,9 @@ static void qede_update_pf_params(struct qed_dev *cdev)
{ {
struct qed_pf_params pf_params; struct qed_pf_params pf_params;
/* 64 rx + 64 tx */ /* 64 rx + 64 tx + 64 XDP */
memset(&pf_params, 0, sizeof(struct qed_pf_params)); memset(&pf_params, 0, sizeof(struct qed_pf_params));
pf_params.eth_pf_params.num_cons = 128; pf_params.eth_pf_params.num_cons = 192;
qed_ops->common->update_pf_params(cdev, &pf_params); qed_ops->common->update_pf_params(cdev, &pf_params);
} }
...@@ -2953,7 +3059,7 @@ static void qede_free_rx_buffers(struct qede_dev *edev, ...@@ -2953,7 +3059,7 @@ static void qede_free_rx_buffers(struct qede_dev *edev,
data = rx_buf->data; data = rx_buf->data;
dma_unmap_page(&edev->pdev->dev, dma_unmap_page(&edev->pdev->dev,
rx_buf->mapping, PAGE_SIZE, DMA_FROM_DEVICE); rx_buf->mapping, PAGE_SIZE, rxq->data_direction);
rx_buf->data = NULL; rx_buf->data = NULL;
__free_page(data); __free_page(data);
...@@ -3114,7 +3220,10 @@ static int qede_alloc_mem_rxq(struct qede_dev *edev, struct qede_rx_queue *rxq) ...@@ -3114,7 +3220,10 @@ static int qede_alloc_mem_rxq(struct qede_dev *edev, struct qede_rx_queue *rxq)
static void qede_free_mem_txq(struct qede_dev *edev, struct qede_tx_queue *txq) static void qede_free_mem_txq(struct qede_dev *edev, struct qede_tx_queue *txq)
{ {
/* Free the parallel SW ring */ /* Free the parallel SW ring */
kfree(txq->sw_tx_ring); if (txq->is_xdp)
kfree(txq->sw_tx_ring.pages);
else
kfree(txq->sw_tx_ring.skbs);
/* Free the real RQ ring used by FW */ /* Free the real RQ ring used by FW */
edev->ops->common->chain_free(edev->cdev, &txq->tx_pbl); edev->ops->common->chain_free(edev->cdev, &txq->tx_pbl);
...@@ -3123,17 +3232,22 @@ static void qede_free_mem_txq(struct qede_dev *edev, struct qede_tx_queue *txq) ...@@ -3123,17 +3232,22 @@ static void qede_free_mem_txq(struct qede_dev *edev, struct qede_tx_queue *txq)
/* This function allocates all memory needed per Tx queue */ /* This function allocates all memory needed per Tx queue */
static int qede_alloc_mem_txq(struct qede_dev *edev, struct qede_tx_queue *txq) static int qede_alloc_mem_txq(struct qede_dev *edev, struct qede_tx_queue *txq)
{ {
int size, rc;
union eth_tx_bd_types *p_virt; union eth_tx_bd_types *p_virt;
int size, rc;
txq->num_tx_buffers = edev->q_num_tx_buffers; txq->num_tx_buffers = edev->q_num_tx_buffers;
/* Allocate the parallel driver ring for Tx buffers */ /* Allocate the parallel driver ring for Tx buffers */
size = sizeof(*txq->sw_tx_ring) * TX_RING_SIZE; if (txq->is_xdp) {
txq->sw_tx_ring = kzalloc(size, GFP_KERNEL); size = sizeof(*txq->sw_tx_ring.pages) * TX_RING_SIZE;
if (!txq->sw_tx_ring) { txq->sw_tx_ring.pages = kzalloc(size, GFP_KERNEL);
DP_NOTICE(edev, "Tx buffers ring allocation failed\n"); if (!txq->sw_tx_ring.pages)
goto err; goto err;
} else {
size = sizeof(*txq->sw_tx_ring.skbs) * TX_RING_SIZE;
txq->sw_tx_ring.skbs = kzalloc(size, GFP_KERNEL);
if (!txq->sw_tx_ring.skbs)
goto err;
} }
rc = edev->ops->common->chain_alloc(edev->cdev, rc = edev->ops->common->chain_alloc(edev->cdev,
...@@ -3169,26 +3283,31 @@ static void qede_free_mem_fp(struct qede_dev *edev, struct qede_fastpath *fp) ...@@ -3169,26 +3283,31 @@ static void qede_free_mem_fp(struct qede_dev *edev, struct qede_fastpath *fp)
*/ */
static int qede_alloc_mem_fp(struct qede_dev *edev, struct qede_fastpath *fp) static int qede_alloc_mem_fp(struct qede_dev *edev, struct qede_fastpath *fp)
{ {
int rc; int rc = 0;
rc = qede_alloc_mem_sb(edev, fp->sb_info, fp->id); rc = qede_alloc_mem_sb(edev, fp->sb_info, fp->id);
if (rc) if (rc)
goto err; goto out;
if (fp->type & QEDE_FASTPATH_RX) { if (fp->type & QEDE_FASTPATH_RX) {
rc = qede_alloc_mem_rxq(edev, fp->rxq); rc = qede_alloc_mem_rxq(edev, fp->rxq);
if (rc) if (rc)
goto err; goto out;
}
if (fp->type & QEDE_FASTPATH_XDP) {
rc = qede_alloc_mem_txq(edev, fp->xdp_tx);
if (rc)
goto out;
} }
if (fp->type & QEDE_FASTPATH_TX) { if (fp->type & QEDE_FASTPATH_TX) {
rc = qede_alloc_mem_txq(edev, fp->txq); rc = qede_alloc_mem_txq(edev, fp->txq);
if (rc) if (rc)
goto err; goto out;
} }
return 0; out:
err:
return rc; return rc;
} }
...@@ -3236,9 +3355,20 @@ static void qede_init_fp(struct qede_dev *edev) ...@@ -3236,9 +3355,20 @@ static void qede_init_fp(struct qede_dev *edev)
fp->edev = edev; fp->edev = edev;
fp->id = queue_id; fp->id = queue_id;
if (fp->type & QEDE_FASTPATH_XDP) {
fp->xdp_tx->index = QEDE_TXQ_IDX_TO_XDP(edev,
rxq_index);
fp->xdp_tx->is_xdp = 1;
}
if (fp->type & QEDE_FASTPATH_RX) { if (fp->type & QEDE_FASTPATH_RX) {
fp->rxq->rxq_id = rxq_index++; fp->rxq->rxq_id = rxq_index++;
/* Determine how to map buffers for this queue */
if (fp->type & QEDE_FASTPATH_XDP)
fp->rxq->data_direction = DMA_BIDIRECTIONAL;
else
fp->rxq->data_direction = DMA_FROM_DEVICE;
fp->rxq->dev = &edev->pdev->dev; fp->rxq->dev = &edev->pdev->dev;
} }
...@@ -3449,6 +3579,12 @@ static int qede_stop_queues(struct qede_dev *edev) ...@@ -3449,6 +3579,12 @@ static int qede_stop_queues(struct qede_dev *edev)
if (rc) if (rc)
return rc; return rc;
} }
if (fp->type & QEDE_FASTPATH_XDP) {
rc = qede_drain_txq(edev, fp->xdp_tx, true);
if (rc)
return rc;
}
} }
/* Stop all Queues in reverse order */ /* Stop all Queues in reverse order */
...@@ -3471,8 +3607,14 @@ static int qede_stop_queues(struct qede_dev *edev) ...@@ -3471,8 +3607,14 @@ static int qede_stop_queues(struct qede_dev *edev)
} }
} }
if (fp->type & QEDE_FASTPATH_XDP) /* Stop the XDP forwarding queue */
if (fp->type & QEDE_FASTPATH_XDP) {
rc = qede_stop_txq(edev, fp->xdp_tx, i);
if (rc)
return rc;
bpf_prog_put(fp->rxq->xdp_prog); bpf_prog_put(fp->rxq->xdp_prog);
}
} }
/* Stop the vport */ /* Stop the vport */
...@@ -3496,7 +3638,14 @@ static int qede_start_txq(struct qede_dev *edev, ...@@ -3496,7 +3638,14 @@ static int qede_start_txq(struct qede_dev *edev,
memset(&params, 0, sizeof(params)); memset(&params, 0, sizeof(params));
memset(&ret_params, 0, sizeof(ret_params)); memset(&ret_params, 0, sizeof(ret_params));
params.queue_id = txq->index; /* Let the XDP queue share the queue-zone with one of the regular txq.
* We don't really care about its coalescing.
*/
if (txq->is_xdp)
params.queue_id = QEDE_TXQ_XDP_TO_IDX(edev, txq);
else
params.queue_id = txq->index;
params.sb = fp->sb_info->igu_sb_id; params.sb = fp->sb_info->igu_sb_id;
params.sb_idx = sb_idx; params.sb_idx = sb_idx;
...@@ -3601,6 +3750,10 @@ static int qede_start_queues(struct qede_dev *edev, bool clear_stats) ...@@ -3601,6 +3750,10 @@ static int qede_start_queues(struct qede_dev *edev, bool clear_stats)
} }
if (fp->type & QEDE_FASTPATH_XDP) { if (fp->type & QEDE_FASTPATH_XDP) {
rc = qede_start_txq(edev, fp, fp->xdp_tx, i, XDP_PI);
if (rc)
return rc;
fp->rxq->xdp_prog = bpf_prog_add(edev->xdp_prog, 1); fp->rxq->xdp_prog = bpf_prog_add(edev->xdp_prog, 1);
if (IS_ERR(fp->rxq->xdp_prog)) { if (IS_ERR(fp->rxq->xdp_prog)) {
rc = PTR_ERR(fp->rxq->xdp_prog); rc = PTR_ERR(fp->rxq->xdp_prog);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment