162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* Copyright(c) 2013 - 2018 Intel Corporation. */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/list.h> 562306a36Sopenharmony_ci#include <linux/errno.h> 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include "iavf.h" 862306a36Sopenharmony_ci#include "iavf_prototype.h" 962306a36Sopenharmony_ci#include "iavf_client.h" 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_cistatic 1262306a36Sopenharmony_ciconst char iavf_client_interface_version_str[] = IAVF_CLIENT_VERSION_STR; 1362306a36Sopenharmony_cistatic struct iavf_client *vf_registered_client; 1462306a36Sopenharmony_cistatic LIST_HEAD(iavf_devices); 1562306a36Sopenharmony_cistatic DEFINE_MUTEX(iavf_device_mutex); 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_cistatic u32 iavf_client_virtchnl_send(struct iavf_info *ldev, 1862306a36Sopenharmony_ci struct iavf_client *client, 1962306a36Sopenharmony_ci u8 *msg, u16 len); 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistatic int iavf_client_setup_qvlist(struct iavf_info *ldev, 2262306a36Sopenharmony_ci struct iavf_client *client, 2362306a36Sopenharmony_ci struct iavf_qvlist_info *qvlist_info); 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_cistatic struct iavf_ops iavf_lan_ops = { 2662306a36Sopenharmony_ci .virtchnl_send = iavf_client_virtchnl_send, 2762306a36Sopenharmony_ci .setup_qvlist = iavf_client_setup_qvlist, 2862306a36Sopenharmony_ci}; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci/** 3162306a36Sopenharmony_ci * iavf_client_get_params - retrieve relevant client parameters 3262306a36Sopenharmony_ci * @vsi: VSI with parameters 3362306a36Sopenharmony_ci * @params: client param struct 3462306a36Sopenharmony_ci **/ 3562306a36Sopenharmony_cistatic 3662306a36Sopenharmony_civoid iavf_client_get_params(struct iavf_vsi *vsi, struct iavf_params *params) 3762306a36Sopenharmony_ci{ 3862306a36Sopenharmony_ci int i; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci memset(params, 0, sizeof(struct iavf_params)); 4162306a36Sopenharmony_ci params->mtu = vsi->netdev->mtu; 4262306a36Sopenharmony_ci params->link_up = vsi->back->link_up; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci for (i = 0; i < IAVF_MAX_USER_PRIORITY; i++) { 4562306a36Sopenharmony_ci params->qos.prio_qos[i].tc = 0; 4662306a36Sopenharmony_ci params->qos.prio_qos[i].qs_handle = vsi->qs_handle; 4762306a36Sopenharmony_ci } 4862306a36Sopenharmony_ci} 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci/** 5162306a36Sopenharmony_ci * iavf_notify_client_message - call the client message receive callback 5262306a36Sopenharmony_ci * @vsi: the VSI associated with this client 5362306a36Sopenharmony_ci * @msg: message buffer 5462306a36Sopenharmony_ci * @len: length of message 5562306a36Sopenharmony_ci * 5662306a36Sopenharmony_ci * If there is a client to this VSI, call the client 5762306a36Sopenharmony_ci **/ 5862306a36Sopenharmony_civoid iavf_notify_client_message(struct iavf_vsi *vsi, u8 *msg, u16 len) 5962306a36Sopenharmony_ci{ 6062306a36Sopenharmony_ci struct iavf_client_instance *cinst; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci if (!vsi) 6362306a36Sopenharmony_ci return; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci cinst = vsi->back->cinst; 6662306a36Sopenharmony_ci if (!cinst || !cinst->client || !cinst->client->ops || 6762306a36Sopenharmony_ci !cinst->client->ops->virtchnl_receive) { 6862306a36Sopenharmony_ci dev_dbg(&vsi->back->pdev->dev, 6962306a36Sopenharmony_ci "Cannot locate client instance virtchnl_receive function\n"); 7062306a36Sopenharmony_ci return; 7162306a36Sopenharmony_ci } 7262306a36Sopenharmony_ci cinst->client->ops->virtchnl_receive(&cinst->lan_info, cinst->client, 7362306a36Sopenharmony_ci msg, len); 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci/** 7762306a36Sopenharmony_ci * iavf_notify_client_l2_params - call the client notify callback 7862306a36Sopenharmony_ci * @vsi: the VSI with l2 param changes 7962306a36Sopenharmony_ci * 8062306a36Sopenharmony_ci * If there is a client to this VSI, call the client 8162306a36Sopenharmony_ci **/ 8262306a36Sopenharmony_civoid iavf_notify_client_l2_params(struct iavf_vsi *vsi) 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci struct iavf_client_instance *cinst; 8562306a36Sopenharmony_ci struct iavf_params params; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci if (!vsi) 8862306a36Sopenharmony_ci return; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci cinst = vsi->back->cinst; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci if (!cinst || !cinst->client || !cinst->client->ops || 9362306a36Sopenharmony_ci !cinst->client->ops->l2_param_change) { 9462306a36Sopenharmony_ci dev_dbg(&vsi->back->pdev->dev, 9562306a36Sopenharmony_ci "Cannot locate client instance l2_param_change function\n"); 9662306a36Sopenharmony_ci return; 9762306a36Sopenharmony_ci } 9862306a36Sopenharmony_ci iavf_client_get_params(vsi, ¶ms); 9962306a36Sopenharmony_ci cinst->lan_info.params = params; 10062306a36Sopenharmony_ci cinst->client->ops->l2_param_change(&cinst->lan_info, cinst->client, 10162306a36Sopenharmony_ci ¶ms); 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci/** 10562306a36Sopenharmony_ci * iavf_notify_client_open - call the client open callback 10662306a36Sopenharmony_ci * @vsi: the VSI with netdev opened 10762306a36Sopenharmony_ci * 10862306a36Sopenharmony_ci * If there is a client to this netdev, call the client with open 10962306a36Sopenharmony_ci **/ 11062306a36Sopenharmony_civoid iavf_notify_client_open(struct iavf_vsi *vsi) 11162306a36Sopenharmony_ci{ 11262306a36Sopenharmony_ci struct iavf_adapter *adapter = vsi->back; 11362306a36Sopenharmony_ci struct iavf_client_instance *cinst = adapter->cinst; 11462306a36Sopenharmony_ci int ret; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci if (!cinst || !cinst->client || !cinst->client->ops || 11762306a36Sopenharmony_ci !cinst->client->ops->open) { 11862306a36Sopenharmony_ci dev_dbg(&vsi->back->pdev->dev, 11962306a36Sopenharmony_ci "Cannot locate client instance open function\n"); 12062306a36Sopenharmony_ci return; 12162306a36Sopenharmony_ci } 12262306a36Sopenharmony_ci if (!(test_bit(__IAVF_CLIENT_INSTANCE_OPENED, &cinst->state))) { 12362306a36Sopenharmony_ci ret = cinst->client->ops->open(&cinst->lan_info, cinst->client); 12462306a36Sopenharmony_ci if (!ret) 12562306a36Sopenharmony_ci set_bit(__IAVF_CLIENT_INSTANCE_OPENED, &cinst->state); 12662306a36Sopenharmony_ci } 12762306a36Sopenharmony_ci} 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci/** 13062306a36Sopenharmony_ci * iavf_client_release_qvlist - send a message to the PF to release rdma qv map 13162306a36Sopenharmony_ci * @ldev: pointer to L2 context. 13262306a36Sopenharmony_ci * 13362306a36Sopenharmony_ci * Return 0 on success or < 0 on error 13462306a36Sopenharmony_ci **/ 13562306a36Sopenharmony_cistatic int iavf_client_release_qvlist(struct iavf_info *ldev) 13662306a36Sopenharmony_ci{ 13762306a36Sopenharmony_ci struct iavf_adapter *adapter = ldev->vf; 13862306a36Sopenharmony_ci enum iavf_status err; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci if (adapter->aq_required) 14162306a36Sopenharmony_ci return -EAGAIN; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci err = iavf_aq_send_msg_to_pf(&adapter->hw, 14462306a36Sopenharmony_ci VIRTCHNL_OP_RELEASE_RDMA_IRQ_MAP, 14562306a36Sopenharmony_ci IAVF_SUCCESS, NULL, 0, NULL); 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci if (err) 14862306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, 14962306a36Sopenharmony_ci "Unable to send RDMA vector release message to PF, error %d, aq status %d\n", 15062306a36Sopenharmony_ci err, adapter->hw.aq.asq_last_status); 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci return err; 15362306a36Sopenharmony_ci} 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci/** 15662306a36Sopenharmony_ci * iavf_notify_client_close - call the client close callback 15762306a36Sopenharmony_ci * @vsi: the VSI with netdev closed 15862306a36Sopenharmony_ci * @reset: true when close called due to reset pending 15962306a36Sopenharmony_ci * 16062306a36Sopenharmony_ci * If there is a client to this netdev, call the client with close 16162306a36Sopenharmony_ci **/ 16262306a36Sopenharmony_civoid iavf_notify_client_close(struct iavf_vsi *vsi, bool reset) 16362306a36Sopenharmony_ci{ 16462306a36Sopenharmony_ci struct iavf_adapter *adapter = vsi->back; 16562306a36Sopenharmony_ci struct iavf_client_instance *cinst = adapter->cinst; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci if (!cinst || !cinst->client || !cinst->client->ops || 16862306a36Sopenharmony_ci !cinst->client->ops->close) { 16962306a36Sopenharmony_ci dev_dbg(&vsi->back->pdev->dev, 17062306a36Sopenharmony_ci "Cannot locate client instance close function\n"); 17162306a36Sopenharmony_ci return; 17262306a36Sopenharmony_ci } 17362306a36Sopenharmony_ci cinst->client->ops->close(&cinst->lan_info, cinst->client, reset); 17462306a36Sopenharmony_ci iavf_client_release_qvlist(&cinst->lan_info); 17562306a36Sopenharmony_ci clear_bit(__IAVF_CLIENT_INSTANCE_OPENED, &cinst->state); 17662306a36Sopenharmony_ci} 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci/** 17962306a36Sopenharmony_ci * iavf_client_add_instance - add a client instance to the instance list 18062306a36Sopenharmony_ci * @adapter: pointer to the board struct 18162306a36Sopenharmony_ci * 18262306a36Sopenharmony_ci * Returns cinst ptr on success, NULL on failure 18362306a36Sopenharmony_ci **/ 18462306a36Sopenharmony_cistatic struct iavf_client_instance * 18562306a36Sopenharmony_ciiavf_client_add_instance(struct iavf_adapter *adapter) 18662306a36Sopenharmony_ci{ 18762306a36Sopenharmony_ci struct iavf_client_instance *cinst = NULL; 18862306a36Sopenharmony_ci struct iavf_vsi *vsi = &adapter->vsi; 18962306a36Sopenharmony_ci struct netdev_hw_addr *mac = NULL; 19062306a36Sopenharmony_ci struct iavf_params params; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci if (!vf_registered_client) 19362306a36Sopenharmony_ci goto out; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci if (adapter->cinst) { 19662306a36Sopenharmony_ci cinst = adapter->cinst; 19762306a36Sopenharmony_ci goto out; 19862306a36Sopenharmony_ci } 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci cinst = kzalloc(sizeof(*cinst), GFP_KERNEL); 20162306a36Sopenharmony_ci if (!cinst) 20262306a36Sopenharmony_ci goto out; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci cinst->lan_info.vf = (void *)adapter; 20562306a36Sopenharmony_ci cinst->lan_info.netdev = vsi->netdev; 20662306a36Sopenharmony_ci cinst->lan_info.pcidev = adapter->pdev; 20762306a36Sopenharmony_ci cinst->lan_info.fid = 0; 20862306a36Sopenharmony_ci cinst->lan_info.ftype = IAVF_CLIENT_FTYPE_VF; 20962306a36Sopenharmony_ci cinst->lan_info.hw_addr = adapter->hw.hw_addr; 21062306a36Sopenharmony_ci cinst->lan_info.ops = &iavf_lan_ops; 21162306a36Sopenharmony_ci cinst->lan_info.version.major = IAVF_CLIENT_VERSION_MAJOR; 21262306a36Sopenharmony_ci cinst->lan_info.version.minor = IAVF_CLIENT_VERSION_MINOR; 21362306a36Sopenharmony_ci cinst->lan_info.version.build = IAVF_CLIENT_VERSION_BUILD; 21462306a36Sopenharmony_ci iavf_client_get_params(vsi, ¶ms); 21562306a36Sopenharmony_ci cinst->lan_info.params = params; 21662306a36Sopenharmony_ci set_bit(__IAVF_CLIENT_INSTANCE_NONE, &cinst->state); 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci cinst->lan_info.msix_count = adapter->num_rdma_msix; 21962306a36Sopenharmony_ci cinst->lan_info.msix_entries = 22062306a36Sopenharmony_ci &adapter->msix_entries[adapter->rdma_base_vector]; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci mac = list_first_entry(&cinst->lan_info.netdev->dev_addrs.list, 22362306a36Sopenharmony_ci struct netdev_hw_addr, list); 22462306a36Sopenharmony_ci if (mac) 22562306a36Sopenharmony_ci ether_addr_copy(cinst->lan_info.lanmac, mac->addr); 22662306a36Sopenharmony_ci else 22762306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, "MAC address list is empty!\n"); 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci cinst->client = vf_registered_client; 23062306a36Sopenharmony_ci adapter->cinst = cinst; 23162306a36Sopenharmony_ciout: 23262306a36Sopenharmony_ci return cinst; 23362306a36Sopenharmony_ci} 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci/** 23662306a36Sopenharmony_ci * iavf_client_del_instance - removes a client instance from the list 23762306a36Sopenharmony_ci * @adapter: pointer to the board struct 23862306a36Sopenharmony_ci * 23962306a36Sopenharmony_ci **/ 24062306a36Sopenharmony_cistatic 24162306a36Sopenharmony_civoid iavf_client_del_instance(struct iavf_adapter *adapter) 24262306a36Sopenharmony_ci{ 24362306a36Sopenharmony_ci kfree(adapter->cinst); 24462306a36Sopenharmony_ci adapter->cinst = NULL; 24562306a36Sopenharmony_ci} 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci/** 24862306a36Sopenharmony_ci * iavf_client_subtask - client maintenance work 24962306a36Sopenharmony_ci * @adapter: board private structure 25062306a36Sopenharmony_ci **/ 25162306a36Sopenharmony_civoid iavf_client_subtask(struct iavf_adapter *adapter) 25262306a36Sopenharmony_ci{ 25362306a36Sopenharmony_ci struct iavf_client *client = vf_registered_client; 25462306a36Sopenharmony_ci struct iavf_client_instance *cinst; 25562306a36Sopenharmony_ci int ret = 0; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci if (adapter->state < __IAVF_DOWN) 25862306a36Sopenharmony_ci return; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci /* first check client is registered */ 26162306a36Sopenharmony_ci if (!client) 26262306a36Sopenharmony_ci return; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci /* Add the client instance to the instance list */ 26562306a36Sopenharmony_ci cinst = iavf_client_add_instance(adapter); 26662306a36Sopenharmony_ci if (!cinst) 26762306a36Sopenharmony_ci return; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci dev_info(&adapter->pdev->dev, "Added instance of Client %s\n", 27062306a36Sopenharmony_ci client->name); 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci if (!test_bit(__IAVF_CLIENT_INSTANCE_OPENED, &cinst->state)) { 27362306a36Sopenharmony_ci /* Send an Open request to the client */ 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci if (client->ops && client->ops->open) 27662306a36Sopenharmony_ci ret = client->ops->open(&cinst->lan_info, client); 27762306a36Sopenharmony_ci if (!ret) 27862306a36Sopenharmony_ci set_bit(__IAVF_CLIENT_INSTANCE_OPENED, 27962306a36Sopenharmony_ci &cinst->state); 28062306a36Sopenharmony_ci else 28162306a36Sopenharmony_ci /* remove client instance */ 28262306a36Sopenharmony_ci iavf_client_del_instance(adapter); 28362306a36Sopenharmony_ci } 28462306a36Sopenharmony_ci} 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci/** 28762306a36Sopenharmony_ci * iavf_lan_add_device - add a lan device struct to the list of lan devices 28862306a36Sopenharmony_ci * @adapter: pointer to the board struct 28962306a36Sopenharmony_ci * 29062306a36Sopenharmony_ci * Returns 0 on success or none 0 on error 29162306a36Sopenharmony_ci **/ 29262306a36Sopenharmony_ciint iavf_lan_add_device(struct iavf_adapter *adapter) 29362306a36Sopenharmony_ci{ 29462306a36Sopenharmony_ci struct iavf_device *ldev; 29562306a36Sopenharmony_ci int ret = 0; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci mutex_lock(&iavf_device_mutex); 29862306a36Sopenharmony_ci list_for_each_entry(ldev, &iavf_devices, list) { 29962306a36Sopenharmony_ci if (ldev->vf == adapter) { 30062306a36Sopenharmony_ci ret = -EEXIST; 30162306a36Sopenharmony_ci goto out; 30262306a36Sopenharmony_ci } 30362306a36Sopenharmony_ci } 30462306a36Sopenharmony_ci ldev = kzalloc(sizeof(*ldev), GFP_KERNEL); 30562306a36Sopenharmony_ci if (!ldev) { 30662306a36Sopenharmony_ci ret = -ENOMEM; 30762306a36Sopenharmony_ci goto out; 30862306a36Sopenharmony_ci } 30962306a36Sopenharmony_ci ldev->vf = adapter; 31062306a36Sopenharmony_ci INIT_LIST_HEAD(&ldev->list); 31162306a36Sopenharmony_ci list_add(&ldev->list, &iavf_devices); 31262306a36Sopenharmony_ci dev_info(&adapter->pdev->dev, "Added LAN device bus=0x%02x dev=0x%02x func=0x%02x\n", 31362306a36Sopenharmony_ci adapter->hw.bus.bus_id, adapter->hw.bus.device, 31462306a36Sopenharmony_ci adapter->hw.bus.func); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci /* Since in some cases register may have happened before a device gets 31762306a36Sopenharmony_ci * added, we can schedule a subtask to go initiate the clients. 31862306a36Sopenharmony_ci */ 31962306a36Sopenharmony_ci adapter->flags |= IAVF_FLAG_SERVICE_CLIENT_REQUESTED; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ciout: 32262306a36Sopenharmony_ci mutex_unlock(&iavf_device_mutex); 32362306a36Sopenharmony_ci return ret; 32462306a36Sopenharmony_ci} 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci/** 32762306a36Sopenharmony_ci * iavf_lan_del_device - removes a lan device from the device list 32862306a36Sopenharmony_ci * @adapter: pointer to the board struct 32962306a36Sopenharmony_ci * 33062306a36Sopenharmony_ci * Returns 0 on success or non-0 on error 33162306a36Sopenharmony_ci **/ 33262306a36Sopenharmony_ciint iavf_lan_del_device(struct iavf_adapter *adapter) 33362306a36Sopenharmony_ci{ 33462306a36Sopenharmony_ci struct iavf_device *ldev, *tmp; 33562306a36Sopenharmony_ci int ret = -ENODEV; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci mutex_lock(&iavf_device_mutex); 33862306a36Sopenharmony_ci list_for_each_entry_safe(ldev, tmp, &iavf_devices, list) { 33962306a36Sopenharmony_ci if (ldev->vf == adapter) { 34062306a36Sopenharmony_ci dev_info(&adapter->pdev->dev, 34162306a36Sopenharmony_ci "Deleted LAN device bus=0x%02x dev=0x%02x func=0x%02x\n", 34262306a36Sopenharmony_ci adapter->hw.bus.bus_id, adapter->hw.bus.device, 34362306a36Sopenharmony_ci adapter->hw.bus.func); 34462306a36Sopenharmony_ci list_del(&ldev->list); 34562306a36Sopenharmony_ci kfree(ldev); 34662306a36Sopenharmony_ci ret = 0; 34762306a36Sopenharmony_ci break; 34862306a36Sopenharmony_ci } 34962306a36Sopenharmony_ci } 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci mutex_unlock(&iavf_device_mutex); 35262306a36Sopenharmony_ci return ret; 35362306a36Sopenharmony_ci} 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci/** 35662306a36Sopenharmony_ci * iavf_client_release - release client specific resources 35762306a36Sopenharmony_ci * @client: pointer to the registered client 35862306a36Sopenharmony_ci * 35962306a36Sopenharmony_ci **/ 36062306a36Sopenharmony_cistatic void iavf_client_release(struct iavf_client *client) 36162306a36Sopenharmony_ci{ 36262306a36Sopenharmony_ci struct iavf_client_instance *cinst; 36362306a36Sopenharmony_ci struct iavf_device *ldev; 36462306a36Sopenharmony_ci struct iavf_adapter *adapter; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci mutex_lock(&iavf_device_mutex); 36762306a36Sopenharmony_ci list_for_each_entry(ldev, &iavf_devices, list) { 36862306a36Sopenharmony_ci adapter = ldev->vf; 36962306a36Sopenharmony_ci cinst = adapter->cinst; 37062306a36Sopenharmony_ci if (!cinst) 37162306a36Sopenharmony_ci continue; 37262306a36Sopenharmony_ci if (test_bit(__IAVF_CLIENT_INSTANCE_OPENED, &cinst->state)) { 37362306a36Sopenharmony_ci if (client->ops && client->ops->close) 37462306a36Sopenharmony_ci client->ops->close(&cinst->lan_info, client, 37562306a36Sopenharmony_ci false); 37662306a36Sopenharmony_ci iavf_client_release_qvlist(&cinst->lan_info); 37762306a36Sopenharmony_ci clear_bit(__IAVF_CLIENT_INSTANCE_OPENED, &cinst->state); 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci dev_warn(&adapter->pdev->dev, 38062306a36Sopenharmony_ci "Client %s instance closed\n", client->name); 38162306a36Sopenharmony_ci } 38262306a36Sopenharmony_ci /* delete the client instance */ 38362306a36Sopenharmony_ci iavf_client_del_instance(adapter); 38462306a36Sopenharmony_ci dev_info(&adapter->pdev->dev, "Deleted client instance of Client %s\n", 38562306a36Sopenharmony_ci client->name); 38662306a36Sopenharmony_ci } 38762306a36Sopenharmony_ci mutex_unlock(&iavf_device_mutex); 38862306a36Sopenharmony_ci} 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci/** 39162306a36Sopenharmony_ci * iavf_client_prepare - prepare client specific resources 39262306a36Sopenharmony_ci * @client: pointer to the registered client 39362306a36Sopenharmony_ci * 39462306a36Sopenharmony_ci **/ 39562306a36Sopenharmony_cistatic void iavf_client_prepare(struct iavf_client *client) 39662306a36Sopenharmony_ci{ 39762306a36Sopenharmony_ci struct iavf_device *ldev; 39862306a36Sopenharmony_ci struct iavf_adapter *adapter; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci mutex_lock(&iavf_device_mutex); 40162306a36Sopenharmony_ci list_for_each_entry(ldev, &iavf_devices, list) { 40262306a36Sopenharmony_ci adapter = ldev->vf; 40362306a36Sopenharmony_ci /* Signal the watchdog to service the client */ 40462306a36Sopenharmony_ci adapter->flags |= IAVF_FLAG_SERVICE_CLIENT_REQUESTED; 40562306a36Sopenharmony_ci } 40662306a36Sopenharmony_ci mutex_unlock(&iavf_device_mutex); 40762306a36Sopenharmony_ci} 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci/** 41062306a36Sopenharmony_ci * iavf_client_virtchnl_send - send a message to the PF instance 41162306a36Sopenharmony_ci * @ldev: pointer to L2 context. 41262306a36Sopenharmony_ci * @client: Client pointer. 41362306a36Sopenharmony_ci * @msg: pointer to message buffer 41462306a36Sopenharmony_ci * @len: message length 41562306a36Sopenharmony_ci * 41662306a36Sopenharmony_ci * Return 0 on success or < 0 on error 41762306a36Sopenharmony_ci **/ 41862306a36Sopenharmony_cistatic u32 iavf_client_virtchnl_send(struct iavf_info *ldev, 41962306a36Sopenharmony_ci struct iavf_client *client, 42062306a36Sopenharmony_ci u8 *msg, u16 len) 42162306a36Sopenharmony_ci{ 42262306a36Sopenharmony_ci struct iavf_adapter *adapter = ldev->vf; 42362306a36Sopenharmony_ci enum iavf_status err; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci if (adapter->aq_required) 42662306a36Sopenharmony_ci return -EAGAIN; 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci err = iavf_aq_send_msg_to_pf(&adapter->hw, VIRTCHNL_OP_RDMA, 42962306a36Sopenharmony_ci IAVF_SUCCESS, msg, len, NULL); 43062306a36Sopenharmony_ci if (err) 43162306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, "Unable to send RDMA message to PF, error %d, aq status %d\n", 43262306a36Sopenharmony_ci err, adapter->hw.aq.asq_last_status); 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci return err; 43562306a36Sopenharmony_ci} 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci/** 43862306a36Sopenharmony_ci * iavf_client_setup_qvlist - send a message to the PF to setup rdma qv map 43962306a36Sopenharmony_ci * @ldev: pointer to L2 context. 44062306a36Sopenharmony_ci * @client: Client pointer. 44162306a36Sopenharmony_ci * @qvlist_info: queue and vector list 44262306a36Sopenharmony_ci * 44362306a36Sopenharmony_ci * Return 0 on success or < 0 on error 44462306a36Sopenharmony_ci **/ 44562306a36Sopenharmony_cistatic int iavf_client_setup_qvlist(struct iavf_info *ldev, 44662306a36Sopenharmony_ci struct iavf_client *client, 44762306a36Sopenharmony_ci struct iavf_qvlist_info *qvlist_info) 44862306a36Sopenharmony_ci{ 44962306a36Sopenharmony_ci struct virtchnl_rdma_qvlist_info *v_qvlist_info; 45062306a36Sopenharmony_ci struct iavf_adapter *adapter = ldev->vf; 45162306a36Sopenharmony_ci struct iavf_qv_info *qv_info; 45262306a36Sopenharmony_ci enum iavf_status err; 45362306a36Sopenharmony_ci u32 v_idx, i; 45462306a36Sopenharmony_ci size_t msg_size; 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci if (adapter->aq_required) 45762306a36Sopenharmony_ci return -EAGAIN; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci /* A quick check on whether the vectors belong to the client */ 46062306a36Sopenharmony_ci for (i = 0; i < qvlist_info->num_vectors; i++) { 46162306a36Sopenharmony_ci qv_info = &qvlist_info->qv_info[i]; 46262306a36Sopenharmony_ci if (!qv_info) 46362306a36Sopenharmony_ci continue; 46462306a36Sopenharmony_ci v_idx = qv_info->v_idx; 46562306a36Sopenharmony_ci if ((v_idx >= 46662306a36Sopenharmony_ci (adapter->rdma_base_vector + adapter->num_rdma_msix)) || 46762306a36Sopenharmony_ci (v_idx < adapter->rdma_base_vector)) 46862306a36Sopenharmony_ci return -EINVAL; 46962306a36Sopenharmony_ci } 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci v_qvlist_info = (struct virtchnl_rdma_qvlist_info *)qvlist_info; 47262306a36Sopenharmony_ci msg_size = virtchnl_struct_size(v_qvlist_info, qv_info, 47362306a36Sopenharmony_ci v_qvlist_info->num_vectors); 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci adapter->client_pending |= BIT(VIRTCHNL_OP_CONFIG_RDMA_IRQ_MAP); 47662306a36Sopenharmony_ci err = iavf_aq_send_msg_to_pf(&adapter->hw, 47762306a36Sopenharmony_ci VIRTCHNL_OP_CONFIG_RDMA_IRQ_MAP, IAVF_SUCCESS, 47862306a36Sopenharmony_ci (u8 *)v_qvlist_info, msg_size, NULL); 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci if (err) { 48162306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, 48262306a36Sopenharmony_ci "Unable to send RDMA vector config message to PF, error %d, aq status %d\n", 48362306a36Sopenharmony_ci err, adapter->hw.aq.asq_last_status); 48462306a36Sopenharmony_ci goto out; 48562306a36Sopenharmony_ci } 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci err = -EBUSY; 48862306a36Sopenharmony_ci for (i = 0; i < 5; i++) { 48962306a36Sopenharmony_ci msleep(100); 49062306a36Sopenharmony_ci if (!(adapter->client_pending & 49162306a36Sopenharmony_ci BIT(VIRTCHNL_OP_CONFIG_RDMA_IRQ_MAP))) { 49262306a36Sopenharmony_ci err = 0; 49362306a36Sopenharmony_ci break; 49462306a36Sopenharmony_ci } 49562306a36Sopenharmony_ci } 49662306a36Sopenharmony_ciout: 49762306a36Sopenharmony_ci return err; 49862306a36Sopenharmony_ci} 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci/** 50162306a36Sopenharmony_ci * iavf_register_client - Register a iavf client driver with the L2 driver 50262306a36Sopenharmony_ci * @client: pointer to the iavf_client struct 50362306a36Sopenharmony_ci * 50462306a36Sopenharmony_ci * Returns 0 on success or non-0 on error 50562306a36Sopenharmony_ci **/ 50662306a36Sopenharmony_ciint iavf_register_client(struct iavf_client *client) 50762306a36Sopenharmony_ci{ 50862306a36Sopenharmony_ci int ret = 0; 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci if (!client) { 51162306a36Sopenharmony_ci ret = -EIO; 51262306a36Sopenharmony_ci goto out; 51362306a36Sopenharmony_ci } 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci if (strlen(client->name) == 0) { 51662306a36Sopenharmony_ci pr_info("iavf: Failed to register client with no name\n"); 51762306a36Sopenharmony_ci ret = -EIO; 51862306a36Sopenharmony_ci goto out; 51962306a36Sopenharmony_ci } 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci if (vf_registered_client) { 52262306a36Sopenharmony_ci pr_info("iavf: Client %s has already been registered!\n", 52362306a36Sopenharmony_ci client->name); 52462306a36Sopenharmony_ci ret = -EEXIST; 52562306a36Sopenharmony_ci goto out; 52662306a36Sopenharmony_ci } 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci if ((client->version.major != IAVF_CLIENT_VERSION_MAJOR) || 52962306a36Sopenharmony_ci (client->version.minor != IAVF_CLIENT_VERSION_MINOR)) { 53062306a36Sopenharmony_ci pr_info("iavf: Failed to register client %s due to mismatched client interface version\n", 53162306a36Sopenharmony_ci client->name); 53262306a36Sopenharmony_ci pr_info("Client is using version: %02d.%02d.%02d while LAN driver supports %s\n", 53362306a36Sopenharmony_ci client->version.major, client->version.minor, 53462306a36Sopenharmony_ci client->version.build, 53562306a36Sopenharmony_ci iavf_client_interface_version_str); 53662306a36Sopenharmony_ci ret = -EIO; 53762306a36Sopenharmony_ci goto out; 53862306a36Sopenharmony_ci } 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci vf_registered_client = client; 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci iavf_client_prepare(client); 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci pr_info("iavf: Registered client %s with return code %d\n", 54562306a36Sopenharmony_ci client->name, ret); 54662306a36Sopenharmony_ciout: 54762306a36Sopenharmony_ci return ret; 54862306a36Sopenharmony_ci} 54962306a36Sopenharmony_ciEXPORT_SYMBOL(iavf_register_client); 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci/** 55262306a36Sopenharmony_ci * iavf_unregister_client - Unregister a iavf client driver with the L2 driver 55362306a36Sopenharmony_ci * @client: pointer to the iavf_client struct 55462306a36Sopenharmony_ci * 55562306a36Sopenharmony_ci * Returns 0 on success or non-0 on error 55662306a36Sopenharmony_ci **/ 55762306a36Sopenharmony_ciint iavf_unregister_client(struct iavf_client *client) 55862306a36Sopenharmony_ci{ 55962306a36Sopenharmony_ci int ret = 0; 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci /* When a unregister request comes through we would have to send 56262306a36Sopenharmony_ci * a close for each of the client instances that were opened. 56362306a36Sopenharmony_ci * client_release function is called to handle this. 56462306a36Sopenharmony_ci */ 56562306a36Sopenharmony_ci iavf_client_release(client); 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci if (vf_registered_client != client) { 56862306a36Sopenharmony_ci pr_info("iavf: Client %s has not been registered\n", 56962306a36Sopenharmony_ci client->name); 57062306a36Sopenharmony_ci ret = -ENODEV; 57162306a36Sopenharmony_ci goto out; 57262306a36Sopenharmony_ci } 57362306a36Sopenharmony_ci vf_registered_client = NULL; 57462306a36Sopenharmony_ci pr_info("iavf: Unregistered client %s\n", client->name); 57562306a36Sopenharmony_ciout: 57662306a36Sopenharmony_ci return ret; 57762306a36Sopenharmony_ci} 57862306a36Sopenharmony_ciEXPORT_SYMBOL(iavf_unregister_client); 579