151a8f9d7SAlvaro Karsz /* SPDX-License-Identifier: GPL-2.0-only */ 251a8f9d7SAlvaro Karsz /* 351a8f9d7SAlvaro Karsz * SolidRun DPU driver for control plane 451a8f9d7SAlvaro Karsz * 5*3f3a1675SAlvaro Karsz * Copyright (C) 2022-2023 SolidRun 651a8f9d7SAlvaro Karsz * 751a8f9d7SAlvaro Karsz * Author: Alvaro Karsz <alvaro.karsz@solid-run.com> 851a8f9d7SAlvaro Karsz * 951a8f9d7SAlvaro Karsz */ 1051a8f9d7SAlvaro Karsz #ifndef _SNET_VDPA_H_ 1151a8f9d7SAlvaro Karsz #define _SNET_VDPA_H_ 1251a8f9d7SAlvaro Karsz 1351a8f9d7SAlvaro Karsz #include <linux/vdpa.h> 1451a8f9d7SAlvaro Karsz #include <linux/pci.h> 1551a8f9d7SAlvaro Karsz 1651a8f9d7SAlvaro Karsz #define SNET_NAME_SIZE 256 1751a8f9d7SAlvaro Karsz 1851a8f9d7SAlvaro Karsz #define SNET_ERR(pdev, fmt, ...) dev_err(&(pdev)->dev, "%s"fmt, "snet_vdpa: ", ##__VA_ARGS__) 1951a8f9d7SAlvaro Karsz #define SNET_WARN(pdev, fmt, ...) dev_warn(&(pdev)->dev, "%s"fmt, "snet_vdpa: ", ##__VA_ARGS__) 2051a8f9d7SAlvaro Karsz #define SNET_INFO(pdev, fmt, ...) dev_info(&(pdev)->dev, "%s"fmt, "snet_vdpa: ", ##__VA_ARGS__) 2151a8f9d7SAlvaro Karsz #define SNET_DBG(pdev, fmt, ...) dev_dbg(&(pdev)->dev, "%s"fmt, "snet_vdpa: ", ##__VA_ARGS__) 2251a8f9d7SAlvaro Karsz #define SNET_HAS_FEATURE(s, f) ((s)->negotiated_features & BIT_ULL(f)) 23*3f3a1675SAlvaro Karsz /* Check if negotiated config version is at least @ver */ 24*3f3a1675SAlvaro Karsz #define SNET_CFG_VER(snet, ver) ((snet)->psnet->negotiated_cfg_ver >= (ver)) 25*3f3a1675SAlvaro Karsz 2651a8f9d7SAlvaro Karsz /* VQ struct */ 2751a8f9d7SAlvaro Karsz struct snet_vq { 2851a8f9d7SAlvaro Karsz /* VQ callback */ 2951a8f9d7SAlvaro Karsz struct vdpa_callback cb; 30*3f3a1675SAlvaro Karsz /* VQ state received from bus */ 31*3f3a1675SAlvaro Karsz struct vdpa_vq_state vq_state; 3251a8f9d7SAlvaro Karsz /* desc base address */ 3351a8f9d7SAlvaro Karsz u64 desc_area; 3451a8f9d7SAlvaro Karsz /* device base address */ 3551a8f9d7SAlvaro Karsz u64 device_area; 3651a8f9d7SAlvaro Karsz /* driver base address */ 3751a8f9d7SAlvaro Karsz u64 driver_area; 3851a8f9d7SAlvaro Karsz /* Queue size */ 3951a8f9d7SAlvaro Karsz u32 num; 4051a8f9d7SAlvaro Karsz /* Serial ID for VQ */ 4151a8f9d7SAlvaro Karsz u32 sid; 4251a8f9d7SAlvaro Karsz /* is ready flag */ 4351a8f9d7SAlvaro Karsz bool ready; 4451a8f9d7SAlvaro Karsz /* IRQ number */ 4551a8f9d7SAlvaro Karsz u32 irq; 4651a8f9d7SAlvaro Karsz /* IRQ index, DPU uses this to parse data from MSI-X table */ 4751a8f9d7SAlvaro Karsz u32 irq_idx; 4851a8f9d7SAlvaro Karsz /* IRQ name */ 4951a8f9d7SAlvaro Karsz char irq_name[SNET_NAME_SIZE]; 5051a8f9d7SAlvaro Karsz /* pointer to mapped PCI BAR register used by this VQ to kick */ 5151a8f9d7SAlvaro Karsz void __iomem *kick_ptr; 5251a8f9d7SAlvaro Karsz }; 5351a8f9d7SAlvaro Karsz 5451a8f9d7SAlvaro Karsz struct snet { 5551a8f9d7SAlvaro Karsz /* vdpa device */ 5651a8f9d7SAlvaro Karsz struct vdpa_device vdpa; 5751a8f9d7SAlvaro Karsz /* Config callback */ 5851a8f9d7SAlvaro Karsz struct vdpa_callback cb; 59*3f3a1675SAlvaro Karsz /* To lock the control mechanism */ 60*3f3a1675SAlvaro Karsz struct mutex ctrl_lock; 61*3f3a1675SAlvaro Karsz /* Spinlock to protect critical parts in the control mechanism */ 62*3f3a1675SAlvaro Karsz spinlock_t ctrl_spinlock; 6351a8f9d7SAlvaro Karsz /* array of virqueues */ 6451a8f9d7SAlvaro Karsz struct snet_vq **vqs; 6551a8f9d7SAlvaro Karsz /* Used features */ 6651a8f9d7SAlvaro Karsz u64 negotiated_features; 6751a8f9d7SAlvaro Karsz /* Device serial ID */ 6851a8f9d7SAlvaro Karsz u32 sid; 6951a8f9d7SAlvaro Karsz /* device status */ 7051a8f9d7SAlvaro Karsz u8 status; 7151a8f9d7SAlvaro Karsz /* boolean indicating if snet config was passed to the device */ 7251a8f9d7SAlvaro Karsz bool dpu_ready; 7351a8f9d7SAlvaro Karsz /* IRQ number */ 7451a8f9d7SAlvaro Karsz u32 cfg_irq; 7551a8f9d7SAlvaro Karsz /* IRQ index, DPU uses this to parse data from MSI-X table */ 7651a8f9d7SAlvaro Karsz u32 cfg_irq_idx; 7751a8f9d7SAlvaro Karsz /* IRQ name */ 7851a8f9d7SAlvaro Karsz char cfg_irq_name[SNET_NAME_SIZE]; 7951a8f9d7SAlvaro Karsz /* BAR to access the VF */ 8051a8f9d7SAlvaro Karsz void __iomem *bar; 8151a8f9d7SAlvaro Karsz /* PCI device */ 8251a8f9d7SAlvaro Karsz struct pci_dev *pdev; 8351a8f9d7SAlvaro Karsz /* Pointer to snet pdev parent device */ 8451a8f9d7SAlvaro Karsz struct psnet *psnet; 8551a8f9d7SAlvaro Karsz /* Pointer to snet config device */ 8651a8f9d7SAlvaro Karsz struct snet_dev_cfg *cfg; 8751a8f9d7SAlvaro Karsz }; 8851a8f9d7SAlvaro Karsz 8951a8f9d7SAlvaro Karsz struct snet_dev_cfg { 9051a8f9d7SAlvaro Karsz /* Device ID following VirtIO spec. */ 9151a8f9d7SAlvaro Karsz u32 virtio_id; 9251a8f9d7SAlvaro Karsz /* Number of VQs for this device */ 9351a8f9d7SAlvaro Karsz u32 vq_num; 9451a8f9d7SAlvaro Karsz /* Size of every VQ */ 9551a8f9d7SAlvaro Karsz u32 vq_size; 9651a8f9d7SAlvaro Karsz /* Virtual Function id */ 9751a8f9d7SAlvaro Karsz u32 vfid; 9851a8f9d7SAlvaro Karsz /* Device features, following VirtIO spec */ 9951a8f9d7SAlvaro Karsz u64 features; 10051a8f9d7SAlvaro Karsz /* Reserved for future usage */ 10151a8f9d7SAlvaro Karsz u32 rsvd[6]; 10251a8f9d7SAlvaro Karsz /* VirtIO device specific config size */ 10351a8f9d7SAlvaro Karsz u32 cfg_size; 10451a8f9d7SAlvaro Karsz /* VirtIO device specific config address */ 10551a8f9d7SAlvaro Karsz void __iomem *virtio_cfg; 10651a8f9d7SAlvaro Karsz } __packed; 10751a8f9d7SAlvaro Karsz 10851a8f9d7SAlvaro Karsz struct snet_cfg { 10951a8f9d7SAlvaro Karsz /* Magic key */ 11051a8f9d7SAlvaro Karsz u32 key; 11151a8f9d7SAlvaro Karsz /* Size of total config in bytes */ 11251a8f9d7SAlvaro Karsz u32 cfg_size; 11351a8f9d7SAlvaro Karsz /* Config version */ 11451a8f9d7SAlvaro Karsz u32 cfg_ver; 11551a8f9d7SAlvaro Karsz /* Number of Virtual Functions to create */ 11651a8f9d7SAlvaro Karsz u32 vf_num; 11751a8f9d7SAlvaro Karsz /* BAR to use for the VFs */ 11851a8f9d7SAlvaro Karsz u32 vf_bar; 11951a8f9d7SAlvaro Karsz /* Where should we write the SNET's config */ 12051a8f9d7SAlvaro Karsz u32 host_cfg_off; 12151a8f9d7SAlvaro Karsz /* Max. allowed size for a SNET's config */ 12251a8f9d7SAlvaro Karsz u32 max_size_host_cfg; 12351a8f9d7SAlvaro Karsz /* VirtIO config offset in BAR */ 12451a8f9d7SAlvaro Karsz u32 virtio_cfg_off; 12551a8f9d7SAlvaro Karsz /* Offset in PCI BAR for VQ kicks */ 12651a8f9d7SAlvaro Karsz u32 kick_off; 12751a8f9d7SAlvaro Karsz /* Offset in PCI BAR for HW monitoring */ 12851a8f9d7SAlvaro Karsz u32 hwmon_off; 129*3f3a1675SAlvaro Karsz /* Offset in PCI BAR for Control mechanism */ 130*3f3a1675SAlvaro Karsz u32 ctrl_off; 13151a8f9d7SAlvaro Karsz /* Config general flags - enum snet_cfg_flags */ 13251a8f9d7SAlvaro Karsz u32 flags; 13351a8f9d7SAlvaro Karsz /* Reserved for future usage */ 13451a8f9d7SAlvaro Karsz u32 rsvd[6]; 13551a8f9d7SAlvaro Karsz /* Number of snet devices */ 13651a8f9d7SAlvaro Karsz u32 devices_num; 13751a8f9d7SAlvaro Karsz /* The actual devices */ 13851a8f9d7SAlvaro Karsz struct snet_dev_cfg **devs; 13951a8f9d7SAlvaro Karsz } __packed; 14051a8f9d7SAlvaro Karsz 14151a8f9d7SAlvaro Karsz /* SolidNET PCIe device, one device per PCIe physical function */ 14251a8f9d7SAlvaro Karsz struct psnet { 14351a8f9d7SAlvaro Karsz /* PCI BARs */ 14451a8f9d7SAlvaro Karsz void __iomem *bars[PCI_STD_NUM_BARS]; 14551a8f9d7SAlvaro Karsz /* Negotiated config version */ 14651a8f9d7SAlvaro Karsz u32 negotiated_cfg_ver; 14751a8f9d7SAlvaro Karsz /* Next IRQ index to use in case when the IRQs are allocated from this device */ 14851a8f9d7SAlvaro Karsz u32 next_irq; 14951a8f9d7SAlvaro Karsz /* BAR number used to communicate with the device */ 15051a8f9d7SAlvaro Karsz u8 barno; 15151a8f9d7SAlvaro Karsz /* spinlock to protect data that can be changed by SNET devices */ 15251a8f9d7SAlvaro Karsz spinlock_t lock; 15351a8f9d7SAlvaro Karsz /* Pointer to the device's config read from BAR */ 15451a8f9d7SAlvaro Karsz struct snet_cfg cfg; 15551a8f9d7SAlvaro Karsz /* Name of monitor device */ 15651a8f9d7SAlvaro Karsz char hwmon_name[SNET_NAME_SIZE]; 15751a8f9d7SAlvaro Karsz }; 15851a8f9d7SAlvaro Karsz 15951a8f9d7SAlvaro Karsz enum snet_cfg_flags { 16051a8f9d7SAlvaro Karsz /* Create a HWMON device */ 16151a8f9d7SAlvaro Karsz SNET_CFG_FLAG_HWMON = BIT(0), 16251a8f9d7SAlvaro Karsz /* USE IRQs from the physical function */ 16351a8f9d7SAlvaro Karsz SNET_CFG_FLAG_IRQ_PF = BIT(1), 16451a8f9d7SAlvaro Karsz }; 16551a8f9d7SAlvaro Karsz 16651a8f9d7SAlvaro Karsz #define PSNET_FLAG_ON(p, f) ((p)->cfg.flags & (f)) 16751a8f9d7SAlvaro Karsz 16851a8f9d7SAlvaro Karsz static inline u32 psnet_read32(struct psnet *psnet, u32 off) 16951a8f9d7SAlvaro Karsz { 17051a8f9d7SAlvaro Karsz return ioread32(psnet->bars[psnet->barno] + off); 17151a8f9d7SAlvaro Karsz } 17251a8f9d7SAlvaro Karsz 17351a8f9d7SAlvaro Karsz static inline u32 snet_read32(struct snet *snet, u32 off) 17451a8f9d7SAlvaro Karsz { 17551a8f9d7SAlvaro Karsz return ioread32(snet->bar + off); 17651a8f9d7SAlvaro Karsz } 17751a8f9d7SAlvaro Karsz 17851a8f9d7SAlvaro Karsz static inline void snet_write32(struct snet *snet, u32 off, u32 val) 17951a8f9d7SAlvaro Karsz { 18051a8f9d7SAlvaro Karsz iowrite32(val, snet->bar + off); 18151a8f9d7SAlvaro Karsz } 18251a8f9d7SAlvaro Karsz 18351a8f9d7SAlvaro Karsz static inline u64 psnet_read64(struct psnet *psnet, u32 off) 18451a8f9d7SAlvaro Karsz { 18551a8f9d7SAlvaro Karsz u64 val; 18651a8f9d7SAlvaro Karsz /* 64bits are written in 2 halves, low part first */ 18751a8f9d7SAlvaro Karsz val = (u64)psnet_read32(psnet, off); 18851a8f9d7SAlvaro Karsz val |= ((u64)psnet_read32(psnet, off + 4) << 32); 18951a8f9d7SAlvaro Karsz return val; 19051a8f9d7SAlvaro Karsz } 19151a8f9d7SAlvaro Karsz 19251a8f9d7SAlvaro Karsz static inline void snet_write64(struct snet *snet, u32 off, u64 val) 19351a8f9d7SAlvaro Karsz { 19451a8f9d7SAlvaro Karsz /* The DPU expects a 64bit integer in 2 halves, the low part first */ 19551a8f9d7SAlvaro Karsz snet_write32(snet, off, (u32)val); 19651a8f9d7SAlvaro Karsz snet_write32(snet, off + 4, (u32)(val >> 32)); 19751a8f9d7SAlvaro Karsz } 19851a8f9d7SAlvaro Karsz 19951a8f9d7SAlvaro Karsz #if IS_ENABLED(CONFIG_HWMON) 20051a8f9d7SAlvaro Karsz void psnet_create_hwmon(struct pci_dev *pdev); 20151a8f9d7SAlvaro Karsz #endif 20251a8f9d7SAlvaro Karsz 203*3f3a1675SAlvaro Karsz void snet_ctrl_clear(struct snet *snet); 204*3f3a1675SAlvaro Karsz int snet_destroy_dev(struct snet *snet); 205*3f3a1675SAlvaro Karsz int snet_read_vq_state(struct snet *snet, u16 idx, struct vdpa_vq_state *state); 206*3f3a1675SAlvaro Karsz 20751a8f9d7SAlvaro Karsz #endif //_SNET_VDPA_H_ 208