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.

Merge branch 'pds_core'

Shannon Nelson says:

====================
pds_core driver

Summary:
--------
This patchset implements a new driver for use with the AMD/Pensando
Distributed Services Card (DSC), intended to provide core configuration
services through the auxiliary_bus and through a couple of EXPORTed
functions for use initially in VFio and vDPA feature specific drivers.

To keep this patchset to a manageable size, the pds_vdpa and pds_vfio
drivers have been split out into their own patchsets to be reviewed
separately.

Detail:
-------
AMD/Pensando is making available a new set of devices for supporting vDPA,
VFio, and potentially other features in the Distributed Services Card
(DSC). These features are implemented through a PF that serves as a Core
device for controlling and configuring its VF devices. These VF devices
have separate drivers that use the auxiliary_bus to work through the Core
device as the control path.

Currently, the DSC supports standard ethernet operations using the
ionic driver. This is not replaced by the Core-based devices - these
new devices are in addition to the existing Ethernet device. Typical DSC
configurations will include both PDS devices and Ionic Eth devices.
However, there is a potential future path for ethernet services to come
through this device as well.

The Core device is a new PCI PF/VF device managed by a new driver
'pds_core'. The PF device has access to an admin queue for configuring
the services used by the VFs, and sets up auxiliary_bus devices for each
vDPA VF for communicating with the drivers for the vDPA devices. The VFs
may be for VFio or vDPA, and other services in the future; these VF types
are selected as part of the DSC internal FW configurations, which is out
of the scope of this patchset.

When the vDPA support set is enabled in the core PF through its devlink
param, auxiliary_bus devices are created for each VF that supports the
feature. The vDPA driver then connects to and uses this auxiliary_device
to do control path configuration through the PF device. This can then be
used with the vdpa kernel module to provide devices for virtio_vdpa kernel
module for host interfaces, or vhost_vdpa kernel module for interfaces
exported into your favorite VM.

A cheap ASCII diagram of a vDPA instance looks something like this:

,----------.
| vdpa |
'----------'
| ||
ctl data
| ||
.----------. ||
| pds_vdpa | ||
'----------' ||
| ||
pds_core.vDPA.1 ||
| ||
.---------------. ||
| pds_core | ||
'---------------' ||
|| || ||
09:00.0 09:00.1
== PCI ============================================
|| ||
.----------. .----------.
,------| PF |---| VF |-------,
| '----------' '----------' |
| DSC |
| |
------------------------------------------

Changes:
v11:
- change strncpy to strscpy
Reported-by: kernel test robot <lkp@intel.com>
Link: https://lore.kernel.org/oe-kbuild-all/202304181137.WaZTYyAa-lkp@intel.com/

v10:
Link: https://lore.kernel.org/netdev/20230418003228.28234-1-shannon.nelson@amd.com/
- remove CONFIG_DEBUG_FS guard static inline stuff
- remove unnecessary 0 and null initializations
- verify in driver load that PDS_CORE_DRV_NAME matches KBUILD_MODNAME
- remove debugfs irqs_show(), redundant with /proc
- return -ENOMEM if intr_info = kcalloc() fails
- move the status code enum into pds_core_if.h as part of API definition
- fix up one place in pdsc_devcmd_wait() we're using the status codes where we could use the errno
- remove redundant calls to flush_workqueue()
- grab config_lock before testing state bits in pdsc_fw_reporter_diagnose()
- change pdsc_color_match() to return bool
- remove useless VIF setup loop and just setup vDPA services for now
- remove pf pointer from struct padev and have clients use pci_physfn()
- drop use of "vf" in auxdev.c function names, make more generic
- remove last of client ops struct and simply export the functions
- drop drivers@pensando.io from MAINTAINERS and add new include dir
- include dynamic_debug.h in adminq.c to protect dynamic_hex_dump()
- fixed fw_slot type from u8 to int for handling error returns
- fixed comment spelling
- changed void arg in pdsc_adminq_post() to struct pdsc *

v9:
Link: https://lore.kernel.org/netdev/20230406234143.11318-1-shannon.nelson@amd.com/
- change pdsc field name id to uid to clarify the unique id used for aux device
- remove unnecessary pf->state and other checks in aux device creation
- hardcode fw slotnames for devlink info, don't use strings from FW
- handle errors from PDS_CORE_CMD_INIT devcmd call
- tighten up health thread use of config_lock
- remove pdsc_queue_health_check() layer over queuing health check
- start pds_core.rst file in first patch, add to it incrementally
- give more user interaction info in commit messages
- removed a few more extraneous includes

v8:
Link: https://lore.kernel.org/netdev/20230330234628.14627-1-shannon.nelson@amd.com/
- fixed deadlock problem, use devl_health_reporter_destroy() when devlink is locked
- don't clear client_id until after auxiliary_device_uninit()

v7:
Link: https://lore.kernel.org/netdev/20230330192313.62018-1-shannon.nelson@amd.com/
- use explicit devlink locking and devl_* APIs
- move some of devlink setup logic into probe and remove
- use debugfs_create_u{type}() for state and queue head and tail
- add include for linux/vmalloc.h
Reported-by: kernel test robot <lkp@intel.com>
Link: https://lore.kernel.org/oe-kbuild-all/202303260420.Tgq0qobF-lkp@intel.com/

v6:
Link: https://lore.kernel.org/netdev/20230324190243.27722-1-shannon.nelson@amd.com/
- removed version.h include noticed by kernel test robot's version check
Reported-by: kernel test robot <lkp@intel.com>
Link: https://lore.kernel.org/oe-kbuild-all/202303230742.pX3ply0t-lkp@intel.com/
- fixed up the more egregious checkpatch line length complaints
- make sure pdsc_auxbus_dev_register() checks padev pointer errcode

v5:
Link: https://lore.kernel.org/netdev/20230322185626.38758-1-shannon.nelson@amd.com/
- added devlink health reporter for FW issues
- removed asic_type, asic_rev, serial_num, fw_version from debugfs as
they are available through other means
- trimed OS info in pdsc_identify(), we don't need to send that much info to the FW
- removed reg/unreg from auxbus client API, they are now in the core when VF
is started
- removed need for pdsc definition in client by simplifying the padev to only carry
struct pci_dev pointers rather than full struct pdsc to the pf and vf
- removed the unused pdsc argument in pdsc_notify()
- moved include/linux/pds/pds_core.h to driver/../pds_core/core.h
- restored a few pds_core_if.h interface values and structs that are shared
with FW source
- moved final config_lock unlock to before tear down of timer and workqueue
to be sure there are no deadlocks while waiting for any stragglers
- changed use of PAGE_SIZE to local PDS_PAGE_SIZE to keep with FW layout needs
without regard to kernel PAGE_SIZE configuration
- removed the redundant *adminqcq argument from pdsc_adminq_post()

v4:
Link: https://lore.kernel.org/netdev/20230308051310.12544-1-shannon.nelson@amd.com/
- reworked to attach to both Core PF and vDPA VF PCI devices
- now creates auxiliary_device as part of each VF PCI probe, removes them on PCI remove
- auxiliary devices now use simple unique id rather than PCI address for identifier
- replaced home-grown event publishing with kernel-based notifier service
- dropped live_migration parameter, not needed when not creating aux device for it
- replaced devm_* functions with traditional interfaces
- added MAINTAINERS entry
- removed lingering traces of set/get_vf attribute adminq commands
- trimmed some include lists
- cleaned a kernel test robot complaint about a stray unused variable
Link: https://lore.kernel.org/oe-kbuild-all/202302181049.yeUQMeWY-lkp@intel.com/

v3:
Link: https://lore.kernel.org/netdev/20230217225558.19837-1-shannon.nelson@amd.com/
- changed names from "pensando" to "amd" and updated copyright strings
- dropped the DEVLINK_PARAM_GENERIC_ID_FW_BANK for future development
- changed the auxiliary device creation to be triggered by the
PCI bus event BOUND_DRIVER, and torn down at UNBIND_DRIVER in order
to properly handle users using the sysfs bind/unbind functions
- dropped some noisy log messages
- rebased to current net-next

RFC to v2:
Link: https://lore.kernel.org/netdev/20221207004443.33779-1-shannon.nelson@amd.com/
- added separate devlink param patches for DEVLINK_PARAM_GENERIC_ID_ENABLE_MIGRATION
and DEVLINK_PARAM_GENERIC_ID_FW_BANK, and dropped the driver specific implementations
- updated descriptions for the new devlink parameters
- dropped netdev support
- dropped vDPA patches, will followup later
- separated fw update and fw bank select into their own patches

RFC:
Link: https://lore.kernel.org/netdev/20221118225656.48309-1-snelson@pensando.io/
====================

Signed-off-by: David S. Miller <davem@davemloft.net>

