|  | // SPDX-License-Identifier: GPL-2.0 or Linux-OpenIB | 
|  | /* Copyright (c) 2015 - 2021 Intel Corporation */ | 
|  | #include "main.h" | 
|  | #include "i40iw_hw.h" | 
|  | #include <linux/net/intel/i40e_client.h> | 
|  |  | 
|  | static struct i40e_client i40iw_client; | 
|  |  | 
|  | /** | 
|  | * i40iw_l2param_change - handle mss change | 
|  | * @cdev_info: parent lan device information structure with data/ops | 
|  | * @client: client for parameter change | 
|  | * @params: new parameters from L2 | 
|  | */ | 
|  | static void i40iw_l2param_change(struct i40e_info *cdev_info, | 
|  | struct i40e_client *client, | 
|  | struct i40e_params *params) | 
|  | { | 
|  | struct irdma_l2params l2params = {}; | 
|  | struct irdma_device *iwdev; | 
|  | struct ib_device *ibdev; | 
|  |  | 
|  | ibdev = ib_device_get_by_netdev(cdev_info->netdev, RDMA_DRIVER_IRDMA); | 
|  | if (!ibdev) | 
|  | return; | 
|  |  | 
|  | iwdev = to_iwdev(ibdev); | 
|  |  | 
|  | if (iwdev->vsi.mtu != params->mtu) { | 
|  | l2params.mtu_changed = true; | 
|  | l2params.mtu = params->mtu; | 
|  | } | 
|  | irdma_change_l2params(&iwdev->vsi, &l2params); | 
|  | ib_device_put(ibdev); | 
|  | } | 
|  |  | 
|  | /** | 
|  | * i40iw_close - client interface operation close for iwarp/uda device | 
|  | * @cdev_info: parent lan device information structure with data/ops | 
|  | * @client: client to close | 
|  | * @reset: flag to indicate close on reset | 
|  | * | 
|  | * Called by the lan driver during the processing of client unregister | 
|  | * Destroy and clean up the driver resources | 
|  | */ | 
|  | static void i40iw_close(struct i40e_info *cdev_info, struct i40e_client *client, | 
|  | bool reset) | 
|  | { | 
|  | struct irdma_device *iwdev; | 
|  | struct ib_device *ibdev; | 
|  |  | 
|  | ibdev = ib_device_get_by_netdev(cdev_info->netdev, RDMA_DRIVER_IRDMA); | 
|  | if (WARN_ON(!ibdev)) | 
|  | return; | 
|  |  | 
|  | iwdev = to_iwdev(ibdev); | 
|  | if (reset) | 
|  | iwdev->rf->reset = true; | 
|  |  | 
|  | iwdev->iw_status = 0; | 
|  | irdma_port_ibevent(iwdev); | 
|  | ib_unregister_device_and_put(ibdev); | 
|  | pr_debug("INIT: Gen1 PF[%d] close complete\n", PCI_FUNC(cdev_info->pcidev->devfn)); | 
|  | } | 
|  |  | 
|  | static void i40iw_request_reset(struct irdma_pci_f *rf) | 
|  | { | 
|  | struct i40e_info *cdev_info = rf->cdev; | 
|  |  | 
|  | cdev_info->ops->request_reset(cdev_info, &i40iw_client, 1); | 
|  | } | 
|  |  | 
|  | static void i40iw_fill_device_info(struct irdma_device *iwdev, struct i40e_info *cdev_info) | 
|  | { | 
|  | struct irdma_pci_f *rf = iwdev->rf; | 
|  |  | 
|  | rf->rdma_ver = IRDMA_GEN_1; | 
|  | rf->gen_ops.request_reset = i40iw_request_reset; | 
|  | rf->pcidev = cdev_info->pcidev; | 
|  | rf->pf_id = cdev_info->fid; | 
|  | rf->hw.hw_addr = cdev_info->hw_addr; | 
|  | rf->cdev = cdev_info; | 
|  | rf->msix_count = cdev_info->msix_count; | 
|  | rf->msix_entries = cdev_info->msix_entries; | 
|  | rf->limits_sel = 5; | 
|  | rf->protocol_used = IRDMA_IWARP_PROTOCOL_ONLY; | 
|  | rf->iwdev = iwdev; | 
|  |  | 
|  | iwdev->init_state = INITIAL_STATE; | 
|  | iwdev->rcv_wnd = IRDMA_CM_DEFAULT_RCV_WND_SCALED; | 
|  | iwdev->rcv_wscale = IRDMA_CM_DEFAULT_RCV_WND_SCALE; | 
|  | iwdev->netdev = cdev_info->netdev; | 
|  | iwdev->vsi_num = 0; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * i40iw_open - client interface operation open for iwarp/uda device | 
|  | * @cdev_info: parent lan device information structure with data/ops | 
|  | * @client: iwarp client information, provided during registration | 
|  | * | 
|  | * Called by the lan driver during the processing of client register | 
|  | * Create device resources, set up queues, pble and hmc objects and | 
|  | * register the device with the ib verbs interface | 
|  | * Return 0 if successful, otherwise return error | 
|  | */ | 
|  | static int i40iw_open(struct i40e_info *cdev_info, struct i40e_client *client) | 
|  | { | 
|  | struct irdma_l2params l2params = {}; | 
|  | struct irdma_device *iwdev; | 
|  | struct irdma_pci_f *rf; | 
|  | int err = -EIO; | 
|  | int i; | 
|  | u16 qset; | 
|  | u16 last_qset = IRDMA_NO_QSET; | 
|  |  | 
|  | iwdev = ib_alloc_device(irdma_device, ibdev); | 
|  | if (!iwdev) | 
|  | return -ENOMEM; | 
|  |  | 
|  | iwdev->rf = kzalloc(sizeof(*rf), GFP_KERNEL); | 
|  | if (!iwdev->rf) { | 
|  | ib_dealloc_device(&iwdev->ibdev); | 
|  | return -ENOMEM; | 
|  | } | 
|  |  | 
|  | i40iw_fill_device_info(iwdev, cdev_info); | 
|  | rf = iwdev->rf; | 
|  |  | 
|  | if (irdma_ctrl_init_hw(rf)) { | 
|  | err = -EIO; | 
|  | goto err_ctrl_init; | 
|  | } | 
|  |  | 
|  | l2params.mtu = (cdev_info->params.mtu) ? cdev_info->params.mtu : IRDMA_DEFAULT_MTU; | 
|  | for (i = 0; i < I40E_CLIENT_MAX_USER_PRIORITY; i++) { | 
|  | qset = cdev_info->params.qos.prio_qos[i].qs_handle; | 
|  | l2params.up2tc[i] = cdev_info->params.qos.prio_qos[i].tc; | 
|  | l2params.qs_handle_list[i] = qset; | 
|  | if (last_qset == IRDMA_NO_QSET) | 
|  | last_qset = qset; | 
|  | else if ((qset != last_qset) && (qset != IRDMA_NO_QSET)) | 
|  | iwdev->dcb_vlan_mode = true; | 
|  | } | 
|  |  | 
|  | if (irdma_rt_init_hw(iwdev, &l2params)) { | 
|  | err = -EIO; | 
|  | goto err_rt_init; | 
|  | } | 
|  |  | 
|  | err = irdma_ib_register_device(iwdev); | 
|  | if (err) | 
|  | goto err_ibreg; | 
|  |  | 
|  | ibdev_dbg(&iwdev->ibdev, "INIT: Gen1 PF[%d] open success\n", | 
|  | PCI_FUNC(rf->pcidev->devfn)); | 
|  |  | 
|  | return 0; | 
|  |  | 
|  | err_ibreg: | 
|  | irdma_rt_deinit_hw(iwdev); | 
|  | err_rt_init: | 
|  | irdma_ctrl_deinit_hw(rf); | 
|  | err_ctrl_init: | 
|  | kfree(iwdev->rf); | 
|  | ib_dealloc_device(&iwdev->ibdev); | 
|  |  | 
|  | return err; | 
|  | } | 
|  |  | 
|  | /* client interface functions */ | 
|  | static const struct i40e_client_ops i40e_ops = { | 
|  | .open = i40iw_open, | 
|  | .close = i40iw_close, | 
|  | .l2_param_change = i40iw_l2param_change | 
|  | }; | 
|  |  | 
|  | static struct i40e_client i40iw_client = { | 
|  | .ops = &i40e_ops, | 
|  | .type = I40E_CLIENT_IWARP, | 
|  | }; | 
|  |  | 
|  | static int i40iw_probe(struct auxiliary_device *aux_dev, const struct auxiliary_device_id *id) | 
|  | { | 
|  | struct i40e_auxiliary_device *i40e_adev = container_of(aux_dev, | 
|  | struct i40e_auxiliary_device, | 
|  | aux_dev); | 
|  | struct i40e_info *cdev_info = i40e_adev->ldev; | 
|  |  | 
|  | strncpy(i40iw_client.name, "irdma", I40E_CLIENT_STR_LENGTH); | 
|  | i40e_client_device_register(cdev_info, &i40iw_client); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static void i40iw_remove(struct auxiliary_device *aux_dev) | 
|  | { | 
|  | struct i40e_auxiliary_device *i40e_adev = container_of(aux_dev, | 
|  | struct i40e_auxiliary_device, | 
|  | aux_dev); | 
|  | struct i40e_info *cdev_info = i40e_adev->ldev; | 
|  |  | 
|  | i40e_client_device_unregister(cdev_info); | 
|  | } | 
|  |  | 
|  | static const struct auxiliary_device_id i40iw_auxiliary_id_table[] = { | 
|  | {.name = "i40e.iwarp", }, | 
|  | {}, | 
|  | }; | 
|  |  | 
|  | MODULE_DEVICE_TABLE(auxiliary, i40iw_auxiliary_id_table); | 
|  |  | 
|  | struct auxiliary_driver i40iw_auxiliary_drv = { | 
|  | .name = "gen_1", | 
|  | .id_table = i40iw_auxiliary_id_table, | 
|  | .probe = i40iw_probe, | 
|  | .remove = i40iw_remove, | 
|  | }; |