+/**
+ * Initialize Tx UAR registers for primary process.
+ *
+ * @param txq
+ * Pointer to Tx queue structure.
+ */
+static void
+txq_uar_init(struct txq *txq)
+{
+ struct mlx4_priv *priv = txq->priv;
+ struct mlx4_proc_priv *ppriv = MLX4_PROC_PRIV(PORT_ID(priv));
+
+ MLX4_ASSERT(rte_eal_process_type() == RTE_PROC_PRIMARY);
+ MLX4_ASSERT(ppriv);
+ ppriv->uar_table[txq->stats.idx] = txq->msq.db;
+}
+
+#ifdef HAVE_IBV_MLX4_UAR_MMAP_OFFSET
+/**
+ * Remap UAR register of a Tx queue for secondary process.
+ *
+ * Remapped address is stored at the table in the process private structure of
+ * the device, indexed by queue index.
+ *
+ * @param txq
+ * Pointer to Tx queue structure.
+ * @param fd
+ * Verbs file descriptor to map UAR pages.
+ *
+ * @return
+ * 0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+static int
+txq_uar_init_secondary(struct txq *txq, int fd)
+{
+ struct mlx4_priv *priv = txq->priv;
+ struct mlx4_proc_priv *ppriv = MLX4_PROC_PRIV(PORT_ID(priv));
+ void *addr;
+ uintptr_t uar_va;
+ uintptr_t offset;
+ const size_t page_size = sysconf(_SC_PAGESIZE);
+
+ MLX4_ASSERT(ppriv);
+ /*
+ * As rdma-core, UARs are mapped in size of OS page
+ * size. Ref to libmlx4 function: mlx4_init_context()
+ */
+ uar_va = (uintptr_t)txq->msq.db;
+ offset = uar_va & (page_size - 1); /* Offset in page. */
+ addr = mmap(NULL, page_size, PROT_WRITE, MAP_SHARED, fd,
+ txq->msq.uar_mmap_offset);
+ if (addr == MAP_FAILED) {
+ ERROR("port %u mmap failed for BF reg of txq %u",
+ txq->port_id, txq->stats.idx);
+ rte_errno = ENXIO;
+ return -rte_errno;
+ }
+ addr = RTE_PTR_ADD(addr, offset);
+ ppriv->uar_table[txq->stats.idx] = addr;
+ return 0;
+}
+
+/**
+ * Unmap UAR register of a Tx queue for secondary process.
+ *
+ * @param txq
+ * Pointer to Tx queue structure.
+ */
+static void
+txq_uar_uninit_secondary(struct txq *txq)
+{
+ struct mlx4_proc_priv *ppriv = MLX4_PROC_PRIV(PORT_ID(txq->priv));
+ const size_t page_size = sysconf(_SC_PAGESIZE);
+ void *addr;
+
+ addr = ppriv->uar_table[txq->stats.idx];
+ munmap(RTE_PTR_ALIGN_FLOOR(addr, page_size), page_size);
+}
+
+/**
+ * Initialize Tx UAR registers for secondary process.
+ *
+ * @param dev
+ * Pointer to Ethernet device.
+ * @param fd
+ * Verbs file descriptor to map UAR pages.
+ *
+ * @return
+ * 0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+int
+mlx4_tx_uar_init_secondary(struct rte_eth_dev *dev, int fd)
+{
+ const unsigned int txqs_n = dev->data->nb_tx_queues;
+ struct txq *txq;
+ unsigned int i;
+ int ret;
+
+ MLX4_ASSERT(rte_eal_process_type() == RTE_PROC_SECONDARY);
+ for (i = 0; i != txqs_n; ++i) {
+ txq = dev->data->tx_queues[i];
+ if (!txq)
+ continue;
+ MLX4_ASSERT(txq->stats.idx == (uint16_t)i);
+ ret = txq_uar_init_secondary(txq, fd);
+ if (ret)
+ goto error;
+ }
+ return 0;
+error:
+ /* Rollback. */
+ do {
+ txq = dev->data->tx_queues[i];
+ if (!txq)
+ continue;
+ txq_uar_uninit_secondary(txq);
+ } while (i--);
+ return -rte_errno;
+}
+
+void
+mlx4_tx_uar_uninit_secondary(struct rte_eth_dev *dev)
+{
+ struct mlx4_proc_priv *ppriv =
+ (struct mlx4_proc_priv *)dev->process_private;
+ const size_t page_size = sysconf(_SC_PAGESIZE);
+ void *addr;
+ size_t i;
+
+ if (page_size == (size_t)-1) {
+ ERROR("Failed to get mem page size");
+ return;
+ }
+ for (i = 0; i < ppriv->uar_table_sz; i++) {
+ addr = ppriv->uar_table[i];
+ if (addr)
+ munmap(RTE_PTR_ALIGN_FLOOR(addr, page_size), page_size);
+ }
+}
+
+#else
+int
+mlx4_tx_uar_init_secondary(struct rte_eth_dev *dev __rte_unused,
+ int fd __rte_unused)
+{
+ MLX4_ASSERT(rte_eal_process_type() == RTE_PROC_SECONDARY);
+ ERROR("UAR remap is not supported");
+ rte_errno = ENOTSUP;
+ return -rte_errno;
+}
+
+void
+mlx4_tx_uar_uninit_secondary(struct rte_eth_dev *dev __rte_unused)
+{
+ assert(rte_eal_process_type() == RTE_PROC_SECONDARY);
+ ERROR("UAR remap is not supported");
+}
+#endif
+