| /* SPDX-License-Identifier: GPL-2.0-only */ |
| /* |
| * SolidRun DPU driver for control plane |
| * |
| * Copyright (C) 2022 SolidRun |
| * |
| * Author: Alvaro Karsz <alvaro.karsz@solid-run.com> |
| * |
| */ |
| #ifndef _SNET_VDPA_H_ |
| #define _SNET_VDPA_H_ |
| |
| #include <linux/vdpa.h> |
| #include <linux/pci.h> |
| |
| #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)) |
| /* VQ struct */ |
| struct snet_vq { |
| /* VQ callback */ |
| struct vdpa_callback cb; |
| /* 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; |
| /* 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 SNET messages */ |
| u32 msg_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 |
| |
| #endif //_SNET_VDPA_H_ |