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

Configure Feed

Select the types of activity you want to include in your feed.

pds_core: set up device and adminq

Set up the basic adminq and notifyq queue structures. These are
used mostly by the client drivers for feature configuration.
These are essentially the same adminq and notifyq as in the
ionic driver.

Part of this includes querying for device identity and FW
information, so we can make that available to devlink dev info.

$ devlink dev info pci/0000:b5:00.0
pci/0000:b5:00.0:
driver pds_core
serial_number FLM18420073
versions:
fixed:
asic.id 0x0
asic.rev 0x0
running:
fw 1.51.0-73
stored:
fw.goldfw 1.15.9-C-22
fw.mainfwa 1.60.0-73
fw.mainfwb 1.60.0-57

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
45d76f49 25b450c0

+1419 -5
+47
Documentation/networking/device_drivers/ethernet/amd/pds_core.rst
··· 26 26 pds_core 0000:b6:00.0: 252.048 Gb/s available PCIe bandwidth (16.0 GT/s PCIe x16 link) 27 27 pds_core 0000:b6:00.0: FW: 1.60.0-73 28 28 29 + Driver and firmware version information can be gathered with devlink:: 30 + 31 + $ devlink dev info pci/0000:b5:00.0 32 + pci/0000:b5:00.0: 33 + driver pds_core 34 + serial_number FLM18420073 35 + versions: 36 + fixed: 37 + asic.id 0x0 38 + asic.rev 0x0 39 + running: 40 + fw 1.51.0-73 41 + stored: 42 + fw.goldfw 1.15.9-C-22 43 + fw.mainfwa 1.60.0-73 44 + fw.mainfwb 1.60.0-57 45 + 46 + Info versions 47 + ============= 48 + 49 + The ``pds_core`` driver reports the following versions 50 + 51 + .. list-table:: devlink info versions implemented 52 + :widths: 5 5 90 53 + 54 + * - Name 55 + - Type 56 + - Description 57 + * - ``fw`` 58 + - running 59 + - Version of firmware running on the device 60 + * - ``fw.goldfw`` 61 + - stored 62 + - Version of firmware stored in the goldfw slot 63 + * - ``fw.mainfwa`` 64 + - stored 65 + - Version of firmware stored in the mainfwa slot 66 + * - ``fw.mainfwb`` 67 + - stored 68 + - Version of firmware stored in the mainfwb slot 69 + * - ``asic.id`` 70 + - fixed 71 + - The ASIC type for this device 72 + * - ``asic.rev`` 73 + - fixed 74 + - The revision of the ASIC for this device 75 + 29 76 Health Reporters 30 77 ================ 31 78
+429 -4
drivers/net/ethernet/amd/pds_core/core.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0 2 2 /* Copyright(c) 2023 Advanced Micro Devices, Inc */ 3 3 4 + #include <linux/pci.h> 5 + #include <linux/vmalloc.h> 6 + 4 7 #include "core.h" 8 + 9 + void pdsc_work_thread(struct work_struct *work) 10 + { 11 + /* stub */ 12 + } 13 + 14 + irqreturn_t pdsc_adminq_isr(int irq, void *data) 15 + { 16 + /* stub */ 17 + return IRQ_HANDLED; 18 + } 19 + 20 + void pdsc_intr_free(struct pdsc *pdsc, int index) 21 + { 22 + struct pdsc_intr_info *intr_info; 23 + 24 + if (index >= pdsc->nintrs || index < 0) { 25 + WARN(true, "bad intr index %d\n", index); 26 + return; 27 + } 28 + 29 + intr_info = &pdsc->intr_info[index]; 30 + if (!intr_info->vector) 31 + return; 32 + dev_dbg(pdsc->dev, "%s: idx %d vec %d name %s\n", 33 + __func__, index, intr_info->vector, intr_info->name); 34 + 35 + pds_core_intr_mask(&pdsc->intr_ctrl[index], PDS_CORE_INTR_MASK_SET); 36 + pds_core_intr_clean(&pdsc->intr_ctrl[index]); 37 + 38 + free_irq(intr_info->vector, intr_info->data); 39 + 40 + memset(intr_info, 0, sizeof(*intr_info)); 41 + } 42 + 43 + int pdsc_intr_alloc(struct pdsc *pdsc, char *name, 44 + irq_handler_t handler, void *data) 45 + { 46 + struct pdsc_intr_info *intr_info; 47 + unsigned int index; 48 + int err; 49 + 50 + /* Find the first available interrupt */ 51 + for (index = 0; index < pdsc->nintrs; index++) 52 + if (!pdsc->intr_info[index].vector) 53 + break; 54 + if (index >= pdsc->nintrs) { 55 + dev_warn(pdsc->dev, "%s: no intr, index=%d nintrs=%d\n", 56 + __func__, index, pdsc->nintrs); 57 + return -ENOSPC; 58 + } 59 + 60 + pds_core_intr_clean_flags(&pdsc->intr_ctrl[index], 61 + PDS_CORE_INTR_CRED_RESET_COALESCE); 62 + 63 + intr_info = &pdsc->intr_info[index]; 64 + 65 + intr_info->index = index; 66 + intr_info->data = data; 67 + strscpy(intr_info->name, name, sizeof(intr_info->name)); 68 + 69 + /* Get the OS vector number for the interrupt */ 70 + err = pci_irq_vector(pdsc->pdev, index); 71 + if (err < 0) { 72 + dev_err(pdsc->dev, "failed to get intr vector index %d: %pe\n", 73 + index, ERR_PTR(err)); 74 + goto err_out_free_intr; 75 + } 76 + intr_info->vector = err; 77 + 78 + /* Init the device's intr mask */ 79 + pds_core_intr_clean(&pdsc->intr_ctrl[index]); 80 + pds_core_intr_mask_assert(&pdsc->intr_ctrl[index], 1); 81 + pds_core_intr_mask(&pdsc->intr_ctrl[index], PDS_CORE_INTR_MASK_SET); 82 + 83 + /* Register the isr with a name */ 84 + err = request_irq(intr_info->vector, handler, 0, intr_info->name, data); 85 + if (err) { 86 + dev_err(pdsc->dev, "failed to get intr irq vector %d: %pe\n", 87 + intr_info->vector, ERR_PTR(err)); 88 + goto err_out_free_intr; 89 + } 90 + 91 + return index; 92 + 93 + err_out_free_intr: 94 + pdsc_intr_free(pdsc, index); 95 + return err; 96 + } 97 + 98 + static void pdsc_qcq_intr_free(struct pdsc *pdsc, struct pdsc_qcq *qcq) 99 + { 100 + if (!(qcq->flags & PDS_CORE_QCQ_F_INTR) || 101 + qcq->intx == PDS_CORE_INTR_INDEX_NOT_ASSIGNED) 102 + return; 103 + 104 + pdsc_intr_free(pdsc, qcq->intx); 105 + qcq->intx = PDS_CORE_INTR_INDEX_NOT_ASSIGNED; 106 + } 107 + 108 + static int pdsc_qcq_intr_alloc(struct pdsc *pdsc, struct pdsc_qcq *qcq) 109 + { 110 + char name[PDSC_INTR_NAME_MAX_SZ]; 111 + int index; 112 + 113 + if (!(qcq->flags & PDS_CORE_QCQ_F_INTR)) { 114 + qcq->intx = PDS_CORE_INTR_INDEX_NOT_ASSIGNED; 115 + return 0; 116 + } 117 + 118 + snprintf(name, sizeof(name), "%s-%d-%s", 119 + PDS_CORE_DRV_NAME, pdsc->pdev->bus->number, qcq->q.name); 120 + index = pdsc_intr_alloc(pdsc, name, pdsc_adminq_isr, qcq); 121 + if (index < 0) 122 + return index; 123 + qcq->intx = index; 124 + 125 + return 0; 126 + } 127 + 128 + void pdsc_qcq_free(struct pdsc *pdsc, struct pdsc_qcq *qcq) 129 + { 130 + struct device *dev = pdsc->dev; 131 + 132 + if (!(qcq && qcq->pdsc)) 133 + return; 134 + 135 + pdsc_debugfs_del_qcq(qcq); 136 + 137 + pdsc_qcq_intr_free(pdsc, qcq); 138 + 139 + if (qcq->q_base) 140 + dma_free_coherent(dev, qcq->q_size, 141 + qcq->q_base, qcq->q_base_pa); 142 + 143 + if (qcq->cq_base) 144 + dma_free_coherent(dev, qcq->cq_size, 145 + qcq->cq_base, qcq->cq_base_pa); 146 + 147 + if (qcq->cq.info) 148 + vfree(qcq->cq.info); 149 + 150 + if (qcq->q.info) 151 + vfree(qcq->q.info); 152 + 153 + memset(qcq, 0, sizeof(*qcq)); 154 + } 155 + 156 + static void pdsc_q_map(struct pdsc_queue *q, void *base, dma_addr_t base_pa) 157 + { 158 + struct pdsc_q_info *cur; 159 + unsigned int i; 160 + 161 + q->base = base; 162 + q->base_pa = base_pa; 163 + 164 + for (i = 0, cur = q->info; i < q->num_descs; i++, cur++) 165 + cur->desc = base + (i * q->desc_size); 166 + } 167 + 168 + static void pdsc_cq_map(struct pdsc_cq *cq, void *base, dma_addr_t base_pa) 169 + { 170 + struct pdsc_cq_info *cur; 171 + unsigned int i; 172 + 173 + cq->base = base; 174 + cq->base_pa = base_pa; 175 + 176 + for (i = 0, cur = cq->info; i < cq->num_descs; i++, cur++) 177 + cur->comp = base + (i * cq->desc_size); 178 + } 179 + 180 + int pdsc_qcq_alloc(struct pdsc *pdsc, unsigned int type, unsigned int index, 181 + const char *name, unsigned int flags, unsigned int num_descs, 182 + unsigned int desc_size, unsigned int cq_desc_size, 183 + unsigned int pid, struct pdsc_qcq *qcq) 184 + { 185 + struct device *dev = pdsc->dev; 186 + void *q_base, *cq_base; 187 + dma_addr_t cq_base_pa; 188 + dma_addr_t q_base_pa; 189 + int err; 190 + 191 + qcq->q.info = vzalloc(num_descs * sizeof(*qcq->q.info)); 192 + if (!qcq->q.info) { 193 + err = -ENOMEM; 194 + goto err_out; 195 + } 196 + 197 + qcq->pdsc = pdsc; 198 + qcq->flags = flags; 199 + INIT_WORK(&qcq->work, pdsc_work_thread); 200 + 201 + qcq->q.type = type; 202 + qcq->q.index = index; 203 + qcq->q.num_descs = num_descs; 204 + qcq->q.desc_size = desc_size; 205 + qcq->q.tail_idx = 0; 206 + qcq->q.head_idx = 0; 207 + qcq->q.pid = pid; 208 + snprintf(qcq->q.name, sizeof(qcq->q.name), "%s%u", name, index); 209 + 210 + err = pdsc_qcq_intr_alloc(pdsc, qcq); 211 + if (err) 212 + goto err_out_free_q_info; 213 + 214 + qcq->cq.info = vzalloc(num_descs * sizeof(*qcq->cq.info)); 215 + if (!qcq->cq.info) { 216 + err = -ENOMEM; 217 + goto err_out_free_irq; 218 + } 219 + 220 + qcq->cq.bound_intr = &pdsc->intr_info[qcq->intx]; 221 + qcq->cq.num_descs = num_descs; 222 + qcq->cq.desc_size = cq_desc_size; 223 + qcq->cq.tail_idx = 0; 224 + qcq->cq.done_color = 1; 225 + 226 + if (flags & PDS_CORE_QCQ_F_NOTIFYQ) { 227 + /* q & cq need to be contiguous in case of notifyq */ 228 + qcq->q_size = PDS_PAGE_SIZE + 229 + ALIGN(num_descs * desc_size, PDS_PAGE_SIZE) + 230 + ALIGN(num_descs * cq_desc_size, PDS_PAGE_SIZE); 231 + qcq->q_base = dma_alloc_coherent(dev, 232 + qcq->q_size + qcq->cq_size, 233 + &qcq->q_base_pa, 234 + GFP_KERNEL); 235 + if (!qcq->q_base) { 236 + err = -ENOMEM; 237 + goto err_out_free_cq_info; 238 + } 239 + q_base = PTR_ALIGN(qcq->q_base, PDS_PAGE_SIZE); 240 + q_base_pa = ALIGN(qcq->q_base_pa, PDS_PAGE_SIZE); 241 + pdsc_q_map(&qcq->q, q_base, q_base_pa); 242 + 243 + cq_base = PTR_ALIGN(q_base + 244 + ALIGN(num_descs * desc_size, PDS_PAGE_SIZE), 245 + PDS_PAGE_SIZE); 246 + cq_base_pa = ALIGN(qcq->q_base_pa + 247 + ALIGN(num_descs * desc_size, PDS_PAGE_SIZE), 248 + PDS_PAGE_SIZE); 249 + 250 + } else { 251 + /* q DMA descriptors */ 252 + qcq->q_size = PDS_PAGE_SIZE + (num_descs * desc_size); 253 + qcq->q_base = dma_alloc_coherent(dev, qcq->q_size, 254 + &qcq->q_base_pa, 255 + GFP_KERNEL); 256 + if (!qcq->q_base) { 257 + err = -ENOMEM; 258 + goto err_out_free_cq_info; 259 + } 260 + q_base = PTR_ALIGN(qcq->q_base, PDS_PAGE_SIZE); 261 + q_base_pa = ALIGN(qcq->q_base_pa, PDS_PAGE_SIZE); 262 + pdsc_q_map(&qcq->q, q_base, q_base_pa); 263 + 264 + /* cq DMA descriptors */ 265 + qcq->cq_size = PDS_PAGE_SIZE + (num_descs * cq_desc_size); 266 + qcq->cq_base = dma_alloc_coherent(dev, qcq->cq_size, 267 + &qcq->cq_base_pa, 268 + GFP_KERNEL); 269 + if (!qcq->cq_base) { 270 + err = -ENOMEM; 271 + goto err_out_free_q; 272 + } 273 + cq_base = PTR_ALIGN(qcq->cq_base, PDS_PAGE_SIZE); 274 + cq_base_pa = ALIGN(qcq->cq_base_pa, PDS_PAGE_SIZE); 275 + } 276 + 277 + pdsc_cq_map(&qcq->cq, cq_base, cq_base_pa); 278 + qcq->cq.bound_q = &qcq->q; 279 + 280 + pdsc_debugfs_add_qcq(pdsc, qcq); 281 + 282 + return 0; 283 + 284 + err_out_free_q: 285 + dma_free_coherent(dev, qcq->q_size, qcq->q_base, qcq->q_base_pa); 286 + err_out_free_cq_info: 287 + vfree(qcq->cq.info); 288 + err_out_free_irq: 289 + pdsc_qcq_intr_free(pdsc, qcq); 290 + err_out_free_q_info: 291 + vfree(qcq->q.info); 292 + memset(qcq, 0, sizeof(*qcq)); 293 + err_out: 294 + dev_err(dev, "qcq alloc of %s%d failed %d\n", name, index, err); 295 + return err; 296 + } 297 + 298 + static int pdsc_core_init(struct pdsc *pdsc) 299 + { 300 + union pds_core_dev_comp comp = {}; 301 + union pds_core_dev_cmd cmd = { 302 + .init.opcode = PDS_CORE_CMD_INIT, 303 + }; 304 + struct pds_core_dev_init_data_out cido; 305 + struct pds_core_dev_init_data_in cidi; 306 + u32 dbid_count; 307 + u32 dbpage_num; 308 + size_t sz; 309 + int err; 310 + 311 + cidi.adminq_q_base = cpu_to_le64(pdsc->adminqcq.q_base_pa); 312 + cidi.adminq_cq_base = cpu_to_le64(pdsc->adminqcq.cq_base_pa); 313 + cidi.notifyq_cq_base = cpu_to_le64(pdsc->notifyqcq.cq.base_pa); 314 + cidi.flags = cpu_to_le32(PDS_CORE_QINIT_F_IRQ | PDS_CORE_QINIT_F_ENA); 315 + cidi.intr_index = cpu_to_le16(pdsc->adminqcq.intx); 316 + cidi.adminq_ring_size = ilog2(pdsc->adminqcq.q.num_descs); 317 + cidi.notifyq_ring_size = ilog2(pdsc->notifyqcq.q.num_descs); 318 + 319 + mutex_lock(&pdsc->devcmd_lock); 320 + 321 + sz = min_t(size_t, sizeof(cidi), sizeof(pdsc->cmd_regs->data)); 322 + memcpy_toio(&pdsc->cmd_regs->data, &cidi, sz); 323 + 324 + err = pdsc_devcmd_locked(pdsc, &cmd, &comp, pdsc->devcmd_timeout); 325 + if (!err) { 326 + sz = min_t(size_t, sizeof(cido), sizeof(pdsc->cmd_regs->data)); 327 + memcpy_fromio(&cido, &pdsc->cmd_regs->data, sz); 328 + } 329 + 330 + mutex_unlock(&pdsc->devcmd_lock); 331 + if (err) { 332 + dev_err(pdsc->dev, "Device init command failed: %pe\n", 333 + ERR_PTR(err)); 334 + return err; 335 + } 336 + 337 + pdsc->hw_index = le32_to_cpu(cido.core_hw_index); 338 + 339 + dbid_count = le32_to_cpu(pdsc->dev_ident.ndbpgs_per_lif); 340 + dbpage_num = pdsc->hw_index * dbid_count; 341 + pdsc->kern_dbpage = pdsc_map_dbpage(pdsc, dbpage_num); 342 + if (!pdsc->kern_dbpage) { 343 + dev_err(pdsc->dev, "Cannot map dbpage, aborting\n"); 344 + return -ENOMEM; 345 + } 346 + 347 + pdsc->adminqcq.q.hw_type = cido.adminq_hw_type; 348 + pdsc->adminqcq.q.hw_index = le32_to_cpu(cido.adminq_hw_index); 349 + pdsc->adminqcq.q.dbval = PDS_CORE_DBELL_QID(pdsc->adminqcq.q.hw_index); 350 + 351 + pdsc->notifyqcq.q.hw_type = cido.notifyq_hw_type; 352 + pdsc->notifyqcq.q.hw_index = le32_to_cpu(cido.notifyq_hw_index); 353 + pdsc->notifyqcq.q.dbval = PDS_CORE_DBELL_QID(pdsc->notifyqcq.q.hw_index); 354 + 355 + pdsc->last_eid = 0; 356 + 357 + return err; 358 + } 5 359 6 360 int pdsc_setup(struct pdsc *pdsc, bool init) 7 361 { 362 + int numdescs; 8 363 int err; 9 364 10 365 if (init) ··· 369 14 if (err) 370 15 return err; 371 16 17 + /* Scale the descriptor ring length based on number of CPUs and VFs */ 18 + numdescs = max_t(int, PDSC_ADMINQ_MIN_LENGTH, num_online_cpus()); 19 + numdescs += 2 * pci_sriov_get_totalvfs(pdsc->pdev); 20 + numdescs = roundup_pow_of_two(numdescs); 21 + err = pdsc_qcq_alloc(pdsc, PDS_CORE_QTYPE_ADMINQ, 0, "adminq", 22 + PDS_CORE_QCQ_F_CORE | PDS_CORE_QCQ_F_INTR, 23 + numdescs, 24 + sizeof(union pds_core_adminq_cmd), 25 + sizeof(union pds_core_adminq_comp), 26 + 0, &pdsc->adminqcq); 27 + if (err) 28 + goto err_out_teardown; 29 + 30 + err = pdsc_qcq_alloc(pdsc, PDS_CORE_QTYPE_NOTIFYQ, 0, "notifyq", 31 + PDS_CORE_QCQ_F_NOTIFYQ, 32 + PDSC_NOTIFYQ_LENGTH, 33 + sizeof(struct pds_core_notifyq_cmd), 34 + sizeof(union pds_core_notifyq_comp), 35 + 0, &pdsc->notifyqcq); 36 + if (err) 37 + goto err_out_teardown; 38 + 39 + /* NotifyQ rides on the AdminQ interrupt */ 40 + pdsc->notifyqcq.intx = pdsc->adminqcq.intx; 41 + 42 + /* Set up the Core with the AdminQ and NotifyQ info */ 43 + err = pdsc_core_init(pdsc); 44 + if (err) 45 + goto err_out_teardown; 46 + 372 47 clear_bit(PDSC_S_FW_DEAD, &pdsc->state); 373 48 return 0; 49 + 50 + err_out_teardown: 51 + pdsc_teardown(pdsc, init); 52 + return err; 374 53 } 375 54 376 55 void pdsc_teardown(struct pdsc *pdsc, bool removing) 377 56 { 378 - pdsc_devcmd_reset(pdsc); 57 + int i; 379 58 380 - if (removing) { 381 - kfree(pdsc->intr_info); 382 - pdsc->intr_info = NULL; 59 + pdsc_devcmd_reset(pdsc); 60 + pdsc_qcq_free(pdsc, &pdsc->notifyqcq); 61 + pdsc_qcq_free(pdsc, &pdsc->adminqcq); 62 + 63 + if (pdsc->intr_info) { 64 + for (i = 0; i < pdsc->nintrs; i++) 65 + pdsc_intr_free(pdsc, i); 66 + 67 + if (removing) { 68 + kfree(pdsc->intr_info); 69 + pdsc->intr_info = NULL; 70 + } 383 71 } 384 72 385 73 if (pdsc->kern_dbpage) { ··· 431 33 } 432 34 433 35 set_bit(PDSC_S_FW_DEAD, &pdsc->state); 36 + } 37 + 38 + int pdsc_start(struct pdsc *pdsc) 39 + { 40 + pds_core_intr_mask(&pdsc->intr_ctrl[pdsc->adminqcq.intx], 41 + PDS_CORE_INTR_MASK_CLEAR); 42 + 43 + return 0; 44 + } 45 + 46 + void pdsc_stop(struct pdsc *pdsc) 47 + { 48 + int i; 49 + 50 + if (!pdsc->intr_info) 51 + return; 52 + 53 + /* Mask interrupts that are in use */ 54 + for (i = 0; i < pdsc->nintrs; i++) 55 + if (pdsc->intr_info[i].vector) 56 + pds_core_intr_mask(&pdsc->intr_ctrl[i], 57 + PDS_CORE_INTR_MASK_SET); 434 58 } 435 59 436 60 static void pdsc_fw_down(struct pdsc *pdsc) ··· 464 44 465 45 devlink_health_report(pdsc->fw_reporter, "FW down reported", pdsc); 466 46 47 + pdsc_stop(pdsc); 467 48 pdsc_teardown(pdsc, PDSC_TEARDOWN_RECOVERY); 468 49 } 469 50 ··· 478 57 } 479 58 480 59 err = pdsc_setup(pdsc, PDSC_SETUP_RECOVERY); 60 + if (err) 61 + goto err_out; 62 + 63 + err = pdsc_start(pdsc); 481 64 if (err) 482 65 goto err_out; 483 66
+151
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_adminq.h> 12 13 #include <linux/pds/pds_intr.h> 13 14 14 15 #define PDSC_DRV_DESCRIPTION "AMD/Pensando Core Driver" 15 16 16 17 #define PDSC_WATCHDOG_SECS 5 18 + #define PDSC_QUEUE_NAME_MAX_SZ 32 19 + #define PDSC_ADMINQ_MIN_LENGTH 16 /* must be a power of two */ 20 + #define PDSC_NOTIFYQ_LENGTH 64 /* must be a power of two */ 17 21 #define PDSC_TEARDOWN_RECOVERY false 18 22 #define PDSC_TEARDOWN_REMOVING true 19 23 #define PDSC_SETUP_RECOVERY false ··· 37 33 char serial_num[PDS_CORE_DEVINFO_SERIAL_BUFLEN + 1]; 38 34 }; 39 35 36 + struct pdsc_queue { 37 + struct pdsc_q_info *info; 38 + u64 dbval; 39 + u16 head_idx; 40 + u16 tail_idx; 41 + u8 hw_type; 42 + unsigned int index; 43 + unsigned int num_descs; 44 + u64 dbell_count; 45 + u64 features; 46 + unsigned int type; 47 + unsigned int hw_index; 48 + union { 49 + void *base; 50 + struct pds_core_admin_cmd *adminq; 51 + }; 52 + dma_addr_t base_pa; /* must be page aligned */ 53 + unsigned int desc_size; 54 + unsigned int pid; 55 + char name[PDSC_QUEUE_NAME_MAX_SZ]; 56 + }; 57 + 40 58 #define PDSC_INTR_NAME_MAX_SZ 32 41 59 42 60 struct pdsc_intr_info { ··· 66 40 unsigned int index; 67 41 unsigned int vector; 68 42 void *data; 43 + }; 44 + 45 + struct pdsc_cq_info { 46 + void *comp; 47 + }; 48 + 49 + struct pdsc_buf_info { 50 + struct page *page; 51 + dma_addr_t dma_addr; 52 + u32 page_offset; 53 + u32 len; 54 + }; 55 + 56 + struct pdsc_q_info { 57 + union { 58 + void *desc; 59 + struct pdsc_admin_cmd *adminq_desc; 60 + }; 61 + unsigned int bytes; 62 + unsigned int nbufs; 63 + struct pdsc_buf_info bufs[PDS_CORE_MAX_FRAGS]; 64 + struct pdsc_wait_context *wc; 65 + void *dest; 66 + }; 67 + 68 + struct pdsc_cq { 69 + struct pdsc_cq_info *info; 70 + struct pdsc_queue *bound_q; 71 + struct pdsc_intr_info *bound_intr; 72 + u16 tail_idx; 73 + bool done_color; 74 + unsigned int num_descs; 75 + unsigned int desc_size; 76 + void *base; 77 + dma_addr_t base_pa; /* must be page aligned */ 78 + } ____cacheline_aligned_in_smp; 79 + 80 + struct pdsc_qcq { 81 + struct pdsc *pdsc; 82 + void *q_base; 83 + dma_addr_t q_base_pa; /* might not be page aligned */ 84 + void *cq_base; 85 + dma_addr_t cq_base_pa; /* might not be page aligned */ 86 + u32 q_size; 87 + u32 cq_size; 88 + bool armed; 89 + unsigned int flags; 90 + 91 + struct work_struct work; 92 + struct pdsc_queue q; 93 + struct pdsc_cq cq; 94 + int intx; 95 + 96 + u32 accum_work; 97 + struct dentry *dentry; 69 98 }; 70 99 71 100 /* No state flags set means we are in a steady running state */ ··· 162 81 unsigned int devcmd_timeout; 163 82 struct mutex devcmd_lock; /* lock for dev_cmd operations */ 164 83 struct mutex config_lock; /* lock for configuration operations */ 84 + spinlock_t adminq_lock; /* lock for adminq operations */ 165 85 struct pds_core_dev_info_regs __iomem *info_regs; 166 86 struct pds_core_dev_cmd_regs __iomem *cmd_regs; 167 87 struct pds_core_intr __iomem *intr_ctrl; ··· 170 88 u64 __iomem *db_pages; 171 89 dma_addr_t phy_db_pages; 172 90 u64 __iomem *kern_dbpage; 91 + 92 + struct pdsc_qcq adminqcq; 93 + struct pdsc_qcq notifyqcq; 94 + u64 last_eid; 173 95 }; 96 + 97 + /** enum pds_core_dbell_bits - bitwise composition of dbell values. 98 + * 99 + * @PDS_CORE_DBELL_QID_MASK: unshifted mask of valid queue id bits. 100 + * @PDS_CORE_DBELL_QID_SHIFT: queue id shift amount in dbell value. 101 + * @PDS_CORE_DBELL_QID: macro to build QID component of dbell value. 102 + * 103 + * @PDS_CORE_DBELL_RING_MASK: unshifted mask of valid ring bits. 104 + * @PDS_CORE_DBELL_RING_SHIFT: ring shift amount in dbell value. 105 + * @PDS_CORE_DBELL_RING: macro to build ring component of dbell value. 106 + * 107 + * @PDS_CORE_DBELL_RING_0: ring zero dbell component value. 108 + * @PDS_CORE_DBELL_RING_1: ring one dbell component value. 109 + * @PDS_CORE_DBELL_RING_2: ring two dbell component value. 110 + * @PDS_CORE_DBELL_RING_3: ring three dbell component value. 111 + * 112 + * @PDS_CORE_DBELL_INDEX_MASK: bit mask of valid index bits, no shift needed. 113 + */ 114 + enum pds_core_dbell_bits { 115 + PDS_CORE_DBELL_QID_MASK = 0xffffff, 116 + PDS_CORE_DBELL_QID_SHIFT = 24, 117 + 118 + #define PDS_CORE_DBELL_QID(n) \ 119 + (((u64)(n) & PDS_CORE_DBELL_QID_MASK) << PDS_CORE_DBELL_QID_SHIFT) 120 + 121 + PDS_CORE_DBELL_RING_MASK = 0x7, 122 + PDS_CORE_DBELL_RING_SHIFT = 16, 123 + 124 + #define PDS_CORE_DBELL_RING(n) \ 125 + (((u64)(n) & PDS_CORE_DBELL_RING_MASK) << PDS_CORE_DBELL_RING_SHIFT) 126 + 127 + PDS_CORE_DBELL_RING_0 = 0, 128 + PDS_CORE_DBELL_RING_1 = PDS_CORE_DBELL_RING(1), 129 + PDS_CORE_DBELL_RING_2 = PDS_CORE_DBELL_RING(2), 130 + PDS_CORE_DBELL_RING_3 = PDS_CORE_DBELL_RING(3), 131 + 132 + PDS_CORE_DBELL_INDEX_MASK = 0xffff, 133 + }; 134 + 135 + static inline void pds_core_dbell_ring(u64 __iomem *db_page, 136 + enum pds_core_logical_qtype qtype, 137 + u64 val) 138 + { 139 + writeq(val, &db_page[qtype]); 140 + } 174 141 175 142 int pdsc_fw_reporter_diagnose(struct devlink_health_reporter *reporter, 176 143 struct devlink_fmsg *fmsg, 177 144 struct netlink_ext_ack *extack); 145 + int pdsc_dl_info_get(struct devlink *dl, struct devlink_info_req *req, 146 + struct netlink_ext_ack *extack); 147 + 148 + void __iomem *pdsc_map_dbpage(struct pdsc *pdsc, int page_num); 178 149 179 150 void pdsc_debugfs_create(void); 180 151 void pdsc_debugfs_destroy(void); ··· 235 100 void pdsc_debugfs_del_dev(struct pdsc *pdsc); 236 101 void pdsc_debugfs_add_ident(struct pdsc *pdsc); 237 102 void pdsc_debugfs_add_irqs(struct pdsc *pdsc); 103 + void pdsc_debugfs_add_qcq(struct pdsc *pdsc, struct pdsc_qcq *qcq); 104 + void pdsc_debugfs_del_qcq(struct pdsc_qcq *qcq); 238 105 239 106 int pdsc_err_to_errno(enum pds_core_status_code code); 240 107 bool pdsc_is_fw_running(struct pdsc *pdsc); ··· 250 113 int pdsc_dev_reinit(struct pdsc *pdsc); 251 114 int pdsc_dev_init(struct pdsc *pdsc); 252 115 116 + int pdsc_intr_alloc(struct pdsc *pdsc, char *name, 117 + irq_handler_t handler, void *data); 118 + void pdsc_intr_free(struct pdsc *pdsc, int index); 119 + void pdsc_qcq_free(struct pdsc *pdsc, struct pdsc_qcq *qcq); 120 + int pdsc_qcq_alloc(struct pdsc *pdsc, unsigned int type, unsigned int index, 121 + const char *name, unsigned int flags, unsigned int num_descs, 122 + unsigned int desc_size, unsigned int cq_desc_size, 123 + unsigned int pid, struct pdsc_qcq *qcq); 253 124 int pdsc_setup(struct pdsc *pdsc, bool init); 254 125 void pdsc_teardown(struct pdsc *pdsc, bool removing); 126 + int pdsc_start(struct pdsc *pdsc); 127 + void pdsc_stop(struct pdsc *pdsc); 255 128 void pdsc_health_thread(struct work_struct *work); 129 + 130 + void pdsc_process_adminq(struct pdsc_qcq *qcq); 131 + void pdsc_work_thread(struct work_struct *work); 132 + irqreturn_t pdsc_adminq_isr(int irq, void *data); 256 133 257 134 #endif /* _PDSC_H_ */
+77
drivers/net/ethernet/amd/pds_core/debugfs.c
··· 67 67 debugfs_create_file("identity", 0400, pdsc->dentry, 68 68 pdsc, &identity_fops); 69 69 } 70 + 71 + static const struct debugfs_reg32 intr_ctrl_regs[] = { 72 + { .name = "coal_init", .offset = 0, }, 73 + { .name = "mask", .offset = 4, }, 74 + { .name = "credits", .offset = 8, }, 75 + { .name = "mask_on_assert", .offset = 12, }, 76 + { .name = "coal_timer", .offset = 16, }, 77 + }; 78 + 79 + void pdsc_debugfs_add_qcq(struct pdsc *pdsc, struct pdsc_qcq *qcq) 80 + { 81 + struct dentry *qcq_dentry, *q_dentry, *cq_dentry; 82 + struct dentry *intr_dentry; 83 + struct debugfs_regset32 *intr_ctrl_regset; 84 + struct pdsc_intr_info *intr = &pdsc->intr_info[qcq->intx]; 85 + struct pdsc_queue *q = &qcq->q; 86 + struct pdsc_cq *cq = &qcq->cq; 87 + 88 + qcq_dentry = debugfs_create_dir(q->name, pdsc->dentry); 89 + if (IS_ERR_OR_NULL(qcq_dentry)) 90 + return; 91 + qcq->dentry = qcq_dentry; 92 + 93 + debugfs_create_x64("q_base_pa", 0400, qcq_dentry, &qcq->q_base_pa); 94 + debugfs_create_x32("q_size", 0400, qcq_dentry, &qcq->q_size); 95 + debugfs_create_x64("cq_base_pa", 0400, qcq_dentry, &qcq->cq_base_pa); 96 + debugfs_create_x32("cq_size", 0400, qcq_dentry, &qcq->cq_size); 97 + debugfs_create_x32("accum_work", 0400, qcq_dentry, &qcq->accum_work); 98 + 99 + q_dentry = debugfs_create_dir("q", qcq->dentry); 100 + if (IS_ERR_OR_NULL(q_dentry)) 101 + return; 102 + 103 + debugfs_create_u32("index", 0400, q_dentry, &q->index); 104 + debugfs_create_u32("num_descs", 0400, q_dentry, &q->num_descs); 105 + debugfs_create_u32("desc_size", 0400, q_dentry, &q->desc_size); 106 + debugfs_create_u32("pid", 0400, q_dentry, &q->pid); 107 + 108 + debugfs_create_u16("tail", 0400, q_dentry, &q->tail_idx); 109 + debugfs_create_u16("head", 0400, q_dentry, &q->head_idx); 110 + 111 + cq_dentry = debugfs_create_dir("cq", qcq->dentry); 112 + if (IS_ERR_OR_NULL(cq_dentry)) 113 + return; 114 + 115 + debugfs_create_x64("base_pa", 0400, cq_dentry, &cq->base_pa); 116 + debugfs_create_u32("num_descs", 0400, cq_dentry, &cq->num_descs); 117 + debugfs_create_u32("desc_size", 0400, cq_dentry, &cq->desc_size); 118 + debugfs_create_bool("done_color", 0400, cq_dentry, &cq->done_color); 119 + debugfs_create_u16("tail", 0400, cq_dentry, &cq->tail_idx); 120 + 121 + if (qcq->flags & PDS_CORE_QCQ_F_INTR) { 122 + intr_dentry = debugfs_create_dir("intr", qcq->dentry); 123 + if (IS_ERR_OR_NULL(intr_dentry)) 124 + return; 125 + 126 + debugfs_create_u32("index", 0400, intr_dentry, &intr->index); 127 + debugfs_create_u32("vector", 0400, intr_dentry, &intr->vector); 128 + 129 + intr_ctrl_regset = kzalloc(sizeof(*intr_ctrl_regset), 130 + GFP_KERNEL); 131 + if (!intr_ctrl_regset) 132 + return; 133 + intr_ctrl_regset->regs = intr_ctrl_regs; 134 + intr_ctrl_regset->nregs = ARRAY_SIZE(intr_ctrl_regs); 135 + intr_ctrl_regset->base = &pdsc->intr_ctrl[intr->index]; 136 + 137 + debugfs_create_regset32("intr_ctrl", 0400, intr_dentry, 138 + intr_ctrl_regset); 139 + } 140 + }; 141 + 142 + void pdsc_debugfs_del_qcq(struct pdsc_qcq *qcq) 143 + { 144 + debugfs_remove_recursive(qcq->dentry); 145 + qcq->dentry = NULL; 146 + }
+61
drivers/net/ethernet/amd/pds_core/devlink.c
··· 3 3 4 4 #include "core.h" 5 5 6 + static char *fw_slotnames[] = { 7 + "fw.goldfw", 8 + "fw.mainfwa", 9 + "fw.mainfwb", 10 + }; 11 + 12 + int pdsc_dl_info_get(struct devlink *dl, struct devlink_info_req *req, 13 + struct netlink_ext_ack *extack) 14 + { 15 + union pds_core_dev_cmd cmd = { 16 + .fw_control.opcode = PDS_CORE_CMD_FW_CONTROL, 17 + .fw_control.oper = PDS_CORE_FW_GET_LIST, 18 + }; 19 + struct pds_core_fw_list_info fw_list; 20 + struct pdsc *pdsc = devlink_priv(dl); 21 + union pds_core_dev_comp comp; 22 + char buf[16]; 23 + int listlen; 24 + int err; 25 + int i; 26 + 27 + mutex_lock(&pdsc->devcmd_lock); 28 + err = pdsc_devcmd_locked(pdsc, &cmd, &comp, pdsc->devcmd_timeout * 2); 29 + memcpy_fromio(&fw_list, pdsc->cmd_regs->data, sizeof(fw_list)); 30 + mutex_unlock(&pdsc->devcmd_lock); 31 + if (err && err != -EIO) 32 + return err; 33 + 34 + listlen = fw_list.num_fw_slots; 35 + for (i = 0; i < listlen; i++) { 36 + if (i < ARRAY_SIZE(fw_slotnames)) 37 + strscpy(buf, fw_slotnames[i], sizeof(buf)); 38 + else 39 + snprintf(buf, sizeof(buf), "fw.slot_%d", i); 40 + err = devlink_info_version_stored_put(req, buf, 41 + fw_list.fw_names[i].fw_version); 42 + } 43 + 44 + err = devlink_info_version_running_put(req, 45 + DEVLINK_INFO_VERSION_GENERIC_FW, 46 + pdsc->dev_info.fw_version); 47 + if (err) 48 + return err; 49 + 50 + snprintf(buf, sizeof(buf), "0x%x", pdsc->dev_info.asic_type); 51 + err = devlink_info_version_fixed_put(req, 52 + DEVLINK_INFO_VERSION_GENERIC_ASIC_ID, 53 + buf); 54 + if (err) 55 + return err; 56 + 57 + snprintf(buf, sizeof(buf), "0x%x", pdsc->dev_info.asic_rev); 58 + err = devlink_info_version_fixed_put(req, 59 + DEVLINK_INFO_VERSION_GENERIC_ASIC_REV, 60 + buf); 61 + if (err) 62 + return err; 63 + 64 + return devlink_info_serial_number_put(req, pdsc->dev_info.serial_num); 65 + } 66 + 6 67 int pdsc_fw_reporter_diagnose(struct devlink_health_reporter *reporter, 7 68 struct devlink_fmsg *fmsg, 8 69 struct netlink_ext_ack *extack)
+16 -1
drivers/net/ethernet/amd/pds_core/main.c
··· 125 125 return err; 126 126 } 127 127 128 + void __iomem *pdsc_map_dbpage(struct pdsc *pdsc, int page_num) 129 + { 130 + return pci_iomap_range(pdsc->pdev, 131 + pdsc->bars[PDS_CORE_PCI_BAR_DBELL].res_index, 132 + (u64)page_num << PAGE_SHIFT, PAGE_SIZE); 133 + } 134 + 128 135 static int pdsc_init_vf(struct pdsc *vf) 129 136 { 130 137 return -1; ··· 173 166 174 167 mutex_init(&pdsc->devcmd_lock); 175 168 mutex_init(&pdsc->config_lock); 169 + spin_lock_init(&pdsc->adminq_lock); 176 170 177 171 mutex_lock(&pdsc->config_lock); 178 172 set_bit(PDSC_S_FW_DEAD, &pdsc->state); ··· 181 173 err = pdsc_setup(pdsc, PDSC_SETUP_INIT); 182 174 if (err) 183 175 goto err_out_unmap_bars; 176 + err = pdsc_start(pdsc); 177 + if (err) 178 + goto err_out_teardown; 184 179 185 180 mutex_unlock(&pdsc->config_lock); 186 181 ··· 195 184 dev_warn(pdsc->dev, "Failed to create fw reporter: %pe\n", hr); 196 185 err = PTR_ERR(hr); 197 186 devl_unlock(dl); 198 - goto err_out_teardown; 187 + goto err_out_stop; 199 188 } 200 189 pdsc->fw_reporter = hr; 201 190 ··· 207 196 208 197 return 0; 209 198 199 + err_out_stop: 200 + pdsc_stop(pdsc); 210 201 err_out_teardown: 211 202 pdsc_teardown(pdsc, PDSC_TEARDOWN_REMOVING); 212 203 err_out_unmap_bars: ··· 227 214 } 228 215 229 216 static const struct devlink_ops pdsc_dl_ops = { 217 + .info_get = pdsc_dl_info_get, 230 218 }; 231 219 232 220 static const struct devlink_ops pdsc_dl_vf_ops = { ··· 329 315 mutex_lock(&pdsc->config_lock); 330 316 set_bit(PDSC_S_STOPPING_DRIVER, &pdsc->state); 331 317 318 + pdsc_stop(pdsc); 332 319 pdsc_teardown(pdsc, PDSC_TEARDOWN_REMOVING); 333 320 mutex_unlock(&pdsc->config_lock); 334 321 mutex_destroy(&pdsc->config_lock);
+638
include/linux/pds/pds_adminq.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* Copyright(c) 2023 Advanced Micro Devices, Inc */ 3 + 4 + #ifndef _PDS_CORE_ADMINQ_H_ 5 + #define _PDS_CORE_ADMINQ_H_ 6 + 7 + enum pds_core_adminq_flags { 8 + PDS_AQ_FLAG_FASTPOLL = BIT(1), /* completion poll at 1ms */ 9 + }; 10 + 11 + /* 12 + * enum pds_core_adminq_opcode - AdminQ command opcodes 13 + * These commands are only processed on AdminQ, not available in devcmd 14 + */ 15 + enum pds_core_adminq_opcode { 16 + PDS_AQ_CMD_NOP = 0, 17 + 18 + /* Client control */ 19 + PDS_AQ_CMD_CLIENT_REG = 6, 20 + PDS_AQ_CMD_CLIENT_UNREG = 7, 21 + PDS_AQ_CMD_CLIENT_CMD = 8, 22 + 23 + /* LIF commands */ 24 + PDS_AQ_CMD_LIF_IDENTIFY = 20, 25 + PDS_AQ_CMD_LIF_INIT = 21, 26 + PDS_AQ_CMD_LIF_RESET = 22, 27 + PDS_AQ_CMD_LIF_GETATTR = 23, 28 + PDS_AQ_CMD_LIF_SETATTR = 24, 29 + PDS_AQ_CMD_LIF_SETPHC = 25, 30 + 31 + PDS_AQ_CMD_RX_MODE_SET = 30, 32 + PDS_AQ_CMD_RX_FILTER_ADD = 31, 33 + PDS_AQ_CMD_RX_FILTER_DEL = 32, 34 + 35 + /* Queue commands */ 36 + PDS_AQ_CMD_Q_IDENTIFY = 39, 37 + PDS_AQ_CMD_Q_INIT = 40, 38 + PDS_AQ_CMD_Q_CONTROL = 41, 39 + 40 + /* SR/IOV commands */ 41 + PDS_AQ_CMD_VF_GETATTR = 60, 42 + PDS_AQ_CMD_VF_SETATTR = 61, 43 + }; 44 + 45 + /* 46 + * enum pds_core_notifyq_opcode - NotifyQ event codes 47 + */ 48 + enum pds_core_notifyq_opcode { 49 + PDS_EVENT_LINK_CHANGE = 1, 50 + PDS_EVENT_RESET = 2, 51 + PDS_EVENT_XCVR = 5, 52 + PDS_EVENT_CLIENT = 6, 53 + }; 54 + 55 + #define PDS_COMP_COLOR_MASK 0x80 56 + 57 + /** 58 + * struct pds_core_notifyq_event - Generic event reporting structure 59 + * @eid: event number 60 + * @ecode: event code 61 + * 62 + * This is the generic event report struct from which the other 63 + * actual events will be formed. 64 + */ 65 + struct pds_core_notifyq_event { 66 + __le64 eid; 67 + __le16 ecode; 68 + }; 69 + 70 + /** 71 + * struct pds_core_link_change_event - Link change event notification 72 + * @eid: event number 73 + * @ecode: event code = PDS_EVENT_LINK_CHANGE 74 + * @link_status: link up/down, with error bits 75 + * @link_speed: speed of the network link 76 + * 77 + * Sent when the network link state changes between UP and DOWN 78 + */ 79 + struct pds_core_link_change_event { 80 + __le64 eid; 81 + __le16 ecode; 82 + __le16 link_status; 83 + __le32 link_speed; /* units of 1Mbps: e.g. 10000 = 10Gbps */ 84 + }; 85 + 86 + /** 87 + * struct pds_core_reset_event - Reset event notification 88 + * @eid: event number 89 + * @ecode: event code = PDS_EVENT_RESET 90 + * @reset_code: reset type 91 + * @state: 0=pending, 1=complete, 2=error 92 + * 93 + * Sent when the NIC or some subsystem is going to be or 94 + * has been reset. 95 + */ 96 + struct pds_core_reset_event { 97 + __le64 eid; 98 + __le16 ecode; 99 + u8 reset_code; 100 + u8 state; 101 + }; 102 + 103 + /** 104 + * struct pds_core_client_event - Client event notification 105 + * @eid: event number 106 + * @ecode: event code = PDS_EVENT_CLIENT 107 + * @client_id: client to sent event to 108 + * @client_event: wrapped event struct for the client 109 + * 110 + * Sent when an event needs to be passed on to a client 111 + */ 112 + struct pds_core_client_event { 113 + __le64 eid; 114 + __le16 ecode; 115 + __le16 client_id; 116 + u8 client_event[54]; 117 + }; 118 + 119 + /** 120 + * struct pds_core_notifyq_cmd - Placeholder for building qcq 121 + * @data: anonymous field for building the qcq 122 + */ 123 + struct pds_core_notifyq_cmd { 124 + __le32 data; /* Not used but needed for qcq structure */ 125 + }; 126 + 127 + /* 128 + * union pds_core_notifyq_comp - Overlay of notifyq event structures 129 + */ 130 + union pds_core_notifyq_comp { 131 + struct { 132 + __le64 eid; 133 + __le16 ecode; 134 + }; 135 + struct pds_core_notifyq_event event; 136 + struct pds_core_link_change_event link_change; 137 + struct pds_core_reset_event reset; 138 + u8 data[64]; 139 + }; 140 + 141 + #define PDS_DEVNAME_LEN 32 142 + /** 143 + * struct pds_core_client_reg_cmd - Register a new client with DSC 144 + * @opcode: opcode PDS_AQ_CMD_CLIENT_REG 145 + * @rsvd: word boundary padding 146 + * @devname: text name of client device 147 + * @vif_type: what type of device (enum pds_core_vif_types) 148 + * 149 + * Tell the DSC of the new client, and receive a client_id from DSC. 150 + */ 151 + struct pds_core_client_reg_cmd { 152 + u8 opcode; 153 + u8 rsvd[3]; 154 + char devname[PDS_DEVNAME_LEN]; 155 + u8 vif_type; 156 + }; 157 + 158 + /** 159 + * struct pds_core_client_reg_comp - Client registration completion 160 + * @status: Status of the command (enum pdc_core_status_code) 161 + * @rsvd: Word boundary padding 162 + * @comp_index: Index in the descriptor ring for which this is the completion 163 + * @client_id: New id assigned by DSC 164 + * @rsvd1: Word boundary padding 165 + * @color: Color bit 166 + */ 167 + struct pds_core_client_reg_comp { 168 + u8 status; 169 + u8 rsvd; 170 + __le16 comp_index; 171 + __le16 client_id; 172 + u8 rsvd1[9]; 173 + u8 color; 174 + }; 175 + 176 + /** 177 + * struct pds_core_client_unreg_cmd - Unregister a client from DSC 178 + * @opcode: opcode PDS_AQ_CMD_CLIENT_UNREG 179 + * @rsvd: word boundary padding 180 + * @client_id: id of client being removed 181 + * 182 + * Tell the DSC this client is going away and remove its context 183 + * This uses the generic completion. 184 + */ 185 + struct pds_core_client_unreg_cmd { 186 + u8 opcode; 187 + u8 rsvd; 188 + __le16 client_id; 189 + }; 190 + 191 + /** 192 + * struct pds_core_client_request_cmd - Pass along a wrapped client AdminQ cmd 193 + * @opcode: opcode PDS_AQ_CMD_CLIENT_CMD 194 + * @rsvd: word boundary padding 195 + * @client_id: id of client being removed 196 + * @client_cmd: the wrapped client command 197 + * 198 + * Proxy post an adminq command for the client. 199 + * This uses the generic completion. 200 + */ 201 + struct pds_core_client_request_cmd { 202 + u8 opcode; 203 + u8 rsvd; 204 + __le16 client_id; 205 + u8 client_cmd[60]; 206 + }; 207 + 208 + #define PDS_CORE_MAX_FRAGS 16 209 + 210 + #define PDS_CORE_QCQ_F_INITED BIT(0) 211 + #define PDS_CORE_QCQ_F_SG BIT(1) 212 + #define PDS_CORE_QCQ_F_INTR BIT(2) 213 + #define PDS_CORE_QCQ_F_TX_STATS BIT(3) 214 + #define PDS_CORE_QCQ_F_RX_STATS BIT(4) 215 + #define PDS_CORE_QCQ_F_NOTIFYQ BIT(5) 216 + #define PDS_CORE_QCQ_F_CMB_RINGS BIT(6) 217 + #define PDS_CORE_QCQ_F_CORE BIT(7) 218 + 219 + enum pds_core_lif_type { 220 + PDS_CORE_LIF_TYPE_DEFAULT = 0, 221 + }; 222 + 223 + /** 224 + * union pds_core_lif_config - LIF configuration 225 + * @state: LIF state (enum pds_core_lif_state) 226 + * @rsvd: Word boundary padding 227 + * @name: LIF name 228 + * @rsvd2: Word boundary padding 229 + * @features: LIF features active (enum pds_core_hw_features) 230 + * @queue_count: Queue counts per queue-type 231 + * @words: Full union buffer size 232 + */ 233 + union pds_core_lif_config { 234 + struct { 235 + u8 state; 236 + u8 rsvd[3]; 237 + char name[PDS_CORE_IFNAMSIZ]; 238 + u8 rsvd2[12]; 239 + __le64 features; 240 + __le32 queue_count[PDS_CORE_QTYPE_MAX]; 241 + } __packed; 242 + __le32 words[64]; 243 + }; 244 + 245 + /** 246 + * struct pds_core_lif_status - LIF status register 247 + * @eid: most recent NotifyQ event id 248 + * @rsvd: full struct size 249 + */ 250 + struct pds_core_lif_status { 251 + __le64 eid; 252 + u8 rsvd[56]; 253 + }; 254 + 255 + /** 256 + * struct pds_core_lif_info - LIF info structure 257 + * @config: LIF configuration structure 258 + * @status: LIF status structure 259 + */ 260 + struct pds_core_lif_info { 261 + union pds_core_lif_config config; 262 + struct pds_core_lif_status status; 263 + }; 264 + 265 + /** 266 + * struct pds_core_lif_identity - LIF identity information (type-specific) 267 + * @features: LIF features (see enum pds_core_hw_features) 268 + * @version: Identify structure version 269 + * @hw_index: LIF hardware index 270 + * @rsvd: Word boundary padding 271 + * @max_nb_sessions: Maximum number of sessions supported 272 + * @rsvd2: buffer padding 273 + * @config: LIF config struct with features, q counts 274 + */ 275 + struct pds_core_lif_identity { 276 + __le64 features; 277 + u8 version; 278 + u8 hw_index; 279 + u8 rsvd[2]; 280 + __le32 max_nb_sessions; 281 + u8 rsvd2[120]; 282 + union pds_core_lif_config config; 283 + }; 284 + 285 + /** 286 + * struct pds_core_lif_identify_cmd - Get LIF identity info command 287 + * @opcode: Opcode PDS_AQ_CMD_LIF_IDENTIFY 288 + * @type: LIF type (enum pds_core_lif_type) 289 + * @client_id: Client identifier 290 + * @ver: Version of identify returned by device 291 + * @rsvd: Word boundary padding 292 + * @ident_pa: DMA address to receive identity info 293 + * 294 + * Firmware will copy LIF identity data (struct pds_core_lif_identity) 295 + * into the buffer address given. 296 + */ 297 + struct pds_core_lif_identify_cmd { 298 + u8 opcode; 299 + u8 type; 300 + __le16 client_id; 301 + u8 ver; 302 + u8 rsvd[3]; 303 + __le64 ident_pa; 304 + }; 305 + 306 + /** 307 + * struct pds_core_lif_identify_comp - LIF identify command completion 308 + * @status: Status of the command (enum pds_core_status_code) 309 + * @ver: Version of identify returned by device 310 + * @bytes: Bytes copied into the buffer 311 + * @rsvd: Word boundary padding 312 + * @color: Color bit 313 + */ 314 + struct pds_core_lif_identify_comp { 315 + u8 status; 316 + u8 ver; 317 + __le16 bytes; 318 + u8 rsvd[11]; 319 + u8 color; 320 + }; 321 + 322 + /** 323 + * struct pds_core_lif_init_cmd - LIF init command 324 + * @opcode: Opcode PDS_AQ_CMD_LIF_INIT 325 + * @type: LIF type (enum pds_core_lif_type) 326 + * @client_id: Client identifier 327 + * @rsvd: Word boundary padding 328 + * @info_pa: Destination address for LIF info (struct pds_core_lif_info) 329 + */ 330 + struct pds_core_lif_init_cmd { 331 + u8 opcode; 332 + u8 type; 333 + __le16 client_id; 334 + __le32 rsvd; 335 + __le64 info_pa; 336 + }; 337 + 338 + /** 339 + * struct pds_core_lif_init_comp - LIF init command completion 340 + * @status: Status of the command (enum pds_core_status_code) 341 + * @rsvd: Word boundary padding 342 + * @hw_index: Hardware index of the initialized LIF 343 + * @rsvd1: Word boundary padding 344 + * @color: Color bit 345 + */ 346 + struct pds_core_lif_init_comp { 347 + u8 status; 348 + u8 rsvd; 349 + __le16 hw_index; 350 + u8 rsvd1[11]; 351 + u8 color; 352 + }; 353 + 354 + /** 355 + * struct pds_core_lif_reset_cmd - LIF reset command 356 + * Will reset only the specified LIF. 357 + * @opcode: Opcode PDS_AQ_CMD_LIF_RESET 358 + * @rsvd: Word boundary padding 359 + * @client_id: Client identifier 360 + */ 361 + struct pds_core_lif_reset_cmd { 362 + u8 opcode; 363 + u8 rsvd; 364 + __le16 client_id; 365 + }; 366 + 367 + /** 368 + * enum pds_core_lif_attr - List of LIF attributes 369 + * @PDS_CORE_LIF_ATTR_STATE: LIF state attribute 370 + * @PDS_CORE_LIF_ATTR_NAME: LIF name attribute 371 + * @PDS_CORE_LIF_ATTR_FEATURES: LIF features attribute 372 + * @PDS_CORE_LIF_ATTR_STATS_CTRL: LIF statistics control attribute 373 + */ 374 + enum pds_core_lif_attr { 375 + PDS_CORE_LIF_ATTR_STATE = 0, 376 + PDS_CORE_LIF_ATTR_NAME = 1, 377 + PDS_CORE_LIF_ATTR_FEATURES = 4, 378 + PDS_CORE_LIF_ATTR_STATS_CTRL = 6, 379 + }; 380 + 381 + /** 382 + * struct pds_core_lif_setattr_cmd - Set LIF attributes on the NIC 383 + * @opcode: Opcode PDS_AQ_CMD_LIF_SETATTR 384 + * @attr: Attribute type (enum pds_core_lif_attr) 385 + * @client_id: Client identifier 386 + * @state: LIF state (enum pds_core_lif_state) 387 + * @name: The name string, 0 terminated 388 + * @features: Features (enum pds_core_hw_features) 389 + * @stats_ctl: Stats control commands (enum pds_core_stats_ctl_cmd) 390 + * @rsvd: Command Buffer padding 391 + */ 392 + struct pds_core_lif_setattr_cmd { 393 + u8 opcode; 394 + u8 attr; 395 + __le16 client_id; 396 + union { 397 + u8 state; 398 + char name[PDS_CORE_IFNAMSIZ]; 399 + __le64 features; 400 + u8 stats_ctl; 401 + u8 rsvd[60]; 402 + } __packed; 403 + }; 404 + 405 + /** 406 + * struct pds_core_lif_setattr_comp - LIF set attr command completion 407 + * @status: Status of the command (enum pds_core_status_code) 408 + * @rsvd: Word boundary padding 409 + * @comp_index: Index in the descriptor ring for which this is the completion 410 + * @features: Features (enum pds_core_hw_features) 411 + * @rsvd2: Word boundary padding 412 + * @color: Color bit 413 + */ 414 + struct pds_core_lif_setattr_comp { 415 + u8 status; 416 + u8 rsvd; 417 + __le16 comp_index; 418 + union { 419 + __le64 features; 420 + u8 rsvd2[11]; 421 + } __packed; 422 + u8 color; 423 + }; 424 + 425 + /** 426 + * struct pds_core_lif_getattr_cmd - Get LIF attributes from the NIC 427 + * @opcode: Opcode PDS_AQ_CMD_LIF_GETATTR 428 + * @attr: Attribute type (enum pds_core_lif_attr) 429 + * @client_id: Client identifier 430 + */ 431 + struct pds_core_lif_getattr_cmd { 432 + u8 opcode; 433 + u8 attr; 434 + __le16 client_id; 435 + }; 436 + 437 + /** 438 + * struct pds_core_lif_getattr_comp - LIF get attr command completion 439 + * @status: Status of the command (enum pds_core_status_code) 440 + * @rsvd: Word boundary padding 441 + * @comp_index: Index in the descriptor ring for which this is the completion 442 + * @state: LIF state (enum pds_core_lif_state) 443 + * @name: LIF name string, 0 terminated 444 + * @features: Features (enum pds_core_hw_features) 445 + * @rsvd2: Word boundary padding 446 + * @color: Color bit 447 + */ 448 + struct pds_core_lif_getattr_comp { 449 + u8 status; 450 + u8 rsvd; 451 + __le16 comp_index; 452 + union { 453 + u8 state; 454 + __le64 features; 455 + u8 rsvd2[11]; 456 + } __packed; 457 + u8 color; 458 + }; 459 + 460 + /** 461 + * union pds_core_q_identity - Queue identity information 462 + * @version: Queue type version that can be used with FW 463 + * @supported: Bitfield of queue versions, first bit = ver 0 464 + * @rsvd: Word boundary padding 465 + * @features: Queue features 466 + * @desc_sz: Descriptor size 467 + * @comp_sz: Completion descriptor size 468 + * @rsvd2: Word boundary padding 469 + */ 470 + struct pds_core_q_identity { 471 + u8 version; 472 + u8 supported; 473 + u8 rsvd[6]; 474 + #define PDS_CORE_QIDENT_F_CQ 0x01 /* queue has completion ring */ 475 + __le64 features; 476 + __le16 desc_sz; 477 + __le16 comp_sz; 478 + u8 rsvd2[6]; 479 + }; 480 + 481 + /** 482 + * struct pds_core_q_identify_cmd - queue identify command 483 + * @opcode: Opcode PDS_AQ_CMD_Q_IDENTIFY 484 + * @type: Logical queue type (enum pds_core_logical_qtype) 485 + * @client_id: Client identifier 486 + * @ver: Highest queue type version that the driver supports 487 + * @rsvd: Word boundary padding 488 + * @ident_pa: DMA address to receive the data (struct pds_core_q_identity) 489 + */ 490 + struct pds_core_q_identify_cmd { 491 + u8 opcode; 492 + u8 type; 493 + __le16 client_id; 494 + u8 ver; 495 + u8 rsvd[3]; 496 + __le64 ident_pa; 497 + }; 498 + 499 + /** 500 + * struct pds_core_q_identify_comp - queue identify command completion 501 + * @status: Status of the command (enum pds_core_status_code) 502 + * @rsvd: Word boundary padding 503 + * @comp_index: Index in the descriptor ring for which this is the completion 504 + * @ver: Queue type version that can be used with FW 505 + * @rsvd1: Word boundary padding 506 + * @color: Color bit 507 + */ 508 + struct pds_core_q_identify_comp { 509 + u8 status; 510 + u8 rsvd; 511 + __le16 comp_index; 512 + u8 ver; 513 + u8 rsvd1[10]; 514 + u8 color; 515 + }; 516 + 517 + /** 518 + * struct pds_core_q_init_cmd - Queue init command 519 + * @opcode: Opcode PDS_AQ_CMD_Q_INIT 520 + * @type: Logical queue type 521 + * @client_id: Client identifier 522 + * @ver: Queue type version 523 + * @rsvd: Word boundary padding 524 + * @index: (LIF, qtype) relative admin queue index 525 + * @intr_index: Interrupt control register index, or Event queue index 526 + * @pid: Process ID 527 + * @flags: 528 + * IRQ: Interrupt requested on completion 529 + * ENA: Enable the queue. If ENA=0 the queue is initialized 530 + * but remains disabled, to be later enabled with the 531 + * Queue Enable command. If ENA=1, then queue is 532 + * initialized and then enabled. 533 + * @cos: Class of service for this queue 534 + * @ring_size: Queue ring size, encoded as a log2(size), in 535 + * number of descriptors. The actual ring size is 536 + * (1 << ring_size). For example, to select a ring size 537 + * of 64 descriptors write ring_size = 6. The minimum 538 + * ring_size value is 2 for a ring of 4 descriptors. 539 + * The maximum ring_size value is 12 for a ring of 4k 540 + * descriptors. Values of ring_size <2 and >12 are 541 + * reserved. 542 + * @ring_base: Queue ring base address 543 + * @cq_ring_base: Completion queue ring base address 544 + */ 545 + struct pds_core_q_init_cmd { 546 + u8 opcode; 547 + u8 type; 548 + __le16 client_id; 549 + u8 ver; 550 + u8 rsvd[3]; 551 + __le32 index; 552 + __le16 pid; 553 + __le16 intr_index; 554 + __le16 flags; 555 + #define PDS_CORE_QINIT_F_IRQ 0x01 /* Request interrupt on completion */ 556 + #define PDS_CORE_QINIT_F_ENA 0x02 /* Enable the queue */ 557 + u8 cos; 558 + #define PDS_CORE_QSIZE_MIN_LG2 2 559 + #define PDS_CORE_QSIZE_MAX_LG2 12 560 + u8 ring_size; 561 + __le64 ring_base; 562 + __le64 cq_ring_base; 563 + } __packed; 564 + 565 + /** 566 + * struct pds_core_q_init_comp - Queue init command completion 567 + * @status: Status of the command (enum pds_core_status_code) 568 + * @rsvd: Word boundary padding 569 + * @comp_index: Index in the descriptor ring for which this is the completion 570 + * @hw_index: Hardware Queue ID 571 + * @hw_type: Hardware Queue type 572 + * @rsvd2: Word boundary padding 573 + * @color: Color 574 + */ 575 + struct pds_core_q_init_comp { 576 + u8 status; 577 + u8 rsvd; 578 + __le16 comp_index; 579 + __le32 hw_index; 580 + u8 hw_type; 581 + u8 rsvd2[6]; 582 + u8 color; 583 + }; 584 + 585 + union pds_core_adminq_cmd { 586 + u8 opcode; 587 + u8 bytes[64]; 588 + 589 + struct pds_core_client_reg_cmd client_reg; 590 + struct pds_core_client_unreg_cmd client_unreg; 591 + struct pds_core_client_request_cmd client_request; 592 + 593 + struct pds_core_lif_identify_cmd lif_ident; 594 + struct pds_core_lif_init_cmd lif_init; 595 + struct pds_core_lif_reset_cmd lif_reset; 596 + struct pds_core_lif_setattr_cmd lif_setattr; 597 + struct pds_core_lif_getattr_cmd lif_getattr; 598 + 599 + struct pds_core_q_identify_cmd q_ident; 600 + struct pds_core_q_init_cmd q_init; 601 + }; 602 + 603 + union pds_core_adminq_comp { 604 + struct { 605 + u8 status; 606 + u8 rsvd; 607 + __le16 comp_index; 608 + u8 rsvd2[11]; 609 + u8 color; 610 + }; 611 + u32 words[4]; 612 + 613 + struct pds_core_client_reg_comp client_reg; 614 + 615 + struct pds_core_lif_identify_comp lif_ident; 616 + struct pds_core_lif_init_comp lif_init; 617 + struct pds_core_lif_setattr_comp lif_setattr; 618 + struct pds_core_lif_getattr_comp lif_getattr; 619 + 620 + struct pds_core_q_identify_comp q_ident; 621 + struct pds_core_q_init_comp q_init; 622 + }; 623 + 624 + #ifndef __CHECKER__ 625 + static_assert(sizeof(union pds_core_adminq_cmd) == 64); 626 + static_assert(sizeof(union pds_core_adminq_comp) == 16); 627 + static_assert(sizeof(union pds_core_notifyq_comp) == 64); 628 + #endif /* __CHECKER__ */ 629 + 630 + /* The color bit is a 'done' bit for the completion descriptors 631 + * where the meaning alternates between '1' and '0' for alternating 632 + * passes through the completion descriptor ring. 633 + */ 634 + static inline u8 pdsc_color_match(u8 color, u8 done_color) 635 + { 636 + return (!!(color & PDS_COMP_COLOR_MASK)) == done_color; 637 + } 638 + #endif /* _PDS_CORE_ADMINQ_H_ */