162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright (c) 2013, Cisco Systems, Inc. All rights reserved. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * This software is available to you under a choice of one of two 562306a36Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 662306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 762306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the 862306a36Sopenharmony_ci * BSD license below: 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or 1162306a36Sopenharmony_ci * without modification, are permitted provided that the following 1262306a36Sopenharmony_ci * conditions are met: 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * - Redistributions of source code must retain the above 1562306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 1662306a36Sopenharmony_ci * disclaimer. 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * - Redistributions in binary form must reproduce the above 1962306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 2062306a36Sopenharmony_ci * disclaimer in the documentation and/or other materials 2162306a36Sopenharmony_ci * provided with the distribution. 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 2462306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 2562306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 2662306a36Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 2762306a36Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 2862306a36Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 2962306a36Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 3062306a36Sopenharmony_ci * SOFTWARE. 3162306a36Sopenharmony_ci * 3262306a36Sopenharmony_ci * Author: Upinder Malhi <umalhi@cisco.com> 3362306a36Sopenharmony_ci * Author: Anant Deepak <anadeepa@cisco.com> 3462306a36Sopenharmony_ci * Author: Cesare Cantu' <cantuc@cisco.com> 3562306a36Sopenharmony_ci * Author: Jeff Squyres <jsquyres@cisco.com> 3662306a36Sopenharmony_ci * Author: Kiran Thirumalai <kithirum@cisco.com> 3762306a36Sopenharmony_ci * Author: Xuyang Wang <xuywang@cisco.com> 3862306a36Sopenharmony_ci * Author: Reese Faucette <rfaucett@cisco.com> 3962306a36Sopenharmony_ci * 4062306a36Sopenharmony_ci */ 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci#include <linux/module.h> 4362306a36Sopenharmony_ci#include <linux/inetdevice.h> 4462306a36Sopenharmony_ci#include <linux/init.h> 4562306a36Sopenharmony_ci#include <linux/slab.h> 4662306a36Sopenharmony_ci#include <linux/errno.h> 4762306a36Sopenharmony_ci#include <linux/pci.h> 4862306a36Sopenharmony_ci#include <linux/netdevice.h> 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci#include <rdma/ib_user_verbs.h> 5162306a36Sopenharmony_ci#include <rdma/ib_addr.h> 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci#include "usnic_abi.h" 5462306a36Sopenharmony_ci#include "usnic_common_util.h" 5562306a36Sopenharmony_ci#include "usnic_ib.h" 5662306a36Sopenharmony_ci#include "usnic_ib_qp_grp.h" 5762306a36Sopenharmony_ci#include "usnic_log.h" 5862306a36Sopenharmony_ci#include "usnic_fwd.h" 5962306a36Sopenharmony_ci#include "usnic_debugfs.h" 6062306a36Sopenharmony_ci#include "usnic_ib_verbs.h" 6162306a36Sopenharmony_ci#include "usnic_transport.h" 6262306a36Sopenharmony_ci#include "usnic_uiom.h" 6362306a36Sopenharmony_ci#include "usnic_ib_sysfs.h" 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ciunsigned int usnic_log_lvl = USNIC_LOG_LVL_ERR; 6662306a36Sopenharmony_ciunsigned int usnic_ib_share_vf = 1; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_cistatic const char usnic_version[] = 6962306a36Sopenharmony_ci DRV_NAME ": Cisco VIC (USNIC) Verbs Driver v" 7062306a36Sopenharmony_ci DRV_VERSION " (" DRV_RELDATE ")\n"; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistatic DEFINE_MUTEX(usnic_ib_ibdev_list_lock); 7362306a36Sopenharmony_cistatic LIST_HEAD(usnic_ib_ibdev_list); 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci/* Callback dump funcs */ 7662306a36Sopenharmony_cistatic int usnic_ib_dump_vf_hdr(void *obj, char *buf, int buf_sz) 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci struct usnic_ib_vf *vf = obj; 7962306a36Sopenharmony_ci return scnprintf(buf, buf_sz, "PF: %s ", dev_name(&vf->pf->ib_dev.dev)); 8062306a36Sopenharmony_ci} 8162306a36Sopenharmony_ci/* End callback dump funcs */ 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_cistatic void usnic_ib_dump_vf(struct usnic_ib_vf *vf, char *buf, int buf_sz) 8462306a36Sopenharmony_ci{ 8562306a36Sopenharmony_ci usnic_vnic_dump(vf->vnic, buf, buf_sz, vf, 8662306a36Sopenharmony_ci usnic_ib_dump_vf_hdr, 8762306a36Sopenharmony_ci usnic_ib_qp_grp_dump_hdr, usnic_ib_qp_grp_dump_rows); 8862306a36Sopenharmony_ci} 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_civoid usnic_ib_log_vf(struct usnic_ib_vf *vf) 9162306a36Sopenharmony_ci{ 9262306a36Sopenharmony_ci char *buf = kzalloc(1000, GFP_KERNEL); 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci if (!buf) 9562306a36Sopenharmony_ci return; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci usnic_ib_dump_vf(vf, buf, 1000); 9862306a36Sopenharmony_ci usnic_dbg("%s\n", buf); 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci kfree(buf); 10162306a36Sopenharmony_ci} 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci/* Start of netdev section */ 10462306a36Sopenharmony_cistatic void usnic_ib_qp_grp_modify_active_to_err(struct usnic_ib_dev *us_ibdev) 10562306a36Sopenharmony_ci{ 10662306a36Sopenharmony_ci struct usnic_ib_ucontext *ctx; 10762306a36Sopenharmony_ci struct usnic_ib_qp_grp *qp_grp; 10862306a36Sopenharmony_ci enum ib_qp_state cur_state; 10962306a36Sopenharmony_ci int status; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci BUG_ON(!mutex_is_locked(&us_ibdev->usdev_lock)); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci list_for_each_entry(ctx, &us_ibdev->ctx_list, link) { 11462306a36Sopenharmony_ci list_for_each_entry(qp_grp, &ctx->qp_grp_list, link) { 11562306a36Sopenharmony_ci cur_state = qp_grp->state; 11662306a36Sopenharmony_ci if (cur_state == IB_QPS_INIT || 11762306a36Sopenharmony_ci cur_state == IB_QPS_RTR || 11862306a36Sopenharmony_ci cur_state == IB_QPS_RTS) { 11962306a36Sopenharmony_ci status = usnic_ib_qp_grp_modify(qp_grp, 12062306a36Sopenharmony_ci IB_QPS_ERR, 12162306a36Sopenharmony_ci NULL); 12262306a36Sopenharmony_ci if (status) { 12362306a36Sopenharmony_ci usnic_err("Failed to transition qp grp %u from %s to %s\n", 12462306a36Sopenharmony_ci qp_grp->grp_id, 12562306a36Sopenharmony_ci usnic_ib_qp_grp_state_to_string 12662306a36Sopenharmony_ci (cur_state), 12762306a36Sopenharmony_ci usnic_ib_qp_grp_state_to_string 12862306a36Sopenharmony_ci (IB_QPS_ERR)); 12962306a36Sopenharmony_ci } 13062306a36Sopenharmony_ci } 13162306a36Sopenharmony_ci } 13262306a36Sopenharmony_ci } 13362306a36Sopenharmony_ci} 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_cistatic void usnic_ib_handle_usdev_event(struct usnic_ib_dev *us_ibdev, 13662306a36Sopenharmony_ci unsigned long event) 13762306a36Sopenharmony_ci{ 13862306a36Sopenharmony_ci struct net_device *netdev; 13962306a36Sopenharmony_ci struct ib_event ib_event; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci memset(&ib_event, 0, sizeof(ib_event)); 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci mutex_lock(&us_ibdev->usdev_lock); 14462306a36Sopenharmony_ci netdev = us_ibdev->netdev; 14562306a36Sopenharmony_ci switch (event) { 14662306a36Sopenharmony_ci case NETDEV_REBOOT: 14762306a36Sopenharmony_ci usnic_info("PF Reset on %s\n", dev_name(&us_ibdev->ib_dev.dev)); 14862306a36Sopenharmony_ci usnic_ib_qp_grp_modify_active_to_err(us_ibdev); 14962306a36Sopenharmony_ci ib_event.event = IB_EVENT_PORT_ERR; 15062306a36Sopenharmony_ci ib_event.device = &us_ibdev->ib_dev; 15162306a36Sopenharmony_ci ib_event.element.port_num = 1; 15262306a36Sopenharmony_ci ib_dispatch_event(&ib_event); 15362306a36Sopenharmony_ci break; 15462306a36Sopenharmony_ci case NETDEV_UP: 15562306a36Sopenharmony_ci case NETDEV_DOWN: 15662306a36Sopenharmony_ci case NETDEV_CHANGE: 15762306a36Sopenharmony_ci if (!us_ibdev->ufdev->link_up && 15862306a36Sopenharmony_ci netif_carrier_ok(netdev)) { 15962306a36Sopenharmony_ci usnic_fwd_carrier_up(us_ibdev->ufdev); 16062306a36Sopenharmony_ci usnic_info("Link UP on %s\n", 16162306a36Sopenharmony_ci dev_name(&us_ibdev->ib_dev.dev)); 16262306a36Sopenharmony_ci ib_event.event = IB_EVENT_PORT_ACTIVE; 16362306a36Sopenharmony_ci ib_event.device = &us_ibdev->ib_dev; 16462306a36Sopenharmony_ci ib_event.element.port_num = 1; 16562306a36Sopenharmony_ci ib_dispatch_event(&ib_event); 16662306a36Sopenharmony_ci } else if (us_ibdev->ufdev->link_up && 16762306a36Sopenharmony_ci !netif_carrier_ok(netdev)) { 16862306a36Sopenharmony_ci usnic_fwd_carrier_down(us_ibdev->ufdev); 16962306a36Sopenharmony_ci usnic_info("Link DOWN on %s\n", 17062306a36Sopenharmony_ci dev_name(&us_ibdev->ib_dev.dev)); 17162306a36Sopenharmony_ci usnic_ib_qp_grp_modify_active_to_err(us_ibdev); 17262306a36Sopenharmony_ci ib_event.event = IB_EVENT_PORT_ERR; 17362306a36Sopenharmony_ci ib_event.device = &us_ibdev->ib_dev; 17462306a36Sopenharmony_ci ib_event.element.port_num = 1; 17562306a36Sopenharmony_ci ib_dispatch_event(&ib_event); 17662306a36Sopenharmony_ci } else { 17762306a36Sopenharmony_ci usnic_dbg("Ignoring %s on %s\n", 17862306a36Sopenharmony_ci netdev_cmd_to_name(event), 17962306a36Sopenharmony_ci dev_name(&us_ibdev->ib_dev.dev)); 18062306a36Sopenharmony_ci } 18162306a36Sopenharmony_ci break; 18262306a36Sopenharmony_ci case NETDEV_CHANGEADDR: 18362306a36Sopenharmony_ci if (!memcmp(us_ibdev->ufdev->mac, netdev->dev_addr, 18462306a36Sopenharmony_ci sizeof(us_ibdev->ufdev->mac))) { 18562306a36Sopenharmony_ci usnic_dbg("Ignoring addr change on %s\n", 18662306a36Sopenharmony_ci dev_name(&us_ibdev->ib_dev.dev)); 18762306a36Sopenharmony_ci } else { 18862306a36Sopenharmony_ci usnic_info(" %s old mac: %pM new mac: %pM\n", 18962306a36Sopenharmony_ci dev_name(&us_ibdev->ib_dev.dev), 19062306a36Sopenharmony_ci us_ibdev->ufdev->mac, 19162306a36Sopenharmony_ci netdev->dev_addr); 19262306a36Sopenharmony_ci usnic_fwd_set_mac(us_ibdev->ufdev, netdev->dev_addr); 19362306a36Sopenharmony_ci usnic_ib_qp_grp_modify_active_to_err(us_ibdev); 19462306a36Sopenharmony_ci ib_event.event = IB_EVENT_GID_CHANGE; 19562306a36Sopenharmony_ci ib_event.device = &us_ibdev->ib_dev; 19662306a36Sopenharmony_ci ib_event.element.port_num = 1; 19762306a36Sopenharmony_ci ib_dispatch_event(&ib_event); 19862306a36Sopenharmony_ci } 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci break; 20162306a36Sopenharmony_ci case NETDEV_CHANGEMTU: 20262306a36Sopenharmony_ci if (us_ibdev->ufdev->mtu != netdev->mtu) { 20362306a36Sopenharmony_ci usnic_info("MTU Change on %s old: %u new: %u\n", 20462306a36Sopenharmony_ci dev_name(&us_ibdev->ib_dev.dev), 20562306a36Sopenharmony_ci us_ibdev->ufdev->mtu, netdev->mtu); 20662306a36Sopenharmony_ci usnic_fwd_set_mtu(us_ibdev->ufdev, netdev->mtu); 20762306a36Sopenharmony_ci usnic_ib_qp_grp_modify_active_to_err(us_ibdev); 20862306a36Sopenharmony_ci } else { 20962306a36Sopenharmony_ci usnic_dbg("Ignoring MTU change on %s\n", 21062306a36Sopenharmony_ci dev_name(&us_ibdev->ib_dev.dev)); 21162306a36Sopenharmony_ci } 21262306a36Sopenharmony_ci break; 21362306a36Sopenharmony_ci default: 21462306a36Sopenharmony_ci usnic_dbg("Ignoring event %s on %s", 21562306a36Sopenharmony_ci netdev_cmd_to_name(event), 21662306a36Sopenharmony_ci dev_name(&us_ibdev->ib_dev.dev)); 21762306a36Sopenharmony_ci } 21862306a36Sopenharmony_ci mutex_unlock(&us_ibdev->usdev_lock); 21962306a36Sopenharmony_ci} 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_cistatic int usnic_ib_netdevice_event(struct notifier_block *notifier, 22262306a36Sopenharmony_ci unsigned long event, void *ptr) 22362306a36Sopenharmony_ci{ 22462306a36Sopenharmony_ci struct usnic_ib_dev *us_ibdev; 22562306a36Sopenharmony_ci struct ib_device *ibdev; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci struct net_device *netdev = netdev_notifier_info_to_dev(ptr); 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci ibdev = ib_device_get_by_netdev(netdev, RDMA_DRIVER_USNIC); 23062306a36Sopenharmony_ci if (!ibdev) 23162306a36Sopenharmony_ci return NOTIFY_DONE; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci us_ibdev = container_of(ibdev, struct usnic_ib_dev, ib_dev); 23462306a36Sopenharmony_ci usnic_ib_handle_usdev_event(us_ibdev, event); 23562306a36Sopenharmony_ci ib_device_put(ibdev); 23662306a36Sopenharmony_ci return NOTIFY_DONE; 23762306a36Sopenharmony_ci} 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_cistatic struct notifier_block usnic_ib_netdevice_notifier = { 24062306a36Sopenharmony_ci .notifier_call = usnic_ib_netdevice_event 24162306a36Sopenharmony_ci}; 24262306a36Sopenharmony_ci/* End of netdev section */ 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci/* Start of inet section */ 24562306a36Sopenharmony_cistatic int usnic_ib_handle_inet_event(struct usnic_ib_dev *us_ibdev, 24662306a36Sopenharmony_ci unsigned long event, void *ptr) 24762306a36Sopenharmony_ci{ 24862306a36Sopenharmony_ci struct in_ifaddr *ifa = ptr; 24962306a36Sopenharmony_ci struct ib_event ib_event; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci mutex_lock(&us_ibdev->usdev_lock); 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci switch (event) { 25462306a36Sopenharmony_ci case NETDEV_DOWN: 25562306a36Sopenharmony_ci usnic_info("%s via ip notifiers", 25662306a36Sopenharmony_ci netdev_cmd_to_name(event)); 25762306a36Sopenharmony_ci usnic_fwd_del_ipaddr(us_ibdev->ufdev); 25862306a36Sopenharmony_ci usnic_ib_qp_grp_modify_active_to_err(us_ibdev); 25962306a36Sopenharmony_ci ib_event.event = IB_EVENT_GID_CHANGE; 26062306a36Sopenharmony_ci ib_event.device = &us_ibdev->ib_dev; 26162306a36Sopenharmony_ci ib_event.element.port_num = 1; 26262306a36Sopenharmony_ci ib_dispatch_event(&ib_event); 26362306a36Sopenharmony_ci break; 26462306a36Sopenharmony_ci case NETDEV_UP: 26562306a36Sopenharmony_ci usnic_fwd_add_ipaddr(us_ibdev->ufdev, ifa->ifa_address); 26662306a36Sopenharmony_ci usnic_info("%s via ip notifiers: ip %pI4", 26762306a36Sopenharmony_ci netdev_cmd_to_name(event), 26862306a36Sopenharmony_ci &us_ibdev->ufdev->inaddr); 26962306a36Sopenharmony_ci ib_event.event = IB_EVENT_GID_CHANGE; 27062306a36Sopenharmony_ci ib_event.device = &us_ibdev->ib_dev; 27162306a36Sopenharmony_ci ib_event.element.port_num = 1; 27262306a36Sopenharmony_ci ib_dispatch_event(&ib_event); 27362306a36Sopenharmony_ci break; 27462306a36Sopenharmony_ci default: 27562306a36Sopenharmony_ci usnic_info("Ignoring event %s on %s", 27662306a36Sopenharmony_ci netdev_cmd_to_name(event), 27762306a36Sopenharmony_ci dev_name(&us_ibdev->ib_dev.dev)); 27862306a36Sopenharmony_ci } 27962306a36Sopenharmony_ci mutex_unlock(&us_ibdev->usdev_lock); 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci return NOTIFY_DONE; 28262306a36Sopenharmony_ci} 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_cistatic int usnic_ib_inetaddr_event(struct notifier_block *notifier, 28562306a36Sopenharmony_ci unsigned long event, void *ptr) 28662306a36Sopenharmony_ci{ 28762306a36Sopenharmony_ci struct usnic_ib_dev *us_ibdev; 28862306a36Sopenharmony_ci struct in_ifaddr *ifa = ptr; 28962306a36Sopenharmony_ci struct net_device *netdev = ifa->ifa_dev->dev; 29062306a36Sopenharmony_ci struct ib_device *ibdev; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci ibdev = ib_device_get_by_netdev(netdev, RDMA_DRIVER_USNIC); 29362306a36Sopenharmony_ci if (!ibdev) 29462306a36Sopenharmony_ci return NOTIFY_DONE; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci us_ibdev = container_of(ibdev, struct usnic_ib_dev, ib_dev); 29762306a36Sopenharmony_ci usnic_ib_handle_inet_event(us_ibdev, event, ptr); 29862306a36Sopenharmony_ci ib_device_put(ibdev); 29962306a36Sopenharmony_ci return NOTIFY_DONE; 30062306a36Sopenharmony_ci} 30162306a36Sopenharmony_cistatic struct notifier_block usnic_ib_inetaddr_notifier = { 30262306a36Sopenharmony_ci .notifier_call = usnic_ib_inetaddr_event 30362306a36Sopenharmony_ci}; 30462306a36Sopenharmony_ci/* End of inet section*/ 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_cistatic int usnic_port_immutable(struct ib_device *ibdev, u32 port_num, 30762306a36Sopenharmony_ci struct ib_port_immutable *immutable) 30862306a36Sopenharmony_ci{ 30962306a36Sopenharmony_ci struct ib_port_attr attr; 31062306a36Sopenharmony_ci int err; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci immutable->core_cap_flags = RDMA_CORE_PORT_USNIC; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci err = ib_query_port(ibdev, port_num, &attr); 31562306a36Sopenharmony_ci if (err) 31662306a36Sopenharmony_ci return err; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci immutable->gid_tbl_len = attr.gid_tbl_len; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci return 0; 32162306a36Sopenharmony_ci} 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_cistatic void usnic_get_dev_fw_str(struct ib_device *device, char *str) 32462306a36Sopenharmony_ci{ 32562306a36Sopenharmony_ci struct usnic_ib_dev *us_ibdev = 32662306a36Sopenharmony_ci container_of(device, struct usnic_ib_dev, ib_dev); 32762306a36Sopenharmony_ci struct ethtool_drvinfo info; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci mutex_lock(&us_ibdev->usdev_lock); 33062306a36Sopenharmony_ci us_ibdev->netdev->ethtool_ops->get_drvinfo(us_ibdev->netdev, &info); 33162306a36Sopenharmony_ci mutex_unlock(&us_ibdev->usdev_lock); 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci snprintf(str, IB_FW_VERSION_NAME_MAX, "%s", info.fw_version); 33462306a36Sopenharmony_ci} 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_cistatic const struct ib_device_ops usnic_dev_ops = { 33762306a36Sopenharmony_ci .owner = THIS_MODULE, 33862306a36Sopenharmony_ci .driver_id = RDMA_DRIVER_USNIC, 33962306a36Sopenharmony_ci .uverbs_abi_ver = USNIC_UVERBS_ABI_VERSION, 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci .alloc_pd = usnic_ib_alloc_pd, 34262306a36Sopenharmony_ci .alloc_ucontext = usnic_ib_alloc_ucontext, 34362306a36Sopenharmony_ci .create_cq = usnic_ib_create_cq, 34462306a36Sopenharmony_ci .create_qp = usnic_ib_create_qp, 34562306a36Sopenharmony_ci .dealloc_pd = usnic_ib_dealloc_pd, 34662306a36Sopenharmony_ci .dealloc_ucontext = usnic_ib_dealloc_ucontext, 34762306a36Sopenharmony_ci .dereg_mr = usnic_ib_dereg_mr, 34862306a36Sopenharmony_ci .destroy_cq = usnic_ib_destroy_cq, 34962306a36Sopenharmony_ci .destroy_qp = usnic_ib_destroy_qp, 35062306a36Sopenharmony_ci .device_group = &usnic_attr_group, 35162306a36Sopenharmony_ci .get_dev_fw_str = usnic_get_dev_fw_str, 35262306a36Sopenharmony_ci .get_link_layer = usnic_ib_port_link_layer, 35362306a36Sopenharmony_ci .get_port_immutable = usnic_port_immutable, 35462306a36Sopenharmony_ci .mmap = usnic_ib_mmap, 35562306a36Sopenharmony_ci .modify_qp = usnic_ib_modify_qp, 35662306a36Sopenharmony_ci .query_device = usnic_ib_query_device, 35762306a36Sopenharmony_ci .query_gid = usnic_ib_query_gid, 35862306a36Sopenharmony_ci .query_port = usnic_ib_query_port, 35962306a36Sopenharmony_ci .query_qp = usnic_ib_query_qp, 36062306a36Sopenharmony_ci .reg_user_mr = usnic_ib_reg_mr, 36162306a36Sopenharmony_ci INIT_RDMA_OBJ_SIZE(ib_pd, usnic_ib_pd, ibpd), 36262306a36Sopenharmony_ci INIT_RDMA_OBJ_SIZE(ib_cq, usnic_ib_cq, ibcq), 36362306a36Sopenharmony_ci INIT_RDMA_OBJ_SIZE(ib_qp, usnic_ib_qp_grp, ibqp), 36462306a36Sopenharmony_ci INIT_RDMA_OBJ_SIZE(ib_ucontext, usnic_ib_ucontext, ibucontext), 36562306a36Sopenharmony_ci}; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci/* Start of PF discovery section */ 36862306a36Sopenharmony_cistatic void *usnic_ib_device_add(struct pci_dev *dev) 36962306a36Sopenharmony_ci{ 37062306a36Sopenharmony_ci struct usnic_ib_dev *us_ibdev; 37162306a36Sopenharmony_ci union ib_gid gid; 37262306a36Sopenharmony_ci struct in_device *ind; 37362306a36Sopenharmony_ci struct net_device *netdev; 37462306a36Sopenharmony_ci int ret; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci usnic_dbg("\n"); 37762306a36Sopenharmony_ci netdev = pci_get_drvdata(dev); 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci us_ibdev = ib_alloc_device(usnic_ib_dev, ib_dev); 38062306a36Sopenharmony_ci if (!us_ibdev) { 38162306a36Sopenharmony_ci usnic_err("Device %s context alloc failed\n", 38262306a36Sopenharmony_ci netdev_name(pci_get_drvdata(dev))); 38362306a36Sopenharmony_ci return ERR_PTR(-EFAULT); 38462306a36Sopenharmony_ci } 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci us_ibdev->ufdev = usnic_fwd_dev_alloc(dev); 38762306a36Sopenharmony_ci if (!us_ibdev->ufdev) { 38862306a36Sopenharmony_ci usnic_err("Failed to alloc ufdev for %s\n", pci_name(dev)); 38962306a36Sopenharmony_ci goto err_dealloc; 39062306a36Sopenharmony_ci } 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci mutex_init(&us_ibdev->usdev_lock); 39362306a36Sopenharmony_ci INIT_LIST_HEAD(&us_ibdev->vf_dev_list); 39462306a36Sopenharmony_ci INIT_LIST_HEAD(&us_ibdev->ctx_list); 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci us_ibdev->pdev = dev; 39762306a36Sopenharmony_ci us_ibdev->netdev = pci_get_drvdata(dev); 39862306a36Sopenharmony_ci us_ibdev->ib_dev.node_type = RDMA_NODE_USNIC_UDP; 39962306a36Sopenharmony_ci us_ibdev->ib_dev.phys_port_cnt = USNIC_IB_PORT_CNT; 40062306a36Sopenharmony_ci us_ibdev->ib_dev.num_comp_vectors = USNIC_IB_NUM_COMP_VECTORS; 40162306a36Sopenharmony_ci us_ibdev->ib_dev.dev.parent = &dev->dev; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci ib_set_device_ops(&us_ibdev->ib_dev, &usnic_dev_ops); 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci ret = ib_device_set_netdev(&us_ibdev->ib_dev, us_ibdev->netdev, 1); 40662306a36Sopenharmony_ci if (ret) 40762306a36Sopenharmony_ci goto err_fwd_dealloc; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci dma_set_max_seg_size(&dev->dev, SZ_2G); 41062306a36Sopenharmony_ci if (ib_register_device(&us_ibdev->ib_dev, "usnic_%d", &dev->dev)) 41162306a36Sopenharmony_ci goto err_fwd_dealloc; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci usnic_fwd_set_mtu(us_ibdev->ufdev, us_ibdev->netdev->mtu); 41462306a36Sopenharmony_ci usnic_fwd_set_mac(us_ibdev->ufdev, us_ibdev->netdev->dev_addr); 41562306a36Sopenharmony_ci if (netif_carrier_ok(us_ibdev->netdev)) 41662306a36Sopenharmony_ci usnic_fwd_carrier_up(us_ibdev->ufdev); 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci rcu_read_lock(); 41962306a36Sopenharmony_ci ind = __in_dev_get_rcu(netdev); 42062306a36Sopenharmony_ci if (ind) { 42162306a36Sopenharmony_ci const struct in_ifaddr *ifa; 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci ifa = rcu_dereference(ind->ifa_list); 42462306a36Sopenharmony_ci if (ifa) 42562306a36Sopenharmony_ci usnic_fwd_add_ipaddr(us_ibdev->ufdev, ifa->ifa_address); 42662306a36Sopenharmony_ci } 42762306a36Sopenharmony_ci rcu_read_unlock(); 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci usnic_mac_ip_to_gid(us_ibdev->netdev->perm_addr, 43062306a36Sopenharmony_ci us_ibdev->ufdev->inaddr, &gid.raw[0]); 43162306a36Sopenharmony_ci memcpy(&us_ibdev->ib_dev.node_guid, &gid.global.interface_id, 43262306a36Sopenharmony_ci sizeof(gid.global.interface_id)); 43362306a36Sopenharmony_ci kref_init(&us_ibdev->vf_cnt); 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci usnic_info("Added ibdev: %s netdev: %s with mac %pM Link: %u MTU: %u\n", 43662306a36Sopenharmony_ci dev_name(&us_ibdev->ib_dev.dev), 43762306a36Sopenharmony_ci netdev_name(us_ibdev->netdev), us_ibdev->ufdev->mac, 43862306a36Sopenharmony_ci us_ibdev->ufdev->link_up, us_ibdev->ufdev->mtu); 43962306a36Sopenharmony_ci return us_ibdev; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_cierr_fwd_dealloc: 44262306a36Sopenharmony_ci usnic_fwd_dev_free(us_ibdev->ufdev); 44362306a36Sopenharmony_cierr_dealloc: 44462306a36Sopenharmony_ci usnic_err("failed -- deallocing device\n"); 44562306a36Sopenharmony_ci ib_dealloc_device(&us_ibdev->ib_dev); 44662306a36Sopenharmony_ci return NULL; 44762306a36Sopenharmony_ci} 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_cistatic void usnic_ib_device_remove(struct usnic_ib_dev *us_ibdev) 45062306a36Sopenharmony_ci{ 45162306a36Sopenharmony_ci usnic_info("Unregistering %s\n", dev_name(&us_ibdev->ib_dev.dev)); 45262306a36Sopenharmony_ci usnic_ib_sysfs_unregister_usdev(us_ibdev); 45362306a36Sopenharmony_ci usnic_fwd_dev_free(us_ibdev->ufdev); 45462306a36Sopenharmony_ci ib_unregister_device(&us_ibdev->ib_dev); 45562306a36Sopenharmony_ci ib_dealloc_device(&us_ibdev->ib_dev); 45662306a36Sopenharmony_ci} 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_cistatic void usnic_ib_undiscover_pf(struct kref *kref) 45962306a36Sopenharmony_ci{ 46062306a36Sopenharmony_ci struct usnic_ib_dev *us_ibdev, *tmp; 46162306a36Sopenharmony_ci struct pci_dev *dev; 46262306a36Sopenharmony_ci bool found = false; 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci dev = container_of(kref, struct usnic_ib_dev, vf_cnt)->pdev; 46562306a36Sopenharmony_ci mutex_lock(&usnic_ib_ibdev_list_lock); 46662306a36Sopenharmony_ci list_for_each_entry_safe(us_ibdev, tmp, 46762306a36Sopenharmony_ci &usnic_ib_ibdev_list, ib_dev_link) { 46862306a36Sopenharmony_ci if (us_ibdev->pdev == dev) { 46962306a36Sopenharmony_ci list_del(&us_ibdev->ib_dev_link); 47062306a36Sopenharmony_ci found = true; 47162306a36Sopenharmony_ci break; 47262306a36Sopenharmony_ci } 47362306a36Sopenharmony_ci } 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci mutex_unlock(&usnic_ib_ibdev_list_lock); 47762306a36Sopenharmony_ci if (found) 47862306a36Sopenharmony_ci usnic_ib_device_remove(us_ibdev); 47962306a36Sopenharmony_ci else 48062306a36Sopenharmony_ci WARN(1, "Failed to remove PF %s\n", pci_name(dev)); 48162306a36Sopenharmony_ci} 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_cistatic struct usnic_ib_dev *usnic_ib_discover_pf(struct usnic_vnic *vnic) 48462306a36Sopenharmony_ci{ 48562306a36Sopenharmony_ci struct usnic_ib_dev *us_ibdev; 48662306a36Sopenharmony_ci struct pci_dev *parent_pci, *vf_pci; 48762306a36Sopenharmony_ci int err; 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci vf_pci = usnic_vnic_get_pdev(vnic); 49062306a36Sopenharmony_ci parent_pci = pci_physfn(vf_pci); 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci BUG_ON(!parent_pci); 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci mutex_lock(&usnic_ib_ibdev_list_lock); 49562306a36Sopenharmony_ci list_for_each_entry(us_ibdev, &usnic_ib_ibdev_list, ib_dev_link) { 49662306a36Sopenharmony_ci if (us_ibdev->pdev == parent_pci) { 49762306a36Sopenharmony_ci kref_get(&us_ibdev->vf_cnt); 49862306a36Sopenharmony_ci goto out; 49962306a36Sopenharmony_ci } 50062306a36Sopenharmony_ci } 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci us_ibdev = usnic_ib_device_add(parent_pci); 50362306a36Sopenharmony_ci if (IS_ERR_OR_NULL(us_ibdev)) { 50462306a36Sopenharmony_ci us_ibdev = us_ibdev ? us_ibdev : ERR_PTR(-EFAULT); 50562306a36Sopenharmony_ci goto out; 50662306a36Sopenharmony_ci } 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci err = usnic_ib_sysfs_register_usdev(us_ibdev); 50962306a36Sopenharmony_ci if (err) { 51062306a36Sopenharmony_ci usnic_ib_device_remove(us_ibdev); 51162306a36Sopenharmony_ci us_ibdev = ERR_PTR(err); 51262306a36Sopenharmony_ci goto out; 51362306a36Sopenharmony_ci } 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci list_add(&us_ibdev->ib_dev_link, &usnic_ib_ibdev_list); 51662306a36Sopenharmony_ciout: 51762306a36Sopenharmony_ci mutex_unlock(&usnic_ib_ibdev_list_lock); 51862306a36Sopenharmony_ci return us_ibdev; 51962306a36Sopenharmony_ci} 52062306a36Sopenharmony_ci/* End of PF discovery section */ 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci/* Start of PCI section */ 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_cistatic const struct pci_device_id usnic_ib_pci_ids[] = { 52562306a36Sopenharmony_ci {PCI_DEVICE(PCI_VENDOR_ID_CISCO, PCI_DEVICE_ID_CISCO_VIC_USPACE_NIC)}, 52662306a36Sopenharmony_ci {0,} 52762306a36Sopenharmony_ci}; 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_cistatic int usnic_ib_pci_probe(struct pci_dev *pdev, 53062306a36Sopenharmony_ci const struct pci_device_id *id) 53162306a36Sopenharmony_ci{ 53262306a36Sopenharmony_ci int err; 53362306a36Sopenharmony_ci struct usnic_ib_dev *pf; 53462306a36Sopenharmony_ci struct usnic_ib_vf *vf; 53562306a36Sopenharmony_ci enum usnic_vnic_res_type res_type; 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci if (!device_iommu_mapped(&pdev->dev)) { 53862306a36Sopenharmony_ci usnic_err("IOMMU required but not present or enabled. USNIC QPs will not function w/o enabling IOMMU\n"); 53962306a36Sopenharmony_ci return -EPERM; 54062306a36Sopenharmony_ci } 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci vf = kzalloc(sizeof(*vf), GFP_KERNEL); 54362306a36Sopenharmony_ci if (!vf) 54462306a36Sopenharmony_ci return -ENOMEM; 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci err = pci_enable_device(pdev); 54762306a36Sopenharmony_ci if (err) { 54862306a36Sopenharmony_ci usnic_err("Failed to enable %s with err %d\n", 54962306a36Sopenharmony_ci pci_name(pdev), err); 55062306a36Sopenharmony_ci goto out_clean_vf; 55162306a36Sopenharmony_ci } 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci err = pci_request_regions(pdev, DRV_NAME); 55462306a36Sopenharmony_ci if (err) { 55562306a36Sopenharmony_ci usnic_err("Failed to request region for %s with err %d\n", 55662306a36Sopenharmony_ci pci_name(pdev), err); 55762306a36Sopenharmony_ci goto out_disable_device; 55862306a36Sopenharmony_ci } 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci pci_set_master(pdev); 56162306a36Sopenharmony_ci pci_set_drvdata(pdev, vf); 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci vf->vnic = usnic_vnic_alloc(pdev); 56462306a36Sopenharmony_ci if (IS_ERR_OR_NULL(vf->vnic)) { 56562306a36Sopenharmony_ci err = vf->vnic ? PTR_ERR(vf->vnic) : -ENOMEM; 56662306a36Sopenharmony_ci usnic_err("Failed to alloc vnic for %s with err %d\n", 56762306a36Sopenharmony_ci pci_name(pdev), err); 56862306a36Sopenharmony_ci goto out_release_regions; 56962306a36Sopenharmony_ci } 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci pf = usnic_ib_discover_pf(vf->vnic); 57262306a36Sopenharmony_ci if (IS_ERR_OR_NULL(pf)) { 57362306a36Sopenharmony_ci usnic_err("Failed to discover pf of vnic %s with err%ld\n", 57462306a36Sopenharmony_ci pci_name(pdev), PTR_ERR(pf)); 57562306a36Sopenharmony_ci err = pf ? PTR_ERR(pf) : -EFAULT; 57662306a36Sopenharmony_ci goto out_clean_vnic; 57762306a36Sopenharmony_ci } 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci vf->pf = pf; 58062306a36Sopenharmony_ci mutex_init(&vf->lock); 58162306a36Sopenharmony_ci mutex_lock(&pf->usdev_lock); 58262306a36Sopenharmony_ci list_add_tail(&vf->link, &pf->vf_dev_list); 58362306a36Sopenharmony_ci /* 58462306a36Sopenharmony_ci * Save max settings (will be same for each VF, easier to re-write than 58562306a36Sopenharmony_ci * to say "if (!set) { set_values(); set=1; } 58662306a36Sopenharmony_ci */ 58762306a36Sopenharmony_ci for (res_type = USNIC_VNIC_RES_TYPE_EOL+1; 58862306a36Sopenharmony_ci res_type < USNIC_VNIC_RES_TYPE_MAX; 58962306a36Sopenharmony_ci res_type++) { 59062306a36Sopenharmony_ci pf->vf_res_cnt[res_type] = usnic_vnic_res_cnt(vf->vnic, 59162306a36Sopenharmony_ci res_type); 59262306a36Sopenharmony_ci } 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci mutex_unlock(&pf->usdev_lock); 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci usnic_info("Registering usnic VF %s into PF %s\n", pci_name(pdev), 59762306a36Sopenharmony_ci dev_name(&pf->ib_dev.dev)); 59862306a36Sopenharmony_ci usnic_ib_log_vf(vf); 59962306a36Sopenharmony_ci return 0; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ciout_clean_vnic: 60262306a36Sopenharmony_ci usnic_vnic_free(vf->vnic); 60362306a36Sopenharmony_ciout_release_regions: 60462306a36Sopenharmony_ci pci_set_drvdata(pdev, NULL); 60562306a36Sopenharmony_ci pci_release_regions(pdev); 60662306a36Sopenharmony_ciout_disable_device: 60762306a36Sopenharmony_ci pci_disable_device(pdev); 60862306a36Sopenharmony_ciout_clean_vf: 60962306a36Sopenharmony_ci kfree(vf); 61062306a36Sopenharmony_ci return err; 61162306a36Sopenharmony_ci} 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_cistatic void usnic_ib_pci_remove(struct pci_dev *pdev) 61462306a36Sopenharmony_ci{ 61562306a36Sopenharmony_ci struct usnic_ib_vf *vf = pci_get_drvdata(pdev); 61662306a36Sopenharmony_ci struct usnic_ib_dev *pf = vf->pf; 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci mutex_lock(&pf->usdev_lock); 61962306a36Sopenharmony_ci list_del(&vf->link); 62062306a36Sopenharmony_ci mutex_unlock(&pf->usdev_lock); 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci kref_put(&pf->vf_cnt, usnic_ib_undiscover_pf); 62362306a36Sopenharmony_ci usnic_vnic_free(vf->vnic); 62462306a36Sopenharmony_ci pci_set_drvdata(pdev, NULL); 62562306a36Sopenharmony_ci pci_release_regions(pdev); 62662306a36Sopenharmony_ci pci_disable_device(pdev); 62762306a36Sopenharmony_ci kfree(vf); 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci usnic_info("Removed VF %s\n", pci_name(pdev)); 63062306a36Sopenharmony_ci} 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci/* PCI driver entry points */ 63362306a36Sopenharmony_cistatic struct pci_driver usnic_ib_pci_driver = { 63462306a36Sopenharmony_ci .name = DRV_NAME, 63562306a36Sopenharmony_ci .id_table = usnic_ib_pci_ids, 63662306a36Sopenharmony_ci .probe = usnic_ib_pci_probe, 63762306a36Sopenharmony_ci .remove = usnic_ib_pci_remove, 63862306a36Sopenharmony_ci}; 63962306a36Sopenharmony_ci/* End of PCI section */ 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci/* Start of module section */ 64262306a36Sopenharmony_cistatic int __init usnic_ib_init(void) 64362306a36Sopenharmony_ci{ 64462306a36Sopenharmony_ci int err; 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci printk_once(KERN_INFO "%s", usnic_version); 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci err = pci_register_driver(&usnic_ib_pci_driver); 64962306a36Sopenharmony_ci if (err) { 65062306a36Sopenharmony_ci usnic_err("Unable to register with PCI\n"); 65162306a36Sopenharmony_ci goto out_umem_fini; 65262306a36Sopenharmony_ci } 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci err = register_netdevice_notifier(&usnic_ib_netdevice_notifier); 65562306a36Sopenharmony_ci if (err) { 65662306a36Sopenharmony_ci usnic_err("Failed to register netdev notifier\n"); 65762306a36Sopenharmony_ci goto out_pci_unreg; 65862306a36Sopenharmony_ci } 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci err = register_inetaddr_notifier(&usnic_ib_inetaddr_notifier); 66162306a36Sopenharmony_ci if (err) { 66262306a36Sopenharmony_ci usnic_err("Failed to register inet addr notifier\n"); 66362306a36Sopenharmony_ci goto out_unreg_netdev_notifier; 66462306a36Sopenharmony_ci } 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci err = usnic_transport_init(); 66762306a36Sopenharmony_ci if (err) { 66862306a36Sopenharmony_ci usnic_err("Failed to initialize transport\n"); 66962306a36Sopenharmony_ci goto out_unreg_inetaddr_notifier; 67062306a36Sopenharmony_ci } 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci usnic_debugfs_init(); 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci return 0; 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ciout_unreg_inetaddr_notifier: 67762306a36Sopenharmony_ci unregister_inetaddr_notifier(&usnic_ib_inetaddr_notifier); 67862306a36Sopenharmony_ciout_unreg_netdev_notifier: 67962306a36Sopenharmony_ci unregister_netdevice_notifier(&usnic_ib_netdevice_notifier); 68062306a36Sopenharmony_ciout_pci_unreg: 68162306a36Sopenharmony_ci pci_unregister_driver(&usnic_ib_pci_driver); 68262306a36Sopenharmony_ciout_umem_fini: 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci return err; 68562306a36Sopenharmony_ci} 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_cistatic void __exit usnic_ib_destroy(void) 68862306a36Sopenharmony_ci{ 68962306a36Sopenharmony_ci usnic_dbg("\n"); 69062306a36Sopenharmony_ci usnic_debugfs_exit(); 69162306a36Sopenharmony_ci usnic_transport_fini(); 69262306a36Sopenharmony_ci unregister_inetaddr_notifier(&usnic_ib_inetaddr_notifier); 69362306a36Sopenharmony_ci unregister_netdevice_notifier(&usnic_ib_netdevice_notifier); 69462306a36Sopenharmony_ci pci_unregister_driver(&usnic_ib_pci_driver); 69562306a36Sopenharmony_ci} 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ciMODULE_DESCRIPTION("Cisco VIC (usNIC) Verbs Driver"); 69862306a36Sopenharmony_ciMODULE_AUTHOR("Upinder Malhi <umalhi@cisco.com>"); 69962306a36Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 70062306a36Sopenharmony_cimodule_param(usnic_log_lvl, uint, S_IRUGO | S_IWUSR); 70162306a36Sopenharmony_cimodule_param(usnic_ib_share_vf, uint, S_IRUGO | S_IWUSR); 70262306a36Sopenharmony_ciMODULE_PARM_DESC(usnic_log_lvl, " Off=0, Err=1, Info=2, Debug=3"); 70362306a36Sopenharmony_ciMODULE_PARM_DESC(usnic_ib_share_vf, "Off=0, On=1 VF sharing amongst QPs"); 70462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, usnic_ib_pci_ids); 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_cimodule_init(usnic_ib_init); 70762306a36Sopenharmony_cimodule_exit(usnic_ib_destroy); 70862306a36Sopenharmony_ci/* End of module section */ 709