static void sfc_mcdi_logger(void *arg, efx_log_msg_t type, void *header, size_t header_size, void *data, size_t data_size) { struct sfc_adapter *sa = (struct sfc_adapter *)arg; char buffer[SFC_MCDI_LOG_BUF_SIZE]; size_t pfxsize; size_t start; if (!sa->mcdi.logging) return; /* The format including prefix added by sfc_info() is the format * consumed by the Solarflare netlogdecode tool. */ pfxsize = snprintf(buffer, sizeof(buffer), "MCDI RPC %s:", type == EFX_LOG_MCDI_REQUEST ? "REQ" : type == EFX_LOG_MCDI_RESPONSE ? "RESP" : "???"); start = sfc_mcdi_do_log(sa, buffer, header, header_size, pfxsize, pfxsize); start = sfc_mcdi_do_log(sa, buffer, data, data_size, pfxsize, start); if (start != pfxsize) { buffer[start] = '\0'; sfc_info(sa, "%s", buffer); } }
static size_t sfc_mcdi_do_log(const struct sfc_adapter *sa, char *buffer, void *data, size_t data_size, size_t pfxsize, size_t position) { uint32_t *words = data; /* Space separator plus 2 characters per byte */ const size_t word_str_space = 1 + 2 * sizeof(*words); size_t i; for (i = 0; i < data_size; i += sizeof(*words)) { if (position + word_str_space >= SFC_MCDI_LOG_BUF_SIZE) { /* Flush at SFC_MCDI_LOG_BUF_SIZE with backslash * at the end which is required by netlogdecode. */ buffer[position] = '\0'; sfc_info(sa, "%s \\", buffer); /* Preserve prefix for the next log message */ position = pfxsize; } position += snprintf(buffer + position, SFC_MCDI_LOG_BUF_SIZE - position, " %08x", *words); words++; } return position; }
void sfc_tx_qstop(struct sfc_adapter *sa, unsigned int sw_index) { struct rte_eth_dev_data *dev_data; struct sfc_txq_info *txq_info; struct sfc_txq *txq; unsigned int retry_count; unsigned int wait_count; sfc_log_init(sa, "TxQ = %u", sw_index); SFC_ASSERT(sw_index < sa->txq_count); txq_info = &sa->txq_info[sw_index]; txq = txq_info->txq; if (txq->state == SFC_TXQ_INITIALIZED) return; SFC_ASSERT(txq->state & SFC_TXQ_STARTED); sa->dp_tx->qstop(txq->dp, &txq->evq->read_ptr); /* * Retry TX queue flushing in case of flush failed or * timeout; in the worst case it can delay for 6 seconds */ for (retry_count = 0; ((txq->state & SFC_TXQ_FLUSHED) == 0) && (retry_count < SFC_TX_QFLUSH_ATTEMPTS); ++retry_count) { if (efx_tx_qflush(txq->common) != 0) { txq->state |= SFC_TXQ_FLUSHING; break; } /* * Wait for TX queue flush done or flush failed event at least * SFC_TX_QFLUSH_POLL_WAIT_MS milliseconds and not more * than 2 seconds (SFC_TX_QFLUSH_POLL_WAIT_MS multiplied * by SFC_TX_QFLUSH_POLL_ATTEMPTS) */ wait_count = 0; do { rte_delay_ms(SFC_TX_QFLUSH_POLL_WAIT_MS); sfc_ev_qpoll(txq->evq); } while ((txq->state & SFC_TXQ_FLUSHING) && wait_count++ < SFC_TX_QFLUSH_POLL_ATTEMPTS); if (txq->state & SFC_TXQ_FLUSHING) sfc_err(sa, "TxQ %u flush timed out", sw_index); if (txq->state & SFC_TXQ_FLUSHED) sfc_info(sa, "TxQ %u flushed", sw_index); } sa->dp_tx->qreap(txq->dp); txq->state = SFC_TXQ_INITIALIZED; efx_tx_qdestroy(txq->common); sfc_ev_qstop(txq->evq); /* * It seems to be used by DPDK for debug purposes only ('rte_ether') */ dev_data = sa->eth_dev->data; dev_data->tx_queue_state[sw_index] = RTE_ETH_QUEUE_STATE_STOPPED; }