Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

pds_core: add devcmd device interfaces

The devcmd interface is the basic connection to the device through the
PCI BAR for low level identification and command services. This does
the early device initialization and finds the identity data, and adds
devcmd routines to be used by later driver bits.

Signed-off-by: Shannon Nelson <shannon.nelson@amd.com>
Acked-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Shannon Nelson and committed by
David S. Miller
523847df 55435ea7

+699 -3
+3 -1
drivers/net/ethernet/amd/pds_core/Makefile
··· 3 3 4 4 obj-$(CONFIG_PDS_CORE) := pds_core.o 5 5 6 - pds_core-y := main.o 6 + pds_core-y := main.o \ 7 + dev.o \ 8 + core.o 7 9 8 10 pds_core-$(CONFIG_DEBUG_FS) += debugfs.o
+36
drivers/net/ethernet/amd/pds_core/core.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* Copyright(c) 2023 Advanced Micro Devices, Inc */ 3 + 4 + #include "core.h" 5 + 6 + int pdsc_setup(struct pdsc *pdsc, bool init) 7 + { 8 + int err = 0; 9 + 10 + if (init) 11 + err = pdsc_dev_init(pdsc); 12 + else 13 + err = pdsc_dev_reinit(pdsc); 14 + if (err) 15 + return err; 16 + 17 + clear_bit(PDSC_S_FW_DEAD, &pdsc->state); 18 + return 0; 19 + } 20 + 21 + void pdsc_teardown(struct pdsc *pdsc, bool removing) 22 + { 23 + pdsc_devcmd_reset(pdsc); 24 + 25 + if (removing) { 26 + kfree(pdsc->intr_info); 27 + pdsc->intr_info = NULL; 28 + } 29 + 30 + if (pdsc->kern_dbpage) { 31 + iounmap(pdsc->kern_dbpage); 32 + pdsc->kern_dbpage = NULL; 33 + } 34 + 35 + set_bit(PDSC_S_FW_DEAD, &pdsc->state); 36 + }
+50
drivers/net/ethernet/amd/pds_core/core.h
··· 9 9 10 10 #include <linux/pds/pds_common.h> 11 11 #include <linux/pds/pds_core_if.h> 12 + #include <linux/pds/pds_intr.h> 12 13 13 14 #define PDSC_DRV_DESCRIPTION "AMD/Pensando Core Driver" 15 + #define PDSC_TEARDOWN_RECOVERY false 16 + #define PDSC_TEARDOWN_REMOVING true 17 + #define PDSC_SETUP_RECOVERY false 18 + #define PDSC_SETUP_INIT true 14 19 15 20 struct pdsc_dev_bar { 16 21 void __iomem *vaddr; 17 22 phys_addr_t bus_addr; 18 23 unsigned long len; 19 24 int res_index; 25 + }; 26 + 27 + struct pdsc_devinfo { 28 + u8 asic_type; 29 + u8 asic_rev; 30 + char fw_version[PDS_CORE_DEVINFO_FWVERS_BUFLEN + 1]; 31 + char serial_num[PDS_CORE_DEVINFO_SERIAL_BUFLEN + 1]; 32 + }; 33 + 34 + #define PDSC_INTR_NAME_MAX_SZ 32 35 + 36 + struct pdsc_intr_info { 37 + char name[PDSC_INTR_NAME_MAX_SZ]; 38 + unsigned int index; 39 + unsigned int vector; 40 + void *data; 20 41 }; 21 42 22 43 /* No state flags set means we are in a steady running state */ ··· 59 38 int uid; 60 39 61 40 unsigned long state; 41 + u8 fw_status; 42 + u8 fw_generation; 43 + unsigned long last_fw_time; 44 + u32 last_hb; 62 45 46 + struct pdsc_devinfo dev_info; 47 + struct pds_core_dev_identity dev_ident; 48 + unsigned int nintrs; 49 + struct pdsc_intr_info *intr_info; /* array of nintrs elements */ 50 + 51 + unsigned int devcmd_timeout; 52 + struct mutex devcmd_lock; /* lock for dev_cmd operations */ 53 + struct mutex config_lock; /* lock for configuration operations */ 63 54 struct pds_core_dev_info_regs __iomem *info_regs; 64 55 struct pds_core_dev_cmd_regs __iomem *cmd_regs; 65 56 struct pds_core_intr __iomem *intr_ctrl; ··· 85 52 void pdsc_debugfs_destroy(void); 86 53 void pdsc_debugfs_add_dev(struct pdsc *pdsc); 87 54 void pdsc_debugfs_del_dev(struct pdsc *pdsc); 55 + void pdsc_debugfs_add_ident(struct pdsc *pdsc); 56 + void pdsc_debugfs_add_irqs(struct pdsc *pdsc); 57 + 58 + int pdsc_err_to_errno(enum pds_core_status_code code); 59 + bool pdsc_is_fw_running(struct pdsc *pdsc); 60 + bool pdsc_is_fw_good(struct pdsc *pdsc); 61 + int pdsc_devcmd(struct pdsc *pdsc, union pds_core_dev_cmd *cmd, 62 + union pds_core_dev_comp *comp, int max_seconds); 63 + int pdsc_devcmd_locked(struct pdsc *pdsc, union pds_core_dev_cmd *cmd, 64 + union pds_core_dev_comp *comp, int max_seconds); 65 + int pdsc_devcmd_init(struct pdsc *pdsc); 66 + int pdsc_devcmd_reset(struct pdsc *pdsc); 67 + int pdsc_dev_reinit(struct pdsc *pdsc); 68 + int pdsc_dev_init(struct pdsc *pdsc); 69 + 70 + int pdsc_setup(struct pdsc *pdsc, bool init); 71 + void pdsc_teardown(struct pdsc *pdsc, bool removing); 88 72 89 73 #endif /* _PDSC_H_ */
+38
drivers/net/ethernet/amd/pds_core/debugfs.c
··· 29 29 debugfs_remove_recursive(pdsc->dentry); 30 30 pdsc->dentry = NULL; 31 31 } 32 + 33 + static int identity_show(struct seq_file *seq, void *v) 34 + { 35 + struct pdsc *pdsc = seq->private; 36 + struct pds_core_dev_identity *ident; 37 + int vt; 38 + 39 + ident = &pdsc->dev_ident; 40 + 41 + seq_printf(seq, "fw_heartbeat: 0x%x\n", 42 + ioread32(&pdsc->info_regs->fw_heartbeat)); 43 + 44 + seq_printf(seq, "nlifs: %d\n", 45 + le32_to_cpu(ident->nlifs)); 46 + seq_printf(seq, "nintrs: %d\n", 47 + le32_to_cpu(ident->nintrs)); 48 + seq_printf(seq, "ndbpgs_per_lif: %d\n", 49 + le32_to_cpu(ident->ndbpgs_per_lif)); 50 + seq_printf(seq, "intr_coal_mult: %d\n", 51 + le32_to_cpu(ident->intr_coal_mult)); 52 + seq_printf(seq, "intr_coal_div: %d\n", 53 + le32_to_cpu(ident->intr_coal_div)); 54 + 55 + seq_puts(seq, "vif_types: "); 56 + for (vt = 0; vt < PDS_DEV_TYPE_MAX; vt++) 57 + seq_printf(seq, "%d ", 58 + le16_to_cpu(pdsc->dev_ident.vif_types[vt])); 59 + seq_puts(seq, "\n"); 60 + 61 + return 0; 62 + } 63 + DEFINE_SHOW_ATTRIBUTE(identity); 64 + 65 + void pdsc_debugfs_add_ident(struct pdsc *pdsc) 66 + { 67 + debugfs_create_file("identity", 0400, pdsc->dentry, 68 + pdsc, &identity_fops); 69 + }
+348
drivers/net/ethernet/amd/pds_core/dev.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* Copyright(c) 2023 Advanced Micro Devices, Inc */ 3 + 4 + #include <linux/errno.h> 5 + #include <linux/pci.h> 6 + #include <linux/utsname.h> 7 + 8 + #include "core.h" 9 + 10 + int pdsc_err_to_errno(enum pds_core_status_code code) 11 + { 12 + switch (code) { 13 + case PDS_RC_SUCCESS: 14 + return 0; 15 + case PDS_RC_EVERSION: 16 + case PDS_RC_EQTYPE: 17 + case PDS_RC_EQID: 18 + case PDS_RC_EINVAL: 19 + case PDS_RC_ENOSUPP: 20 + return -EINVAL; 21 + case PDS_RC_EPERM: 22 + return -EPERM; 23 + case PDS_RC_ENOENT: 24 + return -ENOENT; 25 + case PDS_RC_EAGAIN: 26 + return -EAGAIN; 27 + case PDS_RC_ENOMEM: 28 + return -ENOMEM; 29 + case PDS_RC_EFAULT: 30 + return -EFAULT; 31 + case PDS_RC_EBUSY: 32 + return -EBUSY; 33 + case PDS_RC_EEXIST: 34 + return -EEXIST; 35 + case PDS_RC_EVFID: 36 + return -ENODEV; 37 + case PDS_RC_ECLIENT: 38 + return -ECHILD; 39 + case PDS_RC_ENOSPC: 40 + return -ENOSPC; 41 + case PDS_RC_ERANGE: 42 + return -ERANGE; 43 + case PDS_RC_BAD_ADDR: 44 + return -EFAULT; 45 + case PDS_RC_EOPCODE: 46 + case PDS_RC_EINTR: 47 + case PDS_RC_DEV_CMD: 48 + case PDS_RC_ERROR: 49 + case PDS_RC_ERDMA: 50 + case PDS_RC_EIO: 51 + default: 52 + return -EIO; 53 + } 54 + } 55 + 56 + bool pdsc_is_fw_running(struct pdsc *pdsc) 57 + { 58 + pdsc->fw_status = ioread8(&pdsc->info_regs->fw_status); 59 + pdsc->last_fw_time = jiffies; 60 + pdsc->last_hb = ioread32(&pdsc->info_regs->fw_heartbeat); 61 + 62 + /* Firmware is useful only if the running bit is set and 63 + * fw_status != 0xff (bad PCI read) 64 + */ 65 + return (pdsc->fw_status != 0xff) && 66 + (pdsc->fw_status & PDS_CORE_FW_STS_F_RUNNING); 67 + } 68 + 69 + bool pdsc_is_fw_good(struct pdsc *pdsc) 70 + { 71 + u8 gen = pdsc->fw_status & PDS_CORE_FW_STS_F_GENERATION; 72 + 73 + return pdsc_is_fw_running(pdsc) && gen == pdsc->fw_generation; 74 + } 75 + 76 + static u8 pdsc_devcmd_status(struct pdsc *pdsc) 77 + { 78 + return ioread8(&pdsc->cmd_regs->comp.status); 79 + } 80 + 81 + static bool pdsc_devcmd_done(struct pdsc *pdsc) 82 + { 83 + return ioread32(&pdsc->cmd_regs->done) & PDS_CORE_DEV_CMD_DONE; 84 + } 85 + 86 + static void pdsc_devcmd_dbell(struct pdsc *pdsc) 87 + { 88 + iowrite32(0, &pdsc->cmd_regs->done); 89 + iowrite32(1, &pdsc->cmd_regs->doorbell); 90 + } 91 + 92 + static void pdsc_devcmd_clean(struct pdsc *pdsc) 93 + { 94 + iowrite32(0, &pdsc->cmd_regs->doorbell); 95 + memset_io(&pdsc->cmd_regs->cmd, 0, sizeof(pdsc->cmd_regs->cmd)); 96 + } 97 + 98 + static const char *pdsc_devcmd_str(int opcode) 99 + { 100 + switch (opcode) { 101 + case PDS_CORE_CMD_NOP: 102 + return "PDS_CORE_CMD_NOP"; 103 + case PDS_CORE_CMD_IDENTIFY: 104 + return "PDS_CORE_CMD_IDENTIFY"; 105 + case PDS_CORE_CMD_RESET: 106 + return "PDS_CORE_CMD_RESET"; 107 + case PDS_CORE_CMD_INIT: 108 + return "PDS_CORE_CMD_INIT"; 109 + case PDS_CORE_CMD_FW_DOWNLOAD: 110 + return "PDS_CORE_CMD_FW_DOWNLOAD"; 111 + case PDS_CORE_CMD_FW_CONTROL: 112 + return "PDS_CORE_CMD_FW_CONTROL"; 113 + default: 114 + return "PDS_CORE_CMD_UNKNOWN"; 115 + } 116 + } 117 + 118 + static int pdsc_devcmd_wait(struct pdsc *pdsc, int max_seconds) 119 + { 120 + struct device *dev = pdsc->dev; 121 + unsigned long start_time; 122 + unsigned long max_wait; 123 + unsigned long duration; 124 + int timeout = 0; 125 + int done = 0; 126 + int err = 0; 127 + int status; 128 + int opcode; 129 + 130 + opcode = ioread8(&pdsc->cmd_regs->cmd.opcode); 131 + 132 + start_time = jiffies; 133 + max_wait = start_time + (max_seconds * HZ); 134 + 135 + while (!done && !timeout) { 136 + done = pdsc_devcmd_done(pdsc); 137 + if (done) 138 + break; 139 + 140 + timeout = time_after(jiffies, max_wait); 141 + if (timeout) 142 + break; 143 + 144 + usleep_range(100, 200); 145 + } 146 + duration = jiffies - start_time; 147 + 148 + if (done && duration > HZ) 149 + dev_dbg(dev, "DEVCMD %d %s after %ld secs\n", 150 + opcode, pdsc_devcmd_str(opcode), duration / HZ); 151 + 152 + if (!done || timeout) { 153 + dev_err(dev, "DEVCMD %d %s timeout, done %d timeout %d max_seconds=%d\n", 154 + opcode, pdsc_devcmd_str(opcode), done, timeout, 155 + max_seconds); 156 + err = -ETIMEDOUT; 157 + pdsc_devcmd_clean(pdsc); 158 + } 159 + 160 + status = pdsc_devcmd_status(pdsc); 161 + err = pdsc_err_to_errno(status); 162 + if (err && err != -EAGAIN) 163 + dev_err(dev, "DEVCMD %d %s failed, status=%d err %d %pe\n", 164 + opcode, pdsc_devcmd_str(opcode), status, err, 165 + ERR_PTR(err)); 166 + 167 + return err; 168 + } 169 + 170 + int pdsc_devcmd_locked(struct pdsc *pdsc, union pds_core_dev_cmd *cmd, 171 + union pds_core_dev_comp *comp, int max_seconds) 172 + { 173 + int err; 174 + 175 + memcpy_toio(&pdsc->cmd_regs->cmd, cmd, sizeof(*cmd)); 176 + pdsc_devcmd_dbell(pdsc); 177 + err = pdsc_devcmd_wait(pdsc, max_seconds); 178 + memcpy_fromio(comp, &pdsc->cmd_regs->comp, sizeof(*comp)); 179 + 180 + return err; 181 + } 182 + 183 + int pdsc_devcmd(struct pdsc *pdsc, union pds_core_dev_cmd *cmd, 184 + union pds_core_dev_comp *comp, int max_seconds) 185 + { 186 + int err; 187 + 188 + mutex_lock(&pdsc->devcmd_lock); 189 + err = pdsc_devcmd_locked(pdsc, cmd, comp, max_seconds); 190 + mutex_unlock(&pdsc->devcmd_lock); 191 + 192 + return err; 193 + } 194 + 195 + int pdsc_devcmd_init(struct pdsc *pdsc) 196 + { 197 + union pds_core_dev_comp comp = {}; 198 + union pds_core_dev_cmd cmd = { 199 + .opcode = PDS_CORE_CMD_INIT, 200 + }; 201 + 202 + return pdsc_devcmd(pdsc, &cmd, &comp, pdsc->devcmd_timeout); 203 + } 204 + 205 + int pdsc_devcmd_reset(struct pdsc *pdsc) 206 + { 207 + union pds_core_dev_comp comp = {}; 208 + union pds_core_dev_cmd cmd = { 209 + .reset.opcode = PDS_CORE_CMD_RESET, 210 + }; 211 + 212 + return pdsc_devcmd(pdsc, &cmd, &comp, pdsc->devcmd_timeout); 213 + } 214 + 215 + static int pdsc_devcmd_identify_locked(struct pdsc *pdsc) 216 + { 217 + union pds_core_dev_comp comp = {}; 218 + union pds_core_dev_cmd cmd = { 219 + .identify.opcode = PDS_CORE_CMD_IDENTIFY, 220 + .identify.ver = PDS_CORE_IDENTITY_VERSION_1, 221 + }; 222 + 223 + return pdsc_devcmd_locked(pdsc, &cmd, &comp, pdsc->devcmd_timeout); 224 + } 225 + 226 + static void pdsc_init_devinfo(struct pdsc *pdsc) 227 + { 228 + pdsc->dev_info.asic_type = ioread8(&pdsc->info_regs->asic_type); 229 + pdsc->dev_info.asic_rev = ioread8(&pdsc->info_regs->asic_rev); 230 + pdsc->fw_generation = PDS_CORE_FW_STS_F_GENERATION & 231 + ioread8(&pdsc->info_regs->fw_status); 232 + 233 + memcpy_fromio(pdsc->dev_info.fw_version, 234 + pdsc->info_regs->fw_version, 235 + PDS_CORE_DEVINFO_FWVERS_BUFLEN); 236 + pdsc->dev_info.fw_version[PDS_CORE_DEVINFO_FWVERS_BUFLEN] = 0; 237 + 238 + memcpy_fromio(pdsc->dev_info.serial_num, 239 + pdsc->info_regs->serial_num, 240 + PDS_CORE_DEVINFO_SERIAL_BUFLEN); 241 + pdsc->dev_info.serial_num[PDS_CORE_DEVINFO_SERIAL_BUFLEN] = 0; 242 + 243 + dev_dbg(pdsc->dev, "fw_version %s\n", pdsc->dev_info.fw_version); 244 + } 245 + 246 + static int pdsc_identify(struct pdsc *pdsc) 247 + { 248 + struct pds_core_drv_identity drv = {}; 249 + size_t sz; 250 + int err; 251 + 252 + drv.drv_type = cpu_to_le32(PDS_DRIVER_LINUX); 253 + snprintf(drv.driver_ver_str, sizeof(drv.driver_ver_str), 254 + "%s %s", PDS_CORE_DRV_NAME, utsname()->release); 255 + 256 + /* Next let's get some info about the device 257 + * We use the devcmd_lock at this level in order to 258 + * get safe access to the cmd_regs->data before anyone 259 + * else can mess it up 260 + */ 261 + mutex_lock(&pdsc->devcmd_lock); 262 + 263 + sz = min_t(size_t, sizeof(drv), sizeof(pdsc->cmd_regs->data)); 264 + memcpy_toio(&pdsc->cmd_regs->data, &drv, sz); 265 + 266 + err = pdsc_devcmd_identify_locked(pdsc); 267 + if (!err) { 268 + sz = min_t(size_t, sizeof(pdsc->dev_ident), 269 + sizeof(pdsc->cmd_regs->data)); 270 + memcpy_fromio(&pdsc->dev_ident, &pdsc->cmd_regs->data, sz); 271 + } 272 + mutex_unlock(&pdsc->devcmd_lock); 273 + 274 + if (err) { 275 + dev_err(pdsc->dev, "Cannot identify device: %pe\n", 276 + ERR_PTR(err)); 277 + return err; 278 + } 279 + 280 + if (isprint(pdsc->dev_info.fw_version[0]) && 281 + isascii(pdsc->dev_info.fw_version[0])) 282 + dev_info(pdsc->dev, "FW: %.*s\n", 283 + (int)(sizeof(pdsc->dev_info.fw_version) - 1), 284 + pdsc->dev_info.fw_version); 285 + else 286 + dev_info(pdsc->dev, "FW: (invalid string) 0x%02x 0x%02x 0x%02x 0x%02x ...\n", 287 + (u8)pdsc->dev_info.fw_version[0], 288 + (u8)pdsc->dev_info.fw_version[1], 289 + (u8)pdsc->dev_info.fw_version[2], 290 + (u8)pdsc->dev_info.fw_version[3]); 291 + 292 + return 0; 293 + } 294 + 295 + int pdsc_dev_reinit(struct pdsc *pdsc) 296 + { 297 + pdsc_init_devinfo(pdsc); 298 + 299 + return pdsc_identify(pdsc); 300 + } 301 + 302 + int pdsc_dev_init(struct pdsc *pdsc) 303 + { 304 + unsigned int nintrs; 305 + int err; 306 + 307 + /* Initial init and reset of device */ 308 + pdsc_init_devinfo(pdsc); 309 + pdsc->devcmd_timeout = PDS_CORE_DEVCMD_TIMEOUT; 310 + 311 + err = pdsc_devcmd_reset(pdsc); 312 + if (err) 313 + return err; 314 + 315 + err = pdsc_identify(pdsc); 316 + if (err) 317 + return err; 318 + 319 + pdsc_debugfs_add_ident(pdsc); 320 + 321 + /* Now we can reserve interrupts */ 322 + nintrs = le32_to_cpu(pdsc->dev_ident.nintrs); 323 + nintrs = min_t(unsigned int, num_online_cpus(), nintrs); 324 + 325 + /* Get intr_info struct array for tracking */ 326 + pdsc->intr_info = kcalloc(nintrs, sizeof(*pdsc->intr_info), GFP_KERNEL); 327 + if (!pdsc->intr_info) { 328 + err = -ENOMEM; 329 + goto err_out; 330 + } 331 + 332 + err = pci_alloc_irq_vectors(pdsc->pdev, nintrs, nintrs, PCI_IRQ_MSIX); 333 + if (err != nintrs) { 334 + dev_err(pdsc->dev, "Can't get %d intrs from OS: %pe\n", 335 + nintrs, ERR_PTR(err)); 336 + err = -ENOSPC; 337 + goto err_out; 338 + } 339 + pdsc->nintrs = nintrs; 340 + 341 + return 0; 342 + 343 + err_out: 344 + kfree(pdsc->intr_info); 345 + pdsc->intr_info = NULL; 346 + 347 + return err; 348 + }
+31 -2
drivers/net/ethernet/amd/pds_core/main.c
··· 137 137 if (err) 138 138 goto err_out_release_regions; 139 139 140 + mutex_init(&pdsc->devcmd_lock); 141 + mutex_init(&pdsc->config_lock); 142 + 143 + mutex_lock(&pdsc->config_lock); 144 + set_bit(PDSC_S_FW_DEAD, &pdsc->state); 145 + 146 + err = pdsc_setup(pdsc, PDSC_SETUP_INIT); 147 + if (err) 148 + goto err_out_unmap_bars; 149 + 150 + mutex_unlock(&pdsc->config_lock); 151 + 140 152 dl = priv_to_devlink(pdsc); 141 153 devl_lock(dl); 142 154 devl_register(dl); ··· 156 144 157 145 return 0; 158 146 147 + err_out_unmap_bars: 148 + mutex_unlock(&pdsc->config_lock); 149 + mutex_destroy(&pdsc->config_lock); 150 + mutex_destroy(&pdsc->devcmd_lock); 151 + pci_free_irq_vectors(pdsc->pdev); 152 + pdsc_unmap_bars(pdsc); 159 153 err_out_release_regions: 160 154 pci_release_regions(pdsc->pdev); 161 155 ··· 258 240 devl_unregister(dl); 259 241 devl_unlock(dl); 260 242 261 - pdsc_unmap_bars(pdsc); 262 - pci_release_regions(pdev); 243 + if (!pdev->is_virtfn) { 244 + mutex_lock(&pdsc->config_lock); 245 + set_bit(PDSC_S_STOPPING_DRIVER, &pdsc->state); 246 + 247 + pdsc_teardown(pdsc, PDSC_TEARDOWN_REMOVING); 248 + mutex_unlock(&pdsc->config_lock); 249 + mutex_destroy(&pdsc->config_lock); 250 + mutex_destroy(&pdsc->devcmd_lock); 251 + 252 + pci_free_irq_vectors(pdev); 253 + pdsc_unmap_bars(pdsc); 254 + pci_release_regions(pdev); 255 + } 263 256 264 257 pci_clear_master(pdev); 265 258 pci_disable_device(pdev);
+30
include/linux/pds/pds_common.h
··· 11 11 #define PDS_CORE_ADDR_MASK (BIT_ULL(PDS_ADDR_LEN) - 1) 12 12 #define PDS_PAGE_SIZE 4096 13 13 14 + enum pds_core_driver_type { 15 + PDS_DRIVER_LINUX = 1, 16 + PDS_DRIVER_WIN = 2, 17 + PDS_DRIVER_DPDK = 3, 18 + PDS_DRIVER_FREEBSD = 4, 19 + PDS_DRIVER_IPXE = 5, 20 + PDS_DRIVER_ESXI = 6, 21 + }; 22 + 23 + #define PDS_CORE_IFNAMSIZ 16 24 + 25 + /** 26 + * enum pds_core_logical_qtype - Logical Queue Types 27 + * @PDS_CORE_QTYPE_ADMINQ: Administrative Queue 28 + * @PDS_CORE_QTYPE_NOTIFYQ: Notify Queue 29 + * @PDS_CORE_QTYPE_RXQ: Receive Queue 30 + * @PDS_CORE_QTYPE_TXQ: Transmit Queue 31 + * @PDS_CORE_QTYPE_EQ: Event Queue 32 + * @PDS_CORE_QTYPE_MAX: Max queue type supported 33 + */ 34 + enum pds_core_logical_qtype { 35 + PDS_CORE_QTYPE_ADMINQ = 0, 36 + PDS_CORE_QTYPE_NOTIFYQ = 1, 37 + PDS_CORE_QTYPE_RXQ = 2, 38 + PDS_CORE_QTYPE_TXQ = 3, 39 + PDS_CORE_QTYPE_EQ = 4, 40 + 41 + PDS_CORE_QTYPE_MAX = 16 /* don't change - used in struct size */ 42 + }; 43 + 14 44 #endif /* _PDS_COMMON_H_ */
+163
include/linux/pds/pds_intr.h
··· 1 + /* SPDX-License-Identifier: (GPL-2.0 OR Linux-OpenIB) OR BSD-2-Clause */ 2 + /* Copyright(c) 2023 Advanced Micro Devices, Inc. */ 3 + 4 + #ifndef _PDS_INTR_H_ 5 + #define _PDS_INTR_H_ 6 + 7 + /* 8 + * Interrupt control register 9 + * @coal_init: Coalescing timer initial value, in 10 + * device units. Use @identity->intr_coal_mult 11 + * and @identity->intr_coal_div to convert from 12 + * usecs to device units: 13 + * 14 + * coal_init = coal_usecs * coal_mutl / coal_div 15 + * 16 + * When an interrupt is sent the interrupt 17 + * coalescing timer current value 18 + * (@coalescing_curr) is initialized with this 19 + * value and begins counting down. No more 20 + * interrupts are sent until the coalescing 21 + * timer reaches 0. When @coalescing_init=0 22 + * interrupt coalescing is effectively disabled 23 + * and every interrupt assert results in an 24 + * interrupt. Reset value: 0 25 + * @mask: Interrupt mask. When @mask=1 the interrupt 26 + * resource will not send an interrupt. When 27 + * @mask=0 the interrupt resource will send an 28 + * interrupt if an interrupt event is pending 29 + * or on the next interrupt assertion event. 30 + * Reset value: 1 31 + * @credits: Interrupt credits. This register indicates 32 + * how many interrupt events the hardware has 33 + * sent. When written by software this 34 + * register atomically decrements @int_credits 35 + * by the value written. When @int_credits 36 + * becomes 0 then the "pending interrupt" bit 37 + * in the Interrupt Status register is cleared 38 + * by the hardware and any pending but unsent 39 + * interrupts are cleared. 40 + * !!!IMPORTANT!!! This is a signed register. 41 + * @flags: Interrupt control flags 42 + * @unmask -- When this bit is written with a 1 43 + * the interrupt resource will set mask=0. 44 + * @coal_timer_reset -- When this 45 + * bit is written with a 1 the 46 + * @coalescing_curr will be reloaded with 47 + * @coalescing_init to reset the coalescing 48 + * timer. 49 + * @mask_on_assert: Automatically mask on assertion. When 50 + * @mask_on_assert=1 the interrupt resource 51 + * will set @mask=1 whenever an interrupt is 52 + * sent. When using interrupts in Legacy 53 + * Interrupt mode the driver must select 54 + * @mask_on_assert=0 for proper interrupt 55 + * operation. 56 + * @coalescing_curr: Coalescing timer current value, in 57 + * microseconds. When this value reaches 0 58 + * the interrupt resource is again eligible to 59 + * send an interrupt. If an interrupt event 60 + * is already pending when @coalescing_curr 61 + * reaches 0 the pending interrupt will be 62 + * sent, otherwise an interrupt will be sent 63 + * on the next interrupt assertion event. 64 + */ 65 + struct pds_core_intr { 66 + u32 coal_init; 67 + u32 mask; 68 + u16 credits; 69 + u16 flags; 70 + #define PDS_CORE_INTR_F_UNMASK 0x0001 71 + #define PDS_CORE_INTR_F_TIMER_RESET 0x0002 72 + u32 mask_on_assert; 73 + u32 coalescing_curr; 74 + u32 rsvd6[3]; 75 + }; 76 + 77 + #ifndef __CHECKER__ 78 + static_assert(sizeof(struct pds_core_intr) == 32); 79 + #endif /* __CHECKER__ */ 80 + 81 + #define PDS_CORE_INTR_CTRL_REGS_MAX 2048 82 + #define PDS_CORE_INTR_CTRL_COAL_MAX 0x3F 83 + #define PDS_CORE_INTR_INDEX_NOT_ASSIGNED -1 84 + 85 + struct pds_core_intr_status { 86 + u32 status[2]; 87 + }; 88 + 89 + /** 90 + * enum pds_core_intr_mask_vals - valid values for mask and mask_assert. 91 + * @PDS_CORE_INTR_MASK_CLEAR: unmask interrupt. 92 + * @PDS_CORE_INTR_MASK_SET: mask interrupt. 93 + */ 94 + enum pds_core_intr_mask_vals { 95 + PDS_CORE_INTR_MASK_CLEAR = 0, 96 + PDS_CORE_INTR_MASK_SET = 1, 97 + }; 98 + 99 + /** 100 + * enum pds_core_intr_credits_bits - Bitwise composition of credits values. 101 + * @PDS_CORE_INTR_CRED_COUNT: bit mask of credit count, no shift needed. 102 + * @PDS_CORE_INTR_CRED_COUNT_SIGNED: bit mask of credit count, including sign bit. 103 + * @PDS_CORE_INTR_CRED_UNMASK: unmask the interrupt. 104 + * @PDS_CORE_INTR_CRED_RESET_COALESCE: reset the coalesce timer. 105 + * @PDS_CORE_INTR_CRED_REARM: unmask the and reset the timer. 106 + */ 107 + enum pds_core_intr_credits_bits { 108 + PDS_CORE_INTR_CRED_COUNT = 0x7fffu, 109 + PDS_CORE_INTR_CRED_COUNT_SIGNED = 0xffffu, 110 + PDS_CORE_INTR_CRED_UNMASK = 0x10000u, 111 + PDS_CORE_INTR_CRED_RESET_COALESCE = 0x20000u, 112 + PDS_CORE_INTR_CRED_REARM = (PDS_CORE_INTR_CRED_UNMASK | 113 + PDS_CORE_INTR_CRED_RESET_COALESCE), 114 + }; 115 + 116 + static inline void 117 + pds_core_intr_coal_init(struct pds_core_intr __iomem *intr_ctrl, u32 coal) 118 + { 119 + iowrite32(coal, &intr_ctrl->coal_init); 120 + } 121 + 122 + static inline void 123 + pds_core_intr_mask(struct pds_core_intr __iomem *intr_ctrl, u32 mask) 124 + { 125 + iowrite32(mask, &intr_ctrl->mask); 126 + } 127 + 128 + static inline void 129 + pds_core_intr_credits(struct pds_core_intr __iomem *intr_ctrl, 130 + u32 cred, u32 flags) 131 + { 132 + if (WARN_ON_ONCE(cred > PDS_CORE_INTR_CRED_COUNT)) { 133 + cred = ioread32(&intr_ctrl->credits); 134 + cred &= PDS_CORE_INTR_CRED_COUNT_SIGNED; 135 + } 136 + 137 + iowrite32(cred | flags, &intr_ctrl->credits); 138 + } 139 + 140 + static inline void 141 + pds_core_intr_clean_flags(struct pds_core_intr __iomem *intr_ctrl, u32 flags) 142 + { 143 + u32 cred; 144 + 145 + cred = ioread32(&intr_ctrl->credits); 146 + cred &= PDS_CORE_INTR_CRED_COUNT_SIGNED; 147 + cred |= flags; 148 + iowrite32(cred, &intr_ctrl->credits); 149 + } 150 + 151 + static inline void 152 + pds_core_intr_clean(struct pds_core_intr __iomem *intr_ctrl) 153 + { 154 + pds_core_intr_clean_flags(intr_ctrl, PDS_CORE_INTR_CRED_RESET_COALESCE); 155 + } 156 + 157 + static inline void 158 + pds_core_intr_mask_assert(struct pds_core_intr __iomem *intr_ctrl, u32 mask) 159 + { 160 + iowrite32(mask, &intr_ctrl->mask_on_assert); 161 + } 162 + 163 + #endif /* _PDS_INTR_H_ */