1/* SPDX-License-Identifier: GPL-2.0-only */
2/*
3 * SolidRun DPU driver for control plane
4 *
5 * Copyright (C) 2022-2023 SolidRun
6 *
7 * Author: Alvaro Karsz <alvaro.karsz@solid-run.com>
8 *
9 */
10#ifndef _SNET_VDPA_H_
11#define _SNET_VDPA_H_
12
13#include <linux/vdpa.h>
14#include <linux/pci.h>
15
16#define SNET_NAME_SIZE 256
17
18#define SNET_ERR(pdev, fmt, ...) dev_err(&(pdev)->dev, "%s"fmt, "snet_vdpa: ", ##__VA_ARGS__)
19#define SNET_WARN(pdev, fmt, ...) dev_warn(&(pdev)->dev, "%s"fmt, "snet_vdpa: ", ##__VA_ARGS__)
20#define SNET_INFO(pdev, fmt, ...) dev_info(&(pdev)->dev, "%s"fmt, "snet_vdpa: ", ##__VA_ARGS__)
21#define SNET_DBG(pdev, fmt, ...) dev_dbg(&(pdev)->dev, "%s"fmt, "snet_vdpa: ", ##__VA_ARGS__)
22#define SNET_HAS_FEATURE(s, f) ((s)->negotiated_features & BIT_ULL(f))
23/* Check if negotiated config version is at least @ver */
24#define SNET_CFG_VER(snet, ver) ((snet)->psnet->negotiated_cfg_ver >= (ver))
25
26/* VQ struct */
27struct snet_vq {
28 /* VQ callback */
29 struct vdpa_callback cb;
30 /* VQ state received from bus */
31 struct vdpa_vq_state vq_state;
32 /* desc base address */
33 u64 desc_area;
34 /* device base address */
35 u64 device_area;
36 /* driver base address */
37 u64 driver_area;
38 /* Queue size */
39 u32 num;
40 /* Serial ID for VQ */
41 u32 sid;
42 /* is ready flag */
43 bool ready;
44 /* IRQ number */
45 u32 irq;
46 /* IRQ index, DPU uses this to parse data from MSI-X table */
47 u32 irq_idx;
48 /* IRQ name */
49 char irq_name[SNET_NAME_SIZE];
50 /* pointer to mapped PCI BAR register used by this VQ to kick */
51 void __iomem *kick_ptr;
52};
53
54struct snet {
55 /* vdpa device */
56 struct vdpa_device vdpa;
57 /* Config callback */
58 struct vdpa_callback cb;
59 /* To lock the control mechanism */
60 struct mutex ctrl_lock;
61 /* Spinlock to protect critical parts in the control mechanism */
62 spinlock_t ctrl_spinlock;
63 /* array of virqueues */
64 struct snet_vq **vqs;
65 /* Used features */
66 u64 negotiated_features;
67 /* Device serial ID */
68 u32 sid;
69 /* device status */
70 u8 status;
71 /* boolean indicating if snet config was passed to the device */
72 bool dpu_ready;
73 /* IRQ number */
74 u32 cfg_irq;
75 /* IRQ index, DPU uses this to parse data from MSI-X table */
76 u32 cfg_irq_idx;
77 /* IRQ name */
78 char cfg_irq_name[SNET_NAME_SIZE];
79 /* BAR to access the VF */
80 void __iomem *bar;
81 /* PCI device */
82 struct pci_dev *pdev;
83 /* Pointer to snet pdev parent device */
84 struct psnet *psnet;
85 /* Pointer to snet config device */
86 struct snet_dev_cfg *cfg;
87};
88
89struct snet_dev_cfg {
90 /* Device ID following VirtIO spec. */
91 u32 virtio_id;
92 /* Number of VQs for this device */
93 u32 vq_num;
94 /* Size of every VQ */
95 u32 vq_size;
96 /* Virtual Function id */
97 u32 vfid;
98 /* Device features, following VirtIO spec */
99 u64 features;
100 /* Reserved for future usage */
101 u32 rsvd[6];
102 /* VirtIO device specific config size */
103 u32 cfg_size;
104 /* VirtIO device specific config address */
105 void __iomem *virtio_cfg;
106} __packed;
107
108struct snet_cfg {
109 /* Magic key */
110 u32 key;
111 /* Size of total config in bytes */
112 u32 cfg_size;
113 /* Config version */
114 u32 cfg_ver;
115 /* Number of Virtual Functions to create */
116 u32 vf_num;
117 /* BAR to use for the VFs */
118 u32 vf_bar;
119 /* Where should we write the SNET's config */
120 u32 host_cfg_off;
121 /* Max. allowed size for a SNET's config */
122 u32 max_size_host_cfg;
123 /* VirtIO config offset in BAR */
124 u32 virtio_cfg_off;
125 /* Offset in PCI BAR for VQ kicks */
126 u32 kick_off;
127 /* Offset in PCI BAR for HW monitoring */
128 u32 hwmon_off;
129 /* Offset in PCI BAR for Control mechanism */
130 u32 ctrl_off;
131 /* Config general flags - enum snet_cfg_flags */
132 u32 flags;
133 /* Reserved for future usage */
134 u32 rsvd[6];
135 /* Number of snet devices */
136 u32 devices_num;
137 /* The actual devices */
138 struct snet_dev_cfg **devs;
139} __packed;
140
141/* SolidNET PCIe device, one device per PCIe physical function */
142struct psnet {
143 /* PCI BARs */
144 void __iomem *bars[PCI_STD_NUM_BARS];
145 /* Negotiated config version */
146 u32 negotiated_cfg_ver;
147 /* Next IRQ index to use in case when the IRQs are allocated from this device */
148 u32 next_irq;
149 /* BAR number used to communicate with the device */
150 u8 barno;
151 /* spinlock to protect data that can be changed by SNET devices */
152 spinlock_t lock;
153 /* Pointer to the device's config read from BAR */
154 struct snet_cfg cfg;
155 /* Name of monitor device */
156 char hwmon_name[SNET_NAME_SIZE];
157};
158
159enum snet_cfg_flags {
160 /* Create a HWMON device */
161 SNET_CFG_FLAG_HWMON = BIT(0),
162 /* USE IRQs from the physical function */
163 SNET_CFG_FLAG_IRQ_PF = BIT(1),
164};
165
166#define PSNET_FLAG_ON(p, f) ((p)->cfg.flags & (f))
167
168static inline u32 psnet_read32(struct psnet *psnet, u32 off)
169{
170 return ioread32(psnet->bars[psnet->barno] + off);
171}
172
173static inline u32 snet_read32(struct snet *snet, u32 off)
174{
175 return ioread32(snet->bar + off);
176}
177
178static inline void snet_write32(struct snet *snet, u32 off, u32 val)
179{
180 iowrite32(val, snet->bar + off);
181}
182
183static inline u64 psnet_read64(struct psnet *psnet, u32 off)
184{
185 u64 val;
186 /* 64bits are written in 2 halves, low part first */
187 val = (u64)psnet_read32(psnet, off);
188 val |= ((u64)psnet_read32(psnet, off: off + 4) << 32);
189 return val;
190}
191
192static inline void snet_write64(struct snet *snet, u32 off, u64 val)
193{
194 /* The DPU expects a 64bit integer in 2 halves, the low part first */
195 snet_write32(snet, off, val: (u32)val);
196 snet_write32(snet, off: off + 4, val: (u32)(val >> 32));
197}
198
199#if IS_ENABLED(CONFIG_HWMON)
200void psnet_create_hwmon(struct pci_dev *pdev);
201#endif
202
203void snet_ctrl_clear(struct snet *snet);
204int snet_destroy_dev(struct snet *snet);
205int snet_read_vq_state(struct snet *snet, u16 idx, struct vdpa_vq_state *state);
206int snet_suspend_dev(struct snet *snet);
207int snet_resume_dev(struct snet *snet);
208
209#endif //_SNET_VDPA_H_
210

source code of linux/drivers/vdpa/solidrun/snet_vdpa.h