data = readq(base + MLXBF_GIGE_RX_MAC_FILTER_GENERAL);
data |= MLXBF_GIGE_RX_MAC_FILTER_EN_MULTICAST;
writeq(data, base + MLXBF_GIGE_RX_MAC_FILTER_GENERAL);
}
data = readq(base + MLXBF_GIGE_RX_MAC_FILTER_GENERAL);
data &= ~MLXBF_GIGE_RX_MAC_FILTER_EN_MULTICAST;
writeq(data, base + MLXBF_GIGE_RX_MAC_FILTER_GENERAL);
}
/* Enable MAC receive filter mask for specified index */
control = readq(base + MLXBF_GIGE_CONTROL);
control |= (MLXBF_GIGE_CONTROL_EN_SPECIFIC_MAC << index);
writeq(control, base + MLXBF_GIGE_CONTROL);
}
/* Disable MAC receive filter mask for specified index */
control = readq(base + MLXBF_GIGE_CONTROL);
control &= ~(MLXBF_GIGE_CONTROL_EN_SPECIFIC_MAC << index);
writeq(control, base + MLXBF_GIGE_CONTROL);
}
/* Enable MAC_ID_RANGE match functionality */
control = readq(base + MLXBF_GIGE_CONTROL);
control |= MLXBF_GIGE_CONTROL_MAC_ID_RANGE_EN;
writeq(control, base + MLXBF_GIGE_CONTROL);
/* Set start of destination MAC range check to 0 */
writeq(0, base + MLXBF_GIGE_RX_MAC_FILTER_DMAC_RANGE_START);
/* Set end of destination MAC range check to all FFs */
end_mac = BCAST_MAC_ADDR;
writeq(end_mac, base + MLXBF_GIGE_RX_MAC_FILTER_DMAC_RANGE_END);
}
/* Disable MAC_ID_RANGE match functionality */
control = readq(base + MLXBF_GIGE_CONTROL);
control &= ~MLXBF_GIGE_CONTROL_MAC_ID_RANGE_EN;
writeq(control, base + MLXBF_GIGE_CONTROL);
/* NOTE: no need to change DMAC_RANGE_START or END; * those values are ignored since MAC_ID_RANGE_EN=0
*/
}
/* Receive Initialization * 1) Configures RX MAC filters via MMIO registers * 2) Allocates RX WQE array using coherent DMA mapping * 3) Initializes each element of RX WQE array with a receive * buffer pointer (also using coherent DMA mapping) * 4) Allocates RX CQE array using coherent DMA mapping * 5) Completes other misc receive initialization
*/ int mlxbf_gige_rx_init(struct mlxbf_gige *priv)
{
size_t wq_size, cq_size;
dma_addr_t *rx_wqe_ptr;
dma_addr_t rx_buf_dma;
u64 data; int i, j;
/* Configure MAC RX filter #0 to allow RX of broadcast pkts */
mlxbf_gige_set_mac_rx_filter(priv, MLXBF_GIGE_BCAST_MAC_FILTER_IDX,
BCAST_MAC_ADDR);
/* Initialize 'rx_wqe_ptr' to point to first RX WQE in array * Each RX WQE is simply a receive buffer pointer, so walk * the entire array, allocating a 2KB buffer for each element
*/
rx_wqe_ptr = priv->rx_wqe_base;
for (i = 0; i < priv->rx_q_entries; i++) {
priv->rx_skb[i] = mlxbf_gige_alloc_skb(priv, MLXBF_GIGE_DEFAULT_BUF_SZ,
&rx_buf_dma, DMA_FROM_DEVICE); if (!priv->rx_skb[i]) goto free_wqe_and_skb;
*rx_wqe_ptr++ = rx_buf_dma;
}
/* Write RX WQE base address into MMIO reg */
writeq(priv->rx_wqe_base_dma, priv->base + MLXBF_GIGE_RX_WQ_BASE);
for (i = 0; i < priv->rx_q_entries; i++)
priv->rx_cqe_base[i] |= MLXBF_GIGE_RX_CQE_VALID_MASK;
/* Write RX CQE base address into MMIO reg */
writeq(priv->rx_cqe_base_dma, priv->base + MLXBF_GIGE_RX_CQ_BASE);
/* Write RX_WQE_PI with current number of replenished buffers */
writeq(priv->rx_q_entries, priv->base + MLXBF_GIGE_RX_WQE_PI);
/* Enable removal of CRC during RX */
data = readq(priv->base + MLXBF_GIGE_RX);
data |= MLXBF_GIGE_RX_STRIP_CRC_EN;
writeq(data, priv->base + MLXBF_GIGE_RX);
/* Enable RX MAC filter pass and discard counters */
writeq(MLXBF_GIGE_RX_MAC_FILTER_COUNT_DISC_EN,
priv->base + MLXBF_GIGE_RX_MAC_FILTER_COUNT_DISC);
writeq(MLXBF_GIGE_RX_MAC_FILTER_COUNT_PASS_EN,
priv->base + MLXBF_GIGE_RX_MAC_FILTER_COUNT_PASS);
/* Clear MLXBF_GIGE_INT_MASK 'receive pkt' bit to * indicate readiness to receive interrupts
*/
data = readq(priv->base + MLXBF_GIGE_INT_MASK);
data &= ~MLXBF_GIGE_INT_MASK_RX_RECEIVE_PACKET;
writeq(data, priv->base + MLXBF_GIGE_INT_MASK);
/* Enable RX DMA to write new packets to memory */
data = readq(priv->base + MLXBF_GIGE_RX_DMA);
data |= MLXBF_GIGE_RX_DMA_EN;
writeq(data, priv->base + MLXBF_GIGE_RX_DMA);
/* Receive Deinitialization * This routine will free allocations done by mlxbf_gige_rx_init(), * namely the RX WQE and RX CQE arrays, as well as all RX buffers
*/ void mlxbf_gige_rx_deinit(struct mlxbf_gige *priv)
{
dma_addr_t *rx_wqe_ptr;
size_t size;
u64 data; int i;
/* Disable RX DMA to prevent packet transfers to memory */
data = readq(priv->base + MLXBF_GIGE_RX_DMA);
data &= ~MLXBF_GIGE_RX_DMA_EN;
writeq(data, priv->base + MLXBF_GIGE_RX_DMA);
rx_wqe_ptr = priv->rx_wqe_base;
for (i = 0; i < priv->rx_q_entries; i++) {
dma_unmap_single(priv->dev, *rx_wqe_ptr, MLXBF_GIGE_DEFAULT_BUF_SZ,
DMA_FROM_DEVICE);
dev_kfree_skb(priv->rx_skb[i]);
rx_wqe_ptr++;
}
/* Index into RX buffer array is rx_pi w/wrap based on RX_CQE_SIZE */
rx_pi = readq(priv->base + MLXBF_GIGE_RX_WQE_PI);
rx_pi_rem = rx_pi % priv->rx_q_entries;
/* Alloc another RX SKB for this same index */
rx_skb = mlxbf_gige_alloc_skb(priv, MLXBF_GIGE_DEFAULT_BUF_SZ,
&rx_buf_dma, DMA_FROM_DEVICE); if (!rx_skb) returnfalse;
priv->rx_skb[rx_pi_rem] = rx_skb;
dma_unmap_single(priv->dev, *rx_wqe_addr,
MLXBF_GIGE_DEFAULT_BUF_SZ, DMA_FROM_DEVICE);
skb_put(skb, datalen);
skb->ip_summed = CHECKSUM_NONE; /* device did not checksum packet */
/* Read receive consumer index before replenish so that this routine * returns accurate return value even if packet is received into * just-replenished buffer prior to exiting this routine.
*/
rx_ci = readq(priv->base + MLXBF_GIGE_RX_CQE_PACKET_CI);
rx_ci_rem = rx_ci % priv->rx_q_entries;
/* Let hardware know we've replenished one buffer */
rx_pi++;
/* Ensure completion of all writes before notifying HW of replenish */
wmb();
writeq(rx_pi, priv->base + MLXBF_GIGE_RX_WQE_PI);
/* Driver poll() function called by NAPI infrastructure */ int mlxbf_gige_poll(struct napi_struct *napi, int budget)
{ struct mlxbf_gige *priv; bool remaining_pkts; int work_done = 0;
u64 data;
do {
remaining_pkts = mlxbf_gige_rx_packet(priv, &work_done);
} while (remaining_pkts && work_done < budget);
/* If amount of work done < budget, turn off NAPI polling * via napi_complete_done(napi, work_done) and then * re-enable interrupts.
*/ if (work_done < budget && napi_complete_done(napi, work_done)) { /* Clear MLXBF_GIGE_INT_MASK 'receive pkt' bit to * indicate receive readiness
*/
data = readq(priv->base + MLXBF_GIGE_INT_MASK);
data &= ~MLXBF_GIGE_INT_MASK_RX_RECEIVE_PACKET;
writeq(data, priv->base + MLXBF_GIGE_INT_MASK);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.