···9191 dev_info(&GET_DEV(accel_dev), "Resetting device qat_dev%d\n",9292 accel_dev->accel_id);93939494+ if (!parent)9595+ parent = pdev;9696+9497 if (!pci_wait_for_pending_transaction(pdev))9598 dev_info(&GET_DEV(accel_dev),9699 "Transaction still in progress. Proceeding\n");
···5050#include "adf_common_drv.h"51515252static LIST_HEAD(accel_table);5353+static LIST_HEAD(vfs_table);5354static DEFINE_MUTEX(table_lock);5455static uint32_t num_devices;5656+5757+struct vf_id_map {5858+ u32 bdf;5959+ u32 id;6060+ u32 fake_id;6161+ bool attached;6262+ struct list_head list;6363+};6464+6565+static int adf_get_vf_id(struct adf_accel_dev *vf)6666+{6767+ return ((7 * (PCI_SLOT(accel_to_pci_dev(vf)->devfn) - 1)) +6868+ PCI_FUNC(accel_to_pci_dev(vf)->devfn) +6969+ (PCI_SLOT(accel_to_pci_dev(vf)->devfn) - 1));7070+}7171+7272+static int adf_get_vf_num(struct adf_accel_dev *vf)7373+{7474+ return (accel_to_pci_dev(vf)->bus->number << 8) | adf_get_vf_id(vf);7575+}7676+7777+static struct vf_id_map *adf_find_vf(u32 bdf)7878+{7979+ struct list_head *itr;8080+8181+ list_for_each(itr, &vfs_table) {8282+ struct vf_id_map *ptr =8383+ list_entry(itr, struct vf_id_map, list);8484+8585+ if (ptr->bdf == bdf)8686+ return ptr;8787+ }8888+ return NULL;8989+}9090+9191+static int adf_get_vf_real_id(u32 fake)9292+{9393+ struct list_head *itr;9494+9595+ list_for_each(itr, &vfs_table) {9696+ struct vf_id_map *ptr =9797+ list_entry(itr, struct vf_id_map, list);9898+ if (ptr->fake_id == fake)9999+ return ptr->id;100100+ }101101+ return -1;102102+}103103+104104+/**105105+ * adf_clean_vf_map() - Cleans VF id mapings106106+ *107107+ * Function cleans internal ids for virtual functions.108108+ * @vf: flag indicating whether mappings is cleaned109109+ * for vfs only or for vfs and pfs110110+ */111111+void adf_clean_vf_map(bool vf)112112+{113113+ struct vf_id_map *map;114114+ struct list_head *ptr, *tmp;115115+116116+ mutex_lock(&table_lock);117117+ list_for_each_safe(ptr, tmp, &vfs_table) {118118+ map = list_entry(ptr, struct vf_id_map, list);119119+ if (map->bdf != -1)120120+ num_devices--;121121+122122+ if (vf && map->bdf == -1)123123+ continue;124124+125125+ list_del(ptr);126126+ kfree(map);127127+ }128128+ mutex_unlock(&table_lock);129129+}130130+EXPORT_SYMBOL_GPL(adf_clean_vf_map);131131+132132+/**133133+ * adf_devmgr_update_class_index() - Update internal index134134+ * @hw_data: Pointer to internal device data.135135+ *136136+ * Function updates internal dev index for VFs137137+ */138138+void adf_devmgr_update_class_index(struct adf_hw_device_data *hw_data)139139+{140140+ struct adf_hw_device_class *class = hw_data->dev_class;141141+ struct list_head *itr;142142+ int i = 0;143143+144144+ list_for_each(itr, &accel_table) {145145+ struct adf_accel_dev *ptr =146146+ list_entry(itr, struct adf_accel_dev, list);147147+148148+ if (ptr->hw_device->dev_class == class)149149+ ptr->hw_device->instance_id = i++;150150+151151+ if (i == class->instances)152152+ break;153153+ }154154+}155155+EXPORT_SYMBOL_GPL(adf_devmgr_update_class_index);5515656157/**57158 * adf_devmgr_add_dev() - Add accel_dev to the acceleration framework58159 * @accel_dev: Pointer to acceleration device.160160+ * @pf: Corresponding PF if the accel_dev is a VF59161 *60162 * Function adds acceleration device to the acceleration framework.61163 * To be used by QAT device specific drivers.62164 *63165 * Return: 0 on success, error code otherwise.64166 */6565-int adf_devmgr_add_dev(struct adf_accel_dev *accel_dev)167167+int adf_devmgr_add_dev(struct adf_accel_dev *accel_dev,168168+ struct adf_accel_dev *pf)66169{67170 struct list_head *itr;171171+ int ret = 0;6817269173 if (num_devices == ADF_MAX_DEVICES) {70174 dev_err(&GET_DEV(accel_dev), "Only support up to %d devices\n",···17773 }1787417975 mutex_lock(&table_lock);180180- list_for_each(itr, &accel_table) {181181- struct adf_accel_dev *ptr =7676+ atomic_set(&accel_dev->ref_count, 0);7777+7878+ /* PF on host or VF on guest */7979+ if (!accel_dev->is_vf || (accel_dev->is_vf && !pf)) {8080+ struct vf_id_map *map;8181+8282+ list_for_each(itr, &accel_table) {8383+ struct adf_accel_dev *ptr =18284 list_entry(itr, struct adf_accel_dev, list);18385184184- if (ptr == accel_dev) {185185- mutex_unlock(&table_lock);186186- return -EEXIST;8686+ if (ptr == accel_dev) {8787+ ret = -EEXIST;8888+ goto unlock;8989+ }18790 }9191+9292+ list_add_tail(&accel_dev->list, &accel_table);9393+ accel_dev->accel_id = num_devices++;9494+9595+ map = kzalloc(sizeof(*map), GFP_KERNEL);9696+ if (!map) {9797+ ret = -ENOMEM;9898+ goto unlock;9999+ }100100+ map->bdf = ~0;101101+ map->id = accel_dev->accel_id;102102+ map->fake_id = map->id;103103+ map->attached = true;104104+ list_add_tail(&map->list, &vfs_table);105105+ } else if (accel_dev->is_vf && pf) {106106+ /* VF on host */107107+ struct adf_accel_vf_info *vf_info;108108+ struct vf_id_map *map;109109+110110+ vf_info = pf->pf.vf_info + adf_get_vf_id(accel_dev);111111+112112+ map = adf_find_vf(adf_get_vf_num(accel_dev));113113+ if (map) {114114+ struct vf_id_map *next;115115+116116+ accel_dev->accel_id = map->id;117117+ list_add_tail(&accel_dev->list, &accel_table);118118+ map->fake_id++;119119+ map->attached = true;120120+ next = list_next_entry(map, list);121121+ while (next && &next->list != &vfs_table) {122122+ next->fake_id++;123123+ next = list_next_entry(next, list);124124+ }125125+126126+ ret = 0;127127+ goto unlock;128128+ }129129+130130+ map = kzalloc(sizeof(*map), GFP_KERNEL);131131+ if (!map) {132132+ ret = -ENOMEM;133133+ goto unlock;134134+ }135135+136136+ accel_dev->accel_id = num_devices++;137137+ list_add_tail(&accel_dev->list, &accel_table);138138+ map->bdf = adf_get_vf_num(accel_dev);139139+ map->id = accel_dev->accel_id;140140+ map->fake_id = map->id;141141+ map->attached = true;142142+ list_add_tail(&map->list, &vfs_table);188143 }189189- atomic_set(&accel_dev->ref_count, 0);190190- list_add_tail(&accel_dev->list, &accel_table);191191- accel_dev->accel_id = num_devices++;144144+unlock:192145 mutex_unlock(&table_lock);193193- return 0;146146+ return ret;194147}195148EXPORT_SYMBOL_GPL(adf_devmgr_add_dev);196149···25998/**26099 * adf_devmgr_rm_dev() - Remove accel_dev from the acceleration framework.261100 * @accel_dev: Pointer to acceleration device.101101+ * @pf: Corresponding PF if the accel_dev is a VF262102 *263103 * Function removes acceleration device from the acceleration framework.264104 * To be used by QAT device specific drivers.265105 *266106 * Return: void267107 */268268-void adf_devmgr_rm_dev(struct adf_accel_dev *accel_dev)108108+void adf_devmgr_rm_dev(struct adf_accel_dev *accel_dev,109109+ struct adf_accel_dev *pf)269110{270111 mutex_lock(&table_lock);112112+ if (!accel_dev->is_vf || (accel_dev->is_vf && !pf)) {113113+ num_devices--;114114+ } else if (accel_dev->is_vf && pf) {115115+ struct vf_id_map *map, *next;116116+117117+ map = adf_find_vf(adf_get_vf_num(accel_dev));118118+ if (!map) {119119+ dev_err(&GET_DEV(accel_dev), "Failed to find VF map\n");120120+ goto unlock;121121+ }122122+ map->fake_id--;123123+ map->attached = false;124124+ next = list_next_entry(map, list);125125+ while (next && &next->list != &vfs_table) {126126+ next->fake_id--;127127+ next = list_next_entry(next, list);128128+ }129129+ }130130+unlock:271131 list_del(&accel_dev->list);272272- num_devices--;273132 mutex_unlock(&table_lock);274133}275134EXPORT_SYMBOL_GPL(adf_devmgr_rm_dev);···335154struct adf_accel_dev *adf_devmgr_get_dev_by_id(uint32_t id)336155{337156 struct list_head *itr;157157+ int real_id;338158339159 mutex_lock(&table_lock);160160+ real_id = adf_get_vf_real_id(id);161161+ if (real_id < 0)162162+ goto unlock;163163+164164+ id = real_id;165165+340166 list_for_each(itr, &accel_table) {341167 struct adf_accel_dev *ptr =342168 list_entry(itr, struct adf_accel_dev, list);343343-344169 if (ptr->accel_id == id) {345170 mutex_unlock(&table_lock);346171 return ptr;347172 }348173 }174174+unlock:349175 mutex_unlock(&table_lock);350176 return NULL;351177}···368180 return -ENODEV;369181}370182371371-void adf_devmgr_get_num_dev(uint32_t *num)183183+static int adf_get_num_dettached_vfs(void)372184{373373- *num = num_devices;185185+ struct list_head *itr;186186+ int vfs = 0;187187+188188+ mutex_lock(&table_lock);189189+ list_for_each(itr, &vfs_table) {190190+ struct vf_id_map *ptr =191191+ list_entry(itr, struct vf_id_map, list);192192+ if (ptr->bdf != ~0 && !ptr->attached)193193+ vfs++;194194+ }195195+ mutex_unlock(&table_lock);196196+ return vfs;374197}375198199199+void adf_devmgr_get_num_dev(uint32_t *num)200200+{201201+ *num = num_devices - adf_get_num_dettached_vfs();202202+}203203+204204+/**205205+ * adf_dev_in_use() - Check whether accel_dev is currently in use206206+ * @accel_dev: Pointer to acceleration device.207207+ *208208+ * To be used by QAT device specific drivers.209209+ *210210+ * Return: 1 when device is in use, 0 otherwise.211211+ */376212int adf_dev_in_use(struct adf_accel_dev *accel_dev)377213{378214 return atomic_read(&accel_dev->ref_count) != 0;379215}216216+EXPORT_SYMBOL_GPL(adf_dev_in_use);380217218218+/**219219+ * adf_dev_get() - Increment accel_dev reference count220220+ * @accel_dev: Pointer to acceleration device.221221+ *222222+ * Increment the accel_dev refcount and if this is the first time223223+ * incrementing it during this period the accel_dev is in use,224224+ * increment the module refcount too.225225+ * To be used by QAT device specific drivers.226226+ *227227+ * Return: 0 when successful, EFAULT when fail to bump module refcount228228+ */381229int adf_dev_get(struct adf_accel_dev *accel_dev)382230{383231 if (atomic_add_return(1, &accel_dev->ref_count) == 1)···421197 return -EFAULT;422198 return 0;423199}200200+EXPORT_SYMBOL_GPL(adf_dev_get);424201202202+/**203203+ * adf_dev_put() - Decrement accel_dev reference count204204+ * @accel_dev: Pointer to acceleration device.205205+ *206206+ * Decrement the accel_dev refcount and if this is the last time207207+ * decrementing it during this period the accel_dev is in use,208208+ * decrement the module refcount too.209209+ * To be used by QAT device specific drivers.210210+ *211211+ * Return: void212212+ */425213void adf_dev_put(struct adf_accel_dev *accel_dev)426214{427215 if (atomic_sub_return(1, &accel_dev->ref_count) == 0)428216 module_put(accel_dev->owner);429217}218218+EXPORT_SYMBOL_GPL(adf_dev_put);430219220220+/**221221+ * adf_devmgr_in_reset() - Check whether device is in reset222222+ * @accel_dev: Pointer to acceleration device.223223+ *224224+ * To be used by QAT device specific drivers.225225+ *226226+ * Return: 1 when the device is being reset, 0 otherwise.227227+ */431228int adf_devmgr_in_reset(struct adf_accel_dev *accel_dev)432229{433230 return test_bit(ADF_STATUS_RESTARTING, &accel_dev->status);434231}232232+EXPORT_SYMBOL_GPL(adf_devmgr_in_reset);435233234234+/**235235+ * adf_dev_started() - Check whether device has started236236+ * @accel_dev: Pointer to acceleration device.237237+ *238238+ * To be used by QAT device specific drivers.239239+ *240240+ * Return: 1 when the device has started, 0 otherwise241241+ */436242int adf_dev_started(struct adf_accel_dev *accel_dev)437243{438244 return test_bit(ADF_STATUS_STARTED, &accel_dev->status);439245}246246+EXPORT_SYMBOL_GPL(adf_dev_started);
+7-3
drivers/crypto/qat/qat_common/adf_init.c
···187187 }188188189189 hw_data->enable_error_correction(accel_dev);190190+ hw_data->enable_vf2pf_comms(accel_dev);190191191192 return 0;192193}···236235 clear_bit(ADF_STATUS_STARTING, &accel_dev->status);237236 set_bit(ADF_STATUS_STARTED, &accel_dev->status);238237239239- if (qat_algs_register() || qat_asym_algs_register()) {238238+ if (!list_empty(&accel_dev->crypto_list) &&239239+ (qat_algs_register() || qat_asym_algs_register())) {240240 dev_err(&GET_DEV(accel_dev),241241 "Failed to register crypto algs\n");242242 set_bit(ADF_STATUS_STARTING, &accel_dev->status);···272270 clear_bit(ADF_STATUS_STARTING, &accel_dev->status);273271 clear_bit(ADF_STATUS_STARTED, &accel_dev->status);274272275275- if (qat_algs_unregister())273273+ if (!list_empty(&accel_dev->crypto_list) && qat_algs_unregister())276274 dev_err(&GET_DEV(accel_dev),277275 "Failed to unregister crypto algs\n");278276279279- qat_asym_algs_unregister();277277+ if (!list_empty(&accel_dev->crypto_list))278278+ qat_asym_algs_unregister();280279281280 list_for_each(list_itr, &service_table) {282281 service = list_entry(list_itr, struct service_hndl, list);···366363 if (hw_data->exit_admin_comms)367364 hw_data->exit_admin_comms(accel_dev);368365366366+ hw_data->disable_iov(accel_dev);369367 adf_cleanup_etr_data(accel_dev);370368}371369EXPORT_SYMBOL_GPL(adf_dev_shutdown);
+336
drivers/crypto/qat/qat_common/adf_pf2vf_msg.c
···11+/*22+ This file is provided under a dual BSD/GPLv2 license. When using or33+ redistributing this file, you may do so under either license.44+55+ GPL LICENSE SUMMARY66+ Copyright(c) 2015 Intel Corporation.77+ This program is free software; you can redistribute it and/or modify88+ it under the terms of version 2 of the GNU General Public License as99+ published by the Free Software Foundation.1010+1111+ This program is distributed in the hope that it will be useful, but1212+ WITHOUT ANY WARRANTY; without even the implied warranty of1313+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU1414+ General Public License for more details.1515+1616+ Contact Information:1717+ qat-linux@intel.com1818+1919+ BSD LICENSE2020+ Copyright(c) 2015 Intel Corporation.2121+ Redistribution and use in source and binary forms, with or without2222+ modification, are permitted provided that the following conditions2323+ are met:2424+2525+ * Redistributions of source code must retain the above copyright2626+ notice, this list of conditions and the following disclaimer.2727+ * Redistributions in binary form must reproduce the above copyright2828+ notice, this list of conditions and the following disclaimer in2929+ the documentation and/or other materials provided with the3030+ distribution.3131+ * Neither the name of Intel Corporation nor the names of its3232+ contributors may be used to endorse or promote products derived3333+ from this software without specific prior written permission.3434+3535+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS3636+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT3737+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR3838+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT3939+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,4040+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT4141+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,4242+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY4343+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT4444+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE4545+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.4646+*/4747+4848+#include <linux/pci.h>4949+#include <linux/mutex.h>5050+#include <linux/delay.h>5151+#include "adf_accel_devices.h"5252+#include "adf_common_drv.h"5353+#include "adf_pf2vf_msg.h"5454+5555+#define ADF_DH895XCC_EP_OFFSET 0x3A0005656+#define ADF_DH895XCC_ERRMSK3 (ADF_DH895XCC_EP_OFFSET + 0x1C)5757+#define ADF_DH895XCC_ERRMSK3_VF2PF_L_MASK(vf_mask) ((vf_mask & 0xFFFF) << 9)5858+#define ADF_DH895XCC_ERRMSK5 (ADF_DH895XCC_EP_OFFSET + 0xDC)5959+#define ADF_DH895XCC_ERRMSK5_VF2PF_U_MASK(vf_mask) (vf_mask >> 16)6060+6161+/**6262+ * adf_enable_pf2vf_interrupts() - Enable PF to VF interrupts6363+ * @accel_dev: Pointer to acceleration device.6464+ *6565+ * Function enables PF to VF interrupts6666+ */6767+void adf_enable_pf2vf_interrupts(struct adf_accel_dev *accel_dev)6868+{6969+ struct adf_accel_pci *pci_info = &accel_dev->accel_pci_dev;7070+ struct adf_hw_device_data *hw_data = accel_dev->hw_device;7171+ void __iomem *pmisc_bar_addr =7272+ pci_info->pci_bars[hw_data->get_misc_bar_id(hw_data)].virt_addr;7373+7474+ ADF_CSR_WR(pmisc_bar_addr, hw_data->get_vintmsk_offset(0), 0x0);7575+}7676+EXPORT_SYMBOL_GPL(adf_enable_pf2vf_interrupts);7777+7878+/**7979+ * adf_disable_pf2vf_interrupts() - Disable PF to VF interrupts8080+ * @accel_dev: Pointer to acceleration device.8181+ *8282+ * Function disables PF to VF interrupts8383+ */8484+void adf_disable_pf2vf_interrupts(struct adf_accel_dev *accel_dev)8585+{8686+ struct adf_accel_pci *pci_info = &accel_dev->accel_pci_dev;8787+ struct adf_hw_device_data *hw_data = accel_dev->hw_device;8888+ void __iomem *pmisc_bar_addr =8989+ pci_info->pci_bars[hw_data->get_misc_bar_id(hw_data)].virt_addr;9090+9191+ ADF_CSR_WR(pmisc_bar_addr, hw_data->get_vintmsk_offset(0), 0x2);9292+}9393+EXPORT_SYMBOL_GPL(adf_disable_pf2vf_interrupts);9494+9595+void adf_enable_vf2pf_interrupts(struct adf_accel_dev *accel_dev,9696+ u32 vf_mask)9797+{9898+ struct adf_hw_device_data *hw_data = accel_dev->hw_device;9999+ struct adf_bar *pmisc =100100+ &GET_BARS(accel_dev)[hw_data->get_misc_bar_id(hw_data)];101101+ void __iomem *pmisc_addr = pmisc->virt_addr;102102+ u32 reg;103103+104104+ /* Enable VF2PF Messaging Ints - VFs 1 through 16 per vf_mask[15:0] */105105+ if (vf_mask & 0xFFFF) {106106+ reg = ADF_CSR_RD(pmisc_addr, ADF_DH895XCC_ERRMSK3);107107+ reg &= ~ADF_DH895XCC_ERRMSK3_VF2PF_L_MASK(vf_mask);108108+ ADF_CSR_WR(pmisc_addr, ADF_DH895XCC_ERRMSK3, reg);109109+ }110110+111111+ /* Enable VF2PF Messaging Ints - VFs 17 through 32 per vf_mask[31:16] */112112+ if (vf_mask >> 16) {113113+ reg = ADF_CSR_RD(pmisc_addr, ADF_DH895XCC_ERRMSK5);114114+ reg &= ~ADF_DH895XCC_ERRMSK5_VF2PF_U_MASK(vf_mask);115115+ ADF_CSR_WR(pmisc_addr, ADF_DH895XCC_ERRMSK5, reg);116116+ }117117+}118118+119119+/**120120+ * adf_disable_pf2vf_interrupts() - Disable VF to PF interrupts121121+ * @accel_dev: Pointer to acceleration device.122122+ *123123+ * Function disables VF to PF interrupts124124+ */125125+void adf_disable_vf2pf_interrupts(struct adf_accel_dev *accel_dev, u32 vf_mask)126126+{127127+ struct adf_hw_device_data *hw_data = accel_dev->hw_device;128128+ struct adf_bar *pmisc =129129+ &GET_BARS(accel_dev)[hw_data->get_misc_bar_id(hw_data)];130130+ void __iomem *pmisc_addr = pmisc->virt_addr;131131+ u32 reg;132132+133133+ /* Disable VF2PF interrupts for VFs 1 through 16 per vf_mask[15:0] */134134+ if (vf_mask & 0xFFFF) {135135+ reg = ADF_CSR_RD(pmisc_addr, ADF_DH895XCC_ERRMSK3) |136136+ ADF_DH895XCC_ERRMSK3_VF2PF_L_MASK(vf_mask);137137+ ADF_CSR_WR(pmisc_addr, ADF_DH895XCC_ERRMSK3, reg);138138+ }139139+140140+ /* Disable VF2PF interrupts for VFs 17 through 32 per vf_mask[31:16] */141141+ if (vf_mask >> 16) {142142+ reg = ADF_CSR_RD(pmisc_addr, ADF_DH895XCC_ERRMSK5) |143143+ ADF_DH895XCC_ERRMSK5_VF2PF_U_MASK(vf_mask);144144+ ADF_CSR_WR(pmisc_addr, ADF_DH895XCC_ERRMSK5, reg);145145+ }146146+}147147+EXPORT_SYMBOL_GPL(adf_disable_vf2pf_interrupts);148148+149149+static int __adf_iov_putmsg(struct adf_accel_dev *accel_dev, u32 msg, u8 vf_nr)150150+{151151+ struct adf_accel_pci *pci_info = &accel_dev->accel_pci_dev;152152+ struct adf_hw_device_data *hw_data = accel_dev->hw_device;153153+ void __iomem *pmisc_bar_addr =154154+ pci_info->pci_bars[hw_data->get_misc_bar_id(hw_data)].virt_addr;155155+ u32 val, pf2vf_offset, count = 0;156156+ u32 local_in_use_mask, local_in_use_pattern;157157+ u32 remote_in_use_mask, remote_in_use_pattern;158158+ struct mutex *lock; /* lock preventing concurrent acces of CSR */159159+ u32 int_bit;160160+ int ret = 0;161161+162162+ if (accel_dev->is_vf) {163163+ pf2vf_offset = hw_data->get_pf2vf_offset(0);164164+ lock = &accel_dev->vf.vf2pf_lock;165165+ local_in_use_mask = ADF_VF2PF_IN_USE_BY_VF_MASK;166166+ local_in_use_pattern = ADF_VF2PF_IN_USE_BY_VF;167167+ remote_in_use_mask = ADF_PF2VF_IN_USE_BY_PF_MASK;168168+ remote_in_use_pattern = ADF_PF2VF_IN_USE_BY_PF;169169+ int_bit = ADF_VF2PF_INT;170170+ } else {171171+ pf2vf_offset = hw_data->get_pf2vf_offset(vf_nr);172172+ lock = &accel_dev->pf.vf_info[vf_nr].pf2vf_lock;173173+ local_in_use_mask = ADF_PF2VF_IN_USE_BY_PF_MASK;174174+ local_in_use_pattern = ADF_PF2VF_IN_USE_BY_PF;175175+ remote_in_use_mask = ADF_VF2PF_IN_USE_BY_VF_MASK;176176+ remote_in_use_pattern = ADF_VF2PF_IN_USE_BY_VF;177177+ int_bit = ADF_PF2VF_INT;178178+ }179179+180180+ mutex_lock(lock);181181+182182+ /* Check if PF2VF CSR is in use by remote function */183183+ val = ADF_CSR_RD(pmisc_bar_addr, pf2vf_offset);184184+ if ((val & remote_in_use_mask) == remote_in_use_pattern) {185185+ dev_dbg(&GET_DEV(accel_dev),186186+ "PF2VF CSR in use by remote function\n");187187+ ret = -EBUSY;188188+ goto out;189189+ }190190+191191+ /* Attempt to get ownership of PF2VF CSR */192192+ msg &= ~local_in_use_mask;193193+ msg |= local_in_use_pattern;194194+ ADF_CSR_WR(pmisc_bar_addr, pf2vf_offset, msg);195195+196196+ /* Wait in case remote func also attempting to get ownership */197197+ msleep(ADF_IOV_MSG_COLLISION_DETECT_DELAY);198198+199199+ val = ADF_CSR_RD(pmisc_bar_addr, pf2vf_offset);200200+ if ((val & local_in_use_mask) != local_in_use_pattern) {201201+ dev_dbg(&GET_DEV(accel_dev),202202+ "PF2VF CSR in use by remote - collision detected\n");203203+ ret = -EBUSY;204204+ goto out;205205+ }206206+207207+ /*208208+ * This function now owns the PV2VF CSR. The IN_USE_BY pattern must209209+ * remain in the PF2VF CSR for all writes including ACK from remote210210+ * until this local function relinquishes the CSR. Send the message211211+ * by interrupting the remote.212212+ */213213+ ADF_CSR_WR(pmisc_bar_addr, pf2vf_offset, msg | int_bit);214214+215215+ /* Wait for confirmation from remote func it received the message */216216+ do {217217+ msleep(ADF_IOV_MSG_ACK_DELAY);218218+ val = ADF_CSR_RD(pmisc_bar_addr, pf2vf_offset);219219+ } while ((val & int_bit) && (count++ < ADF_IOV_MSG_ACK_MAX_RETRY));220220+221221+ if (val & int_bit) {222222+ dev_dbg(&GET_DEV(accel_dev), "ACK not received from remote\n");223223+ val &= ~int_bit;224224+ ret = -EIO;225225+ }226226+227227+ /* Finished with PF2VF CSR; relinquish it and leave msg in CSR */228228+ ADF_CSR_WR(pmisc_bar_addr, pf2vf_offset, val & ~local_in_use_mask);229229+out:230230+ mutex_unlock(lock);231231+ return ret;232232+}233233+234234+/**235235+ * adf_iov_putmsg() - send PF2VF message236236+ * @accel_dev: Pointer to acceleration device.237237+ * @msg: Message to send238238+ * @vf_nr: VF number to which the message will be sent239239+ *240240+ * Function sends a messge from the PF to a VF241241+ *242242+ * Return: 0 on success, error code otherwise.243243+ */244244+int adf_iov_putmsg(struct adf_accel_dev *accel_dev, u32 msg, u8 vf_nr)245245+{246246+ u32 count = 0;247247+ int ret;248248+249249+ do {250250+ ret = __adf_iov_putmsg(accel_dev, msg, vf_nr);251251+ if (ret)252252+ msleep(ADF_IOV_MSG_RETRY_DELAY);253253+ } while (ret && (count++ < ADF_IOV_MSG_MAX_RETRIES));254254+255255+ return ret;256256+}257257+EXPORT_SYMBOL_GPL(adf_iov_putmsg);258258+259259+void adf_pf2vf_notify_restarting(struct adf_accel_dev *accel_dev)260260+{261261+ struct adf_accel_vf_info *vf;262262+ u32 msg = (ADF_PF2VF_MSGORIGIN_SYSTEM |263263+ (ADF_PF2VF_MSGTYPE_RESTARTING << ADF_PF2VF_MSGTYPE_SHIFT));264264+ int i, num_vfs = pci_num_vf(accel_to_pci_dev(accel_dev));265265+266266+ for (i = 0, vf = accel_dev->pf.vf_info; i < num_vfs; i++, vf++) {267267+ if (vf->init && adf_iov_putmsg(accel_dev, msg, i))268268+ dev_err(&GET_DEV(accel_dev),269269+ "Failed to send restarting msg to VF%d\n", i);270270+ }271271+}272272+273273+static int adf_vf2pf_request_version(struct adf_accel_dev *accel_dev)274274+{275275+ unsigned long timeout = msecs_to_jiffies(ADF_IOV_MSG_RESP_TIMEOUT);276276+ struct adf_hw_device_data *hw_data = accel_dev->hw_device;277277+ u32 msg = 0;278278+ int ret;279279+280280+ msg = ADF_VF2PF_MSGORIGIN_SYSTEM;281281+ msg |= ADF_VF2PF_MSGTYPE_COMPAT_VER_REQ << ADF_VF2PF_MSGTYPE_SHIFT;282282+ msg |= ADF_PFVF_COMPATIBILITY_VERSION << ADF_VF2PF_COMPAT_VER_REQ_SHIFT;283283+ BUILD_BUG_ON(ADF_PFVF_COMPATIBILITY_VERSION > 255);284284+285285+ /* Send request from VF to PF */286286+ ret = adf_iov_putmsg(accel_dev, msg, 0);287287+ if (ret) {288288+ dev_err(&GET_DEV(accel_dev),289289+ "Failed to send Compatibility Version Request.\n");290290+ return ret;291291+ }292292+293293+ /* Wait for response */294294+ if (!wait_for_completion_timeout(&accel_dev->vf.iov_msg_completion,295295+ timeout)) {296296+ dev_err(&GET_DEV(accel_dev),297297+ "IOV request/response message timeout expired\n");298298+ return -EIO;299299+ }300300+301301+ /* Response from PF received, check compatibility */302302+ switch (accel_dev->vf.compatible) {303303+ case ADF_PF2VF_VF_COMPATIBLE:304304+ break;305305+ case ADF_PF2VF_VF_COMPAT_UNKNOWN:306306+ /* VF is newer than PF and decides whether it is compatible */307307+ if (accel_dev->vf.pf_version >= hw_data->min_iov_compat_ver)308308+ break;309309+ /* fall through */310310+ case ADF_PF2VF_VF_INCOMPATIBLE:311311+ dev_err(&GET_DEV(accel_dev),312312+ "PF (vers %d) and VF (vers %d) are not compatible\n",313313+ accel_dev->vf.pf_version,314314+ ADF_PFVF_COMPATIBILITY_VERSION);315315+ return -EINVAL;316316+ default:317317+ dev_err(&GET_DEV(accel_dev),318318+ "Invalid response from PF; assume not compatible\n");319319+ return -EINVAL;320320+ }321321+ return ret;322322+}323323+324324+/**325325+ * adf_enable_vf2pf_comms() - Function enables communication from vf to pf326326+ *327327+ * @accel_dev: Pointer to acceleration device virtual function.328328+ *329329+ * Return: 0 on success, error code otherwise.330330+ */331331+int adf_enable_vf2pf_comms(struct adf_accel_dev *accel_dev)332332+{333333+ adf_enable_pf2vf_interrupts(accel_dev);334334+ return adf_vf2pf_request_version(accel_dev);335335+}336336+EXPORT_SYMBOL_GPL(adf_enable_vf2pf_comms);
+144
drivers/crypto/qat/qat_common/adf_pf2vf_msg.h
···11+/*22+ This file is provided under a dual BSD/GPLv2 license. When using or33+ redistributing this file, you may do so under either license.44+55+ GPL LICENSE SUMMARY66+ Copyright(c) 2015 Intel Corporation.77+ This program is free software; you can redistribute it and/or modify88+ it under the terms of version 2 of the GNU General Public License as99+ published by the Free Software Foundation.1010+1111+ This program is distributed in the hope that it will be useful, but1212+ WITHOUT ANY WARRANTY; without even the implied warranty of1313+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU1414+ General Public License for more details.1515+1616+ Contact Information:1717+ qat-linux@intel.com1818+1919+ BSD LICENSE2020+ Copyright(c) 2015 Intel Corporation.2121+ Redistribution and use in source and binary forms, with or without2222+ modification, are permitted provided that the following conditions2323+ are met:2424+2525+ * Redistributions of source code must retain the above copyright2626+ notice, this list of conditions and the following disclaimer.2727+ * Redistributions in binary form must reproduce the above copyright2828+ notice, this list of conditions and the following disclaimer in2929+ the documentation and/or other materials provided with the3030+ distribution.3131+ * Neither the name of Intel Corporation nor the names of its3232+ contributors may be used to endorse or promote products derived3333+ from this software without specific prior written permission.3434+3535+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS3636+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT3737+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR3838+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT3939+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,4040+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT4141+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,4242+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY4343+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT4444+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE4545+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.4646+*/4747+#ifndef ADF_PF2VF_MSG_H4848+#define ADF_PF2VF_MSG_H4949+5050+/*5151+ * PF<->VF Messaging5252+ * The PF has an array of 32-bit PF2VF registers, one for each VF. The5353+ * PF can access all these registers; each VF can access only the one5454+ * register associated with that particular VF.5555+ *5656+ * The register functionally is split into two parts:5757+ * The bottom half is for PF->VF messages. In particular when the first5858+ * bit of this register (bit 0) gets set an interrupt will be triggered5959+ * in the respective VF.6060+ * The top half is for VF->PF messages. In particular when the first bit6161+ * of this half of register (bit 16) gets set an interrupt will be triggered6262+ * in the PF.6363+ *6464+ * The remaining bits within this register are available to encode messages.6565+ * and implement a collision control mechanism to prevent concurrent use of6666+ * the PF2VF register by both the PF and VF.6767+ *6868+ * 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 166969+ * _______________________________________________7070+ * | | | | | | | | | | | | | | | | |7171+ * +-----------------------------------------------+7272+ * \___________________________/ \_________/ ^ ^7373+ * ^ ^ | |7474+ * | | | VF2PF Int7575+ * | | Message Origin7676+ * | Message Type7777+ * Message-specific Data/Reserved7878+ *7979+ * 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 08080+ * _______________________________________________8181+ * | | | | | | | | | | | | | | | | |8282+ * +-----------------------------------------------+8383+ * \___________________________/ \_________/ ^ ^8484+ * ^ ^ | |8585+ * | | | PF2VF Int8686+ * | | Message Origin8787+ * | Message Type8888+ * Message-specific Data/Reserved8989+ *9090+ * Message Origin (Should always be 1)9191+ * A legacy out-of-tree QAT driver allowed for a set of messages not supported9292+ * by this driver; these had a Msg Origin of 0 and are ignored by this driver.9393+ *9494+ * When a PF or VF attempts to send a message in the lower or upper 16 bits,9595+ * respectively, the other 16 bits are written to first with a defined9696+ * IN_USE_BY pattern as part of a collision control scheme (see adf_iov_putmsg).9797+ */9898+9999+#define ADF_PFVF_COMPATIBILITY_VERSION 0x1 /* PF<->VF compat */100100+101101+/* PF->VF messages */102102+#define ADF_PF2VF_INT BIT(0)103103+#define ADF_PF2VF_MSGORIGIN_SYSTEM BIT(1)104104+#define ADF_PF2VF_MSGTYPE_MASK 0x0000003C105105+#define ADF_PF2VF_MSGTYPE_SHIFT 2106106+#define ADF_PF2VF_MSGTYPE_RESTARTING 0x01107107+#define ADF_PF2VF_MSGTYPE_VERSION_RESP 0x02108108+#define ADF_PF2VF_IN_USE_BY_PF 0x6AC20000109109+#define ADF_PF2VF_IN_USE_BY_PF_MASK 0xFFFE0000110110+111111+/* PF->VF Version Response */112112+#define ADF_PF2VF_VERSION_RESP_VERS_MASK 0x00003FC0113113+#define ADF_PF2VF_VERSION_RESP_VERS_SHIFT 6114114+#define ADF_PF2VF_VERSION_RESP_RESULT_MASK 0x0000C000115115+#define ADF_PF2VF_VERSION_RESP_RESULT_SHIFT 14116116+#define ADF_PF2VF_VF_COMPATIBLE 1117117+#define ADF_PF2VF_VF_INCOMPATIBLE 2118118+#define ADF_PF2VF_VF_COMPAT_UNKNOWN 3119119+120120+/* VF->PF messages */121121+#define ADF_VF2PF_IN_USE_BY_VF 0x00006AC2122122+#define ADF_VF2PF_IN_USE_BY_VF_MASK 0x0000FFFE123123+#define ADF_VF2PF_INT BIT(16)124124+#define ADF_VF2PF_MSGORIGIN_SYSTEM BIT(17)125125+#define ADF_VF2PF_MSGTYPE_MASK 0x003C0000126126+#define ADF_VF2PF_MSGTYPE_SHIFT 18127127+#define ADF_VF2PF_MSGTYPE_INIT 0x3128128+#define ADF_VF2PF_MSGTYPE_SHUTDOWN 0x4129129+#define ADF_VF2PF_MSGTYPE_VERSION_REQ 0x5130130+#define ADF_VF2PF_MSGTYPE_COMPAT_VER_REQ 0x6131131+132132+/* VF->PF Compatible Version Request */133133+#define ADF_VF2PF_COMPAT_VER_REQ_SHIFT 22134134+135135+/* Collision detection */136136+#define ADF_IOV_MSG_COLLISION_DETECT_DELAY 10137137+#define ADF_IOV_MSG_ACK_DELAY 2138138+#define ADF_IOV_MSG_ACK_MAX_RETRY 100139139+#define ADF_IOV_MSG_RETRY_DELAY 5140140+#define ADF_IOV_MSG_MAX_RETRIES 3141141+#define ADF_IOV_MSG_RESP_TIMEOUT (ADF_IOV_MSG_ACK_DELAY * \142142+ ADF_IOV_MSG_ACK_MAX_RETRY + \143143+ ADF_IOV_MSG_COLLISION_DETECT_DELAY)144144+#endif /* ADF_IOV_MSG_H */
+406
drivers/crypto/qat/qat_common/adf_sriov.c
···11+/*22+ This file is provided under a dual BSD/GPLv2 license. When using or33+ redistributing this file, you may do so under either license.44+55+ GPL LICENSE SUMMARY66+ Copyright(c) 2015 Intel Corporation.77+ This program is free software; you can redistribute it and/or modify88+ it under the terms of version 2 of the GNU General Public License as99+ published by the Free Software Foundation.1010+1111+ This program is distributed in the hope that it will be useful, but1212+ WITHOUT ANY WARRANTY; without even the implied warranty of1313+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU1414+ General Public License for more details.1515+1616+ Contact Information:1717+ qat-linux@intel.com1818+1919+ BSD LICENSE2020+ Copyright(c) 2015 Intel Corporation.2121+ Redistribution and use in source and binary forms, with or without2222+ modification, are permitted provided that the following conditions2323+ are met:2424+2525+ * Redistributions of source code must retain the above copyright2626+ notice, this list of conditions and the following disclaimer.2727+ * Redistributions in binary form must reproduce the above copyright2828+ notice, this list of conditions and the following disclaimer in2929+ the documentation and/or other materials provided with the3030+ distribution.3131+ * Neither the name of Intel Corporation nor the names of its3232+ contributors may be used to endorse or promote products derived3333+ from this software without specific prior written permission.3434+3535+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS3636+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT3737+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR3838+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT3939+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,4040+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT4141+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,4242+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY4343+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT4444+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE4545+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.4646+*/4747+#include <linux/workqueue.h>4848+#include <linux/pci.h>4949+#include <linux/device.h>5050+#include <linux/iommu.h>5151+#include "adf_common_drv.h"5252+#include "adf_cfg.h"5353+#include "adf_pf2vf_msg.h"5454+5555+static struct workqueue_struct *pf2vf_resp_wq;5656+5757+#define ME2FUNCTION_MAP_A_OFFSET (0x3A400 + 0x190)5858+#define ME2FUNCTION_MAP_A_NUM_REGS 965959+6060+#define ME2FUNCTION_MAP_B_OFFSET (0x3A400 + 0x310)6161+#define ME2FUNCTION_MAP_B_NUM_REGS 126262+6363+#define ME2FUNCTION_MAP_REG_SIZE 46464+#define ME2FUNCTION_MAP_VALID BIT(7)6565+6666+#define READ_CSR_ME2FUNCTION_MAP_A(pmisc_bar_addr, index) \6767+ ADF_CSR_RD(pmisc_bar_addr, ME2FUNCTION_MAP_A_OFFSET + \6868+ ME2FUNCTION_MAP_REG_SIZE * index)6969+7070+#define WRITE_CSR_ME2FUNCTION_MAP_A(pmisc_bar_addr, index, value) \7171+ ADF_CSR_WR(pmisc_bar_addr, ME2FUNCTION_MAP_A_OFFSET + \7272+ ME2FUNCTION_MAP_REG_SIZE * index, value)7373+7474+#define READ_CSR_ME2FUNCTION_MAP_B(pmisc_bar_addr, index) \7575+ ADF_CSR_RD(pmisc_bar_addr, ME2FUNCTION_MAP_B_OFFSET + \7676+ ME2FUNCTION_MAP_REG_SIZE * index)7777+7878+#define WRITE_CSR_ME2FUNCTION_MAP_B(pmisc_bar_addr, index, value) \7979+ ADF_CSR_WR(pmisc_bar_addr, ME2FUNCTION_MAP_B_OFFSET + \8080+ ME2FUNCTION_MAP_REG_SIZE * index, value)8181+8282+struct adf_pf2vf_resp_data {8383+ struct work_struct pf2vf_resp_work;8484+ struct adf_accel_dev *accel_dev;8585+ u32 resp;8686+ u8 vf_nr;8787+};8888+8989+static void adf_iov_send_resp(struct work_struct *work)9090+{9191+ struct adf_pf2vf_resp_data *pf2vf_resp_data =9292+ container_of(work, struct adf_pf2vf_resp_data, pf2vf_resp_work);9393+9494+ if (adf_iov_putmsg(pf2vf_resp_data->accel_dev, pf2vf_resp_data->resp,9595+ pf2vf_resp_data->vf_nr)) {9696+ dev_err(&GET_DEV(pf2vf_resp_data->accel_dev),9797+ "Failed to send response\n");9898+ }9999+100100+ kfree(pf2vf_resp_data);101101+}102102+103103+static void adf_vf2pf_bh_handler(void *data)104104+{105105+ struct adf_accel_vf_info *vf_info = (struct adf_accel_vf_info *)data;106106+ struct adf_accel_dev *accel_dev = vf_info->accel_dev;107107+ struct adf_hw_device_data *hw_data = accel_dev->hw_device;108108+ struct adf_bar *pmisc =109109+ &GET_BARS(accel_dev)[hw_data->get_misc_bar_id(hw_data)];110110+ void __iomem *pmisc_addr = pmisc->virt_addr;111111+ u32 msg;112112+113113+ /* Read message from the VF */114114+ msg = ADF_CSR_RD(pmisc_addr, hw_data->get_pf2vf_offset(vf_info->vf_nr));115115+116116+ if (!(msg & ADF_VF2PF_MSGORIGIN_SYSTEM))117117+ /* Ignore legacy non-system (non-kernel) VF2PF messages */118118+ goto err;119119+120120+ switch ((msg & ADF_VF2PF_MSGTYPE_MASK) >> ADF_VF2PF_MSGTYPE_SHIFT) {121121+ case ADF_VF2PF_MSGTYPE_COMPAT_VER_REQ:122122+ {123123+ u8 vf_compat_ver = msg >> ADF_VF2PF_COMPAT_VER_REQ_SHIFT;124124+ struct adf_pf2vf_resp_data *pf2vf_resp_data;125125+ u32 resp = (ADF_PF2VF_MSGORIGIN_SYSTEM |126126+ (ADF_PF2VF_MSGTYPE_VERSION_RESP <<127127+ ADF_PF2VF_MSGTYPE_SHIFT) |128128+ (ADF_PFVF_COMPATIBILITY_VERSION <<129129+ ADF_PF2VF_VERSION_RESP_VERS_SHIFT));130130+131131+ dev_dbg(&GET_DEV(accel_dev),132132+ "Compatibility Version Request from VF%d vers=%u\n",133133+ vf_info->vf_nr + 1, vf_compat_ver);134134+135135+ if (vf_compat_ver < hw_data->min_iov_compat_ver) {136136+ dev_err(&GET_DEV(accel_dev),137137+ "VF (vers %d) incompatible with PF (vers %d)\n",138138+ vf_compat_ver, ADF_PFVF_COMPATIBILITY_VERSION);139139+ resp |= ADF_PF2VF_VF_INCOMPATIBLE <<140140+ ADF_PF2VF_VERSION_RESP_RESULT_SHIFT;141141+ } else if (vf_compat_ver > ADF_PFVF_COMPATIBILITY_VERSION) {142142+ dev_err(&GET_DEV(accel_dev),143143+ "VF (vers %d) compat with PF (vers %d) unkn.\n",144144+ vf_compat_ver, ADF_PFVF_COMPATIBILITY_VERSION);145145+ resp |= ADF_PF2VF_VF_COMPAT_UNKNOWN <<146146+ ADF_PF2VF_VERSION_RESP_RESULT_SHIFT;147147+ } else {148148+ dev_dbg(&GET_DEV(accel_dev),149149+ "VF (vers %d) compatible with PF (vers %d)\n",150150+ vf_compat_ver, ADF_PFVF_COMPATIBILITY_VERSION);151151+ resp |= ADF_PF2VF_VF_COMPATIBLE <<152152+ ADF_PF2VF_VERSION_RESP_RESULT_SHIFT;153153+ }154154+155155+ pf2vf_resp_data = kzalloc(sizeof(*pf2vf_resp_data), GFP_ATOMIC);156156+ if (!pf2vf_resp_data)157157+ return;158158+159159+ pf2vf_resp_data->accel_dev = accel_dev;160160+ pf2vf_resp_data->vf_nr = vf_info->vf_nr;161161+ pf2vf_resp_data->resp = resp;162162+ INIT_WORK(&pf2vf_resp_data->pf2vf_resp_work, adf_iov_send_resp);163163+ queue_work(pf2vf_resp_wq, &pf2vf_resp_data->pf2vf_resp_work);164164+ }165165+ break;166166+ case ADF_VF2PF_MSGTYPE_INIT:167167+ {168168+ dev_dbg(&GET_DEV(accel_dev),169169+ "Init message received from VF%d 0x%x\n",170170+ vf_info->vf_nr + 1, msg);171171+ vf_info->init = true;172172+ }173173+ break;174174+ case ADF_VF2PF_MSGTYPE_SHUTDOWN:175175+ {176176+ dev_dbg(&GET_DEV(accel_dev),177177+ "Shutdown message received from VF%d 0x%x\n",178178+ vf_info->vf_nr + 1, msg);179179+ vf_info->init = false;180180+ }181181+ break;182182+ case ADF_VF2PF_MSGTYPE_VERSION_REQ:183183+ dev_err(&GET_DEV(accel_dev),184184+ "Incompatible VersionRequest received from VF%d 0x%x\n",185185+ vf_info->vf_nr + 1, msg);186186+ break;187187+ default:188188+ goto err;189189+ }190190+191191+ /* To ACK, clear the VF2PFINT bit */192192+ msg &= ~ADF_VF2PF_INT;193193+ ADF_CSR_WR(pmisc_addr, hw_data->get_pf2vf_offset(vf_info->vf_nr), msg);194194+195195+ /* re-enable interrupt on PF from this VF */196196+ adf_enable_vf2pf_interrupts(accel_dev, (1 << vf_info->vf_nr));197197+ return;198198+err:199199+ dev_err(&GET_DEV(accel_dev), "Unknown message from VF%d (0x%x);\n",200200+ vf_info->vf_nr + 1, msg);201201+}202202+203203+static int adf_enable_sriov(struct adf_accel_dev *accel_dev)204204+{205205+ struct pci_dev *pdev = accel_to_pci_dev(accel_dev);206206+ int totalvfs = pci_sriov_get_totalvfs(pdev);207207+ struct adf_hw_device_data *hw_data = accel_dev->hw_device;208208+ struct adf_bar *pmisc =209209+ &GET_BARS(accel_dev)[hw_data->get_misc_bar_id(hw_data)];210210+ void __iomem *pmisc_addr = pmisc->virt_addr;211211+ struct adf_accel_vf_info *vf_info;212212+ int i, ret;213213+ u32 reg;214214+215215+ /* Workqueue for PF2VF responses */216216+ pf2vf_resp_wq = create_workqueue("qat_pf2vf_resp_wq");217217+ if (!pf2vf_resp_wq)218218+ return -ENOMEM;219219+220220+ for (i = 0, vf_info = accel_dev->pf.vf_info; i < totalvfs;221221+ i++, vf_info++) {222222+ /* This ptr will be populated when VFs will be created */223223+ vf_info->accel_dev = accel_dev;224224+ vf_info->vf_nr = i;225225+226226+ tasklet_init(&vf_info->vf2pf_bh_tasklet,227227+ (void *)adf_vf2pf_bh_handler,228228+ (unsigned long)vf_info);229229+ mutex_init(&vf_info->pf2vf_lock);230230+ ratelimit_state_init(&vf_info->vf2pf_ratelimit,231231+ DEFAULT_RATELIMIT_INTERVAL,232232+ DEFAULT_RATELIMIT_BURST);233233+ }234234+235235+ /* Set Valid bits in ME Thread to PCIe Function Mapping Group A */236236+ for (i = 0; i < ME2FUNCTION_MAP_A_NUM_REGS; i++) {237237+ reg = READ_CSR_ME2FUNCTION_MAP_A(pmisc_addr, i);238238+ reg |= ME2FUNCTION_MAP_VALID;239239+ WRITE_CSR_ME2FUNCTION_MAP_A(pmisc_addr, i, reg);240240+ }241241+242242+ /* Set Valid bits in ME Thread to PCIe Function Mapping Group B */243243+ for (i = 0; i < ME2FUNCTION_MAP_B_NUM_REGS; i++) {244244+ reg = READ_CSR_ME2FUNCTION_MAP_B(pmisc_addr, i);245245+ reg |= ME2FUNCTION_MAP_VALID;246246+ WRITE_CSR_ME2FUNCTION_MAP_B(pmisc_addr, i, reg);247247+ }248248+249249+ /* Enable VF to PF interrupts for all VFs */250250+ adf_enable_vf2pf_interrupts(accel_dev, GENMASK_ULL(totalvfs - 1, 0));251251+252252+ /*253253+ * Due to the hardware design, when SR-IOV and the ring arbiter254254+ * are enabled all the VFs supported in hardware must be enabled in255255+ * order for all the hardware resources (i.e. bundles) to be usable.256256+ * When SR-IOV is enabled, each of the VFs will own one bundle.257257+ */258258+ ret = pci_enable_sriov(pdev, totalvfs);259259+ if (ret)260260+ return ret;261261+262262+ return 0;263263+}264264+265265+/**266266+ * adf_disable_sriov() - Disable SRIOV for the device267267+ * @pdev: Pointer to pci device.268268+ *269269+ * Function disables SRIOV for the pci device.270270+ *271271+ * Return: 0 on success, error code otherwise.272272+ */273273+void adf_disable_sriov(struct adf_accel_dev *accel_dev)274274+{275275+ struct adf_hw_device_data *hw_data = accel_dev->hw_device;276276+ struct adf_bar *pmisc =277277+ &GET_BARS(accel_dev)[hw_data->get_misc_bar_id(hw_data)];278278+ void __iomem *pmisc_addr = pmisc->virt_addr;279279+ int totalvfs = pci_sriov_get_totalvfs(accel_to_pci_dev(accel_dev));280280+ struct adf_accel_vf_info *vf;281281+ u32 reg;282282+ int i;283283+284284+ if (!accel_dev->pf.vf_info)285285+ return;286286+287287+ adf_pf2vf_notify_restarting(accel_dev);288288+289289+ pci_disable_sriov(accel_to_pci_dev(accel_dev));290290+291291+ /* Disable VF to PF interrupts */292292+ adf_disable_vf2pf_interrupts(accel_dev, 0xFFFFFFFF);293293+294294+ /* Clear Valid bits in ME Thread to PCIe Function Mapping Group A */295295+ for (i = 0; i < ME2FUNCTION_MAP_A_NUM_REGS; i++) {296296+ reg = READ_CSR_ME2FUNCTION_MAP_A(pmisc_addr, i);297297+ reg &= ~ME2FUNCTION_MAP_VALID;298298+ WRITE_CSR_ME2FUNCTION_MAP_A(pmisc_addr, i, reg);299299+ }300300+301301+ /* Clear Valid bits in ME Thread to PCIe Function Mapping Group B */302302+ for (i = 0; i < ME2FUNCTION_MAP_B_NUM_REGS; i++) {303303+ reg = READ_CSR_ME2FUNCTION_MAP_B(pmisc_addr, i);304304+ reg &= ~ME2FUNCTION_MAP_VALID;305305+ WRITE_CSR_ME2FUNCTION_MAP_B(pmisc_addr, i, reg);306306+ }307307+308308+ for (i = 0, vf = accel_dev->pf.vf_info; i < totalvfs; i++, vf++) {309309+ tasklet_disable(&vf->vf2pf_bh_tasklet);310310+ tasklet_kill(&vf->vf2pf_bh_tasklet);311311+ mutex_destroy(&vf->pf2vf_lock);312312+ }313313+314314+ kfree(accel_dev->pf.vf_info);315315+ accel_dev->pf.vf_info = NULL;316316+317317+ if (pf2vf_resp_wq) {318318+ destroy_workqueue(pf2vf_resp_wq);319319+ pf2vf_resp_wq = NULL;320320+ }321321+}322322+EXPORT_SYMBOL_GPL(adf_disable_sriov);323323+324324+/**325325+ * adf_sriov_configure() - Enable SRIOV for the device326326+ * @pdev: Pointer to pci device.327327+ *328328+ * Function enables SRIOV for the pci device.329329+ *330330+ * Return: 0 on success, error code otherwise.331331+ */332332+int adf_sriov_configure(struct pci_dev *pdev, int numvfs)333333+{334334+ struct adf_accel_dev *accel_dev = adf_devmgr_pci_to_accel_dev(pdev);335335+ int totalvfs = pci_sriov_get_totalvfs(pdev);336336+ unsigned long val;337337+ int ret;338338+339339+ if (!accel_dev) {340340+ dev_err(&pdev->dev, "Failed to find accel_dev\n");341341+ return -EFAULT;342342+ }343343+344344+ if (!iommu_present(&pci_bus_type)) {345345+ dev_err(&pdev->dev,346346+ "IOMMU must be enabled for SR-IOV to work\n");347347+ return -EINVAL;348348+ }349349+350350+ if (accel_dev->pf.vf_info) {351351+ dev_info(&pdev->dev, "Already enabled for this device\n");352352+ return -EINVAL;353353+ }354354+355355+ if (adf_dev_started(accel_dev)) {356356+ if (adf_devmgr_in_reset(accel_dev) ||357357+ adf_dev_in_use(accel_dev)) {358358+ dev_err(&GET_DEV(accel_dev), "Device busy\n");359359+ return -EBUSY;360360+ }361361+362362+ if (adf_dev_stop(accel_dev)) {363363+ dev_err(&GET_DEV(accel_dev),364364+ "Failed to stop qat_dev%d\n",365365+ accel_dev->accel_id);366366+ return -EFAULT;367367+ }368368+369369+ adf_dev_shutdown(accel_dev);370370+ }371371+372372+ if (adf_cfg_section_add(accel_dev, ADF_KERNEL_SEC))373373+ return -EFAULT;374374+ val = 0;375375+ if (adf_cfg_add_key_value_param(accel_dev, ADF_KERNEL_SEC,376376+ ADF_NUM_CY, (void *)&val, ADF_DEC))377377+ return -EFAULT;378378+379379+ set_bit(ADF_STATUS_CONFIGURED, &accel_dev->status);380380+381381+ /* Allocate memory for VF info structs */382382+ accel_dev->pf.vf_info = kcalloc(totalvfs,383383+ sizeof(struct adf_accel_vf_info),384384+ GFP_KERNEL);385385+ if (!accel_dev->pf.vf_info)386386+ return -ENOMEM;387387+388388+ if (adf_dev_init(accel_dev)) {389389+ dev_err(&GET_DEV(accel_dev), "Failed to init qat_dev%d\n",390390+ accel_dev->accel_id);391391+ return -EFAULT;392392+ }393393+394394+ if (adf_dev_start(accel_dev)) {395395+ dev_err(&GET_DEV(accel_dev), "Failed to start qat_dev%d\n",396396+ accel_dev->accel_id);397397+ return -EFAULT;398398+ }399399+400400+ ret = adf_enable_sriov(accel_dev);401401+ if (ret)402402+ return ret;403403+404404+ return numvfs;405405+}406406+EXPORT_SYMBOL_GPL(adf_sriov_configure);