/* SPDX-License-Identifier: GPL-2.0-only */ /* * SolidRun DPU driver for control plane * * Copyright (C) 2022-2023 SolidRun * * Author: Alvaro Karsz * */ #ifndef _SNET_VDPA_H_ #define _SNET_VDPA_H_ #include #include #define SNET_NAME_SIZE 256 #define SNET_ERR(pdev, fmt, ...) dev_err(&(pdev)->dev, "%s"fmt, "snet_vdpa: ", ##__VA_ARGS__) #define SNET_WARN(pdev, fmt, ...) dev_warn(&(pdev)->dev, "%s"fmt, "snet_vdpa: ", ##__VA_ARGS__) #define SNET_INFO(pdev, fmt, ...) dev_info(&(pdev)->dev, "%s"fmt, "snet_vdpa: ", ##__VA_ARGS__) #define SNET_DBG(pdev, fmt, ...) dev_dbg(&(pdev)->dev, "%s"fmt, "snet_vdpa: ", ##__VA_ARGS__) #define SNET_HAS_FEATURE(s, f) ((s)->negotiated_features & BIT_ULL(f)) /* Check if negotiated config version is at least @ver */ #define SNET_CFG_VER(snet, ver) ((snet)->psnet->negotiated_cfg_ver >= (ver)) /* VQ struct */ struct snet_vq { /* VQ callback */ struct vdpa_callback cb; /* VQ state received from bus */ struct vdpa_vq_state vq_state; /* desc base address */ u64 desc_area; /* device base address */ u64 device_area; /* driver base address */ u64 driver_area; /* Queue size */ u32 num; /* Serial ID for VQ */ u32 sid; /* is ready flag */ bool ready; /* IRQ number */ u32 irq; /* IRQ index, DPU uses this to parse data from MSI-X table */ u32 irq_idx; /* IRQ name */ char irq_name[SNET_NAME_SIZE]; /* pointer to mapped PCI BAR register used by this VQ to kick */ void __iomem *kick_ptr; }; struct snet { /* vdpa device */ struct vdpa_device vdpa; /* Config callback */ struct vdpa_callback cb; /* To lock the control mechanism */ struct mutex ctrl_lock; /* Spinlock to protect critical parts in the control mechanism */ spinlock_t ctrl_spinlock; /* array of virqueues */ struct snet_vq **vqs; /* Used features */ u64 negotiated_features; /* Device serial ID */ u32 sid; /* device status */ u8 status; /* boolean indicating if snet config was passed to the device */ bool dpu_ready; /* IRQ number */ u32 cfg_irq; /* IRQ index, DPU uses this to parse data from MSI-X table */ u32 cfg_irq_idx; /* IRQ name */ char cfg_irq_name[SNET_NAME_SIZE]; /* BAR to access the VF */ void __iomem *bar; /* PCI device */ struct pci_dev *pdev; /* Pointer to snet pdev parent device */ struct psnet *psnet; /* Pointer to snet config device */ struct snet_dev_cfg *cfg; }; struct snet_dev_cfg { /* Device ID following VirtIO spec. */ u32 virtio_id; /* Number of VQs for this device */ u32 vq_num; /* Size of every VQ */ u32 vq_size; /* Virtual Function id */ u32 vfid; /* Device features, following VirtIO spec */ u64 features; /* Reserved for future usage */ u32 rsvd[6]; /* VirtIO device specific config size */ u32 cfg_size; /* VirtIO device specific config address */ void __iomem *virtio_cfg; } __packed; struct snet_cfg { /* Magic key */ u32 key; /* Size of total config in bytes */ u32 cfg_size; /* Config version */ u32 cfg_ver; /* Number of Virtual Functions to create */ u32 vf_num; /* BAR to use for the VFs */ u32 vf_bar; /* Where should we write the SNET's config */ u32 host_cfg_off; /* Max. allowed size for a SNET's config */ u32 max_size_host_cfg; /* VirtIO config offset in BAR */ u32 virtio_cfg_off; /* Offset in PCI BAR for VQ kicks */ u32 kick_off; /* Offset in PCI BAR for HW monitoring */ u32 hwmon_off; /* Offset in PCI BAR for Control mechanism */ u32 ctrl_off; /* Config general flags - enum snet_cfg_flags */ u32 flags; /* Reserved for future usage */ u32 rsvd[6]; /* Number of snet devices */ u32 devices_num; /* The actual devices */ struct snet_dev_cfg **devs; } __packed; /* SolidNET PCIe device, one device per PCIe physical function */ struct psnet { /* PCI BARs */ void __iomem *bars[PCI_STD_NUM_BARS]; /* Negotiated config version */ u32 negotiated_cfg_ver; /* Next IRQ index to use in case when the IRQs are allocated from this device */ u32 next_irq; /* BAR number used to communicate with the device */ u8 barno; /* spinlock to protect data that can be changed by SNET devices */ spinlock_t lock; /* Pointer to the device's config read from BAR */ struct snet_cfg cfg; /* Name of monitor device */ char hwmon_name[SNET_NAME_SIZE]; }; enum snet_cfg_flags { /* Create a HWMON device */ SNET_CFG_FLAG_HWMON = BIT(0), /* USE IRQs from the physical function */ SNET_CFG_FLAG_IRQ_PF = BIT(1), }; #define PSNET_FLAG_ON(p, f) ((p)->cfg.flags & (f)) static inline u32 psnet_read32(struct psnet *psnet, u32 off) { return ioread32(psnet->bars[psnet->barno] + off); } static inline u32 snet_read32(struct snet *snet, u32 off) { return ioread32(snet->bar + off); } static inline void snet_write32(struct snet *snet, u32 off, u32 val) { iowrite32(val, snet->bar + off); } static inline u64 psnet_read64(struct psnet *psnet, u32 off) { u64 val; /* 64bits are written in 2 halves, low part first */ val = (u64)psnet_read32(psnet, off); val |= ((u64)psnet_read32(psnet, off + 4) << 32); return val; } static inline void snet_write64(struct snet *snet, u32 off, u64 val) { /* The DPU expects a 64bit integer in 2 halves, the low part first */ snet_write32(snet, off, (u32)val); snet_write32(snet, off + 4, (u32)(val >> 32)); } #if IS_ENABLED(CONFIG_HWMON) void psnet_create_hwmon(struct pci_dev *pdev); #endif void snet_ctrl_clear(struct snet *snet); int snet_destroy_dev(struct snet *snet); int snet_read_vq_state(struct snet *snet, u16 idx, struct vdpa_vq_state *state); int snet_suspend_dev(struct snet *snet); int snet_resume_dev(struct snet *snet); #endif //_SNET_VDPA_H_