+4481
+139
Documentation/networking/device_drivers/ethernet/amd/pds_core.rst
··· 1 + .. SPDX-License-Identifier: GPL-2.0+ 2 + 3 + ======================================================== 4 + Linux Driver for the AMD/Pensando(R) DSC adapter family 5 + ======================================================== 6 + 7 + Copyright(c) 2023 Advanced Micro Devices, Inc 8 + 9 + Identifying the Adapter 10 + ======================= 11 + 12 + To find if one or more AMD/Pensando PCI Core devices are installed on the 13 + host, check for the PCI devices:: 14 + 15 + # lspci -d 1dd8:100c 16 + b5:00.0 Processing accelerators: Pensando Systems Device 100c 17 + b6:00.0 Processing accelerators: Pensando Systems Device 100c 18 + 19 + If such devices are listed as above, then the pds_core.ko driver should find 20 + and configure them for use. There should be log entries in the kernel 21 + messages such as these:: 22 + 23 + $ dmesg | grep pds_core 24 + pds_core 0000:b5:00.0: 252.048 Gb/s available PCIe bandwidth (16.0 GT/s PCIe x16 link) 25 + pds_core 0000:b5:00.0: FW: 1.60.0-73 26 + pds_core 0000:b6:00.0: 252.048 Gb/s available PCIe bandwidth (16.0 GT/s PCIe x16 link) 27 + pds_core 0000:b6:00.0: FW: 1.60.0-73 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 + 76 + Parameters 77 + ========== 78 + 79 + The ``pds_core`` driver implements the following generic 80 + parameters for controlling the functionality to be made available 81 + as auxiliary_bus devices. 82 + 83 + .. list-table:: Generic parameters implemented 84 + :widths: 5 5 8 82 85 + 86 + * - Name 87 + - Mode 88 + - Type 89 + - Description 90 + * - ``enable_vnet`` 91 + - runtime 92 + - Boolean 93 + - Enables vDPA functionality through an auxiliary_bus device 94 + 95 + Firmware Management 96 + =================== 97 + 98 + The ``flash`` command can update a the DSC firmware. The downloaded firmware 99 + will be saved into either of firmware bank 1 or bank 2, whichever is not 100 + currently in use, and that bank will used for the next boot:: 101 + 102 + # devlink dev flash pci/0000:b5:00.0 \ 103 + file pensando/dsc_fw_1.63.0-22.tar 104 + 105 + Health Reporters 106 + ================ 107 + 108 + The driver supports a devlink health reporter for FW status:: 109 + 110 + # devlink health show pci/0000:2b:00.0 reporter fw 111 + pci/0000:2b:00.0: 112 + reporter fw 113 + state healthy error 0 recover 0 114 + # devlink health diagnose pci/0000:2b:00.0 reporter fw 115 + Status: healthy State: 1 Generation: 0 Recoveries: 0 116 + 117 + Enabling the driver 118 + =================== 119 + 120 + The driver is enabled via the standard kernel configuration system, 121 + using the make command:: 122 + 123 + make oldconfig/menuconfig/etc. 124 + 125 + The driver is located in the menu structure at: 126 + 127 + -> Device Drivers 128 + -> Network device support (NETDEVICES [=y]) 129 + -> Ethernet driver support 130 + -> AMD devices 131 + -> AMD/Pensando Ethernet PDS_CORE Support 132 + 133 + Support 134 + ======= 135 + 136 + For general Linux networking support, please use the netdev mailing 137 + list, which is monitored by AMD/Pensando personnel:: 138 + 139 + netdev@vger.kernel.org
+1
Documentation/networking/device_drivers/ethernet/index.rst
··· 14 14 3com/vortex 15 15 amazon/ena 16 16 altera/altera_tse 17 + amd/pds_core 17 18 aquantia/atlantic 18 19 chelsio/cxgb 19 20 cirrus/cs89x0
+9
MAINTAINERS
··· 1041 1041 F: include/uapi/linux/kfd_ioctl.h 1042 1042 F: include/uapi/linux/kfd_sysfs.h 1043 1043 1044 + AMD PDS CORE DRIVER 1045 + M: Shannon Nelson <shannon.nelson@amd.com> 1046 + M: Brett Creeley <brett.creeley@amd.com> 1047 + L: netdev@vger.kernel.org 1048 + S: Supported 1049 + F: Documentation/networking/device_drivers/ethernet/amd/pds_core.rst 1050 + F: drivers/net/ethernet/amd/pds_core/ 1051 + F: include/linux/pds/ 1052 + 1044 1053 AMD SPI DRIVER 1045 1054 M: Sanjay R Mehta <sanju.mehta@amd.com> 1046 1055 S: Maintained
+12
drivers/net/ethernet/amd/Kconfig
··· 186 186 bool 187 187 default n 188 188 189 + config PDS_CORE 190 + tristate "AMD/Pensando Data Systems Core Device Support" 191 + depends on 64BIT && PCI 192 + help 193 + This enables the support for the AMD/Pensando Core device family of 194 + adapters. More specific information on this driver can be 195 + found in 196 + <file:Documentation/networking/device_drivers/ethernet/amd/pds_core.rst>. 197 + 198 + To compile this driver as a module, choose M here. The module 199 + will be called pds_core. 200 + 189 201 endif # NET_VENDOR_AMD
+1
drivers/net/ethernet/amd/Makefile
··· 17 17 obj-$(CONFIG_SUN3LANCE) += sun3lance.o 18 18 obj-$(CONFIG_SUNLANCE) += sunlance.o 19 19 obj-$(CONFIG_AMD_XGBE) += xgbe/ 20 + obj-$(CONFIG_PDS_CORE) += pds_core/
+14
drivers/net/ethernet/amd/pds_core/Makefile
··· 1 + # SPDX-License-Identifier: GPL-2.0 2 + # Copyright (c) 2023 Advanced Micro Devices, Inc. 3 + 4 + obj-$(CONFIG_PDS_CORE) := pds_core.o 5 + 6 + pds_core-y := main.o \ 7 + devlink.o \ 8 + auxbus.o \ 9 + dev.o \ 10 + adminq.o \ 11 + core.o \ 12 + fw.o 13 + 14 + pds_core-$(CONFIG_DEBUG_FS) += debugfs.o
+290
drivers/net/ethernet/amd/pds_core/adminq.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* Copyright(c) 2023 Advanced Micro Devices, Inc */ 3 + 4 + #include <linux/dynamic_debug.h> 5 + 6 + #include "core.h" 7 + 8 + struct pdsc_wait_context { 9 + struct pdsc_qcq *qcq; 10 + struct completion wait_completion; 11 + }; 12 + 13 + static int pdsc_process_notifyq(struct pdsc_qcq *qcq) 14 + { 15 + union pds_core_notifyq_comp *comp; 16 + struct pdsc *pdsc = qcq->pdsc; 17 + struct pdsc_cq *cq = &qcq->cq; 18 + struct pdsc_cq_info *cq_info; 19 + int nq_work = 0; 20 + u64 eid; 21 + 22 + cq_info = &cq->info[cq->tail_idx]; 23 + comp = cq_info->comp; 24 + eid = le64_to_cpu(comp->event.eid); 25 + while (eid > pdsc->last_eid) { 26 + u16 ecode = le16_to_cpu(comp->event.ecode); 27 + 28 + switch (ecode) { 29 + case PDS_EVENT_LINK_CHANGE: 30 + dev_info(pdsc->dev, "NotifyQ LINK_CHANGE ecode %d eid %lld\n", 31 + ecode, eid); 32 + pdsc_notify(PDS_EVENT_LINK_CHANGE, comp); 33 + break; 34 + 35 + case PDS_EVENT_RESET: 36 + dev_info(pdsc->dev, "NotifyQ RESET ecode %d eid %lld\n", 37 + ecode, eid); 38 + pdsc_notify(PDS_EVENT_RESET, comp); 39 + break; 40 + 41 + case PDS_EVENT_XCVR: 42 + dev_info(pdsc->dev, "NotifyQ XCVR ecode %d eid %lld\n", 43 + ecode, eid); 44 + break; 45 + 46 + default: 47 + dev_info(pdsc->dev, "NotifyQ ecode %d eid %lld\n", 48 + ecode, eid); 49 + break; 50 + } 51 + 52 + pdsc->last_eid = eid; 53 + cq->tail_idx = (cq->tail_idx + 1) & (cq->num_descs - 1); 54 + cq_info = &cq->info[cq->tail_idx]; 55 + comp = cq_info->comp; 56 + eid = le64_to_cpu(comp->event.eid); 57 + 58 + nq_work++; 59 + } 60 + 61 + qcq->accum_work += nq_work; 62 + 63 + return nq_work; 64 + } 65 + 66 + void pdsc_process_adminq(struct pdsc_qcq *qcq) 67 + { 68 + union pds_core_adminq_comp *comp; 69 + struct pdsc_queue *q = &qcq->q; 70 + struct pdsc *pdsc = qcq->pdsc; 71 + struct pdsc_cq *cq = &qcq->cq; 72 + struct pdsc_q_info *q_info; 73 + unsigned long irqflags; 74 + int nq_work = 0; 75 + int aq_work = 0; 76 + int credits; 77 + 78 + /* Don't process AdminQ when shutting down */ 79 + if (pdsc->state & BIT_ULL(PDSC_S_STOPPING_DRIVER)) { 80 + dev_err(pdsc->dev, "%s: called while PDSC_S_STOPPING_DRIVER\n", 81 + __func__); 82 + return; 83 + } 84 + 85 + /* Check for NotifyQ event */ 86 + nq_work = pdsc_process_notifyq(&pdsc->notifyqcq); 87 + 88 + /* Check for empty queue, which can happen if the interrupt was 89 + * for a NotifyQ event and there are no new AdminQ completions. 90 + */ 91 + if (q->tail_idx == q->head_idx) 92 + goto credits; 93 + 94 + /* Find the first completion to clean, 95 + * run the callback in the related q_info, 96 + * and continue while we still match done color 97 + */ 98 + spin_lock_irqsave(&pdsc->adminq_lock, irqflags); 99 + comp = cq->info[cq->tail_idx].comp; 100 + while (pdsc_color_match(comp->color, cq->done_color)) { 101 + q_info = &q->info[q->tail_idx]; 102 + q->tail_idx = (q->tail_idx + 1) & (q->num_descs - 1); 103 + 104 + /* Copy out the completion data */ 105 + memcpy(q_info->dest, comp, sizeof(*comp)); 106 + 107 + complete_all(&q_info->wc->wait_completion); 108 + 109 + if (cq->tail_idx == cq->num_descs - 1) 110 + cq->done_color = !cq->done_color; 111 + cq->tail_idx = (cq->tail_idx + 1) & (cq->num_descs - 1); 112 + comp = cq->info[cq->tail_idx].comp; 113 + 114 + aq_work++; 115 + } 116 + spin_unlock_irqrestore(&pdsc->adminq_lock, irqflags); 117 + 118 + qcq->accum_work += aq_work; 119 + 120 + credits: 121 + /* Return the interrupt credits, one for each completion */ 122 + credits = nq_work + aq_work; 123 + if (credits) 124 + pds_core_intr_credits(&pdsc->intr_ctrl[qcq->intx], 125 + credits, 126 + PDS_CORE_INTR_CRED_REARM); 127 + } 128 + 129 + void pdsc_work_thread(struct work_struct *work) 130 + { 131 + struct pdsc_qcq *qcq = container_of(work, struct pdsc_qcq, work); 132 + 133 + pdsc_process_adminq(qcq); 134 + } 135 + 136 + irqreturn_t pdsc_adminq_isr(int irq, void *data) 137 + { 138 + struct pdsc_qcq *qcq = data; 139 + struct pdsc *pdsc = qcq->pdsc; 140 + 141 + /* Don't process AdminQ when shutting down */ 142 + if (pdsc->state & BIT_ULL(PDSC_S_STOPPING_DRIVER)) { 143 + dev_err(pdsc->dev, "%s: called while PDSC_S_STOPPING_DRIVER\n", 144 + __func__); 145 + return IRQ_HANDLED; 146 + } 147 + 148 + queue_work(pdsc->wq, &qcq->work); 149 + pds_core_intr_mask(&pdsc->intr_ctrl[irq], PDS_CORE_INTR_MASK_CLEAR); 150 + 151 + return IRQ_HANDLED; 152 + } 153 + 154 + static int __pdsc_adminq_post(struct pdsc *pdsc, 155 + struct pdsc_qcq *qcq, 156 + union pds_core_adminq_cmd *cmd, 157 + union pds_core_adminq_comp *comp, 158 + struct pdsc_wait_context *wc) 159 + { 160 + struct pdsc_queue *q = &qcq->q; 161 + struct pdsc_q_info *q_info; 162 + unsigned long irqflags; 163 + unsigned int avail; 164 + int index; 165 + int ret; 166 + 167 + spin_lock_irqsave(&pdsc->adminq_lock, irqflags); 168 + 169 + /* Check for space in the queue */ 170 + avail = q->tail_idx; 171 + if (q->head_idx >= avail) 172 + avail += q->num_descs - q->head_idx - 1; 173 + else 174 + avail -= q->head_idx + 1; 175 + if (!avail) { 176 + ret = -ENOSPC; 177 + goto err_out_unlock; 178 + } 179 + 180 + /* Check that the FW is running */ 181 + if (!pdsc_is_fw_running(pdsc)) { 182 + u8 fw_status = ioread8(&pdsc->info_regs->fw_status); 183 + 184 + dev_info(pdsc->dev, "%s: post failed - fw not running %#02x:\n", 185 + __func__, fw_status); 186 + ret = -ENXIO; 187 + 188 + goto err_out_unlock; 189 + } 190 + 191 + /* Post the request */ 192 + index = q->head_idx; 193 + q_info = &q->info[index]; 194 + q_info->wc = wc; 195 + q_info->dest = comp; 196 + memcpy(q_info->desc, cmd, sizeof(*cmd)); 197 + 198 + dev_dbg(pdsc->dev, "head_idx %d tail_idx %d\n", 199 + q->head_idx, q->tail_idx); 200 + dev_dbg(pdsc->dev, "post admin queue command:\n"); 201 + dynamic_hex_dump("cmd ", DUMP_PREFIX_OFFSET, 16, 1, 202 + cmd, sizeof(*cmd), true); 203 + 204 + q->head_idx = (q->head_idx + 1) & (q->num_descs - 1); 205 + 206 + pds_core_dbell_ring(pdsc->kern_dbpage, 207 + q->hw_type, q->dbval | q->head_idx); 208 + ret = index; 209 + 210 + err_out_unlock: 211 + spin_unlock_irqrestore(&pdsc->adminq_lock, irqflags); 212 + return ret; 213 + } 214 + 215 + int pdsc_adminq_post(struct pdsc *pdsc, 216 + union pds_core_adminq_cmd *cmd, 217 + union pds_core_adminq_comp *comp, 218 + bool fast_poll) 219 + { 220 + struct pdsc_wait_context wc = { 221 + .wait_completion = 222 + COMPLETION_INITIALIZER_ONSTACK(wc.wait_completion), 223 + }; 224 + unsigned long poll_interval = 1; 225 + unsigned long poll_jiffies; 226 + unsigned long time_limit; 227 + unsigned long time_start; 228 + unsigned long time_done; 229 + unsigned long remaining; 230 + int err = 0; 231 + int index; 232 + 233 + wc.qcq = &pdsc->adminqcq; 234 + index = __pdsc_adminq_post(pdsc, &pdsc->adminqcq, cmd, comp, &wc); 235 + if (index < 0) { 236 + err = index; 237 + goto err_out; 238 + } 239 + 240 + time_start = jiffies; 241 + time_limit = time_start + HZ * pdsc->devcmd_timeout; 242 + do { 243 + /* Timeslice the actual wait to catch IO errors etc early */ 244 + poll_jiffies = msecs_to_jiffies(poll_interval); 245 + remaining = wait_for_completion_timeout(&wc.wait_completion, 246 + poll_jiffies); 247 + if (remaining) 248 + break; 249 + 250 + if (!pdsc_is_fw_running(pdsc)) { 251 + u8 fw_status = ioread8(&pdsc->info_regs->fw_status); 252 + 253 + dev_dbg(pdsc->dev, "%s: post wait failed - fw not running %#02x:\n", 254 + __func__, fw_status); 255 + err = -ENXIO; 256 + break; 257 + } 258 + 259 + /* When fast_poll is not requested, prevent aggressive polling 260 + * on failures due to timeouts by doing exponential back off. 261 + */ 262 + if (!fast_poll && poll_interval < PDSC_ADMINQ_MAX_POLL_INTERVAL) 263 + poll_interval <<= 1; 264 + } while (time_before(jiffies, time_limit)); 265 + time_done = jiffies; 266 + dev_dbg(pdsc->dev, "%s: elapsed %d msecs\n", 267 + __func__, jiffies_to_msecs(time_done - time_start)); 268 + 269 + /* Check the results */ 270 + if (time_after_eq(time_done, time_limit)) 271 + err = -ETIMEDOUT; 272 + 273 + dev_dbg(pdsc->dev, "read admin queue completion idx %d:\n", index); 274 + dynamic_hex_dump("comp ", DUMP_PREFIX_OFFSET, 16, 1, 275 + comp, sizeof(*comp), true); 276 + 277 + if (remaining && comp->status) 278 + err = pdsc_err_to_errno(comp->status); 279 + 280 + err_out: 281 + if (err) { 282 + dev_dbg(pdsc->dev, "%s: opcode %d status %d err %pe\n", 283 + __func__, cmd->opcode, comp->status, ERR_PTR(err)); 284 + if (err == -ENXIO || err == -ETIMEDOUT) 285 + queue_work(pdsc->wq, &pdsc->health_work); 286 + } 287 + 288 + return err; 289 + } 290 + EXPORT_SYMBOL_GPL(pdsc_adminq_post);
+264
drivers/net/ethernet/amd/pds_core/auxbus.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* Copyright(c) 2023 Advanced Micro Devices, Inc */ 3 + 4 + #include <linux/pci.h> 5 + 6 + #include "core.h" 7 + #include <linux/pds/pds_auxbus.h> 8 + 9 + /** 10 + * pds_client_register - Link the client to the firmware 11 + * @pf_pdev: ptr to the PF driver struct 12 + * @devname: name that includes service into, e.g. pds_core.vDPA 13 + * 14 + * Return: 0 on success, or 15 + * negative for error 16 + */ 17 + int pds_client_register(struct pci_dev *pf_pdev, char *devname) 18 + { 19 + union pds_core_adminq_comp comp = {}; 20 + union pds_core_adminq_cmd cmd = {}; 21 + struct pdsc *pf; 22 + int err; 23 + u16 ci; 24 + 25 + pf = pci_get_drvdata(pf_pdev); 26 + if (pf->state) 27 + return -ENXIO; 28 + 29 + cmd.client_reg.opcode = PDS_AQ_CMD_CLIENT_REG; 30 + strscpy(cmd.client_reg.devname, devname, 31 + sizeof(cmd.client_reg.devname)); 32 + 33 + err = pdsc_adminq_post(pf, &cmd, &comp, false); 34 + if (err) { 35 + dev_info(pf->dev, "register dev_name %s with DSC failed, status %d: %pe\n", 36 + devname, comp.status, ERR_PTR(err)); 37 + return err; 38 + } 39 + 40 + ci = le16_to_cpu(comp.client_reg.client_id); 41 + if (!ci) { 42 + dev_err(pf->dev, "%s: device returned null client_id\n", 43 + __func__); 44 + return -EIO; 45 + } 46 + 47 + dev_dbg(pf->dev, "%s: device returned client_id %d for %s\n", 48 + __func__, ci, devname); 49 + 50 + return ci; 51 + } 52 + EXPORT_SYMBOL_GPL(pds_client_register); 53 + 54 + /** 55 + * pds_client_unregister - Unlink the client from the firmware 56 + * @pf_pdev: ptr to the PF driver struct 57 + * @client_id: id returned from pds_client_register() 58 + * 59 + * Return: 0 on success, or 60 + * negative for error 61 + */ 62 + int pds_client_unregister(struct pci_dev *pf_pdev, u16 client_id) 63 + { 64 + union pds_core_adminq_comp comp = {}; 65 + union pds_core_adminq_cmd cmd = {}; 66 + struct pdsc *pf; 67 + int err; 68 + 69 + pf = pci_get_drvdata(pf_pdev); 70 + if (pf->state) 71 + return -ENXIO; 72 + 73 + cmd.client_unreg.opcode = PDS_AQ_CMD_CLIENT_UNREG; 74 + cmd.client_unreg.client_id = cpu_to_le16(client_id); 75 + 76 + err = pdsc_adminq_post(pf, &cmd, &comp, false); 77 + if (err) 78 + dev_info(pf->dev, "unregister client_id %d failed, status %d: %pe\n", 79 + client_id, comp.status, ERR_PTR(err)); 80 + 81 + return err; 82 + } 83 + EXPORT_SYMBOL_GPL(pds_client_unregister); 84 + 85 + /** 86 + * pds_client_adminq_cmd - Process an adminq request for the client 87 + * @padev: ptr to the client device 88 + * @req: ptr to buffer with request 89 + * @req_len: length of actual struct used for request 90 + * @resp: ptr to buffer where answer is to be copied 91 + * @flags: optional flags from pds_core_adminq_flags 92 + * 93 + * Return: 0 on success, or 94 + * negative for error 95 + * 96 + * Client sends pointers to request and response buffers 97 + * Core copies request data into pds_core_client_request_cmd 98 + * Core sets other fields as needed 99 + * Core posts to AdminQ 100 + * Core copies completion data into response buffer 101 + */ 102 + int pds_client_adminq_cmd(struct pds_auxiliary_dev *padev, 103 + union pds_core_adminq_cmd *req, 104 + size_t req_len, 105 + union pds_core_adminq_comp *resp, 106 + u64 flags) 107 + { 108 + union pds_core_adminq_cmd cmd = {}; 109 + struct pci_dev *pf_pdev; 110 + struct pdsc *pf; 111 + size_t cp_len; 112 + int err; 113 + 114 + pf_pdev = pci_physfn(padev->vf_pdev); 115 + pf = pci_get_drvdata(pf_pdev); 116 + 117 + dev_dbg(pf->dev, "%s: %s opcode %d\n", 118 + __func__, dev_name(&padev->aux_dev.dev), req->opcode); 119 + 120 + if (pf->state) 121 + return -ENXIO; 122 + 123 + /* Wrap the client's request */ 124 + cmd.client_request.opcode = PDS_AQ_CMD_CLIENT_CMD; 125 + cmd.client_request.client_id = cpu_to_le16(padev->client_id); 126 + cp_len = min_t(size_t, req_len, sizeof(cmd.client_request.client_cmd)); 127 + memcpy(cmd.client_request.client_cmd, req, cp_len); 128 + 129 + err = pdsc_adminq_post(pf, &cmd, resp, 130 + !!(flags & PDS_AQ_FLAG_FASTPOLL)); 131 + if (err && err != -EAGAIN) 132 + dev_info(pf->dev, "client admin cmd failed: %pe\n", 133 + ERR_PTR(err)); 134 + 135 + return err; 136 + } 137 + EXPORT_SYMBOL_GPL(pds_client_adminq_cmd); 138 + 139 + static void pdsc_auxbus_dev_release(struct device *dev) 140 + { 141 + struct pds_auxiliary_dev *padev = 142 + container_of(dev, struct pds_auxiliary_dev, aux_dev.dev); 143 + 144 + kfree(padev); 145 + } 146 + 147 + static struct pds_auxiliary_dev *pdsc_auxbus_dev_register(struct pdsc *cf, 148 + struct pdsc *pf, 149 + u16 client_id, 150 + char *name) 151 + { 152 + struct auxiliary_device *aux_dev; 153 + struct pds_auxiliary_dev *padev; 154 + int err; 155 + 156 + padev = kzalloc(sizeof(*padev), GFP_KERNEL); 157 + if (!padev) 158 + return ERR_PTR(-ENOMEM); 159 + 160 + padev->vf_pdev = cf->pdev; 161 + padev->client_id = client_id; 162 + 163 + aux_dev = &padev->aux_dev; 164 + aux_dev->name = name; 165 + aux_dev->id = cf->uid; 166 + aux_dev->dev.parent = cf->dev; 167 + aux_dev->dev.release = pdsc_auxbus_dev_release; 168 + 169 + err = auxiliary_device_init(aux_dev); 170 + if (err < 0) { 171 + dev_warn(cf->dev, "auxiliary_device_init of %s failed: %pe\n", 172 + name, ERR_PTR(err)); 173 + goto err_out; 174 + } 175 + 176 + err = auxiliary_device_add(aux_dev); 177 + if (err) { 178 + dev_warn(cf->dev, "auxiliary_device_add of %s failed: %pe\n", 179 + name, ERR_PTR(err)); 180 + goto err_out_uninit; 181 + } 182 + 183 + return padev; 184 + 185 + err_out_uninit: 186 + auxiliary_device_uninit(aux_dev); 187 + err_out: 188 + kfree(padev); 189 + return ERR_PTR(err); 190 + } 191 + 192 + int pdsc_auxbus_dev_del(struct pdsc *cf, struct pdsc *pf) 193 + { 194 + struct pds_auxiliary_dev *padev; 195 + int err = 0; 196 + 197 + mutex_lock(&pf->config_lock); 198 + 199 + padev = pf->vfs[cf->vf_id].padev; 200 + if (padev) { 201 + pds_client_unregister(pf->pdev, padev->client_id); 202 + auxiliary_device_delete(&padev->aux_dev); 203 + auxiliary_device_uninit(&padev->aux_dev); 204 + padev->client_id = 0; 205 + } 206 + pf->vfs[cf->vf_id].padev = NULL; 207 + 208 + mutex_unlock(&pf->config_lock); 209 + return err; 210 + } 211 + 212 + int pdsc_auxbus_dev_add(struct pdsc *cf, struct pdsc *pf) 213 + { 214 + struct pds_auxiliary_dev *padev; 215 + enum pds_core_vif_types vt; 216 + char devname[PDS_DEVNAME_LEN]; 217 + u16 vt_support; 218 + int client_id; 219 + int err = 0; 220 + 221 + mutex_lock(&pf->config_lock); 222 + 223 + /* We only support vDPA so far, so it is the only one to 224 + * be verified that it is available in the Core device and 225 + * enabled in the devlink param. In the future this might 226 + * become a loop for several VIF types. 227 + */ 228 + 229 + /* Verify that the type is supported and enabled. It is not 230 + * an error if there is no auxbus device support for this 231 + * VF, it just means something else needs to happen with it. 232 + */ 233 + vt = PDS_DEV_TYPE_VDPA; 234 + vt_support = !!le16_to_cpu(pf->dev_ident.vif_types[vt]); 235 + if (!(vt_support && 236 + pf->viftype_status[vt].supported && 237 + pf->viftype_status[vt].enabled)) 238 + goto out_unlock; 239 + 240 + /* Need to register with FW and get the client_id before 241 + * creating the aux device so that the aux client can run 242 + * adminq commands as part its probe 243 + */ 244 + snprintf(devname, sizeof(devname), "%s.%s.%d", 245 + PDS_CORE_DRV_NAME, pf->viftype_status[vt].name, cf->uid); 246 + client_id = pds_client_register(pf->pdev, devname); 247 + if (client_id < 0) { 248 + err = client_id; 249 + goto out_unlock; 250 + } 251 + 252 + padev = pdsc_auxbus_dev_register(cf, pf, client_id, 253 + pf->viftype_status[vt].name); 254 + if (IS_ERR(padev)) { 255 + pds_client_unregister(pf->pdev, client_id); 256 + err = PTR_ERR(padev); 257 + goto out_unlock; 258 + } 259 + pf->vfs[cf->vf_id].padev = padev; 260 + 261 + out_unlock: 262 + mutex_unlock(&pf->config_lock); 263 + return err; 264 + }
+597
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 <linux/pci.h> 5 + #include <linux/vmalloc.h> 6 + 7 + #include "core.h" 8 + 9 + static BLOCKING_NOTIFIER_HEAD(pds_notify_chain); 10 + 11 + int pdsc_register_notify(struct notifier_block *nb) 12 + { 13 + return blocking_notifier_chain_register(&pds_notify_chain, nb); 14 + } 15 + EXPORT_SYMBOL_GPL(pdsc_register_notify); 16 + 17 + void pdsc_unregister_notify(struct notifier_block *nb) 18 + { 19 + blocking_notifier_chain_unregister(&pds_notify_chain, nb); 20 + } 21 + EXPORT_SYMBOL_GPL(pdsc_unregister_notify); 22 + 23 + void pdsc_notify(unsigned long event, void *data) 24 + { 25 + blocking_notifier_call_chain(&pds_notify_chain, event, data); 26 + } 27 + 28 + void pdsc_intr_free(struct pdsc *pdsc, int index) 29 + { 30 + struct pdsc_intr_info *intr_info; 31 + 32 + if (index >= pdsc->nintrs || index < 0) { 33 + WARN(true, "bad intr index %d\n", index); 34 + return; 35 + } 36 + 37 + intr_info = &pdsc->intr_info[index]; 38 + if (!intr_info->vector) 39 + return; 40 + dev_dbg(pdsc->dev, "%s: idx %d vec %d name %s\n", 41 + __func__, index, intr_info->vector, intr_info->name); 42 + 43 + pds_core_intr_mask(&pdsc->intr_ctrl[index], PDS_CORE_INTR_MASK_SET); 44 + pds_core_intr_clean(&pdsc->intr_ctrl[index]); 45 + 46 + free_irq(intr_info->vector, intr_info->data); 47 + 48 + memset(intr_info, 0, sizeof(*intr_info)); 49 + } 50 + 51 + int pdsc_intr_alloc(struct pdsc *pdsc, char *name, 52 + irq_handler_t handler, void *data) 53 + { 54 + struct pdsc_intr_info *intr_info; 55 + unsigned int index; 56 + int err; 57 + 58 + /* Find the first available interrupt */ 59 + for (index = 0; index < pdsc->nintrs; index++) 60 + if (!pdsc->intr_info[index].vector) 61 + break; 62 + if (index >= pdsc->nintrs) { 63 + dev_warn(pdsc->dev, "%s: no intr, index=%d nintrs=%d\n", 64 + __func__, index, pdsc->nintrs); 65 + return -ENOSPC; 66 + } 67 + 68 + pds_core_intr_clean_flags(&pdsc->intr_ctrl[index], 69 + PDS_CORE_INTR_CRED_RESET_COALESCE); 70 + 71 + intr_info = &pdsc->intr_info[index]; 72 + 73 + intr_info->index = index; 74 + intr_info->data = data; 75 + strscpy(intr_info->name, name, sizeof(intr_info->name)); 76 + 77 + /* Get the OS vector number for the interrupt */ 78 + err = pci_irq_vector(pdsc->pdev, index); 79 + if (err < 0) { 80 + dev_err(pdsc->dev, "failed to get intr vector index %d: %pe\n", 81 + index, ERR_PTR(err)); 82 + goto err_out_free_intr; 83 + } 84 + intr_info->vector = err; 85 + 86 + /* Init the device's intr mask */ 87 + pds_core_intr_clean(&pdsc->intr_ctrl[index]); 88 + pds_core_intr_mask_assert(&pdsc->intr_ctrl[index], 1); 89 + pds_core_intr_mask(&pdsc->intr_ctrl[index], PDS_CORE_INTR_MASK_SET); 90 + 91 + /* Register the isr with a name */ 92 + err = request_irq(intr_info->vector, handler, 0, intr_info->name, data); 93 + if (err) { 94 + dev_err(pdsc->dev, "failed to get intr irq vector %d: %pe\n", 95 + intr_info->vector, ERR_PTR(err)); 96 + goto err_out_free_intr; 97 + } 98 + 99 + return index; 100 + 101 + err_out_free_intr: 102 + pdsc_intr_free(pdsc, index); 103 + return err; 104 + } 105 + 106 + static void pdsc_qcq_intr_free(struct pdsc *pdsc, struct pdsc_qcq *qcq) 107 + { 108 + if (!(qcq->flags & PDS_CORE_QCQ_F_INTR) || 109 + qcq->intx == PDS_CORE_INTR_INDEX_NOT_ASSIGNED) 110 + return; 111 + 112 + pdsc_intr_free(pdsc, qcq->intx); 113 + qcq->intx = PDS_CORE_INTR_INDEX_NOT_ASSIGNED; 114 + } 115 + 116 + static int pdsc_qcq_intr_alloc(struct pdsc *pdsc, struct pdsc_qcq *qcq) 117 + { 118 + char name[PDSC_INTR_NAME_MAX_SZ]; 119 + int index; 120 + 121 + if (!(qcq->flags & PDS_CORE_QCQ_F_INTR)) { 122 + qcq->intx = PDS_CORE_INTR_INDEX_NOT_ASSIGNED; 123 + return 0; 124 + } 125 + 126 + snprintf(name, sizeof(name), "%s-%d-%s", 127 + PDS_CORE_DRV_NAME, pdsc->pdev->bus->number, qcq->q.name); 128 + index = pdsc_intr_alloc(pdsc, name, pdsc_adminq_isr, qcq); 129 + if (index < 0) 130 + return index; 131 + qcq->intx = index; 132 + 133 + return 0; 134 + } 135 + 136 + void pdsc_qcq_free(struct pdsc *pdsc, struct pdsc_qcq *qcq) 137 + { 138 + struct device *dev = pdsc->dev; 139 + 140 + if (!(qcq && qcq->pdsc)) 141 + return; 142 + 143 + pdsc_debugfs_del_qcq(qcq); 144 + 145 + pdsc_qcq_intr_free(pdsc, qcq); 146 + 147 + if (qcq->q_base) 148 + dma_free_coherent(dev, qcq->q_size, 149 + qcq->q_base, qcq->q_base_pa); 150 + 151 + if (qcq->cq_base) 152 + dma_free_coherent(dev, qcq->cq_size, 153 + qcq->cq_base, qcq->cq_base_pa); 154 + 155 + if (qcq->cq.info) 156 + vfree(qcq->cq.info); 157 + 158 + if (qcq->q.info) 159 + vfree(qcq->q.info); 160 + 161 + memset(qcq, 0, sizeof(*qcq)); 162 + } 163 + 164 + static void pdsc_q_map(struct pdsc_queue *q, void *base, dma_addr_t base_pa) 165 + { 166 + struct pdsc_q_info *cur; 167 + unsigned int i; 168 + 169 + q->base = base; 170 + q->base_pa = base_pa; 171 + 172 + for (i = 0, cur = q->info; i < q->num_descs; i++, cur++) 173 + cur->desc = base + (i * q->desc_size); 174 + } 175 + 176 + static void pdsc_cq_map(struct pdsc_cq *cq, void *base, dma_addr_t base_pa) 177 + { 178 + struct pdsc_cq_info *cur; 179 + unsigned int i; 180 + 181 + cq->base = base; 182 + cq->base_pa = base_pa; 183 + 184 + for (i = 0, cur = cq->info; i < cq->num_descs; i++, cur++) 185 + cur->comp = base + (i * cq->desc_size); 186 + } 187 + 188 + int pdsc_qcq_alloc(struct pdsc *pdsc, unsigned int type, unsigned int index, 189 + const char *name, unsigned int flags, unsigned int num_descs, 190 + unsigned int desc_size, unsigned int cq_desc_size, 191 + unsigned int pid, struct pdsc_qcq *qcq) 192 + { 193 + struct device *dev = pdsc->dev; 194 + void *q_base, *cq_base; 195 + dma_addr_t cq_base_pa; 196 + dma_addr_t q_base_pa; 197 + int err; 198 + 199 + qcq->q.info = vzalloc(num_descs * sizeof(*qcq->q.info)); 200 + if (!qcq->q.info) { 201 + err = -ENOMEM; 202 + goto err_out; 203 + } 204 + 205 + qcq->pdsc = pdsc; 206 + qcq->flags = flags; 207 + INIT_WORK(&qcq->work, pdsc_work_thread); 208 + 209 + qcq->q.type = type; 210 + qcq->q.index = index; 211 + qcq->q.num_descs = num_descs; 212 + qcq->q.desc_size = desc_size; 213 + qcq->q.tail_idx = 0; 214 + qcq->q.head_idx = 0; 215 + qcq->q.pid = pid; 216 + snprintf(qcq->q.name, sizeof(qcq->q.name), "%s%u", name, index); 217 + 218 + err = pdsc_qcq_intr_alloc(pdsc, qcq); 219 + if (err) 220 + goto err_out_free_q_info; 221 + 222 + qcq->cq.info = vzalloc(num_descs * sizeof(*qcq->cq.info)); 223 + if (!qcq->cq.info) { 224 + err = -ENOMEM; 225 + goto err_out_free_irq; 226 + } 227 + 228 + qcq->cq.bound_intr = &pdsc->intr_info[qcq->intx]; 229 + qcq->cq.num_descs = num_descs; 230 + qcq->cq.desc_size = cq_desc_size; 231 + qcq->cq.tail_idx = 0; 232 + qcq->cq.done_color = 1; 233 + 234 + if (flags & PDS_CORE_QCQ_F_NOTIFYQ) { 235 + /* q & cq need to be contiguous in case of notifyq */ 236 + qcq->q_size = PDS_PAGE_SIZE + 237 + ALIGN(num_descs * desc_size, PDS_PAGE_SIZE) + 238 + ALIGN(num_descs * cq_desc_size, PDS_PAGE_SIZE); 239 + qcq->q_base = dma_alloc_coherent(dev, 240 + qcq->q_size + qcq->cq_size, 241 + &qcq->q_base_pa, 242 + GFP_KERNEL); 243 + if (!qcq->q_base) { 244 + err = -ENOMEM; 245 + goto err_out_free_cq_info; 246 + } 247 + q_base = PTR_ALIGN(qcq->q_base, PDS_PAGE_SIZE); 248 + q_base_pa = ALIGN(qcq->q_base_pa, PDS_PAGE_SIZE); 249 + pdsc_q_map(&qcq->q, q_base, q_base_pa); 250 + 251 + cq_base = PTR_ALIGN(q_base + 252 + ALIGN(num_descs * desc_size, PDS_PAGE_SIZE), 253 + PDS_PAGE_SIZE); 254 + cq_base_pa = ALIGN(qcq->q_base_pa + 255 + ALIGN(num_descs * desc_size, PDS_PAGE_SIZE), 256 + PDS_PAGE_SIZE); 257 + 258 + } else { 259 + /* q DMA descriptors */ 260 + qcq->q_size = PDS_PAGE_SIZE + (num_descs * desc_size); 261 + qcq->q_base = dma_alloc_coherent(dev, qcq->q_size, 262 + &qcq->q_base_pa, 263 + GFP_KERNEL); 264 + if (!qcq->q_base) { 265 + err = -ENOMEM; 266 + goto err_out_free_cq_info; 267 + } 268 + q_base = PTR_ALIGN(qcq->q_base, PDS_PAGE_SIZE); 269 + q_base_pa = ALIGN(qcq->q_base_pa, PDS_PAGE_SIZE); 270 + pdsc_q_map(&qcq->q, q_base, q_base_pa); 271 + 272 + /* cq DMA descriptors */ 273 + qcq->cq_size = PDS_PAGE_SIZE + (num_descs * cq_desc_size); 274 + qcq->cq_base = dma_alloc_coherent(dev, qcq->cq_size, 275 + &qcq->cq_base_pa, 276 + GFP_KERNEL); 277 + if (!qcq->cq_base) { 278 + err = -ENOMEM; 279 + goto err_out_free_q; 280 + } 281 + cq_base = PTR_ALIGN(qcq->cq_base, PDS_PAGE_SIZE); 282 + cq_base_pa = ALIGN(qcq->cq_base_pa, PDS_PAGE_SIZE); 283 + } 284 + 285 + pdsc_cq_map(&qcq->cq, cq_base, cq_base_pa); 286 + qcq->cq.bound_q = &qcq->q; 287 + 288 + pdsc_debugfs_add_qcq(pdsc, qcq); 289 + 290 + return 0; 291 + 292 + err_out_free_q: 293 + dma_free_coherent(dev, qcq->q_size, qcq->q_base, qcq->q_base_pa); 294 + err_out_free_cq_info: 295 + vfree(qcq->cq.info); 296 + err_out_free_irq: 297 + pdsc_qcq_intr_free(pdsc, qcq); 298 + err_out_free_q_info: 299 + vfree(qcq->q.info); 300 + memset(qcq, 0, sizeof(*qcq)); 301 + err_out: 302 + dev_err(dev, "qcq alloc of %s%d failed %d\n", name, index, err); 303 + return err; 304 + } 305 + 306 + static int pdsc_core_init(struct pdsc *pdsc) 307 + { 308 + union pds_core_dev_comp comp = {}; 309 + union pds_core_dev_cmd cmd = { 310 + .init.opcode = PDS_CORE_CMD_INIT, 311 + }; 312 + struct pds_core_dev_init_data_out cido; 313 + struct pds_core_dev_init_data_in cidi; 314 + u32 dbid_count; 315 + u32 dbpage_num; 316 + size_t sz; 317 + int err; 318 + 319 + cidi.adminq_q_base = cpu_to_le64(pdsc->adminqcq.q_base_pa); 320 + cidi.adminq_cq_base = cpu_to_le64(pdsc->adminqcq.cq_base_pa); 321 + cidi.notifyq_cq_base = cpu_to_le64(pdsc->notifyqcq.cq.base_pa); 322 + cidi.flags = cpu_to_le32(PDS_CORE_QINIT_F_IRQ | PDS_CORE_QINIT_F_ENA); 323 + cidi.intr_index = cpu_to_le16(pdsc->adminqcq.intx); 324 + cidi.adminq_ring_size = ilog2(pdsc->adminqcq.q.num_descs); 325 + cidi.notifyq_ring_size = ilog2(pdsc->notifyqcq.q.num_descs); 326 + 327 + mutex_lock(&pdsc->devcmd_lock); 328 + 329 + sz = min_t(size_t, sizeof(cidi), sizeof(pdsc->cmd_regs->data)); 330 + memcpy_toio(&pdsc->cmd_regs->data, &cidi, sz); 331 + 332 + err = pdsc_devcmd_locked(pdsc, &cmd, &comp, pdsc->devcmd_timeout); 333 + if (!err) { 334 + sz = min_t(size_t, sizeof(cido), sizeof(pdsc->cmd_regs->data)); 335 + memcpy_fromio(&cido, &pdsc->cmd_regs->data, sz); 336 + } 337 + 338 + mutex_unlock(&pdsc->devcmd_lock); 339 + if (err) { 340 + dev_err(pdsc->dev, "Device init command failed: %pe\n", 341 + ERR_PTR(err)); 342 + return err; 343 + } 344 + 345 + pdsc->hw_index = le32_to_cpu(cido.core_hw_index); 346 + 347 + dbid_count = le32_to_cpu(pdsc->dev_ident.ndbpgs_per_lif); 348 + dbpage_num = pdsc->hw_index * dbid_count; 349 + pdsc->kern_dbpage = pdsc_map_dbpage(pdsc, dbpage_num); 350 + if (!pdsc->kern_dbpage) { 351 + dev_err(pdsc->dev, "Cannot map dbpage, aborting\n"); 352 + return -ENOMEM; 353 + } 354 + 355 + pdsc->adminqcq.q.hw_type = cido.adminq_hw_type; 356 + pdsc->adminqcq.q.hw_index = le32_to_cpu(cido.adminq_hw_index); 357 + pdsc->adminqcq.q.dbval = PDS_CORE_DBELL_QID(pdsc->adminqcq.q.hw_index); 358 + 359 + pdsc->notifyqcq.q.hw_type = cido.notifyq_hw_type; 360 + pdsc->notifyqcq.q.hw_index = le32_to_cpu(cido.notifyq_hw_index); 361 + pdsc->notifyqcq.q.dbval = PDS_CORE_DBELL_QID(pdsc->notifyqcq.q.hw_index); 362 + 363 + pdsc->last_eid = 0; 364 + 365 + return err; 366 + } 367 + 368 + static struct pdsc_viftype pdsc_viftype_defaults[] = { 369 + [PDS_DEV_TYPE_VDPA] = { .name = PDS_DEV_TYPE_VDPA_STR, 370 + .vif_id = PDS_DEV_TYPE_VDPA, 371 + .dl_id = DEVLINK_PARAM_GENERIC_ID_ENABLE_VNET }, 372 + [PDS_DEV_TYPE_MAX] = {} 373 + }; 374 + 375 + static int pdsc_viftypes_init(struct pdsc *pdsc) 376 + { 377 + enum pds_core_vif_types vt; 378 + 379 + pdsc->viftype_status = kzalloc(sizeof(pdsc_viftype_defaults), 380 + GFP_KERNEL); 381 + if (!pdsc->viftype_status) 382 + return -ENOMEM; 383 + 384 + for (vt = 0; vt < PDS_DEV_TYPE_MAX; vt++) { 385 + bool vt_support; 386 + 387 + if (!pdsc_viftype_defaults[vt].name) 388 + continue; 389 + 390 + /* Grab the defaults */ 391 + pdsc->viftype_status[vt] = pdsc_viftype_defaults[vt]; 392 + 393 + /* See what the Core device has for support */ 394 + vt_support = !!le16_to_cpu(pdsc->dev_ident.vif_types[vt]); 395 + dev_dbg(pdsc->dev, "VIF %s is %ssupported\n", 396 + pdsc->viftype_status[vt].name, 397 + vt_support ? "" : "not "); 398 + 399 + pdsc->viftype_status[vt].supported = vt_support; 400 + } 401 + 402 + return 0; 403 + } 404 + 405 + int pdsc_setup(struct pdsc *pdsc, bool init) 406 + { 407 + int numdescs; 408 + int err; 409 + 410 + if (init) 411 + err = pdsc_dev_init(pdsc); 412 + else 413 + err = pdsc_dev_reinit(pdsc); 414 + if (err) 415 + return err; 416 + 417 + /* Scale the descriptor ring length based on number of CPUs and VFs */ 418 + numdescs = max_t(int, PDSC_ADMINQ_MIN_LENGTH, num_online_cpus()); 419 + numdescs += 2 * pci_sriov_get_totalvfs(pdsc->pdev); 420 + numdescs = roundup_pow_of_two(numdescs); 421 + err = pdsc_qcq_alloc(pdsc, PDS_CORE_QTYPE_ADMINQ, 0, "adminq", 422 + PDS_CORE_QCQ_F_CORE | PDS_CORE_QCQ_F_INTR, 423 + numdescs, 424 + sizeof(union pds_core_adminq_cmd), 425 + sizeof(union pds_core_adminq_comp), 426 + 0, &pdsc->adminqcq); 427 + if (err) 428 + goto err_out_teardown; 429 + 430 + err = pdsc_qcq_alloc(pdsc, PDS_CORE_QTYPE_NOTIFYQ, 0, "notifyq", 431 + PDS_CORE_QCQ_F_NOTIFYQ, 432 + PDSC_NOTIFYQ_LENGTH, 433 + sizeof(struct pds_core_notifyq_cmd), 434 + sizeof(union pds_core_notifyq_comp), 435 + 0, &pdsc->notifyqcq); 436 + if (err) 437 + goto err_out_teardown; 438 + 439 + /* NotifyQ rides on the AdminQ interrupt */ 440 + pdsc->notifyqcq.intx = pdsc->adminqcq.intx; 441 + 442 + /* Set up the Core with the AdminQ and NotifyQ info */ 443 + err = pdsc_core_init(pdsc); 444 + if (err) 445 + goto err_out_teardown; 446 + 447 + /* Set up the VIFs */ 448 + err = pdsc_viftypes_init(pdsc); 449 + if (err) 450 + goto err_out_teardown; 451 + 452 + if (init) 453 + pdsc_debugfs_add_viftype(pdsc); 454 + 455 + clear_bit(PDSC_S_FW_DEAD, &pdsc->state); 456 + return 0; 457 + 458 + err_out_teardown: 459 + pdsc_teardown(pdsc, init); 460 + return err; 461 + } 462 + 463 + void pdsc_teardown(struct pdsc *pdsc, bool removing) 464 + { 465 + int i; 466 + 467 + pdsc_devcmd_reset(pdsc); 468 + pdsc_qcq_free(pdsc, &pdsc->notifyqcq); 469 + pdsc_qcq_free(pdsc, &pdsc->adminqcq); 470 + 471 + kfree(pdsc->viftype_status); 472 + pdsc->viftype_status = NULL; 473 + 474 + if (pdsc->intr_info) { 475 + for (i = 0; i < pdsc->nintrs; i++) 476 + pdsc_intr_free(pdsc, i); 477 + 478 + if (removing) { 479 + kfree(pdsc->intr_info); 480 + pdsc->intr_info = NULL; 481 + } 482 + } 483 + 484 + if (pdsc->kern_dbpage) { 485 + iounmap(pdsc->kern_dbpage); 486 + pdsc->kern_dbpage = NULL; 487 + } 488 + 489 + set_bit(PDSC_S_FW_DEAD, &pdsc->state); 490 + } 491 + 492 + int pdsc_start(struct pdsc *pdsc) 493 + { 494 + pds_core_intr_mask(&pdsc->intr_ctrl[pdsc->adminqcq.intx], 495 + PDS_CORE_INTR_MASK_CLEAR); 496 + 497 + return 0; 498 + } 499 + 500 + void pdsc_stop(struct pdsc *pdsc) 501 + { 502 + int i; 503 + 504 + if (!pdsc->intr_info) 505 + return; 506 + 507 + /* Mask interrupts that are in use */ 508 + for (i = 0; i < pdsc->nintrs; i++) 509 + if (pdsc->intr_info[i].vector) 510 + pds_core_intr_mask(&pdsc->intr_ctrl[i], 511 + PDS_CORE_INTR_MASK_SET); 512 + } 513 + 514 + static void pdsc_fw_down(struct pdsc *pdsc) 515 + { 516 + union pds_core_notifyq_comp reset_event = { 517 + .reset.ecode = cpu_to_le16(PDS_EVENT_RESET), 518 + .reset.state = 0, 519 + }; 520 + 521 + if (test_and_set_bit(PDSC_S_FW_DEAD, &pdsc->state)) { 522 + dev_err(pdsc->dev, "%s: already happening\n", __func__); 523 + return; 524 + } 525 + 526 + /* Notify clients of fw_down */ 527 + devlink_health_report(pdsc->fw_reporter, "FW down reported", pdsc); 528 + pdsc_notify(PDS_EVENT_RESET, &reset_event); 529 + 530 + pdsc_stop(pdsc); 531 + pdsc_teardown(pdsc, PDSC_TEARDOWN_RECOVERY); 532 + } 533 + 534 + static void pdsc_fw_up(struct pdsc *pdsc) 535 + { 536 + union pds_core_notifyq_comp reset_event = { 537 + .reset.ecode = cpu_to_le16(PDS_EVENT_RESET), 538 + .reset.state = 1, 539 + }; 540 + int err; 541 + 542 + if (!test_bit(PDSC_S_FW_DEAD, &pdsc->state)) { 543 + dev_err(pdsc->dev, "%s: fw not dead\n", __func__); 544 + return; 545 + } 546 + 547 + err = pdsc_setup(pdsc, PDSC_SETUP_RECOVERY); 548 + if (err) 549 + goto err_out; 550 + 551 + err = pdsc_start(pdsc); 552 + if (err) 553 + goto err_out; 554 + 555 + /* Notify clients of fw_up */ 556 + pdsc->fw_recoveries++; 557 + devlink_health_reporter_state_update(pdsc->fw_reporter, 558 + DEVLINK_HEALTH_REPORTER_STATE_HEALTHY); 559 + pdsc_notify(PDS_EVENT_RESET, &reset_event); 560 + 561 + return; 562 + 563 + err_out: 564 + pdsc_teardown(pdsc, PDSC_TEARDOWN_RECOVERY); 565 + } 566 + 567 + void pdsc_health_thread(struct work_struct *work) 568 + { 569 + struct pdsc *pdsc = container_of(work, struct pdsc, health_work); 570 + unsigned long mask; 571 + bool healthy; 572 + 573 + mutex_lock(&pdsc->config_lock); 574 + 575 + /* Don't do a check when in a transition state */ 576 + mask = BIT_ULL(PDSC_S_INITING_DRIVER) | 577 + BIT_ULL(PDSC_S_STOPPING_DRIVER); 578 + if (pdsc->state & mask) 579 + goto out_unlock; 580 + 581 + healthy = pdsc_is_fw_good(pdsc); 582 + dev_dbg(pdsc->dev, "%s: health %d fw_status %#02x fw_heartbeat %d\n", 583 + __func__, healthy, pdsc->fw_status, pdsc->last_hb); 584 + 585 + if (test_bit(PDSC_S_FW_DEAD, &pdsc->state)) { 586 + if (healthy) 587 + pdsc_fw_up(pdsc); 588 + } else { 589 + if (!healthy) 590 + pdsc_fw_down(pdsc); 591 + } 592 + 593 + pdsc->fw_generation = pdsc->fw_status & PDS_CORE_FW_STS_F_GENERATION; 594 + 595 + out_unlock: 596 + mutex_unlock(&pdsc->config_lock); 597 + }
+312
drivers/net/ethernet/amd/pds_core/core.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* Copyright(c) 2023 Advanced Micro Devices, Inc */ 3 + 4 + #ifndef _PDSC_H_ 5 + #define _PDSC_H_ 6 + 7 + #include <linux/debugfs.h> 8 + #include <net/devlink.h> 9 + 10 + #include <linux/pds/pds_common.h> 11 + #include <linux/pds/pds_core_if.h> 12 + #include <linux/pds/pds_adminq.h> 13 + #include <linux/pds/pds_intr.h> 14 + 15 + #define PDSC_DRV_DESCRIPTION "AMD/Pensando Core Driver" 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 */ 21 + #define PDSC_TEARDOWN_RECOVERY false 22 + #define PDSC_TEARDOWN_REMOVING true 23 + #define PDSC_SETUP_RECOVERY false 24 + #define PDSC_SETUP_INIT true 25 + 26 + struct pdsc_dev_bar { 27 + void __iomem *vaddr; 28 + phys_addr_t bus_addr; 29 + unsigned long len; 30 + int res_index; 31 + }; 32 + 33 + struct pdsc; 34 + 35 + struct pdsc_vf { 36 + struct pds_auxiliary_dev *padev; 37 + struct pdsc *vf; 38 + u16 index; 39 + __le16 vif_types[PDS_DEV_TYPE_MAX]; 40 + }; 41 + 42 + struct pdsc_devinfo { 43 + u8 asic_type; 44 + u8 asic_rev; 45 + char fw_version[PDS_CORE_DEVINFO_FWVERS_BUFLEN + 1]; 46 + char serial_num[PDS_CORE_DEVINFO_SERIAL_BUFLEN + 1]; 47 + }; 48 + 49 + struct pdsc_queue { 50 + struct pdsc_q_info *info; 51 + u64 dbval; 52 + u16 head_idx; 53 + u16 tail_idx; 54 + u8 hw_type; 55 + unsigned int index; 56 + unsigned int num_descs; 57 + u64 dbell_count; 58 + u64 features; 59 + unsigned int type; 60 + unsigned int hw_index; 61 + union { 62 + void *base; 63 + struct pds_core_admin_cmd *adminq; 64 + }; 65 + dma_addr_t base_pa; /* must be page aligned */ 66 + unsigned int desc_size; 67 + unsigned int pid; 68 + char name[PDSC_QUEUE_NAME_MAX_SZ]; 69 + }; 70 + 71 + #define PDSC_INTR_NAME_MAX_SZ 32 72 + 73 + struct pdsc_intr_info { 74 + char name[PDSC_INTR_NAME_MAX_SZ]; 75 + unsigned int index; 76 + unsigned int vector; 77 + void *data; 78 + }; 79 + 80 + struct pdsc_cq_info { 81 + void *comp; 82 + }; 83 + 84 + struct pdsc_buf_info { 85 + struct page *page; 86 + dma_addr_t dma_addr; 87 + u32 page_offset; 88 + u32 len; 89 + }; 90 + 91 + struct pdsc_q_info { 92 + union { 93 + void *desc; 94 + struct pdsc_admin_cmd *adminq_desc; 95 + }; 96 + unsigned int bytes; 97 + unsigned int nbufs; 98 + struct pdsc_buf_info bufs[PDS_CORE_MAX_FRAGS]; 99 + struct pdsc_wait_context *wc; 100 + void *dest; 101 + }; 102 + 103 + struct pdsc_cq { 104 + struct pdsc_cq_info *info; 105 + struct pdsc_queue *bound_q; 106 + struct pdsc_intr_info *bound_intr; 107 + u16 tail_idx; 108 + bool done_color; 109 + unsigned int num_descs; 110 + unsigned int desc_size; 111 + void *base; 112 + dma_addr_t base_pa; /* must be page aligned */ 113 + } ____cacheline_aligned_in_smp; 114 + 115 + struct pdsc_qcq { 116 + struct pdsc *pdsc; 117 + void *q_base; 118 + dma_addr_t q_base_pa; /* might not be page aligned */ 119 + void *cq_base; 120 + dma_addr_t cq_base_pa; /* might not be page aligned */ 121 + u32 q_size; 122 + u32 cq_size; 123 + bool armed; 124 + unsigned int flags; 125 + 126 + struct work_struct work; 127 + struct pdsc_queue q; 128 + struct pdsc_cq cq; 129 + int intx; 130 + 131 + u32 accum_work; 132 + struct dentry *dentry; 133 + }; 134 + 135 + struct pdsc_viftype { 136 + char *name; 137 + bool supported; 138 + bool enabled; 139 + int dl_id; 140 + int vif_id; 141 + struct pds_auxiliary_dev *padev; 142 + }; 143 + 144 + /* No state flags set means we are in a steady running state */ 145 + enum pdsc_state_flags { 146 + PDSC_S_FW_DEAD, /* stopped, wait on startup or recovery */ 147 + PDSC_S_INITING_DRIVER, /* initial startup from probe */ 148 + PDSC_S_STOPPING_DRIVER, /* driver remove */ 149 + 150 + /* leave this as last */ 151 + PDSC_S_STATE_SIZE 152 + }; 153 + 154 + struct pdsc { 155 + struct pci_dev *pdev; 156 + struct dentry *dentry; 157 + struct device *dev; 158 + struct pdsc_dev_bar bars[PDS_CORE_BARS_MAX]; 159 + struct pdsc_vf *vfs; 160 + int num_vfs; 161 + int vf_id; 162 + int hw_index; 163 + int uid; 164 + 165 + unsigned long state; 166 + u8 fw_status; 167 + u8 fw_generation; 168 + unsigned long last_fw_time; 169 + u32 last_hb; 170 + struct timer_list wdtimer; 171 + unsigned int wdtimer_period; 172 + struct work_struct health_work; 173 + struct devlink_health_reporter *fw_reporter; 174 + u32 fw_recoveries; 175 + 176 + struct pdsc_devinfo dev_info; 177 + struct pds_core_dev_identity dev_ident; 178 + unsigned int nintrs; 179 + struct pdsc_intr_info *intr_info; /* array of nintrs elements */ 180 + 181 + struct workqueue_struct *wq; 182 + 183 + unsigned int devcmd_timeout; 184 + struct mutex devcmd_lock; /* lock for dev_cmd operations */ 185 + struct mutex config_lock; /* lock for configuration operations */ 186 + spinlock_t adminq_lock; /* lock for adminq operations */ 187 + struct pds_core_dev_info_regs __iomem *info_regs; 188 + struct pds_core_dev_cmd_regs __iomem *cmd_regs; 189 + struct pds_core_intr __iomem *intr_ctrl; 190 + u64 __iomem *intr_status; 191 + u64 __iomem *db_pages; 192 + dma_addr_t phy_db_pages; 193 + u64 __iomem *kern_dbpage; 194 + 195 + struct pdsc_qcq adminqcq; 196 + struct pdsc_qcq notifyqcq; 197 + u64 last_eid; 198 + struct pdsc_viftype *viftype_status; 199 + }; 200 + 201 + /** enum pds_core_dbell_bits - bitwise composition of dbell values. 202 + * 203 + * @PDS_CORE_DBELL_QID_MASK: unshifted mask of valid queue id bits. 204 + * @PDS_CORE_DBELL_QID_SHIFT: queue id shift amount in dbell value. 205 + * @PDS_CORE_DBELL_QID: macro to build QID component of dbell value. 206 + * 207 + * @PDS_CORE_DBELL_RING_MASK: unshifted mask of valid ring bits. 208 + * @PDS_CORE_DBELL_RING_SHIFT: ring shift amount in dbell value. 209 + * @PDS_CORE_DBELL_RING: macro to build ring component of dbell value. 210 + * 211 + * @PDS_CORE_DBELL_RING_0: ring zero dbell component value. 212 + * @PDS_CORE_DBELL_RING_1: ring one dbell component value. 213 + * @PDS_CORE_DBELL_RING_2: ring two dbell component value. 214 + * @PDS_CORE_DBELL_RING_3: ring three dbell component value. 215 + * 216 + * @PDS_CORE_DBELL_INDEX_MASK: bit mask of valid index bits, no shift needed. 217 + */ 218 + enum pds_core_dbell_bits { 219 + PDS_CORE_DBELL_QID_MASK = 0xffffff, 220 + PDS_CORE_DBELL_QID_SHIFT = 24, 221 + 222 + #define PDS_CORE_DBELL_QID(n) \ 223 + (((u64)(n) & PDS_CORE_DBELL_QID_MASK) << PDS_CORE_DBELL_QID_SHIFT) 224 + 225 + PDS_CORE_DBELL_RING_MASK = 0x7, 226 + PDS_CORE_DBELL_RING_SHIFT = 16, 227 + 228 + #define PDS_CORE_DBELL_RING(n) \ 229 + (((u64)(n) & PDS_CORE_DBELL_RING_MASK) << PDS_CORE_DBELL_RING_SHIFT) 230 + 231 + PDS_CORE_DBELL_RING_0 = 0, 232 + PDS_CORE_DBELL_RING_1 = PDS_CORE_DBELL_RING(1), 233 + PDS_CORE_DBELL_RING_2 = PDS_CORE_DBELL_RING(2), 234 + PDS_CORE_DBELL_RING_3 = PDS_CORE_DBELL_RING(3), 235 + 236 + PDS_CORE_DBELL_INDEX_MASK = 0xffff, 237 + }; 238 + 239 + static inline void pds_core_dbell_ring(u64 __iomem *db_page, 240 + enum pds_core_logical_qtype qtype, 241 + u64 val) 242 + { 243 + writeq(val, &db_page[qtype]); 244 + } 245 + 246 + int pdsc_fw_reporter_diagnose(struct devlink_health_reporter *reporter, 247 + struct devlink_fmsg *fmsg, 248 + struct netlink_ext_ack *extack); 249 + int pdsc_dl_info_get(struct devlink *dl, struct devlink_info_req *req, 250 + struct netlink_ext_ack *extack); 251 + int pdsc_dl_flash_update(struct devlink *dl, 252 + struct devlink_flash_update_params *params, 253 + struct netlink_ext_ack *extack); 254 + int pdsc_dl_enable_get(struct devlink *dl, u32 id, 255 + struct devlink_param_gset_ctx *ctx); 256 + int pdsc_dl_enable_set(struct devlink *dl, u32 id, 257 + struct devlink_param_gset_ctx *ctx); 258 + int pdsc_dl_enable_validate(struct devlink *dl, u32 id, 259 + union devlink_param_value val, 260 + struct netlink_ext_ack *extack); 261 + 262 + void __iomem *pdsc_map_dbpage(struct pdsc *pdsc, int page_num); 263 + 264 + void pdsc_debugfs_create(void); 265 + void pdsc_debugfs_destroy(void); 266 + void pdsc_debugfs_add_dev(struct pdsc *pdsc); 267 + void pdsc_debugfs_del_dev(struct pdsc *pdsc); 268 + void pdsc_debugfs_add_ident(struct pdsc *pdsc); 269 + void pdsc_debugfs_add_viftype(struct pdsc *pdsc); 270 + void pdsc_debugfs_add_irqs(struct pdsc *pdsc); 271 + void pdsc_debugfs_add_qcq(struct pdsc *pdsc, struct pdsc_qcq *qcq); 272 + void pdsc_debugfs_del_qcq(struct pdsc_qcq *qcq); 273 + 274 + int pdsc_err_to_errno(enum pds_core_status_code code); 275 + bool pdsc_is_fw_running(struct pdsc *pdsc); 276 + bool pdsc_is_fw_good(struct pdsc *pdsc); 277 + int pdsc_devcmd(struct pdsc *pdsc, union pds_core_dev_cmd *cmd, 278 + union pds_core_dev_comp *comp, int max_seconds); 279 + int pdsc_devcmd_locked(struct pdsc *pdsc, union pds_core_dev_cmd *cmd, 280 + union pds_core_dev_comp *comp, int max_seconds); 281 + int pdsc_devcmd_init(struct pdsc *pdsc); 282 + int pdsc_devcmd_reset(struct pdsc *pdsc); 283 + int pdsc_dev_reinit(struct pdsc *pdsc); 284 + int pdsc_dev_init(struct pdsc *pdsc); 285 + 286 + int pdsc_intr_alloc(struct pdsc *pdsc, char *name, 287 + irq_handler_t handler, void *data); 288 + void pdsc_intr_free(struct pdsc *pdsc, int index); 289 + void pdsc_qcq_free(struct pdsc *pdsc, struct pdsc_qcq *qcq); 290 + int pdsc_qcq_alloc(struct pdsc *pdsc, unsigned int type, unsigned int index, 291 + const char *name, unsigned int flags, unsigned int num_descs, 292 + unsigned int desc_size, unsigned int cq_desc_size, 293 + unsigned int pid, struct pdsc_qcq *qcq); 294 + int pdsc_setup(struct pdsc *pdsc, bool init); 295 + void pdsc_teardown(struct pdsc *pdsc, bool removing); 296 + int pdsc_start(struct pdsc *pdsc); 297 + void pdsc_stop(struct pdsc *pdsc); 298 + void pdsc_health_thread(struct work_struct *work); 299 + 300 + int pdsc_register_notify(struct notifier_block *nb); 301 + void pdsc_unregister_notify(struct notifier_block *nb); 302 + void pdsc_notify(unsigned long event, void *data); 303 + int pdsc_auxbus_dev_add(struct pdsc *cf, struct pdsc *pf); 304 + int pdsc_auxbus_dev_del(struct pdsc *cf, struct pdsc *pf); 305 + 306 + void pdsc_process_adminq(struct pdsc_qcq *qcq); 307 + void pdsc_work_thread(struct work_struct *work); 308 + irqreturn_t pdsc_adminq_isr(int irq, void *data); 309 + 310 + int pdsc_firmware_update(struct pdsc *pdsc, const struct firmware *fw, 311 + struct netlink_ext_ack *extack); 312 + #endif /* _PDSC_H_ */
+170
drivers/net/ethernet/amd/pds_core/debugfs.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* Copyright(c) 2023 Advanced Micro Devices, Inc */ 3 + 4 + #include <linux/pci.h> 5 + 6 + #include "core.h" 7 + 8 + static struct dentry *pdsc_dir; 9 + 10 + void pdsc_debugfs_create(void) 11 + { 12 + pdsc_dir = debugfs_create_dir(PDS_CORE_DRV_NAME, NULL); 13 + } 14 + 15 + void pdsc_debugfs_destroy(void) 16 + { 17 + debugfs_remove_recursive(pdsc_dir); 18 + } 19 + 20 + void pdsc_debugfs_add_dev(struct pdsc *pdsc) 21 + { 22 + pdsc->dentry = debugfs_create_dir(pci_name(pdsc->pdev), pdsc_dir); 23 + 24 + debugfs_create_ulong("state", 0400, pdsc->dentry, &pdsc->state); 25 + } 26 + 27 + void pdsc_debugfs_del_dev(struct pdsc *pdsc) 28 + { 29 + debugfs_remove_recursive(pdsc->dentry); 30 + pdsc->dentry = NULL; 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 + } 70 + 71 + static int viftype_show(struct seq_file *seq, void *v) 72 + { 73 + struct pdsc *pdsc = seq->private; 74 + int vt; 75 + 76 + for (vt = 0; vt < PDS_DEV_TYPE_MAX; vt++) { 77 + if (!pdsc->viftype_status[vt].name) 78 + continue; 79 + 80 + seq_printf(seq, "%s\t%d supported %d enabled\n", 81 + pdsc->viftype_status[vt].name, 82 + pdsc->viftype_status[vt].supported, 83 + pdsc->viftype_status[vt].enabled); 84 + } 85 + return 0; 86 + } 87 + DEFINE_SHOW_ATTRIBUTE(viftype); 88 + 89 + void pdsc_debugfs_add_viftype(struct pdsc *pdsc) 90 + { 91 + debugfs_create_file("viftypes", 0400, pdsc->dentry, 92 + pdsc, &viftype_fops); 93 + } 94 + 95 + static const struct debugfs_reg32 intr_ctrl_regs[] = { 96 + { .name = "coal_init", .offset = 0, }, 97 + { .name = "mask", .offset = 4, }, 98 + { .name = "credits", .offset = 8, }, 99 + { .name = "mask_on_assert", .offset = 12, }, 100 + { .name = "coal_timer", .offset = 16, }, 101 + }; 102 + 103 + void pdsc_debugfs_add_qcq(struct pdsc *pdsc, struct pdsc_qcq *qcq) 104 + { 105 + struct dentry *qcq_dentry, *q_dentry, *cq_dentry; 106 + struct dentry *intr_dentry; 107 + struct debugfs_regset32 *intr_ctrl_regset; 108 + struct pdsc_intr_info *intr = &pdsc->intr_info[qcq->intx]; 109 + struct pdsc_queue *q = &qcq->q; 110 + struct pdsc_cq *cq = &qcq->cq; 111 + 112 + qcq_dentry = debugfs_create_dir(q->name, pdsc->dentry); 113 + if (IS_ERR_OR_NULL(qcq_dentry)) 114 + return; 115 + qcq->dentry = qcq_dentry; 116 + 117 + debugfs_create_x64("q_base_pa", 0400, qcq_dentry, &qcq->q_base_pa); 118 + debugfs_create_x32("q_size", 0400, qcq_dentry, &qcq->q_size); 119 + debugfs_create_x64("cq_base_pa", 0400, qcq_dentry, &qcq->cq_base_pa); 120 + debugfs_create_x32("cq_size", 0400, qcq_dentry, &qcq->cq_size); 121 + debugfs_create_x32("accum_work", 0400, qcq_dentry, &qcq->accum_work); 122 + 123 + q_dentry = debugfs_create_dir("q", qcq->dentry); 124 + if (IS_ERR_OR_NULL(q_dentry)) 125 + return; 126 + 127 + debugfs_create_u32("index", 0400, q_dentry, &q->index); 128 + debugfs_create_u32("num_descs", 0400, q_dentry, &q->num_descs); 129 + debugfs_create_u32("desc_size", 0400, q_dentry, &q->desc_size); 130 + debugfs_create_u32("pid", 0400, q_dentry, &q->pid); 131 + 132 + debugfs_create_u16("tail", 0400, q_dentry, &q->tail_idx); 133 + debugfs_create_u16("head", 0400, q_dentry, &q->head_idx); 134 + 135 + cq_dentry = debugfs_create_dir("cq", qcq->dentry); 136 + if (IS_ERR_OR_NULL(cq_dentry)) 137 + return; 138 + 139 + debugfs_create_x64("base_pa", 0400, cq_dentry, &cq->base_pa); 140 + debugfs_create_u32("num_descs", 0400, cq_dentry, &cq->num_descs); 141 + debugfs_create_u32("desc_size", 0400, cq_dentry, &cq->desc_size); 142 + debugfs_create_bool("done_color", 0400, cq_dentry, &cq->done_color); 143 + debugfs_create_u16("tail", 0400, cq_dentry, &cq->tail_idx); 144 + 145 + if (qcq->flags & PDS_CORE_QCQ_F_INTR) { 146 + intr_dentry = debugfs_create_dir("intr", qcq->dentry); 147 + if (IS_ERR_OR_NULL(intr_dentry)) 148 + return; 149 + 150 + debugfs_create_u32("index", 0400, intr_dentry, &intr->index); 151 + debugfs_create_u32("vector", 0400, intr_dentry, &intr->vector); 152 + 153 + intr_ctrl_regset = kzalloc(sizeof(*intr_ctrl_regset), 154 + GFP_KERNEL); 155 + if (!intr_ctrl_regset) 156 + return; 157 + intr_ctrl_regset->regs = intr_ctrl_regs; 158 + intr_ctrl_regset->nregs = ARRAY_SIZE(intr_ctrl_regs); 159 + intr_ctrl_regset->base = &pdsc->intr_ctrl[intr->index]; 160 + 161 + debugfs_create_regset32("intr_ctrl", 0400, intr_dentry, 162 + intr_ctrl_regset); 163 + } 164 + }; 165 + 166 + void pdsc_debugfs_del_qcq(struct pdsc_qcq *qcq) 167 + { 168 + debugfs_remove_recursive(qcq->dentry); 169 + qcq->dentry = NULL; 170 + }
+351
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 + if (err == -ENXIO || err == -ETIMEDOUT) 181 + queue_work(pdsc->wq, &pdsc->health_work); 182 + 183 + return err; 184 + } 185 + 186 + int pdsc_devcmd(struct pdsc *pdsc, union pds_core_dev_cmd *cmd, 187 + union pds_core_dev_comp *comp, int max_seconds) 188 + { 189 + int err; 190 + 191 + mutex_lock(&pdsc->devcmd_lock); 192 + err = pdsc_devcmd_locked(pdsc, cmd, comp, max_seconds); 193 + mutex_unlock(&pdsc->devcmd_lock); 194 + 195 + return err; 196 + } 197 + 198 + int pdsc_devcmd_init(struct pdsc *pdsc) 199 + { 200 + union pds_core_dev_comp comp = {}; 201 + union pds_core_dev_cmd cmd = { 202 + .opcode = PDS_CORE_CMD_INIT, 203 + }; 204 + 205 + return pdsc_devcmd(pdsc, &cmd, &comp, pdsc->devcmd_timeout); 206 + } 207 + 208 + int pdsc_devcmd_reset(struct pdsc *pdsc) 209 + { 210 + union pds_core_dev_comp comp = {}; 211 + union pds_core_dev_cmd cmd = { 212 + .reset.opcode = PDS_CORE_CMD_RESET, 213 + }; 214 + 215 + return pdsc_devcmd(pdsc, &cmd, &comp, pdsc->devcmd_timeout); 216 + } 217 + 218 + static int pdsc_devcmd_identify_locked(struct pdsc *pdsc) 219 + { 220 + union pds_core_dev_comp comp = {}; 221 + union pds_core_dev_cmd cmd = { 222 + .identify.opcode = PDS_CORE_CMD_IDENTIFY, 223 + .identify.ver = PDS_CORE_IDENTITY_VERSION_1, 224 + }; 225 + 226 + return pdsc_devcmd_locked(pdsc, &cmd, &comp, pdsc->devcmd_timeout); 227 + } 228 + 229 + static void pdsc_init_devinfo(struct pdsc *pdsc) 230 + { 231 + pdsc->dev_info.asic_type = ioread8(&pdsc->info_regs->asic_type); 232 + pdsc->dev_info.asic_rev = ioread8(&pdsc->info_regs->asic_rev); 233 + pdsc->fw_generation = PDS_CORE_FW_STS_F_GENERATION & 234 + ioread8(&pdsc->info_regs->fw_status); 235 + 236 + memcpy_fromio(pdsc->dev_info.fw_version, 237 + pdsc->info_regs->fw_version, 238 + PDS_CORE_DEVINFO_FWVERS_BUFLEN); 239 + pdsc->dev_info.fw_version[PDS_CORE_DEVINFO_FWVERS_BUFLEN] = 0; 240 + 241 + memcpy_fromio(pdsc->dev_info.serial_num, 242 + pdsc->info_regs->serial_num, 243 + PDS_CORE_DEVINFO_SERIAL_BUFLEN); 244 + pdsc->dev_info.serial_num[PDS_CORE_DEVINFO_SERIAL_BUFLEN] = 0; 245 + 246 + dev_dbg(pdsc->dev, "fw_version %s\n", pdsc->dev_info.fw_version); 247 + } 248 + 249 + static int pdsc_identify(struct pdsc *pdsc) 250 + { 251 + struct pds_core_drv_identity drv = {}; 252 + size_t sz; 253 + int err; 254 + 255 + drv.drv_type = cpu_to_le32(PDS_DRIVER_LINUX); 256 + snprintf(drv.driver_ver_str, sizeof(drv.driver_ver_str), 257 + "%s %s", PDS_CORE_DRV_NAME, utsname()->release); 258 + 259 + /* Next let's get some info about the device 260 + * We use the devcmd_lock at this level in order to 261 + * get safe access to the cmd_regs->data before anyone 262 + * else can mess it up 263 + */ 264 + mutex_lock(&pdsc->devcmd_lock); 265 + 266 + sz = min_t(size_t, sizeof(drv), sizeof(pdsc->cmd_regs->data)); 267 + memcpy_toio(&pdsc->cmd_regs->data, &drv, sz); 268 + 269 + err = pdsc_devcmd_identify_locked(pdsc); 270 + if (!err) { 271 + sz = min_t(size_t, sizeof(pdsc->dev_ident), 272 + sizeof(pdsc->cmd_regs->data)); 273 + memcpy_fromio(&pdsc->dev_ident, &pdsc->cmd_regs->data, sz); 274 + } 275 + mutex_unlock(&pdsc->devcmd_lock); 276 + 277 + if (err) { 278 + dev_err(pdsc->dev, "Cannot identify device: %pe\n", 279 + ERR_PTR(err)); 280 + return err; 281 + } 282 + 283 + if (isprint(pdsc->dev_info.fw_version[0]) && 284 + isascii(pdsc->dev_info.fw_version[0])) 285 + dev_info(pdsc->dev, "FW: %.*s\n", 286 + (int)(sizeof(pdsc->dev_info.fw_version) - 1), 287 + pdsc->dev_info.fw_version); 288 + else 289 + dev_info(pdsc->dev, "FW: (invalid string) 0x%02x 0x%02x 0x%02x 0x%02x ...\n", 290 + (u8)pdsc->dev_info.fw_version[0], 291 + (u8)pdsc->dev_info.fw_version[1], 292 + (u8)pdsc->dev_info.fw_version[2], 293 + (u8)pdsc->dev_info.fw_version[3]); 294 + 295 + return 0; 296 + } 297 + 298 + int pdsc_dev_reinit(struct pdsc *pdsc) 299 + { 300 + pdsc_init_devinfo(pdsc); 301 + 302 + return pdsc_identify(pdsc); 303 + } 304 + 305 + int pdsc_dev_init(struct pdsc *pdsc) 306 + { 307 + unsigned int nintrs; 308 + int err; 309 + 310 + /* Initial init and reset of device */ 311 + pdsc_init_devinfo(pdsc); 312 + pdsc->devcmd_timeout = PDS_CORE_DEVCMD_TIMEOUT; 313 + 314 + err = pdsc_devcmd_reset(pdsc); 315 + if (err) 316 + return err; 317 + 318 + err = pdsc_identify(pdsc); 319 + if (err) 320 + return err; 321 + 322 + pdsc_debugfs_add_ident(pdsc); 323 + 324 + /* Now we can reserve interrupts */ 325 + nintrs = le32_to_cpu(pdsc->dev_ident.nintrs); 326 + nintrs = min_t(unsigned int, num_online_cpus(), nintrs); 327 + 328 + /* Get intr_info struct array for tracking */ 329 + pdsc->intr_info = kcalloc(nintrs, sizeof(*pdsc->intr_info), GFP_KERNEL); 330 + if (!pdsc->intr_info) { 331 + err = -ENOMEM; 332 + goto err_out; 333 + } 334 + 335 + err = pci_alloc_irq_vectors(pdsc->pdev, nintrs, nintrs, PCI_IRQ_MSIX); 336 + if (err != nintrs) { 337 + dev_err(pdsc->dev, "Can't get %d intrs from OS: %pe\n", 338 + nintrs, ERR_PTR(err)); 339 + err = -ENOSPC; 340 + goto err_out; 341 + } 342 + pdsc->nintrs = nintrs; 343 + 344 + return 0; 345 + 346 + err_out: 347 + kfree(pdsc->intr_info); 348 + pdsc->intr_info = NULL; 349 + 350 + return err; 351 + }
+183
drivers/net/ethernet/amd/pds_core/devlink.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* Copyright(c) 2023 Advanced Micro Devices, Inc */ 3 + 4 + #include "core.h" 5 + #include <linux/pds/pds_auxbus.h> 6 + 7 + static struct 8 + pdsc_viftype *pdsc_dl_find_viftype_by_id(struct pdsc *pdsc, 9 + enum devlink_param_type dl_id) 10 + { 11 + int vt; 12 + 13 + for (vt = 0; vt < PDS_DEV_TYPE_MAX; vt++) { 14 + if (pdsc->viftype_status[vt].dl_id == dl_id) 15 + return &pdsc->viftype_status[vt]; 16 + } 17 + 18 + return NULL; 19 + } 20 + 21 + int pdsc_dl_enable_get(struct devlink *dl, u32 id, 22 + struct devlink_param_gset_ctx *ctx) 23 + { 24 + struct pdsc *pdsc = devlink_priv(dl); 25 + struct pdsc_viftype *vt_entry; 26 + 27 + vt_entry = pdsc_dl_find_viftype_by_id(pdsc, id); 28 + if (!vt_entry) 29 + return -ENOENT; 30 + 31 + ctx->val.vbool = vt_entry->enabled; 32 + 33 + return 0; 34 + } 35 + 36 + int pdsc_dl_enable_set(struct devlink *dl, u32 id, 37 + struct devlink_param_gset_ctx *ctx) 38 + { 39 + struct pdsc *pdsc = devlink_priv(dl); 40 + struct pdsc_viftype *vt_entry; 41 + int err = 0; 42 + int vf_id; 43 + 44 + vt_entry = pdsc_dl_find_viftype_by_id(pdsc, id); 45 + if (!vt_entry || !vt_entry->supported) 46 + return -EOPNOTSUPP; 47 + 48 + if (vt_entry->enabled == ctx->val.vbool) 49 + return 0; 50 + 51 + vt_entry->enabled = ctx->val.vbool; 52 + for (vf_id = 0; vf_id < pdsc->num_vfs; vf_id++) { 53 + struct pdsc *vf = pdsc->vfs[vf_id].vf; 54 + 55 + err = ctx->val.vbool ? pdsc_auxbus_dev_add(vf, pdsc) : 56 + pdsc_auxbus_dev_del(vf, pdsc); 57 + } 58 + 59 + return err; 60 + } 61 + 62 + int pdsc_dl_enable_validate(struct devlink *dl, u32 id, 63 + union devlink_param_value val, 64 + struct netlink_ext_ack *extack) 65 + { 66 + struct pdsc *pdsc = devlink_priv(dl); 67 + struct pdsc_viftype *vt_entry; 68 + 69 + vt_entry = pdsc_dl_find_viftype_by_id(pdsc, id); 70 + if (!vt_entry || !vt_entry->supported) 71 + return -EOPNOTSUPP; 72 + 73 + if (!pdsc->viftype_status[vt_entry->vif_id].supported) 74 + return -ENODEV; 75 + 76 + return 0; 77 + } 78 + 79 + int pdsc_dl_flash_update(struct devlink *dl, 80 + struct devlink_flash_update_params *params, 81 + struct netlink_ext_ack *extack) 82 + { 83 + struct pdsc *pdsc = devlink_priv(dl); 84 + 85 + return pdsc_firmware_update(pdsc, params->fw, extack); 86 + } 87 + 88 + static char *fw_slotnames[] = { 89 + "fw.goldfw", 90 + "fw.mainfwa", 91 + "fw.mainfwb", 92 + }; 93 + 94 + int pdsc_dl_info_get(struct devlink *dl, struct devlink_info_req *req, 95 + struct netlink_ext_ack *extack) 96 + { 97 + union pds_core_dev_cmd cmd = { 98 + .fw_control.opcode = PDS_CORE_CMD_FW_CONTROL, 99 + .fw_control.oper = PDS_CORE_FW_GET_LIST, 100 + }; 101 + struct pds_core_fw_list_info fw_list; 102 + struct pdsc *pdsc = devlink_priv(dl); 103 + union pds_core_dev_comp comp; 104 + char buf[16]; 105 + int listlen; 106 + int err; 107 + int i; 108 + 109 + mutex_lock(&pdsc->devcmd_lock); 110 + err = pdsc_devcmd_locked(pdsc, &cmd, &comp, pdsc->devcmd_timeout * 2); 111 + memcpy_fromio(&fw_list, pdsc->cmd_regs->data, sizeof(fw_list)); 112 + mutex_unlock(&pdsc->devcmd_lock); 113 + if (err && err != -EIO) 114 + return err; 115 + 116 + listlen = fw_list.num_fw_slots; 117 + for (i = 0; i < listlen; i++) { 118 + if (i < ARRAY_SIZE(fw_slotnames)) 119 + strscpy(buf, fw_slotnames[i], sizeof(buf)); 120 + else 121 + snprintf(buf, sizeof(buf), "fw.slot_%d", i); 122 + err = devlink_info_version_stored_put(req, buf, 123 + fw_list.fw_names[i].fw_version); 124 + } 125 + 126 + err = devlink_info_version_running_put(req, 127 + DEVLINK_INFO_VERSION_GENERIC_FW, 128 + pdsc->dev_info.fw_version); 129 + if (err) 130 + return err; 131 + 132 + snprintf(buf, sizeof(buf), "0x%x", pdsc->dev_info.asic_type); 133 + err = devlink_info_version_fixed_put(req, 134 + DEVLINK_INFO_VERSION_GENERIC_ASIC_ID, 135 + buf); 136 + if (err) 137 + return err; 138 + 139 + snprintf(buf, sizeof(buf), "0x%x", pdsc->dev_info.asic_rev); 140 + err = devlink_info_version_fixed_put(req, 141 + DEVLINK_INFO_VERSION_GENERIC_ASIC_REV, 142 + buf); 143 + if (err) 144 + return err; 145 + 146 + return devlink_info_serial_number_put(req, pdsc->dev_info.serial_num); 147 + } 148 + 149 + int pdsc_fw_reporter_diagnose(struct devlink_health_reporter *reporter, 150 + struct devlink_fmsg *fmsg, 151 + struct netlink_ext_ack *extack) 152 + { 153 + struct pdsc *pdsc = devlink_health_reporter_priv(reporter); 154 + int err; 155 + 156 + mutex_lock(&pdsc->config_lock); 157 + 158 + if (test_bit(PDSC_S_FW_DEAD, &pdsc->state)) 159 + err = devlink_fmsg_string_pair_put(fmsg, "Status", "dead"); 160 + else if (!pdsc_is_fw_good(pdsc)) 161 + err = devlink_fmsg_string_pair_put(fmsg, "Status", "unhealthy"); 162 + else 163 + err = devlink_fmsg_string_pair_put(fmsg, "Status", "healthy"); 164 + 165 + mutex_unlock(&pdsc->config_lock); 166 + 167 + if (err) 168 + return err; 169 + 170 + err = devlink_fmsg_u32_pair_put(fmsg, "State", 171 + pdsc->fw_status & 172 + ~PDS_CORE_FW_STS_F_GENERATION); 173 + if (err) 174 + return err; 175 + 176 + err = devlink_fmsg_u32_pair_put(fmsg, "Generation", 177 + pdsc->fw_generation >> 4); 178 + if (err) 179 + return err; 180 + 181 + return devlink_fmsg_u32_pair_put(fmsg, "Recoveries", 182 + pdsc->fw_recoveries); 183 + }
+194
drivers/net/ethernet/amd/pds_core/fw.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* Copyright(c) 2023 Advanced Micro Devices, Inc */ 3 + 4 + #include "core.h" 5 + 6 + /* The worst case wait for the install activity is about 25 minutes when 7 + * installing a new CPLD, which is very seldom. Normal is about 30-35 8 + * seconds. Since the driver can't tell if a CPLD update will happen we 9 + * set the timeout for the ugly case. 10 + */ 11 + #define PDSC_FW_INSTALL_TIMEOUT (25 * 60) 12 + #define PDSC_FW_SELECT_TIMEOUT 30 13 + 14 + /* Number of periodic log updates during fw file download */ 15 + #define PDSC_FW_INTERVAL_FRACTION 32 16 + 17 + static int pdsc_devcmd_fw_download_locked(struct pdsc *pdsc, u64 addr, 18 + u32 offset, u32 length) 19 + { 20 + union pds_core_dev_cmd cmd = { 21 + .fw_download.opcode = PDS_CORE_CMD_FW_DOWNLOAD, 22 + .fw_download.offset = cpu_to_le32(offset), 23 + .fw_download.addr = cpu_to_le64(addr), 24 + .fw_download.length = cpu_to_le32(length), 25 + }; 26 + union pds_core_dev_comp comp; 27 + 28 + return pdsc_devcmd_locked(pdsc, &cmd, &comp, pdsc->devcmd_timeout); 29 + } 30 + 31 + static int pdsc_devcmd_fw_install(struct pdsc *pdsc) 32 + { 33 + union pds_core_dev_cmd cmd = { 34 + .fw_control.opcode = PDS_CORE_CMD_FW_CONTROL, 35 + .fw_control.oper = PDS_CORE_FW_INSTALL_ASYNC 36 + }; 37 + union pds_core_dev_comp comp; 38 + int err; 39 + 40 + err = pdsc_devcmd(pdsc, &cmd, &comp, pdsc->devcmd_timeout); 41 + if (err < 0) 42 + return err; 43 + 44 + return comp.fw_control.slot; 45 + } 46 + 47 + static int pdsc_devcmd_fw_activate(struct pdsc *pdsc, 48 + enum pds_core_fw_slot slot) 49 + { 50 + union pds_core_dev_cmd cmd = { 51 + .fw_control.opcode = PDS_CORE_CMD_FW_CONTROL, 52 + .fw_control.oper = PDS_CORE_FW_ACTIVATE_ASYNC, 53 + .fw_control.slot = slot 54 + }; 55 + union pds_core_dev_comp comp; 56 + 57 + return pdsc_devcmd(pdsc, &cmd, &comp, pdsc->devcmd_timeout); 58 + } 59 + 60 + static int pdsc_fw_status_long_wait(struct pdsc *pdsc, 61 + const char *label, 62 + unsigned long timeout, 63 + u8 fw_cmd, 64 + struct netlink_ext_ack *extack) 65 + { 66 + union pds_core_dev_cmd cmd = { 67 + .fw_control.opcode = PDS_CORE_CMD_FW_CONTROL, 68 + .fw_control.oper = fw_cmd, 69 + }; 70 + union pds_core_dev_comp comp; 71 + unsigned long start_time; 72 + unsigned long end_time; 73 + int err; 74 + 75 + /* Ping on the status of the long running async install 76 + * command. We get EAGAIN while the command is still 77 + * running, else we get the final command status. 78 + */ 79 + start_time = jiffies; 80 + end_time = start_time + (timeout * HZ); 81 + do { 82 + err = pdsc_devcmd(pdsc, &cmd, &comp, pdsc->devcmd_timeout); 83 + msleep(20); 84 + } while (time_before(jiffies, end_time) && 85 + (err == -EAGAIN || err == -ETIMEDOUT)); 86 + 87 + if (err == -EAGAIN || err == -ETIMEDOUT) { 88 + NL_SET_ERR_MSG_MOD(extack, "Firmware wait timed out"); 89 + dev_err(pdsc->dev, "DEV_CMD firmware wait %s timed out\n", 90 + label); 91 + } else if (err) { 92 + NL_SET_ERR_MSG_MOD(extack, "Firmware wait failed"); 93 + } 94 + 95 + return err; 96 + } 97 + 98 + int pdsc_firmware_update(struct pdsc *pdsc, const struct firmware *fw, 99 + struct netlink_ext_ack *extack) 100 + { 101 + u32 buf_sz, copy_sz, offset; 102 + struct devlink *dl; 103 + int next_interval; 104 + u64 data_addr; 105 + int err = 0; 106 + int fw_slot; 107 + 108 + dev_info(pdsc->dev, "Installing firmware\n"); 109 + 110 + dl = priv_to_devlink(pdsc); 111 + devlink_flash_update_status_notify(dl, "Preparing to flash", 112 + NULL, 0, 0); 113 + 114 + buf_sz = sizeof(pdsc->cmd_regs->data); 115 + 116 + dev_dbg(pdsc->dev, 117 + "downloading firmware - size %d part_sz %d nparts %lu\n", 118 + (int)fw->size, buf_sz, DIV_ROUND_UP(fw->size, buf_sz)); 119 + 120 + offset = 0; 121 + next_interval = 0; 122 + data_addr = offsetof(struct pds_core_dev_cmd_regs, data); 123 + while (offset < fw->size) { 124 + if (offset >= next_interval) { 125 + devlink_flash_update_status_notify(dl, "Downloading", 126 + NULL, offset, 127 + fw->size); 128 + next_interval = offset + 129 + (fw->size / PDSC_FW_INTERVAL_FRACTION); 130 + } 131 + 132 + copy_sz = min_t(unsigned int, buf_sz, fw->size - offset); 133 + mutex_lock(&pdsc->devcmd_lock); 134 + memcpy_toio(&pdsc->cmd_regs->data, fw->data + offset, copy_sz); 135 + err = pdsc_devcmd_fw_download_locked(pdsc, data_addr, 136 + offset, copy_sz); 137 + mutex_unlock(&pdsc->devcmd_lock); 138 + if (err) { 139 + dev_err(pdsc->dev, 140 + "download failed offset 0x%x addr 0x%llx len 0x%x: %pe\n", 141 + offset, data_addr, copy_sz, ERR_PTR(err)); 142 + NL_SET_ERR_MSG_MOD(extack, "Segment download failed"); 143 + goto err_out; 144 + } 145 + offset += copy_sz; 146 + } 147 + devlink_flash_update_status_notify(dl, "Downloading", NULL, 148 + fw->size, fw->size); 149 + 150 + devlink_flash_update_timeout_notify(dl, "Installing", NULL, 151 + PDSC_FW_INSTALL_TIMEOUT); 152 + 153 + fw_slot = pdsc_devcmd_fw_install(pdsc); 154 + if (fw_slot < 0) { 155 + err = fw_slot; 156 + dev_err(pdsc->dev, "install failed: %pe\n", ERR_PTR(err)); 157 + NL_SET_ERR_MSG_MOD(extack, "Failed to start firmware install"); 158 + goto err_out; 159 + } 160 + 161 + err = pdsc_fw_status_long_wait(pdsc, "Installing", 162 + PDSC_FW_INSTALL_TIMEOUT, 163 + PDS_CORE_FW_INSTALL_STATUS, 164 + extack); 165 + if (err) 166 + goto err_out; 167 + 168 + devlink_flash_update_timeout_notify(dl, "Selecting", NULL, 169 + PDSC_FW_SELECT_TIMEOUT); 170 + 171 + err = pdsc_devcmd_fw_activate(pdsc, fw_slot); 172 + if (err) { 173 + NL_SET_ERR_MSG_MOD(extack, "Failed to start firmware select"); 174 + goto err_out; 175 + } 176 + 177 + err = pdsc_fw_status_long_wait(pdsc, "Selecting", 178 + PDSC_FW_SELECT_TIMEOUT, 179 + PDS_CORE_FW_ACTIVATE_STATUS, 180 + extack); 181 + if (err) 182 + goto err_out; 183 + 184 + dev_info(pdsc->dev, "Firmware update completed, slot %d\n", fw_slot); 185 + 186 + err_out: 187 + if (err) 188 + devlink_flash_update_status_notify(dl, "Flash failed", 189 + NULL, 0, 0); 190 + else 191 + devlink_flash_update_status_notify(dl, "Flash done", 192 + NULL, 0, 0); 193 + return err; 194 + }
+475
drivers/net/ethernet/amd/pds_core/main.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* Copyright(c) 2023 Advanced Micro Devices, Inc */ 3 + 4 + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 5 + 6 + #include <linux/pci.h> 7 + 8 + #include <linux/pds/pds_common.h> 9 + 10 + #include "core.h" 11 + 12 + MODULE_DESCRIPTION(PDSC_DRV_DESCRIPTION); 13 + MODULE_AUTHOR("Advanced Micro Devices, Inc"); 14 + MODULE_LICENSE("GPL"); 15 + 16 + /* Supported devices */ 17 + static const struct pci_device_id pdsc_id_table[] = { 18 + { PCI_VDEVICE(PENSANDO, PCI_DEVICE_ID_PENSANDO_CORE_PF) }, 19 + { PCI_VDEVICE(PENSANDO, PCI_DEVICE_ID_PENSANDO_VDPA_VF) }, 20 + { 0, } /* end of table */ 21 + }; 22 + MODULE_DEVICE_TABLE(pci, pdsc_id_table); 23 + 24 + static void pdsc_wdtimer_cb(struct timer_list *t) 25 + { 26 + struct pdsc *pdsc = from_timer(pdsc, t, wdtimer); 27 + 28 + dev_dbg(pdsc->dev, "%s: jiffies %ld\n", __func__, jiffies); 29 + mod_timer(&pdsc->wdtimer, 30 + round_jiffies(jiffies + pdsc->wdtimer_period)); 31 + 32 + queue_work(pdsc->wq, &pdsc->health_work); 33 + } 34 + 35 + static void pdsc_unmap_bars(struct pdsc *pdsc) 36 + { 37 + struct pdsc_dev_bar *bars = pdsc->bars; 38 + unsigned int i; 39 + 40 + for (i = 0; i < PDS_CORE_BARS_MAX; i++) { 41 + if (bars[i].vaddr) 42 + pci_iounmap(pdsc->pdev, bars[i].vaddr); 43 + } 44 + } 45 + 46 + static int pdsc_map_bars(struct pdsc *pdsc) 47 + { 48 + struct pdsc_dev_bar *bar = pdsc->bars; 49 + struct pci_dev *pdev = pdsc->pdev; 50 + struct device *dev = pdsc->dev; 51 + struct pdsc_dev_bar *bars; 52 + unsigned int i, j; 53 + int num_bars = 0; 54 + int err; 55 + u32 sig; 56 + 57 + bars = pdsc->bars; 58 + 59 + /* Since the PCI interface in the hardware is configurable, 60 + * we need to poke into all the bars to find the set we're 61 + * expecting. 62 + */ 63 + for (i = 0, j = 0; i < PDS_CORE_BARS_MAX; i++) { 64 + if (!(pci_resource_flags(pdev, i) & IORESOURCE_MEM)) 65 + continue; 66 + 67 + bars[j].len = pci_resource_len(pdev, i); 68 + bars[j].bus_addr = pci_resource_start(pdev, i); 69 + bars[j].res_index = i; 70 + 71 + /* only map the whole bar 0 */ 72 + if (j > 0) { 73 + bars[j].vaddr = NULL; 74 + } else { 75 + bars[j].vaddr = pci_iomap(pdev, i, bars[j].len); 76 + if (!bars[j].vaddr) { 77 + dev_err(dev, "Cannot map BAR %d, aborting\n", i); 78 + return -ENODEV; 79 + } 80 + } 81 + 82 + j++; 83 + } 84 + num_bars = j; 85 + 86 + /* BAR0: dev_cmd and interrupts */ 87 + if (num_bars < 1) { 88 + dev_err(dev, "No bars found\n"); 89 + err = -EFAULT; 90 + goto err_out; 91 + } 92 + 93 + if (bar->len < PDS_CORE_BAR0_SIZE) { 94 + dev_err(dev, "Resource bar size %lu too small\n", bar->len); 95 + err = -EFAULT; 96 + goto err_out; 97 + } 98 + 99 + pdsc->info_regs = bar->vaddr + PDS_CORE_BAR0_DEV_INFO_REGS_OFFSET; 100 + pdsc->cmd_regs = bar->vaddr + PDS_CORE_BAR0_DEV_CMD_REGS_OFFSET; 101 + pdsc->intr_status = bar->vaddr + PDS_CORE_BAR0_INTR_STATUS_OFFSET; 102 + pdsc->intr_ctrl = bar->vaddr + PDS_CORE_BAR0_INTR_CTRL_OFFSET; 103 + 104 + sig = ioread32(&pdsc->info_regs->signature); 105 + if (sig != PDS_CORE_DEV_INFO_SIGNATURE) { 106 + dev_err(dev, "Incompatible firmware signature %x", sig); 107 + err = -EFAULT; 108 + goto err_out; 109 + } 110 + 111 + /* BAR1: doorbells */ 112 + bar++; 113 + if (num_bars < 2) { 114 + dev_err(dev, "Doorbell bar missing\n"); 115 + err = -EFAULT; 116 + goto err_out; 117 + } 118 + 119 + pdsc->db_pages = bar->vaddr; 120 + pdsc->phy_db_pages = bar->bus_addr; 121 + 122 + return 0; 123 + 124 + err_out: 125 + pdsc_unmap_bars(pdsc); 126 + return err; 127 + } 128 + 129 + void __iomem *pdsc_map_dbpage(struct pdsc *pdsc, int page_num) 130 + { 131 + return pci_iomap_range(pdsc->pdev, 132 + pdsc->bars[PDS_CORE_PCI_BAR_DBELL].res_index, 133 + (u64)page_num << PAGE_SHIFT, PAGE_SIZE); 134 + } 135 + 136 + static int pdsc_sriov_configure(struct pci_dev *pdev, int num_vfs) 137 + { 138 + struct pdsc *pdsc = pci_get_drvdata(pdev); 139 + struct device *dev = pdsc->dev; 140 + int ret = 0; 141 + 142 + if (num_vfs > 0) { 143 + pdsc->vfs = kcalloc(num_vfs, sizeof(struct pdsc_vf), 144 + GFP_KERNEL); 145 + if (!pdsc->vfs) 146 + return -ENOMEM; 147 + pdsc->num_vfs = num_vfs; 148 + 149 + ret = pci_enable_sriov(pdev, num_vfs); 150 + if (ret) { 151 + dev_err(dev, "Cannot enable SRIOV: %pe\n", 152 + ERR_PTR(ret)); 153 + goto no_vfs; 154 + } 155 + 156 + return num_vfs; 157 + } 158 + 159 + no_vfs: 160 + pci_disable_sriov(pdev); 161 + 162 + kfree(pdsc->vfs); 163 + pdsc->vfs = NULL; 164 + pdsc->num_vfs = 0; 165 + 166 + return ret; 167 + } 168 + 169 + static int pdsc_init_vf(struct pdsc *vf) 170 + { 171 + struct devlink *dl; 172 + struct pdsc *pf; 173 + int err; 174 + 175 + pf = pdsc_get_pf_struct(vf->pdev); 176 + if (IS_ERR_OR_NULL(pf)) 177 + return PTR_ERR(pf) ?: -1; 178 + 179 + vf->vf_id = pci_iov_vf_id(vf->pdev); 180 + 181 + dl = priv_to_devlink(vf); 182 + devl_lock(dl); 183 + devl_register(dl); 184 + devl_unlock(dl); 185 + 186 + pf->vfs[vf->vf_id].vf = vf; 187 + err = pdsc_auxbus_dev_add(vf, pf); 188 + if (err) { 189 + devl_lock(dl); 190 + devl_unregister(dl); 191 + devl_unlock(dl); 192 + } 193 + 194 + return err; 195 + } 196 + 197 + static const struct devlink_health_reporter_ops pdsc_fw_reporter_ops = { 198 + .name = "fw", 199 + .diagnose = pdsc_fw_reporter_diagnose, 200 + }; 201 + 202 + static const struct devlink_param pdsc_dl_params[] = { 203 + DEVLINK_PARAM_GENERIC(ENABLE_VNET, 204 + BIT(DEVLINK_PARAM_CMODE_RUNTIME), 205 + pdsc_dl_enable_get, 206 + pdsc_dl_enable_set, 207 + pdsc_dl_enable_validate), 208 + }; 209 + 210 + #define PDSC_WQ_NAME_LEN 24 211 + 212 + static int pdsc_init_pf(struct pdsc *pdsc) 213 + { 214 + struct devlink_health_reporter *hr; 215 + char wq_name[PDSC_WQ_NAME_LEN]; 216 + struct devlink *dl; 217 + int err; 218 + 219 + pcie_print_link_status(pdsc->pdev); 220 + 221 + err = pci_request_regions(pdsc->pdev, PDS_CORE_DRV_NAME); 222 + if (err) { 223 + dev_err(pdsc->dev, "Cannot request PCI regions: %pe\n", 224 + ERR_PTR(err)); 225 + return err; 226 + } 227 + 228 + err = pdsc_map_bars(pdsc); 229 + if (err) 230 + goto err_out_release_regions; 231 + 232 + /* General workqueue and timer, but don't start timer yet */ 233 + snprintf(wq_name, sizeof(wq_name), "%s.%d", PDS_CORE_DRV_NAME, pdsc->uid); 234 + pdsc->wq = create_singlethread_workqueue(wq_name); 235 + INIT_WORK(&pdsc->health_work, pdsc_health_thread); 236 + timer_setup(&pdsc->wdtimer, pdsc_wdtimer_cb, 0); 237 + pdsc->wdtimer_period = PDSC_WATCHDOG_SECS * HZ; 238 + 239 + mutex_init(&pdsc->devcmd_lock); 240 + mutex_init(&pdsc->config_lock); 241 + spin_lock_init(&pdsc->adminq_lock); 242 + 243 + mutex_lock(&pdsc->config_lock); 244 + set_bit(PDSC_S_FW_DEAD, &pdsc->state); 245 + 246 + err = pdsc_setup(pdsc, PDSC_SETUP_INIT); 247 + if (err) 248 + goto err_out_unmap_bars; 249 + err = pdsc_start(pdsc); 250 + if (err) 251 + goto err_out_teardown; 252 + 253 + mutex_unlock(&pdsc->config_lock); 254 + 255 + dl = priv_to_devlink(pdsc); 256 + devl_lock(dl); 257 + err = devl_params_register(dl, pdsc_dl_params, 258 + ARRAY_SIZE(pdsc_dl_params)); 259 + if (err) { 260 + dev_warn(pdsc->dev, "Failed to register devlink params: %pe\n", 261 + ERR_PTR(err)); 262 + goto err_out_unlock_dl; 263 + } 264 + 265 + hr = devl_health_reporter_create(dl, &pdsc_fw_reporter_ops, 0, pdsc); 266 + if (IS_ERR(hr)) { 267 + dev_warn(pdsc->dev, "Failed to create fw reporter: %pe\n", hr); 268 + err = PTR_ERR(hr); 269 + goto err_out_unreg_params; 270 + } 271 + pdsc->fw_reporter = hr; 272 + 273 + devl_register(dl); 274 + devl_unlock(dl); 275 + 276 + /* Lastly, start the health check timer */ 277 + mod_timer(&pdsc->wdtimer, round_jiffies(jiffies + pdsc->wdtimer_period)); 278 + 279 + return 0; 280 + 281 + err_out_unreg_params: 282 + devl_params_unregister(dl, pdsc_dl_params, 283 + ARRAY_SIZE(pdsc_dl_params)); 284 + err_out_unlock_dl: 285 + devl_unlock(dl); 286 + pdsc_stop(pdsc); 287 + err_out_teardown: 288 + pdsc_teardown(pdsc, PDSC_TEARDOWN_REMOVING); 289 + err_out_unmap_bars: 290 + mutex_unlock(&pdsc->config_lock); 291 + del_timer_sync(&pdsc->wdtimer); 292 + if (pdsc->wq) 293 + destroy_workqueue(pdsc->wq); 294 + mutex_destroy(&pdsc->config_lock); 295 + mutex_destroy(&pdsc->devcmd_lock); 296 + pci_free_irq_vectors(pdsc->pdev); 297 + pdsc_unmap_bars(pdsc); 298 + err_out_release_regions: 299 + pci_release_regions(pdsc->pdev); 300 + 301 + return err; 302 + } 303 + 304 + static const struct devlink_ops pdsc_dl_ops = { 305 + .info_get = pdsc_dl_info_get, 306 + .flash_update = pdsc_dl_flash_update, 307 + }; 308 + 309 + static const struct devlink_ops pdsc_dl_vf_ops = { 310 + }; 311 + 312 + static DEFINE_IDA(pdsc_ida); 313 + 314 + static int pdsc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 315 + { 316 + struct device *dev = &pdev->dev; 317 + const struct devlink_ops *ops; 318 + struct devlink *dl; 319 + struct pdsc *pdsc; 320 + bool is_pf; 321 + int err; 322 + 323 + is_pf = !pdev->is_virtfn; 324 + ops = is_pf ? &pdsc_dl_ops : &pdsc_dl_vf_ops; 325 + dl = devlink_alloc(ops, sizeof(struct pdsc), dev); 326 + if (!dl) 327 + return -ENOMEM; 328 + pdsc = devlink_priv(dl); 329 + 330 + pdsc->pdev = pdev; 331 + pdsc->dev = &pdev->dev; 332 + set_bit(PDSC_S_INITING_DRIVER, &pdsc->state); 333 + pci_set_drvdata(pdev, pdsc); 334 + pdsc_debugfs_add_dev(pdsc); 335 + 336 + err = ida_alloc(&pdsc_ida, GFP_KERNEL); 337 + if (err < 0) { 338 + dev_err(pdsc->dev, "%s: id alloc failed: %pe\n", 339 + __func__, ERR_PTR(err)); 340 + goto err_out_free_devlink; 341 + } 342 + pdsc->uid = err; 343 + 344 + /* Query system for DMA addressing limitation for the device. */ 345 + err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(PDS_CORE_ADDR_LEN)); 346 + if (err) { 347 + dev_err(dev, "Unable to obtain 64-bit DMA for consistent allocations, aborting: %pe\n", 348 + ERR_PTR(err)); 349 + goto err_out_free_ida; 350 + } 351 + 352 + err = pci_enable_device(pdev); 353 + if (err) { 354 + dev_err(dev, "Cannot enable PCI device: %pe\n", ERR_PTR(err)); 355 + goto err_out_free_ida; 356 + } 357 + pci_set_master(pdev); 358 + 359 + if (is_pf) 360 + err = pdsc_init_pf(pdsc); 361 + else 362 + err = pdsc_init_vf(pdsc); 363 + if (err) { 364 + dev_err(dev, "Cannot init device: %pe\n", ERR_PTR(err)); 365 + goto err_out_clear_master; 366 + } 367 + 368 + clear_bit(PDSC_S_INITING_DRIVER, &pdsc->state); 369 + return 0; 370 + 371 + err_out_clear_master: 372 + pci_clear_master(pdev); 373 + pci_disable_device(pdev); 374 + err_out_free_ida: 375 + ida_free(&pdsc_ida, pdsc->uid); 376 + err_out_free_devlink: 377 + pdsc_debugfs_del_dev(pdsc); 378 + devlink_free(dl); 379 + 380 + return err; 381 + } 382 + 383 + static void pdsc_remove(struct pci_dev *pdev) 384 + { 385 + struct pdsc *pdsc = pci_get_drvdata(pdev); 386 + struct devlink *dl; 387 + 388 + /* Unhook the registrations first to be sure there 389 + * are no requests while we're stopping. 390 + */ 391 + dl = priv_to_devlink(pdsc); 392 + devl_lock(dl); 393 + devl_unregister(dl); 394 + if (!pdev->is_virtfn) { 395 + if (pdsc->fw_reporter) { 396 + devl_health_reporter_destroy(pdsc->fw_reporter); 397 + pdsc->fw_reporter = NULL; 398 + } 399 + devl_params_unregister(dl, pdsc_dl_params, 400 + ARRAY_SIZE(pdsc_dl_params)); 401 + } 402 + devl_unlock(dl); 403 + 404 + if (pdev->is_virtfn) { 405 + struct pdsc *pf; 406 + 407 + pf = pdsc_get_pf_struct(pdsc->pdev); 408 + if (!IS_ERR(pf)) { 409 + pdsc_auxbus_dev_del(pdsc, pf); 410 + pf->vfs[pdsc->vf_id].vf = NULL; 411 + } 412 + } else { 413 + /* Remove the VFs and their aux_bus connections before other 414 + * cleanup so that the clients can use the AdminQ to cleanly 415 + * shut themselves down. 416 + */ 417 + pdsc_sriov_configure(pdev, 0); 418 + 419 + del_timer_sync(&pdsc->wdtimer); 420 + if (pdsc->wq) 421 + destroy_workqueue(pdsc->wq); 422 + 423 + mutex_lock(&pdsc->config_lock); 424 + set_bit(PDSC_S_STOPPING_DRIVER, &pdsc->state); 425 + 426 + pdsc_stop(pdsc); 427 + pdsc_teardown(pdsc, PDSC_TEARDOWN_REMOVING); 428 + mutex_unlock(&pdsc->config_lock); 429 + mutex_destroy(&pdsc->config_lock); 430 + mutex_destroy(&pdsc->devcmd_lock); 431 + 432 + pci_free_irq_vectors(pdev); 433 + pdsc_unmap_bars(pdsc); 434 + pci_release_regions(pdev); 435 + } 436 + 437 + pci_clear_master(pdev); 438 + pci_disable_device(pdev); 439 + 440 + ida_free(&pdsc_ida, pdsc->uid); 441 + pdsc_debugfs_del_dev(pdsc); 442 + devlink_free(dl); 443 + } 444 + 445 + static struct pci_driver pdsc_driver = { 446 + .name = PDS_CORE_DRV_NAME, 447 + .id_table = pdsc_id_table, 448 + .probe = pdsc_probe, 449 + .remove = pdsc_remove, 450 + .sriov_configure = pdsc_sriov_configure, 451 + }; 452 + 453 + void *pdsc_get_pf_struct(struct pci_dev *vf_pdev) 454 + { 455 + return pci_iov_get_pf_drvdata(vf_pdev, &pdsc_driver); 456 + } 457 + EXPORT_SYMBOL_GPL(pdsc_get_pf_struct); 458 + 459 + static int __init pdsc_init_module(void) 460 + { 461 + if (strcmp(KBUILD_MODNAME, PDS_CORE_DRV_NAME)) 462 + return -EINVAL; 463 + 464 + pdsc_debugfs_create(); 465 + return pci_register_driver(&pdsc_driver); 466 + } 467 + 468 + static void __exit pdsc_cleanup_module(void) 469 + { 470 + pci_unregister_driver(&pdsc_driver); 471 + pdsc_debugfs_destroy(); 472 + } 473 + 474 + module_init(pdsc_init_module); 475 + module_exit(pdsc_cleanup_module);
+647
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 + #define PDSC_ADMINQ_MAX_POLL_INTERVAL 256 8 + 9 + enum pds_core_adminq_flags { 10 + PDS_AQ_FLAG_FASTPOLL = BIT(1), /* completion poll at 1ms */ 11 + }; 12 + 13 + /* 14 + * enum pds_core_adminq_opcode - AdminQ command opcodes 15 + * These commands are only processed on AdminQ, not available in devcmd 16 + */ 17 + enum pds_core_adminq_opcode { 18 + PDS_AQ_CMD_NOP = 0, 19 + 20 + /* Client control */ 21 + PDS_AQ_CMD_CLIENT_REG = 6, 22 + PDS_AQ_CMD_CLIENT_UNREG = 7, 23 + PDS_AQ_CMD_CLIENT_CMD = 8, 24 + 25 + /* LIF commands */ 26 + PDS_AQ_CMD_LIF_IDENTIFY = 20, 27 + PDS_AQ_CMD_LIF_INIT = 21, 28 + PDS_AQ_CMD_LIF_RESET = 22, 29 + PDS_AQ_CMD_LIF_GETATTR = 23, 30 + PDS_AQ_CMD_LIF_SETATTR = 24, 31 + PDS_AQ_CMD_LIF_SETPHC = 25, 32 + 33 + PDS_AQ_CMD_RX_MODE_SET = 30, 34 + PDS_AQ_CMD_RX_FILTER_ADD = 31, 35 + PDS_AQ_CMD_RX_FILTER_DEL = 32, 36 + 37 + /* Queue commands */ 38 + PDS_AQ_CMD_Q_IDENTIFY = 39, 39 + PDS_AQ_CMD_Q_INIT = 40, 40 + PDS_AQ_CMD_Q_CONTROL = 41, 41 + 42 + /* SR/IOV commands */ 43 + PDS_AQ_CMD_VF_GETATTR = 60, 44 + PDS_AQ_CMD_VF_SETATTR = 61, 45 + }; 46 + 47 + /* 48 + * enum pds_core_notifyq_opcode - NotifyQ event codes 49 + */ 50 + enum pds_core_notifyq_opcode { 51 + PDS_EVENT_LINK_CHANGE = 1, 52 + PDS_EVENT_RESET = 2, 53 + PDS_EVENT_XCVR = 5, 54 + PDS_EVENT_CLIENT = 6, 55 + }; 56 + 57 + #define PDS_COMP_COLOR_MASK 0x80 58 + 59 + /** 60 + * struct pds_core_notifyq_event - Generic event reporting structure 61 + * @eid: event number 62 + * @ecode: event code 63 + * 64 + * This is the generic event report struct from which the other 65 + * actual events will be formed. 66 + */ 67 + struct pds_core_notifyq_event { 68 + __le64 eid; 69 + __le16 ecode; 70 + }; 71 + 72 + /** 73 + * struct pds_core_link_change_event - Link change event notification 74 + * @eid: event number 75 + * @ecode: event code = PDS_EVENT_LINK_CHANGE 76 + * @link_status: link up/down, with error bits 77 + * @link_speed: speed of the network link 78 + * 79 + * Sent when the network link state changes between UP and DOWN 80 + */ 81 + struct pds_core_link_change_event { 82 + __le64 eid; 83 + __le16 ecode; 84 + __le16 link_status; 85 + __le32 link_speed; /* units of 1Mbps: e.g. 10000 = 10Gbps */ 86 + }; 87 + 88 + /** 89 + * struct pds_core_reset_event - Reset event notification 90 + * @eid: event number 91 + * @ecode: event code = PDS_EVENT_RESET 92 + * @reset_code: reset type 93 + * @state: 0=pending, 1=complete, 2=error 94 + * 95 + * Sent when the NIC or some subsystem is going to be or 96 + * has been reset. 97 + */ 98 + struct pds_core_reset_event { 99 + __le64 eid; 100 + __le16 ecode; 101 + u8 reset_code; 102 + u8 state; 103 + }; 104 + 105 + /** 106 + * struct pds_core_client_event - Client event notification 107 + * @eid: event number 108 + * @ecode: event code = PDS_EVENT_CLIENT 109 + * @client_id: client to sent event to 110 + * @client_event: wrapped event struct for the client 111 + * 112 + * Sent when an event needs to be passed on to a client 113 + */ 114 + struct pds_core_client_event { 115 + __le64 eid; 116 + __le16 ecode; 117 + __le16 client_id; 118 + u8 client_event[54]; 119 + }; 120 + 121 + /** 122 + * struct pds_core_notifyq_cmd - Placeholder for building qcq 123 + * @data: anonymous field for building the qcq 124 + */ 125 + struct pds_core_notifyq_cmd { 126 + __le32 data; /* Not used but needed for qcq structure */ 127 + }; 128 + 129 + /* 130 + * union pds_core_notifyq_comp - Overlay of notifyq event structures 131 + */ 132 + union pds_core_notifyq_comp { 133 + struct { 134 + __le64 eid; 135 + __le16 ecode; 136 + }; 137 + struct pds_core_notifyq_event event; 138 + struct pds_core_link_change_event link_change; 139 + struct pds_core_reset_event reset; 140 + u8 data[64]; 141 + }; 142 + 143 + #define PDS_DEVNAME_LEN 32 144 + /** 145 + * struct pds_core_client_reg_cmd - Register a new client with DSC 146 + * @opcode: opcode PDS_AQ_CMD_CLIENT_REG 147 + * @rsvd: word boundary padding 148 + * @devname: text name of client device 149 + * @vif_type: what type of device (enum pds_core_vif_types) 150 + * 151 + * Tell the DSC of the new client, and receive a client_id from DSC. 152 + */ 153 + struct pds_core_client_reg_cmd { 154 + u8 opcode; 155 + u8 rsvd[3]; 156 + char devname[PDS_DEVNAME_LEN]; 157 + u8 vif_type; 158 + }; 159 + 160 + /** 161 + * struct pds_core_client_reg_comp - Client registration completion 162 + * @status: Status of the command (enum pdc_core_status_code) 163 + * @rsvd: Word boundary padding 164 + * @comp_index: Index in the descriptor ring for which this is the completion 165 + * @client_id: New id assigned by DSC 166 + * @rsvd1: Word boundary padding 167 + * @color: Color bit 168 + */ 169 + struct pds_core_client_reg_comp { 170 + u8 status; 171 + u8 rsvd; 172 + __le16 comp_index; 173 + __le16 client_id; 174 + u8 rsvd1[9]; 175 + u8 color; 176 + }; 177 + 178 + /** 179 + * struct pds_core_client_unreg_cmd - Unregister a client from DSC 180 + * @opcode: opcode PDS_AQ_CMD_CLIENT_UNREG 181 + * @rsvd: word boundary padding 182 + * @client_id: id of client being removed 183 + * 184 + * Tell the DSC this client is going away and remove its context 185 + * This uses the generic completion. 186 + */ 187 + struct pds_core_client_unreg_cmd { 188 + u8 opcode; 189 + u8 rsvd; 190 + __le16 client_id; 191 + }; 192 + 193 + /** 194 + * struct pds_core_client_request_cmd - Pass along a wrapped client AdminQ cmd 195 + * @opcode: opcode PDS_AQ_CMD_CLIENT_CMD 196 + * @rsvd: word boundary padding 197 + * @client_id: id of client being removed 198 + * @client_cmd: the wrapped client command 199 + * 200 + * Proxy post an adminq command for the client. 201 + * This uses the generic completion. 202 + */ 203 + struct pds_core_client_request_cmd { 204 + u8 opcode; 205 + u8 rsvd; 206 + __le16 client_id; 207 + u8 client_cmd[60]; 208 + }; 209 + 210 + #define PDS_CORE_MAX_FRAGS 16 211 + 212 + #define PDS_CORE_QCQ_F_INITED BIT(0) 213 + #define PDS_CORE_QCQ_F_SG BIT(1) 214 + #define PDS_CORE_QCQ_F_INTR BIT(2) 215 + #define PDS_CORE_QCQ_F_TX_STATS BIT(3) 216 + #define PDS_CORE_QCQ_F_RX_STATS BIT(4) 217 + #define PDS_CORE_QCQ_F_NOTIFYQ BIT(5) 218 + #define PDS_CORE_QCQ_F_CMB_RINGS BIT(6) 219 + #define PDS_CORE_QCQ_F_CORE BIT(7) 220 + 221 + enum pds_core_lif_type { 222 + PDS_CORE_LIF_TYPE_DEFAULT = 0, 223 + }; 224 + 225 + /** 226 + * union pds_core_lif_config - LIF configuration 227 + * @state: LIF state (enum pds_core_lif_state) 228 + * @rsvd: Word boundary padding 229 + * @name: LIF name 230 + * @rsvd2: Word boundary padding 231 + * @features: LIF features active (enum pds_core_hw_features) 232 + * @queue_count: Queue counts per queue-type 233 + * @words: Full union buffer size 234 + */ 235 + union pds_core_lif_config { 236 + struct { 237 + u8 state; 238 + u8 rsvd[3]; 239 + char name[PDS_CORE_IFNAMSIZ]; 240 + u8 rsvd2[12]; 241 + __le64 features; 242 + __le32 queue_count[PDS_CORE_QTYPE_MAX]; 243 + } __packed; 244 + __le32 words[64]; 245 + }; 246 + 247 + /** 248 + * struct pds_core_lif_status - LIF status register 249 + * @eid: most recent NotifyQ event id 250 + * @rsvd: full struct size 251 + */ 252 + struct pds_core_lif_status { 253 + __le64 eid; 254 + u8 rsvd[56]; 255 + }; 256 + 257 + /** 258 + * struct pds_core_lif_info - LIF info structure 259 + * @config: LIF configuration structure 260 + * @status: LIF status structure 261 + */ 262 + struct pds_core_lif_info { 263 + union pds_core_lif_config config; 264 + struct pds_core_lif_status status; 265 + }; 266 + 267 + /** 268 + * struct pds_core_lif_identity - LIF identity information (type-specific) 269 + * @features: LIF features (see enum pds_core_hw_features) 270 + * @version: Identify structure version 271 + * @hw_index: LIF hardware index 272 + * @rsvd: Word boundary padding 273 + * @max_nb_sessions: Maximum number of sessions supported 274 + * @rsvd2: buffer padding 275 + * @config: LIF config struct with features, q counts 276 + */ 277 + struct pds_core_lif_identity { 278 + __le64 features; 279 + u8 version; 280 + u8 hw_index; 281 + u8 rsvd[2]; 282 + __le32 max_nb_sessions; 283 + u8 rsvd2[120]; 284 + union pds_core_lif_config config; 285 + }; 286 + 287 + /** 288 + * struct pds_core_lif_identify_cmd - Get LIF identity info command 289 + * @opcode: Opcode PDS_AQ_CMD_LIF_IDENTIFY 290 + * @type: LIF type (enum pds_core_lif_type) 291 + * @client_id: Client identifier 292 + * @ver: Version of identify returned by device 293 + * @rsvd: Word boundary padding 294 + * @ident_pa: DMA address to receive identity info 295 + * 296 + * Firmware will copy LIF identity data (struct pds_core_lif_identity) 297 + * into the buffer address given. 298 + */ 299 + struct pds_core_lif_identify_cmd { 300 + u8 opcode; 301 + u8 type; 302 + __le16 client_id; 303 + u8 ver; 304 + u8 rsvd[3]; 305 + __le64 ident_pa; 306 + }; 307 + 308 + /** 309 + * struct pds_core_lif_identify_comp - LIF identify command completion 310 + * @status: Status of the command (enum pds_core_status_code) 311 + * @ver: Version of identify returned by device 312 + * @bytes: Bytes copied into the buffer 313 + * @rsvd: Word boundary padding 314 + * @color: Color bit 315 + */ 316 + struct pds_core_lif_identify_comp { 317 + u8 status; 318 + u8 ver; 319 + __le16 bytes; 320 + u8 rsvd[11]; 321 + u8 color; 322 + }; 323 + 324 + /** 325 + * struct pds_core_lif_init_cmd - LIF init command 326 + * @opcode: Opcode PDS_AQ_CMD_LIF_INIT 327 + * @type: LIF type (enum pds_core_lif_type) 328 + * @client_id: Client identifier 329 + * @rsvd: Word boundary padding 330 + * @info_pa: Destination address for LIF info (struct pds_core_lif_info) 331 + */ 332 + struct pds_core_lif_init_cmd { 333 + u8 opcode; 334 + u8 type; 335 + __le16 client_id; 336 + __le32 rsvd; 337 + __le64 info_pa; 338 + }; 339 + 340 + /** 341 + * struct pds_core_lif_init_comp - LIF init command completion 342 + * @status: Status of the command (enum pds_core_status_code) 343 + * @rsvd: Word boundary padding 344 + * @hw_index: Hardware index of the initialized LIF 345 + * @rsvd1: Word boundary padding 346 + * @color: Color bit 347 + */ 348 + struct pds_core_lif_init_comp { 349 + u8 status; 350 + u8 rsvd; 351 + __le16 hw_index; 352 + u8 rsvd1[11]; 353 + u8 color; 354 + }; 355 + 356 + /** 357 + * struct pds_core_lif_reset_cmd - LIF reset command 358 + * Will reset only the specified LIF. 359 + * @opcode: Opcode PDS_AQ_CMD_LIF_RESET 360 + * @rsvd: Word boundary padding 361 + * @client_id: Client identifier 362 + */ 363 + struct pds_core_lif_reset_cmd { 364 + u8 opcode; 365 + u8 rsvd; 366 + __le16 client_id; 367 + }; 368 + 369 + /** 370 + * enum pds_core_lif_attr - List of LIF attributes 371 + * @PDS_CORE_LIF_ATTR_STATE: LIF state attribute 372 + * @PDS_CORE_LIF_ATTR_NAME: LIF name attribute 373 + * @PDS_CORE_LIF_ATTR_FEATURES: LIF features attribute 374 + * @PDS_CORE_LIF_ATTR_STATS_CTRL: LIF statistics control attribute 375 + */ 376 + enum pds_core_lif_attr { 377 + PDS_CORE_LIF_ATTR_STATE = 0, 378 + PDS_CORE_LIF_ATTR_NAME = 1, 379 + PDS_CORE_LIF_ATTR_FEATURES = 4, 380 + PDS_CORE_LIF_ATTR_STATS_CTRL = 6, 381 + }; 382 + 383 + /** 384 + * struct pds_core_lif_setattr_cmd - Set LIF attributes on the NIC 385 + * @opcode: Opcode PDS_AQ_CMD_LIF_SETATTR 386 + * @attr: Attribute type (enum pds_core_lif_attr) 387 + * @client_id: Client identifier 388 + * @state: LIF state (enum pds_core_lif_state) 389 + * @name: The name string, 0 terminated 390 + * @features: Features (enum pds_core_hw_features) 391 + * @stats_ctl: Stats control commands (enum pds_core_stats_ctl_cmd) 392 + * @rsvd: Command Buffer padding 393 + */ 394 + struct pds_core_lif_setattr_cmd { 395 + u8 opcode; 396 + u8 attr; 397 + __le16 client_id; 398 + union { 399 + u8 state; 400 + char name[PDS_CORE_IFNAMSIZ]; 401 + __le64 features; 402 + u8 stats_ctl; 403 + u8 rsvd[60]; 404 + } __packed; 405 + }; 406 + 407 + /** 408 + * struct pds_core_lif_setattr_comp - LIF set attr command completion 409 + * @status: Status of the command (enum pds_core_status_code) 410 + * @rsvd: Word boundary padding 411 + * @comp_index: Index in the descriptor ring for which this is the completion 412 + * @features: Features (enum pds_core_hw_features) 413 + * @rsvd2: Word boundary padding 414 + * @color: Color bit 415 + */ 416 + struct pds_core_lif_setattr_comp { 417 + u8 status; 418 + u8 rsvd; 419 + __le16 comp_index; 420 + union { 421 + __le64 features; 422 + u8 rsvd2[11]; 423 + } __packed; 424 + u8 color; 425 + }; 426 + 427 + /** 428 + * struct pds_core_lif_getattr_cmd - Get LIF attributes from the NIC 429 + * @opcode: Opcode PDS_AQ_CMD_LIF_GETATTR 430 + * @attr: Attribute type (enum pds_core_lif_attr) 431 + * @client_id: Client identifier 432 + */ 433 + struct pds_core_lif_getattr_cmd { 434 + u8 opcode; 435 + u8 attr; 436 + __le16 client_id; 437 + }; 438 + 439 + /** 440 + * struct pds_core_lif_getattr_comp - LIF get attr command completion 441 + * @status: Status of the command (enum pds_core_status_code) 442 + * @rsvd: Word boundary padding 443 + * @comp_index: Index in the descriptor ring for which this is the completion 444 + * @state: LIF state (enum pds_core_lif_state) 445 + * @name: LIF name string, 0 terminated 446 + * @features: Features (enum pds_core_hw_features) 447 + * @rsvd2: Word boundary padding 448 + * @color: Color bit 449 + */ 450 + struct pds_core_lif_getattr_comp { 451 + u8 status; 452 + u8 rsvd; 453 + __le16 comp_index; 454 + union { 455 + u8 state; 456 + __le64 features; 457 + u8 rsvd2[11]; 458 + } __packed; 459 + u8 color; 460 + }; 461 + 462 + /** 463 + * union pds_core_q_identity - Queue identity information 464 + * @version: Queue type version that can be used with FW 465 + * @supported: Bitfield of queue versions, first bit = ver 0 466 + * @rsvd: Word boundary padding 467 + * @features: Queue features 468 + * @desc_sz: Descriptor size 469 + * @comp_sz: Completion descriptor size 470 + * @rsvd2: Word boundary padding 471 + */ 472 + struct pds_core_q_identity { 473 + u8 version; 474 + u8 supported; 475 + u8 rsvd[6]; 476 + #define PDS_CORE_QIDENT_F_CQ 0x01 /* queue has completion ring */ 477 + __le64 features; 478 + __le16 desc_sz; 479 + __le16 comp_sz; 480 + u8 rsvd2[6]; 481 + }; 482 + 483 + /** 484 + * struct pds_core_q_identify_cmd - queue identify command 485 + * @opcode: Opcode PDS_AQ_CMD_Q_IDENTIFY 486 + * @type: Logical queue type (enum pds_core_logical_qtype) 487 + * @client_id: Client identifier 488 + * @ver: Highest queue type version that the driver supports 489 + * @rsvd: Word boundary padding 490 + * @ident_pa: DMA address to receive the data (struct pds_core_q_identity) 491 + */ 492 + struct pds_core_q_identify_cmd { 493 + u8 opcode; 494 + u8 type; 495 + __le16 client_id; 496 + u8 ver; 497 + u8 rsvd[3]; 498 + __le64 ident_pa; 499 + }; 500 + 501 + /** 502 + * struct pds_core_q_identify_comp - queue identify command completion 503 + * @status: Status of the command (enum pds_core_status_code) 504 + * @rsvd: Word boundary padding 505 + * @comp_index: Index in the descriptor ring for which this is the completion 506 + * @ver: Queue type version that can be used with FW 507 + * @rsvd1: Word boundary padding 508 + * @color: Color bit 509 + */ 510 + struct pds_core_q_identify_comp { 511 + u8 status; 512 + u8 rsvd; 513 + __le16 comp_index; 514 + u8 ver; 515 + u8 rsvd1[10]; 516 + u8 color; 517 + }; 518 + 519 + /** 520 + * struct pds_core_q_init_cmd - Queue init command 521 + * @opcode: Opcode PDS_AQ_CMD_Q_INIT 522 + * @type: Logical queue type 523 + * @client_id: Client identifier 524 + * @ver: Queue type version 525 + * @rsvd: Word boundary padding 526 + * @index: (LIF, qtype) relative admin queue index 527 + * @intr_index: Interrupt control register index, or Event queue index 528 + * @pid: Process ID 529 + * @flags: 530 + * IRQ: Interrupt requested on completion 531 + * ENA: Enable the queue. If ENA=0 the queue is initialized 532 + * but remains disabled, to be later enabled with the 533 + * Queue Enable command. If ENA=1, then queue is 534 + * initialized and then enabled. 535 + * @cos: Class of service for this queue 536 + * @ring_size: Queue ring size, encoded as a log2(size), in 537 + * number of descriptors. The actual ring size is 538 + * (1 << ring_size). For example, to select a ring size 539 + * of 64 descriptors write ring_size = 6. The minimum 540 + * ring_size value is 2 for a ring of 4 descriptors. 541 + * The maximum ring_size value is 12 for a ring of 4k 542 + * descriptors. Values of ring_size <2 and >12 are 543 + * reserved. 544 + * @ring_base: Queue ring base address 545 + * @cq_ring_base: Completion queue ring base address 546 + */ 547 + struct pds_core_q_init_cmd { 548 + u8 opcode; 549 + u8 type; 550 + __le16 client_id; 551 + u8 ver; 552 + u8 rsvd[3]; 553 + __le32 index; 554 + __le16 pid; 555 + __le16 intr_index; 556 + __le16 flags; 557 + #define PDS_CORE_QINIT_F_IRQ 0x01 /* Request interrupt on completion */ 558 + #define PDS_CORE_QINIT_F_ENA 0x02 /* Enable the queue */ 559 + u8 cos; 560 + #define PDS_CORE_QSIZE_MIN_LG2 2 561 + #define PDS_CORE_QSIZE_MAX_LG2 12 562 + u8 ring_size; 563 + __le64 ring_base; 564 + __le64 cq_ring_base; 565 + } __packed; 566 + 567 + /** 568 + * struct pds_core_q_init_comp - Queue init command completion 569 + * @status: Status of the command (enum pds_core_status_code) 570 + * @rsvd: Word boundary padding 571 + * @comp_index: Index in the descriptor ring for which this is the completion 572 + * @hw_index: Hardware Queue ID 573 + * @hw_type: Hardware Queue type 574 + * @rsvd2: Word boundary padding 575 + * @color: Color 576 + */ 577 + struct pds_core_q_init_comp { 578 + u8 status; 579 + u8 rsvd; 580 + __le16 comp_index; 581 + __le32 hw_index; 582 + u8 hw_type; 583 + u8 rsvd2[6]; 584 + u8 color; 585 + }; 586 + 587 + union pds_core_adminq_cmd { 588 + u8 opcode; 589 + u8 bytes[64]; 590 + 591 + struct pds_core_client_reg_cmd client_reg; 592 + struct pds_core_client_unreg_cmd client_unreg; 593 + struct pds_core_client_request_cmd client_request; 594 + 595 + struct pds_core_lif_identify_cmd lif_ident; 596 + struct pds_core_lif_init_cmd lif_init; 597 + struct pds_core_lif_reset_cmd lif_reset; 598 + struct pds_core_lif_setattr_cmd lif_setattr; 599 + struct pds_core_lif_getattr_cmd lif_getattr; 600 + 601 + struct pds_core_q_identify_cmd q_ident; 602 + struct pds_core_q_init_cmd q_init; 603 + }; 604 + 605 + union pds_core_adminq_comp { 606 + struct { 607 + u8 status; 608 + u8 rsvd; 609 + __le16 comp_index; 610 + u8 rsvd2[11]; 611 + u8 color; 612 + }; 613 + u32 words[4]; 614 + 615 + struct pds_core_client_reg_comp client_reg; 616 + 617 + struct pds_core_lif_identify_comp lif_ident; 618 + struct pds_core_lif_init_comp lif_init; 619 + struct pds_core_lif_setattr_comp lif_setattr; 620 + struct pds_core_lif_getattr_comp lif_getattr; 621 + 622 + struct pds_core_q_identify_comp q_ident; 623 + struct pds_core_q_init_comp q_init; 624 + }; 625 + 626 + #ifndef __CHECKER__ 627 + static_assert(sizeof(union pds_core_adminq_cmd) == 64); 628 + static_assert(sizeof(union pds_core_adminq_comp) == 16); 629 + static_assert(sizeof(union pds_core_notifyq_comp) == 64); 630 + #endif /* __CHECKER__ */ 631 + 632 + /* The color bit is a 'done' bit for the completion descriptors 633 + * where the meaning alternates between '1' and '0' for alternating 634 + * passes through the completion descriptor ring. 635 + */ 636 + static inline bool pdsc_color_match(u8 color, bool done_color) 637 + { 638 + return (!!(color & PDS_COMP_COLOR_MASK)) == done_color; 639 + } 640 + 641 + struct pdsc; 642 + int pdsc_adminq_post(struct pdsc *pdsc, 643 + union pds_core_adminq_cmd *cmd, 644 + union pds_core_adminq_comp *comp, 645 + bool fast_poll); 646 + 647 + #endif /* _PDS_CORE_ADMINQ_H_ */
+20
include/linux/pds/pds_auxbus.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* Copyright(c) 2023 Advanced Micro Devices, Inc */ 3 + 4 + #ifndef _PDSC_AUXBUS_H_ 5 + #define _PDSC_AUXBUS_H_ 6 + 7 + #include <linux/auxiliary_bus.h> 8 + 9 + struct pds_auxiliary_dev { 10 + struct auxiliary_device aux_dev; 11 + struct pci_dev *vf_pdev; 12 + u16 client_id; 13 + }; 14 + 15 + int pds_client_adminq_cmd(struct pds_auxiliary_dev *padev, 16 + union pds_core_adminq_cmd *req, 17 + size_t req_len, 18 + union pds_core_adminq_comp *resp, 19 + u64 flags); 20 + #endif /* _PDSC_AUXBUS_H_ */
+68
include/linux/pds/pds_common.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_COMMON_H_ 5 + #define _PDS_COMMON_H_ 6 + 7 + #define PDS_CORE_DRV_NAME "pds_core" 8 + 9 + /* the device's internal addressing uses up to 52 bits */ 10 + #define PDS_CORE_ADDR_LEN 52 11 + #define PDS_CORE_ADDR_MASK (BIT_ULL(PDS_ADDR_LEN) - 1) 12 + #define PDS_PAGE_SIZE 4096 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 + enum pds_core_vif_types { 24 + PDS_DEV_TYPE_CORE = 0, 25 + PDS_DEV_TYPE_VDPA = 1, 26 + PDS_DEV_TYPE_VFIO = 2, 27 + PDS_DEV_TYPE_ETH = 3, 28 + PDS_DEV_TYPE_RDMA = 4, 29 + PDS_DEV_TYPE_LM = 5, 30 + 31 + /* new ones added before this line */ 32 + PDS_DEV_TYPE_MAX = 16 /* don't change - used in struct size */ 33 + }; 34 + 35 + #define PDS_DEV_TYPE_CORE_STR "Core" 36 + #define PDS_DEV_TYPE_VDPA_STR "vDPA" 37 + #define PDS_DEV_TYPE_VFIO_STR "VFio" 38 + #define PDS_DEV_TYPE_ETH_STR "Eth" 39 + #define PDS_DEV_TYPE_RDMA_STR "RDMA" 40 + #define PDS_DEV_TYPE_LM_STR "LM" 41 + 42 + #define PDS_CORE_IFNAMSIZ 16 43 + 44 + /** 45 + * enum pds_core_logical_qtype - Logical Queue Types 46 + * @PDS_CORE_QTYPE_ADMINQ: Administrative Queue 47 + * @PDS_CORE_QTYPE_NOTIFYQ: Notify Queue 48 + * @PDS_CORE_QTYPE_RXQ: Receive Queue 49 + * @PDS_CORE_QTYPE_TXQ: Transmit Queue 50 + * @PDS_CORE_QTYPE_EQ: Event Queue 51 + * @PDS_CORE_QTYPE_MAX: Max queue type supported 52 + */ 53 + enum pds_core_logical_qtype { 54 + PDS_CORE_QTYPE_ADMINQ = 0, 55 + PDS_CORE_QTYPE_NOTIFYQ = 1, 56 + PDS_CORE_QTYPE_RXQ = 2, 57 + PDS_CORE_QTYPE_TXQ = 3, 58 + PDS_CORE_QTYPE_EQ = 4, 59 + 60 + PDS_CORE_QTYPE_MAX = 16 /* don't change - used in struct size */ 61 + }; 62 + 63 + int pdsc_register_notify(struct notifier_block *nb); 64 + void pdsc_unregister_notify(struct notifier_block *nb); 65 + void *pdsc_get_pf_struct(struct pci_dev *vf_pdev); 66 + int pds_client_register(struct pci_dev *pf_pdev, char *devname); 67 + int pds_client_unregister(struct pci_dev *pf_pdev, u16 client_id); 68 + #endif /* _PDS_COMMON_H_ */
+571
include/linux/pds/pds_core_if.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_CORE_IF_H_ 5 + #define _PDS_CORE_IF_H_ 6 + 7 + #define PCI_VENDOR_ID_PENSANDO 0x1dd8 8 + #define PCI_DEVICE_ID_PENSANDO_CORE_PF 0x100c 9 + #define PCI_DEVICE_ID_VIRTIO_NET_TRANS 0x1000 10 + #define PCI_DEVICE_ID_PENSANDO_IONIC_ETH_VF 0x1003 11 + #define PCI_DEVICE_ID_PENSANDO_VDPA_VF 0x100b 12 + #define PDS_CORE_BARS_MAX 4 13 + #define PDS_CORE_PCI_BAR_DBELL 1 14 + 15 + /* Bar0 */ 16 + #define PDS_CORE_DEV_INFO_SIGNATURE 0x44455649 /* 'DEVI' */ 17 + #define PDS_CORE_BAR0_SIZE 0x8000 18 + #define PDS_CORE_BAR0_DEV_INFO_REGS_OFFSET 0x0000 19 + #define PDS_CORE_BAR0_DEV_CMD_REGS_OFFSET 0x0800 20 + #define PDS_CORE_BAR0_DEV_CMD_DATA_REGS_OFFSET 0x0c00 21 + #define PDS_CORE_BAR0_INTR_STATUS_OFFSET 0x1000 22 + #define PDS_CORE_BAR0_INTR_CTRL_OFFSET 0x2000 23 + #define PDS_CORE_DEV_CMD_DONE 0x00000001 24 + 25 + #define PDS_CORE_DEVCMD_TIMEOUT 5 26 + 27 + #define PDS_CORE_CLIENT_ID 0 28 + #define PDS_CORE_ASIC_TYPE_CAPRI 0 29 + 30 + /* 31 + * enum pds_core_cmd_opcode - Device commands 32 + */ 33 + enum pds_core_cmd_opcode { 34 + /* Core init */ 35 + PDS_CORE_CMD_NOP = 0, 36 + PDS_CORE_CMD_IDENTIFY = 1, 37 + PDS_CORE_CMD_RESET = 2, 38 + PDS_CORE_CMD_INIT = 3, 39 + 40 + PDS_CORE_CMD_FW_DOWNLOAD = 4, 41 + PDS_CORE_CMD_FW_CONTROL = 5, 42 + 43 + /* SR/IOV commands */ 44 + PDS_CORE_CMD_VF_GETATTR = 60, 45 + PDS_CORE_CMD_VF_SETATTR = 61, 46 + PDS_CORE_CMD_VF_CTRL = 62, 47 + 48 + /* Add commands before this line */ 49 + PDS_CORE_CMD_MAX, 50 + PDS_CORE_CMD_COUNT 51 + }; 52 + 53 + /* 54 + * enum pds_core_status_code - Device command return codes 55 + */ 56 + enum pds_core_status_code { 57 + PDS_RC_SUCCESS = 0, /* Success */ 58 + PDS_RC_EVERSION = 1, /* Incorrect version for request */ 59 + PDS_RC_EOPCODE = 2, /* Invalid cmd opcode */ 60 + PDS_RC_EIO = 3, /* I/O error */ 61 + PDS_RC_EPERM = 4, /* Permission denied */ 62 + PDS_RC_EQID = 5, /* Bad qid */ 63 + PDS_RC_EQTYPE = 6, /* Bad qtype */ 64 + PDS_RC_ENOENT = 7, /* No such element */ 65 + PDS_RC_EINTR = 8, /* operation interrupted */ 66 + PDS_RC_EAGAIN = 9, /* Try again */ 67 + PDS_RC_ENOMEM = 10, /* Out of memory */ 68 + PDS_RC_EFAULT = 11, /* Bad address */ 69 + PDS_RC_EBUSY = 12, /* Device or resource busy */ 70 + PDS_RC_EEXIST = 13, /* object already exists */ 71 + PDS_RC_EINVAL = 14, /* Invalid argument */ 72 + PDS_RC_ENOSPC = 15, /* No space left or alloc failure */ 73 + PDS_RC_ERANGE = 16, /* Parameter out of range */ 74 + PDS_RC_BAD_ADDR = 17, /* Descriptor contains a bad ptr */ 75 + PDS_RC_DEV_CMD = 18, /* Device cmd attempted on AdminQ */ 76 + PDS_RC_ENOSUPP = 19, /* Operation not supported */ 77 + PDS_RC_ERROR = 29, /* Generic error */ 78 + PDS_RC_ERDMA = 30, /* Generic RDMA error */ 79 + PDS_RC_EVFID = 31, /* VF ID does not exist */ 80 + PDS_RC_BAD_FW = 32, /* FW file is invalid or corrupted */ 81 + PDS_RC_ECLIENT = 33, /* No such client id */ 82 + }; 83 + 84 + /** 85 + * struct pds_core_drv_identity - Driver identity information 86 + * @drv_type: Driver type (enum pds_core_driver_type) 87 + * @os_dist: OS distribution, numeric format 88 + * @os_dist_str: OS distribution, string format 89 + * @kernel_ver: Kernel version, numeric format 90 + * @kernel_ver_str: Kernel version, string format 91 + * @driver_ver_str: Driver version, string format 92 + */ 93 + struct pds_core_drv_identity { 94 + __le32 drv_type; 95 + __le32 os_dist; 96 + char os_dist_str[128]; 97 + __le32 kernel_ver; 98 + char kernel_ver_str[32]; 99 + char driver_ver_str[32]; 100 + }; 101 + 102 + #define PDS_DEV_TYPE_MAX 16 103 + /** 104 + * struct pds_core_dev_identity - Device identity information 105 + * @version: Version of device identify 106 + * @type: Identify type (0 for now) 107 + * @state: Device state 108 + * @rsvd: Word boundary padding 109 + * @nlifs: Number of LIFs provisioned 110 + * @nintrs: Number of interrupts provisioned 111 + * @ndbpgs_per_lif: Number of doorbell pages per LIF 112 + * @intr_coal_mult: Interrupt coalescing multiplication factor 113 + * Scale user-supplied interrupt coalescing 114 + * value in usecs to device units using: 115 + * device units = usecs * mult / div 116 + * @intr_coal_div: Interrupt coalescing division factor 117 + * Scale user-supplied interrupt coalescing 118 + * value in usecs to device units using: 119 + * device units = usecs * mult / div 120 + * @vif_types: How many of each VIF device type is supported 121 + */ 122 + struct pds_core_dev_identity { 123 + u8 version; 124 + u8 type; 125 + u8 state; 126 + u8 rsvd; 127 + __le32 nlifs; 128 + __le32 nintrs; 129 + __le32 ndbpgs_per_lif; 130 + __le32 intr_coal_mult; 131 + __le32 intr_coal_div; 132 + __le16 vif_types[PDS_DEV_TYPE_MAX]; 133 + }; 134 + 135 + #define PDS_CORE_IDENTITY_VERSION_1 1 136 + 137 + /** 138 + * struct pds_core_dev_identify_cmd - Driver/device identify command 139 + * @opcode: Opcode PDS_CORE_CMD_IDENTIFY 140 + * @ver: Highest version of identify supported by driver 141 + * 142 + * Expects to find driver identification info (struct pds_core_drv_identity) 143 + * in cmd_regs->data. Driver should keep the devcmd interface locked 144 + * while preparing the driver info. 145 + */ 146 + struct pds_core_dev_identify_cmd { 147 + u8 opcode; 148 + u8 ver; 149 + }; 150 + 151 + /** 152 + * struct pds_core_dev_identify_comp - Device identify command completion 153 + * @status: Status of the command (enum pds_core_status_code) 154 + * @ver: Version of identify returned by device 155 + * 156 + * Device identification info (struct pds_core_dev_identity) can be found 157 + * in cmd_regs->data. Driver should keep the devcmd interface locked 158 + * while reading the results. 159 + */ 160 + struct pds_core_dev_identify_comp { 161 + u8 status; 162 + u8 ver; 163 + }; 164 + 165 + /** 166 + * struct pds_core_dev_reset_cmd - Device reset command 167 + * @opcode: Opcode PDS_CORE_CMD_RESET 168 + * 169 + * Resets and clears all LIFs, VDevs, and VIFs on the device. 170 + */ 171 + struct pds_core_dev_reset_cmd { 172 + u8 opcode; 173 + }; 174 + 175 + /** 176 + * struct pds_core_dev_reset_comp - Reset command completion 177 + * @status: Status of the command (enum pds_core_status_code) 178 + */ 179 + struct pds_core_dev_reset_comp { 180 + u8 status; 181 + }; 182 + 183 + /* 184 + * struct pds_core_dev_init_data - Pointers and info needed for the Core 185 + * initialization PDS_CORE_CMD_INIT command. The in and out structs are 186 + * overlays on the pds_core_dev_cmd_regs.data space for passing data down 187 + * to the firmware on init, and then returning initialization results. 188 + */ 189 + struct pds_core_dev_init_data_in { 190 + __le64 adminq_q_base; 191 + __le64 adminq_cq_base; 192 + __le64 notifyq_cq_base; 193 + __le32 flags; 194 + __le16 intr_index; 195 + u8 adminq_ring_size; 196 + u8 notifyq_ring_size; 197 + }; 198 + 199 + struct pds_core_dev_init_data_out { 200 + __le32 core_hw_index; 201 + __le32 adminq_hw_index; 202 + __le32 notifyq_hw_index; 203 + u8 adminq_hw_type; 204 + u8 notifyq_hw_type; 205 + }; 206 + 207 + /** 208 + * struct pds_core_dev_init_cmd - Core device initialize 209 + * @opcode: opcode PDS_CORE_CMD_INIT 210 + * 211 + * Initializes the core device and sets up the AdminQ and NotifyQ. 212 + * Expects to find initialization data (struct pds_core_dev_init_data_in) 213 + * in cmd_regs->data. Driver should keep the devcmd interface locked 214 + * while preparing the driver info. 215 + */ 216 + struct pds_core_dev_init_cmd { 217 + u8 opcode; 218 + }; 219 + 220 + /** 221 + * struct pds_core_dev_init_comp - Core init completion 222 + * @status: Status of the command (enum pds_core_status_code) 223 + * 224 + * Initialization result data (struct pds_core_dev_init_data_in) 225 + * is found in cmd_regs->data. 226 + */ 227 + struct pds_core_dev_init_comp { 228 + u8 status; 229 + }; 230 + 231 + /** 232 + * struct pds_core_fw_download_cmd - Firmware download command 233 + * @opcode: opcode 234 + * @rsvd: Word boundary padding 235 + * @addr: DMA address of the firmware buffer 236 + * @offset: offset of the firmware buffer within the full image 237 + * @length: number of valid bytes in the firmware buffer 238 + */ 239 + struct pds_core_fw_download_cmd { 240 + u8 opcode; 241 + u8 rsvd[3]; 242 + __le32 offset; 243 + __le64 addr; 244 + __le32 length; 245 + }; 246 + 247 + /** 248 + * struct pds_core_fw_download_comp - Firmware download completion 249 + * @status: Status of the command (enum pds_core_status_code) 250 + */ 251 + struct pds_core_fw_download_comp { 252 + u8 status; 253 + }; 254 + 255 + /** 256 + * enum pds_core_fw_control_oper - FW control operations 257 + * @PDS_CORE_FW_INSTALL_ASYNC: Install firmware asynchronously 258 + * @PDS_CORE_FW_INSTALL_STATUS: Firmware installation status 259 + * @PDS_CORE_FW_ACTIVATE_ASYNC: Activate firmware asynchronously 260 + * @PDS_CORE_FW_ACTIVATE_STATUS: Firmware activate status 261 + * @PDS_CORE_FW_UPDATE_CLEANUP: Cleanup any firmware update leftovers 262 + * @PDS_CORE_FW_GET_BOOT: Return current active firmware slot 263 + * @PDS_CORE_FW_SET_BOOT: Set active firmware slot for next boot 264 + * @PDS_CORE_FW_GET_LIST: Return list of installed firmware images 265 + */ 266 + enum pds_core_fw_control_oper { 267 + PDS_CORE_FW_INSTALL_ASYNC = 0, 268 + PDS_CORE_FW_INSTALL_STATUS = 1, 269 + PDS_CORE_FW_ACTIVATE_ASYNC = 2, 270 + PDS_CORE_FW_ACTIVATE_STATUS = 3, 271 + PDS_CORE_FW_UPDATE_CLEANUP = 4, 272 + PDS_CORE_FW_GET_BOOT = 5, 273 + PDS_CORE_FW_SET_BOOT = 6, 274 + PDS_CORE_FW_GET_LIST = 7, 275 + }; 276 + 277 + enum pds_core_fw_slot { 278 + PDS_CORE_FW_SLOT_INVALID = 0, 279 + PDS_CORE_FW_SLOT_A = 1, 280 + PDS_CORE_FW_SLOT_B = 2, 281 + PDS_CORE_FW_SLOT_GOLD = 3, 282 + }; 283 + 284 + /** 285 + * struct pds_core_fw_control_cmd - Firmware control command 286 + * @opcode: opcode 287 + * @rsvd: Word boundary padding 288 + * @oper: firmware control operation (enum pds_core_fw_control_oper) 289 + * @slot: slot to operate on (enum pds_core_fw_slot) 290 + */ 291 + struct pds_core_fw_control_cmd { 292 + u8 opcode; 293 + u8 rsvd[3]; 294 + u8 oper; 295 + u8 slot; 296 + }; 297 + 298 + /** 299 + * struct pds_core_fw_control_comp - Firmware control copletion 300 + * @status: Status of the command (enum pds_core_status_code) 301 + * @rsvd: Word alignment space 302 + * @slot: Slot number (enum pds_core_fw_slot) 303 + * @rsvd1: Struct padding 304 + * @color: Color bit 305 + */ 306 + struct pds_core_fw_control_comp { 307 + u8 status; 308 + u8 rsvd[3]; 309 + u8 slot; 310 + u8 rsvd1[10]; 311 + u8 color; 312 + }; 313 + 314 + struct pds_core_fw_name_info { 315 + #define PDS_CORE_FWSLOT_BUFLEN 8 316 + #define PDS_CORE_FWVERS_BUFLEN 32 317 + char slotname[PDS_CORE_FWSLOT_BUFLEN]; 318 + char fw_version[PDS_CORE_FWVERS_BUFLEN]; 319 + }; 320 + 321 + struct pds_core_fw_list_info { 322 + #define PDS_CORE_FWVERS_LIST_LEN 16 323 + u8 num_fw_slots; 324 + struct pds_core_fw_name_info fw_names[PDS_CORE_FWVERS_LIST_LEN]; 325 + } __packed; 326 + 327 + enum pds_core_vf_attr { 328 + PDS_CORE_VF_ATTR_SPOOFCHK = 1, 329 + PDS_CORE_VF_ATTR_TRUST = 2, 330 + PDS_CORE_VF_ATTR_MAC = 3, 331 + PDS_CORE_VF_ATTR_LINKSTATE = 4, 332 + PDS_CORE_VF_ATTR_VLAN = 5, 333 + PDS_CORE_VF_ATTR_RATE = 6, 334 + PDS_CORE_VF_ATTR_STATSADDR = 7, 335 + }; 336 + 337 + /** 338 + * enum pds_core_vf_link_status - Virtual Function link status 339 + * @PDS_CORE_VF_LINK_STATUS_AUTO: Use link state of the uplink 340 + * @PDS_CORE_VF_LINK_STATUS_UP: Link always up 341 + * @PDS_CORE_VF_LINK_STATUS_DOWN: Link always down 342 + */ 343 + enum pds_core_vf_link_status { 344 + PDS_CORE_VF_LINK_STATUS_AUTO = 0, 345 + PDS_CORE_VF_LINK_STATUS_UP = 1, 346 + PDS_CORE_VF_LINK_STATUS_DOWN = 2, 347 + }; 348 + 349 + /** 350 + * struct pds_core_vf_setattr_cmd - Set VF attributes on the NIC 351 + * @opcode: Opcode 352 + * @attr: Attribute type (enum pds_core_vf_attr) 353 + * @vf_index: VF index 354 + * @macaddr: mac address 355 + * @vlanid: vlan ID 356 + * @maxrate: max Tx rate in Mbps 357 + * @spoofchk: enable address spoof checking 358 + * @trust: enable VF trust 359 + * @linkstate: set link up or down 360 + * @stats: stats addr struct 361 + * @stats.pa: set DMA address for VF stats 362 + * @stats.len: length of VF stats space 363 + * @pad: force union to specific size 364 + */ 365 + struct pds_core_vf_setattr_cmd { 366 + u8 opcode; 367 + u8 attr; 368 + __le16 vf_index; 369 + union { 370 + u8 macaddr[6]; 371 + __le16 vlanid; 372 + __le32 maxrate; 373 + u8 spoofchk; 374 + u8 trust; 375 + u8 linkstate; 376 + struct { 377 + __le64 pa; 378 + __le32 len; 379 + } stats; 380 + u8 pad[60]; 381 + } __packed; 382 + }; 383 + 384 + struct pds_core_vf_setattr_comp { 385 + u8 status; 386 + u8 attr; 387 + __le16 vf_index; 388 + __le16 comp_index; 389 + u8 rsvd[9]; 390 + u8 color; 391 + }; 392 + 393 + /** 394 + * struct pds_core_vf_getattr_cmd - Get VF attributes from the NIC 395 + * @opcode: Opcode 396 + * @attr: Attribute type (enum pds_core_vf_attr) 397 + * @vf_index: VF index 398 + */ 399 + struct pds_core_vf_getattr_cmd { 400 + u8 opcode; 401 + u8 attr; 402 + __le16 vf_index; 403 + }; 404 + 405 + struct pds_core_vf_getattr_comp { 406 + u8 status; 407 + u8 attr; 408 + __le16 vf_index; 409 + union { 410 + u8 macaddr[6]; 411 + __le16 vlanid; 412 + __le32 maxrate; 413 + u8 spoofchk; 414 + u8 trust; 415 + u8 linkstate; 416 + __le64 stats_pa; 417 + u8 pad[11]; 418 + } __packed; 419 + u8 color; 420 + }; 421 + 422 + enum pds_core_vf_ctrl_opcode { 423 + PDS_CORE_VF_CTRL_START_ALL = 0, 424 + PDS_CORE_VF_CTRL_START = 1, 425 + }; 426 + 427 + /** 428 + * struct pds_core_vf_ctrl_cmd - VF control command 429 + * @opcode: Opcode for the command 430 + * @ctrl_opcode: VF control operation type 431 + * @vf_index: VF Index. It is unused if op START_ALL is used. 432 + */ 433 + 434 + struct pds_core_vf_ctrl_cmd { 435 + u8 opcode; 436 + u8 ctrl_opcode; 437 + __le16 vf_index; 438 + }; 439 + 440 + /** 441 + * struct pds_core_vf_ctrl_comp - VF_CTRL command completion. 442 + * @status: Status of the command (enum pds_core_status_code) 443 + */ 444 + struct pds_core_vf_ctrl_comp { 445 + u8 status; 446 + }; 447 + 448 + /* 449 + * union pds_core_dev_cmd - Overlay of core device command structures 450 + */ 451 + union pds_core_dev_cmd { 452 + u8 opcode; 453 + u32 words[16]; 454 + 455 + struct pds_core_dev_identify_cmd identify; 456 + struct pds_core_dev_init_cmd init; 457 + struct pds_core_dev_reset_cmd reset; 458 + struct pds_core_fw_download_cmd fw_download; 459 + struct pds_core_fw_control_cmd fw_control; 460 + 461 + struct pds_core_vf_setattr_cmd vf_setattr; 462 + struct pds_core_vf_getattr_cmd vf_getattr; 463 + struct pds_core_vf_ctrl_cmd vf_ctrl; 464 + }; 465 + 466 + /* 467 + * union pds_core_dev_comp - Overlay of core device completion structures 468 + */ 469 + union pds_core_dev_comp { 470 + u8 status; 471 + u8 bytes[16]; 472 + 473 + struct pds_core_dev_identify_comp identify; 474 + struct pds_core_dev_reset_comp reset; 475 + struct pds_core_dev_init_comp init; 476 + struct pds_core_fw_download_comp fw_download; 477 + struct pds_core_fw_control_comp fw_control; 478 + 479 + struct pds_core_vf_setattr_comp vf_setattr; 480 + struct pds_core_vf_getattr_comp vf_getattr; 481 + struct pds_core_vf_ctrl_comp vf_ctrl; 482 + }; 483 + 484 + /** 485 + * struct pds_core_dev_hwstamp_regs - Hardware current timestamp registers 486 + * @tick_low: Low 32 bits of hardware timestamp 487 + * @tick_high: High 32 bits of hardware timestamp 488 + */ 489 + struct pds_core_dev_hwstamp_regs { 490 + u32 tick_low; 491 + u32 tick_high; 492 + }; 493 + 494 + /** 495 + * struct pds_core_dev_info_regs - Device info register format (read-only) 496 + * @signature: Signature value of 0x44455649 ('DEVI') 497 + * @version: Current version of info 498 + * @asic_type: Asic type 499 + * @asic_rev: Asic revision 500 + * @fw_status: Firmware status 501 + * bit 0 - 1 = fw running 502 + * bit 4-7 - 4 bit generation number, changes on fw restart 503 + * @fw_heartbeat: Firmware heartbeat counter 504 + * @serial_num: Serial number 505 + * @fw_version: Firmware version 506 + * @oprom_regs: oprom_regs to store oprom debug enable/disable and bmp 507 + * @rsvd_pad1024: Struct padding 508 + * @hwstamp: Hardware current timestamp registers 509 + * @rsvd_pad2048: Struct padding 510 + */ 511 + struct pds_core_dev_info_regs { 512 + #define PDS_CORE_DEVINFO_FWVERS_BUFLEN 32 513 + #define PDS_CORE_DEVINFO_SERIAL_BUFLEN 32 514 + u32 signature; 515 + u8 version; 516 + u8 asic_type; 517 + u8 asic_rev; 518 + #define PDS_CORE_FW_STS_F_STOPPED 0x00 519 + #define PDS_CORE_FW_STS_F_RUNNING 0x01 520 + #define PDS_CORE_FW_STS_F_GENERATION 0xF0 521 + u8 fw_status; 522 + __le32 fw_heartbeat; 523 + char fw_version[PDS_CORE_DEVINFO_FWVERS_BUFLEN]; 524 + char serial_num[PDS_CORE_DEVINFO_SERIAL_BUFLEN]; 525 + u8 oprom_regs[32]; /* reserved */ 526 + u8 rsvd_pad1024[916]; 527 + struct pds_core_dev_hwstamp_regs hwstamp; /* on 1k boundary */ 528 + u8 rsvd_pad2048[1016]; 529 + } __packed; 530 + 531 + /** 532 + * struct pds_core_dev_cmd_regs - Device command register format (read-write) 533 + * @doorbell: Device Cmd Doorbell, write-only 534 + * Write a 1 to signal device to process cmd 535 + * @done: Command completed indicator, poll for completion 536 + * bit 0 == 1 when command is complete 537 + * @cmd: Opcode-specific command bytes 538 + * @comp: Opcode-specific response bytes 539 + * @rsvd: Struct padding 540 + * @data: Opcode-specific side-data 541 + */ 542 + struct pds_core_dev_cmd_regs { 543 + u32 doorbell; 544 + u32 done; 545 + union pds_core_dev_cmd cmd; 546 + union pds_core_dev_comp comp; 547 + u8 rsvd[48]; 548 + u32 data[478]; 549 + } __packed; 550 + 551 + /** 552 + * struct pds_core_dev_regs - Device register format for bar 0 page 0 553 + * @info: Device info registers 554 + * @devcmd: Device command registers 555 + */ 556 + struct pds_core_dev_regs { 557 + struct pds_core_dev_info_regs info; 558 + struct pds_core_dev_cmd_regs devcmd; 559 + } __packed; 560 + 561 + #ifndef __CHECKER__ 562 + static_assert(sizeof(struct pds_core_drv_identity) <= 1912); 563 + static_assert(sizeof(struct pds_core_dev_identity) <= 1912); 564 + static_assert(sizeof(union pds_core_dev_cmd) == 64); 565 + static_assert(sizeof(union pds_core_dev_comp) == 16); 566 + static_assert(sizeof(struct pds_core_dev_info_regs) == 2048); 567 + static_assert(sizeof(struct pds_core_dev_cmd_regs) == 2048); 568 + static_assert(sizeof(struct pds_core_dev_regs) == 4096); 569 + #endif /* __CHECKER__ */ 570 + 571 + #endif /* _PDS_CORE_IF_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_ */