# SPDX-License-Identifier: (GPL-2.0 OR Linux-OpenIB) # Copyright (c) 2021 Nvidia, Inc. All rights reserved. See COPYING file #cython: language_level=3 from cpython.mem cimport PyMem_Malloc, PyMem_Free from libc.string cimport strcpy import weakref from pyverbs.pyverbs_error import PyverbsRDMAError cimport pyverbs.providers.mlx5.libmlx5 as dv from pyverbs.base import PyverbsRDMAErrno from pyverbs.base cimport close_weakrefs from pyverbs.device cimport Context cimport pyverbs.libibverbs as v cdef class Mlx5VfioAttr(PyverbsObject): """ Mlx5VfioAttr class, represents mlx5dv_vfio_context_attr C struct. """ def __init__(self, pci_name, flags=0, comp_mask=0): self.pci_name = pci_name self.attr.flags = flags self.attr.comp_mask = comp_mask def __dealloc__(self): if self.attr.pci_name != NULL: PyMem_Free(self.attr.pci_name) self.attr.pci_name = NULL @property def flags(self): return self.attr.flags @flags.setter def flags(self, val): self.attr.flags = val @property def comp_mask(self): return self.attr.comp_mask @comp_mask.setter def comp_mask(self, val): self.attr.comp_mask = val @property def pci_name(self): return self.attr.pci_name[:] @pci_name.setter def pci_name(self, val): if self.attr.pci_name != NULL: PyMem_Free(self.attr.pci_name) pci_name_bytes = val.encode() self.attr.pci_name = PyMem_Malloc(len(pci_name_bytes)) strcpy(self.attr.pci_name, pci_name_bytes) cdef class Mlx5VfioContext(Mlx5Context): """ Mlx5VfioContext class is used to easily initialize and open a context over a mlx5 vfio device. It is initialized based on the passed mlx5 vfio attributes (Mlx5VfioAttr), by getting the relevant vfio device and opening it (creating a context). """ def __init__(self, Mlx5VfioAttr attr): super(Context, self).__init__() cdef v.ibv_device **dev_list self.name = attr.pci_name self.pds = weakref.WeakSet() self.devx_umems = weakref.WeakSet() self.devx_objs = weakref.WeakSet() self.uars = weakref.WeakSet() self.devx_eqs = weakref.WeakSet() dev_list = dv.mlx5dv_get_vfio_device_list(&attr.attr) if dev_list == NULL: raise PyverbsRDMAErrno('Failed to get VFIO device list') self.device = dev_list[0] if self.device == NULL: raise PyverbsRDMAError('Failed to get VFIO device') try: self.context = v.ibv_open_device(self.device) if self.context == NULL: raise PyverbsRDMAErrno('Failed to open mlx5 VFIO device ' f'({self.device.name.decode()})') finally: v.ibv_free_device_list(dev_list) def get_events_fd(self): """ Gets the file descriptor to manage driver events. :return: The file descriptor to be used for managing driver events. """ fd = dv.mlx5dv_vfio_get_events_fd(self.context) if fd < 0: raise PyverbsRDMAError('Failed to get VFIO events FD', -fd) return fd def process_events(self): """ Process events on the vfio device. This method should run from application thread to maintain device events. :return: None """ rc = dv.mlx5dv_vfio_process_events(self.context) if rc: raise PyverbsRDMAError('VFIO process events failed', rc) cpdef close(self): if self.context != NULL: if self.logger: self.logger.debug('Closing Mlx5VfioContext') close_weakrefs([self.pds, self.devx_objs, self.devx_umems, self.uars, self.devx_eqs]) rc = v.ibv_close_device(self.context) if rc != 0: raise PyverbsRDMAErrno(f'Failed to close device {self.name}') self.context = NULL