#include <vlib/linux/vfio.h>
#include <base/roc_api.h>
#include <common.h>
+#include "octeon.h"
static oct_plt_memzone_list_t memzone_list;
if (align)
{
/* Force ROC align alloc in case alignment is less than ROC align */
- align = align < ROC_ALIGN ? ROC_ALIGN : align;
+ align = ((align + ROC_ALIGN - 1) & ~(ROC_ALIGN - 1));
mem = vlib_physmem_alloc_aligned_on_numa (vm, size, align, 0);
}
else
return oct_drv_physmem_alloc (vm, size, align);
}
-static oct_plt_memzone_t *
-memzone_get (u32 index)
+static void *
+oct_plt_realloc (void *addr, u32 size, u32 align)
{
- if (index == ((u32) ~0))
- return 0;
+ align = CLIB_CACHE_LINE_ROUND (align);
+ size = CLIB_CACHE_LINE_ROUND (size);
- return pool_elt_at_index (memzone_list.mem_pool, index);
+ if (align)
+ return clib_mem_realloc_aligned (addr, size, align);
+ else
+ return clib_mem_realloc (addr, size);
}
-static int
-oct_plt_memzone_free (const oct_plt_memzone_t *name)
+static oct_plt_memzone_t *
+oct_plt_memzone_lookup (const char *name)
{
- uword *p;
- p = hash_get_mem (memzone_list.memzone_by_name, name);
-
- if (p[0] == ((u32) ~0))
- return -EINVAL;
-
- hash_unset_mem (memzone_list.memzone_by_name, name);
+ oct_plt_memzone_t *mem_pool;
- pool_put_index (memzone_list.mem_pool, p[0]);
+ pool_foreach (mem_pool, memzone_list.mem_pool)
+ {
+ if (!clib_strcmp (mem_pool->name, name))
+ return mem_pool;
+ }
return 0;
}
-static oct_plt_memzone_t *
-oct_plt_memzone_lookup (const char *name)
+static int
+oct_plt_memzone_free (const oct_plt_memzone_t *mz)
{
- uword *p;
- p = hash_get_mem (memzone_list.memzone_by_name, name);
- if (p)
- return memzone_get (p[0]);
+ if (!mz || !oct_plt_memzone_lookup (mz->name))
+ return -EINVAL;
+
+ pool_put (memzone_list.mem_pool, mz);
return 0;
}
mem_pool->addr = p;
mem_pool->index = mem_pool - memzone_list.mem_pool;
- hash_set_mem (memzone_list.memzone_by_name, name, mem_pool->index);
+ strcpy (mem_pool->name, name);
return mem_pool;
}
+static void
+plt_msix_handler (vlib_main_t *vm, vlib_pci_dev_handle_t handle, uint16_t line)
+{
+ vnet_dev_t *dev = (vnet_dev_t *) vlib_pci_get_private_data (vm, handle);
+ oct_device_t *cd = vnet_dev_get_data (dev);
+
+ if (cd->msix_handler && cd->msix_handler[line].fn)
+ cd->msix_handler[line].fn (cd->msix_handler[line].data);
+}
+
+static int
+oct_plt_get_num_vectors (oct_pci_dev_handle_t handle)
+{
+ vlib_main_t *vm = vlib_get_main ();
+
+ return vlib_pci_get_num_msix_interrupts (vm, handle);
+}
+
+static int
+oct_plt_intr_enable (oct_pci_dev_handle_t handle, uint16_t start,
+ uint16_t count, uint8_t enable,
+ enum oct_msix_rsrc_op_t op)
+{
+ vlib_main_t *vm = vlib_get_main ();
+ vnet_dev_t *dev = (vnet_dev_t *) vlib_pci_get_private_data (vm, handle);
+ oct_device_t *cd = vnet_dev_get_data (dev);
+ clib_error_t *error = NULL;
+
+ if (op == OCT_MSIX_RSRC_ALLOC)
+ {
+ if (cd->msix_handler)
+ {
+ clib_warning ("MSIX handlers already allocated\n");
+ return -EINVAL;
+ }
+ cd->msix_handler = malloc (sizeof (*cd->msix_handler) * (start + count));
+ if (!cd->msix_handler)
+ {
+ clib_warning ("MSIX handlers alilocation failed\n");
+ return -ENOMEM;
+ }
+ }
+ if (enable)
+ error = vlib_pci_enable_msix_irq (vm, handle, start, count);
+ else
+ error = vlib_pci_disable_msix_irq (vm, handle, start, count);
+ if (error)
+ {
+ clib_error_report (error);
+ return -EINVAL;
+ }
+ if (op == OCT_MSIX_RSRC_FREE)
+ {
+ if (cd->msix_handler)
+ free (cd->msix_handler);
+ }
+
+ return 0;
+}
+
+static int
+oct_plt_intr_config (oct_pci_dev_handle_t handle, uint32_t vec,
+ plt_msix_handler_function_t handler, void *data,
+ int enable)
+{
+ vlib_main_t *vm = vlib_get_main ();
+ vnet_dev_t *dev = (vnet_dev_t *) vlib_pci_get_private_data (vm, handle);
+ oct_device_t *cd = vnet_dev_get_data (dev);
+ clib_error_t *error = NULL;
+
+ /* Skip AF_PF_MBOX interrupt FIXME */
+ if (vec == RVU_PF_INT_VEC_AFPF_MBOX)
+ return 0;
+
+ if (enable)
+ {
+ error =
+ vlib_pci_register_msix_handler (vm, handle, vec, 1, plt_msix_handler);
+ if (error)
+ {
+ clib_error_report (error);
+ return -EINVAL;
+ }
+ if (cd->msix_handler)
+ {
+ cd->msix_handler[vec].fn = handler;
+ cd->msix_handler[vec].vec = vec;
+ cd->msix_handler[vec].data = data;
+ }
+ error = vlib_pci_enable_msix_irq (vm, handle, vec, 1);
+ if (error)
+ {
+ clib_error_report (error);
+ return -EINVAL;
+ }
+ }
+ else
+ {
+ error = vlib_pci_disable_msix_irq (vm, handle, vec, 1);
+ if (error)
+ {
+ clib_error_report (error);
+ return -EINVAL;
+ }
+ error = vlib_pci_unregister_msix_handler (vm, handle, vec, 1);
+ if (error)
+ {
+ clib_error_report (error);
+ return -EINVAL;
+ }
+ if (cd->msix_handler)
+ {
+ cd->msix_handler[vec].fn = NULL;
+ cd->msix_handler[vec].data = NULL;
+ }
+ }
+
+ return 0;
+}
+
+static inline __attribute__ ((__always_inline__)) int
+plt_intr_max_intr_get (const struct plt_intr_handle *intr_handle)
+{
+ if (!intr_handle)
+ return -EINVAL;
+
+ return intr_handle->max_intr;
+}
+
+static inline __attribute__ ((__always_inline__)) int
+plt_intr_max_intr_set (struct plt_intr_handle *intr_handle, int max_intr)
+{
+ if (!intr_handle)
+ return -EINVAL;
+
+ intr_handle->max_intr = max_intr;
+
+ return 0;
+}
+
+static int
+irq_get_info (struct plt_intr_handle *intr_handle)
+{
+ int num_vec;
+
+ num_vec = oct_plt_get_num_vectors (intr_handle->pci_handle);
+ if (num_vec == 0)
+ {
+ plt_err ("HW max=%d > PLT_MAX_RXTX_INTR_VEC_ID: %d", num_vec,
+ PLT_MAX_RXTX_INTR_VEC_ID);
+ plt_intr_max_intr_set (intr_handle, PLT_MAX_RXTX_INTR_VEC_ID);
+ }
+ else
+ {
+ if (plt_intr_max_intr_set (intr_handle, num_vec))
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+irq_init (struct plt_intr_handle *intr_handle)
+{
+ int rc = oct_plt_intr_enable (intr_handle->pci_handle, 0,
+ plt_intr_max_intr_get (intr_handle), 0,
+ OCT_MSIX_RSRC_ALLOC);
+
+ if (rc)
+ plt_err ("Failed to set irqs vector rc=%d", rc);
+
+ return rc;
+}
+
+static int
+oct_plt_irq_register (struct oct_pci_intr_handle *intr_handle,
+ oct_plt_pci_intr_callback_fn cb, void *data,
+ unsigned int vec)
+{
+ /* If no max_intr read from VFIO */
+ if (plt_intr_max_intr_get (intr_handle) == 0)
+ {
+ irq_get_info (intr_handle);
+ irq_init (intr_handle);
+ }
+
+ if (vec > (uint32_t) plt_intr_max_intr_get (intr_handle))
+ {
+ plt_err ("Error registering MSI-X interrupts vec:%d > %d", vec,
+ plt_intr_max_intr_get (intr_handle));
+ return -EINVAL;
+ }
+
+ oct_plt_intr_config (intr_handle->pci_handle, vec, cb, data, 1);
+
+ return 0;
+}
+
+static void
+oct_plt_irq_unregister (struct oct_pci_intr_handle *intr_handle,
+ oct_plt_pci_intr_callback_fn cb, void *data,
+ unsigned int vec)
+{
+ if (vec > (uint32_t) plt_intr_max_intr_get (intr_handle))
+ {
+ plt_err ("Error unregistering MSI-X interrupts vec:%d > %d", vec,
+ plt_intr_max_intr_get (intr_handle));
+ return;
+ }
+
+ oct_plt_intr_config (intr_handle->pci_handle, vec, cb, data, 0);
+}
+
+static int
+oct_plt_irq_disable (struct oct_pci_intr_handle *intr_handle)
+{
+ int rc = -EINVAL;
+
+ if (!intr_handle)
+ return rc;
+
+ /* Clear max_intr to indicate re-init next time */
+ rc = oct_plt_intr_enable (intr_handle->pci_handle, 0,
+ plt_intr_max_intr_get (intr_handle), 0,
+ OCT_MSIX_RSRC_FREE);
+ plt_intr_max_intr_set (intr_handle, 0);
+ return rc;
+}
+
+static int
+oct_plt_irq_reconfigure (struct oct_pci_intr_handle *intr_handle,
+ uint16_t max_intr)
+{
+ /* Disable interrupts if enabled. */
+ if (plt_intr_max_intr_get (intr_handle))
+ oct_plt_irq_disable (intr_handle);
+
+ plt_intr_max_intr_set (intr_handle, max_intr);
+ return irq_init (intr_handle);
+}
+
oct_plt_init_param_t oct_plt_init_param = {
.oct_plt_log_reg_class = vlib_log_register_class,
.oct_plt_log = oct_plt_log,
.oct_plt_free = oct_plt_free,
.oct_plt_zmalloc = oct_plt_zmalloc,
+ .oct_plt_realloc = oct_plt_realloc,
.oct_plt_memzone_free = oct_plt_memzone_free,
.oct_plt_memzone_lookup = oct_plt_memzone_lookup,
.oct_plt_memzone_reserve_aligned = oct_plt_memzone_reserve_aligned,
.oct_plt_spinlock_trylock = oct_plt_spinlock_trylock,
.oct_plt_get_thread_index = oct_plt_get_thread_index,
.oct_plt_get_cache_line_size = oct_plt_get_cache_line_size,
+ .oct_plt_irq_reconfigure = oct_plt_irq_reconfigure,
+ .oct_plt_irq_register = oct_plt_irq_register,
+ .oct_plt_irq_unregister = oct_plt_irq_unregister,
+ .oct_plt_irq_disable = oct_plt_irq_disable
};