xref: /openbmc/linux/drivers/infiniband/hw/usnic/usnic_ib_main.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
1e3cf00d0SUpinder Malhi /*
2e3cf00d0SUpinder Malhi  * Copyright (c) 2013, Cisco Systems, Inc. All rights reserved.
3e3cf00d0SUpinder Malhi  *
43805eadeSJeff Squyres  * This software is available to you under a choice of one of two
53805eadeSJeff Squyres  * licenses.  You may choose to be licensed under the terms of the GNU
63805eadeSJeff Squyres  * General Public License (GPL) Version 2, available from the file
73805eadeSJeff Squyres  * COPYING in the main directory of this source tree, or the
83805eadeSJeff Squyres  * BSD license below:
93805eadeSJeff Squyres  *
103805eadeSJeff Squyres  *     Redistribution and use in source and binary forms, with or
113805eadeSJeff Squyres  *     without modification, are permitted provided that the following
123805eadeSJeff Squyres  *     conditions are met:
133805eadeSJeff Squyres  *
143805eadeSJeff Squyres  *      - Redistributions of source code must retain the above
153805eadeSJeff Squyres  *        copyright notice, this list of conditions and the following
163805eadeSJeff Squyres  *        disclaimer.
173805eadeSJeff Squyres  *
183805eadeSJeff Squyres  *      - Redistributions in binary form must reproduce the above
193805eadeSJeff Squyres  *        copyright notice, this list of conditions and the following
203805eadeSJeff Squyres  *        disclaimer in the documentation and/or other materials
213805eadeSJeff Squyres  *        provided with the distribution.
22e3cf00d0SUpinder Malhi  *
23e3cf00d0SUpinder Malhi  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24e3cf00d0SUpinder Malhi  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25e3cf00d0SUpinder Malhi  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26e3cf00d0SUpinder Malhi  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27e3cf00d0SUpinder Malhi  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28e3cf00d0SUpinder Malhi  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29e3cf00d0SUpinder Malhi  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30e3cf00d0SUpinder Malhi  * SOFTWARE.
31e3cf00d0SUpinder Malhi  *
32e3cf00d0SUpinder Malhi  * Author: Upinder Malhi <umalhi@cisco.com>
33e3cf00d0SUpinder Malhi  * Author: Anant Deepak <anadeepa@cisco.com>
34e3cf00d0SUpinder Malhi  * Author: Cesare Cantu' <cantuc@cisco.com>
35e3cf00d0SUpinder Malhi  * Author: Jeff Squyres <jsquyres@cisco.com>
36e3cf00d0SUpinder Malhi  * Author: Kiran Thirumalai <kithirum@cisco.com>
37e3cf00d0SUpinder Malhi  * Author: Xuyang Wang <xuywang@cisco.com>
38e3cf00d0SUpinder Malhi  * Author: Reese Faucette <rfaucett@cisco.com>
39e3cf00d0SUpinder Malhi  *
40e3cf00d0SUpinder Malhi  */
41e3cf00d0SUpinder Malhi 
42e3cf00d0SUpinder Malhi #include <linux/module.h>
43c7845bcaSUpinder Malhi #include <linux/inetdevice.h>
44e3cf00d0SUpinder Malhi #include <linux/init.h>
45e3cf00d0SUpinder Malhi #include <linux/slab.h>
46e3cf00d0SUpinder Malhi #include <linux/errno.h>
47e3cf00d0SUpinder Malhi #include <linux/pci.h>
48e3cf00d0SUpinder Malhi #include <linux/netdevice.h>
49e3cf00d0SUpinder Malhi 
50e3cf00d0SUpinder Malhi #include <rdma/ib_user_verbs.h>
51e3cf00d0SUpinder Malhi #include <rdma/ib_addr.h>
52e3cf00d0SUpinder Malhi 
53e3cf00d0SUpinder Malhi #include "usnic_abi.h"
54e3cf00d0SUpinder Malhi #include "usnic_common_util.h"
55e3cf00d0SUpinder Malhi #include "usnic_ib.h"
56e3cf00d0SUpinder Malhi #include "usnic_ib_qp_grp.h"
57e3cf00d0SUpinder Malhi #include "usnic_log.h"
58e3cf00d0SUpinder Malhi #include "usnic_fwd.h"
59e3cf00d0SUpinder Malhi #include "usnic_debugfs.h"
60e3cf00d0SUpinder Malhi #include "usnic_ib_verbs.h"
61e3cf00d0SUpinder Malhi #include "usnic_transport.h"
62e3cf00d0SUpinder Malhi #include "usnic_uiom.h"
63e3cf00d0SUpinder Malhi #include "usnic_ib_sysfs.h"
64e3cf00d0SUpinder Malhi 
65e3cf00d0SUpinder Malhi unsigned int usnic_log_lvl = USNIC_LOG_LVL_ERR;
66e3cf00d0SUpinder Malhi unsigned int usnic_ib_share_vf = 1;
67e3cf00d0SUpinder Malhi 
68e3cf00d0SUpinder Malhi static const char usnic_version[] =
69e3cf00d0SUpinder Malhi 	DRV_NAME ": Cisco VIC (USNIC) Verbs Driver v"
70e3cf00d0SUpinder Malhi 	DRV_VERSION " (" DRV_RELDATE ")\n";
71e3cf00d0SUpinder Malhi 
72e3cf00d0SUpinder Malhi static DEFINE_MUTEX(usnic_ib_ibdev_list_lock);
73e3cf00d0SUpinder Malhi static LIST_HEAD(usnic_ib_ibdev_list);
74e3cf00d0SUpinder Malhi 
75e3cf00d0SUpinder Malhi /* Callback dump funcs */
usnic_ib_dump_vf_hdr(void * obj,char * buf,int buf_sz)76e3cf00d0SUpinder Malhi static int usnic_ib_dump_vf_hdr(void *obj, char *buf, int buf_sz)
77e3cf00d0SUpinder Malhi {
78e3cf00d0SUpinder Malhi 	struct usnic_ib_vf *vf = obj;
799de69861SJason Gunthorpe 	return scnprintf(buf, buf_sz, "PF: %s ", dev_name(&vf->pf->ib_dev.dev));
80e3cf00d0SUpinder Malhi }
81e3cf00d0SUpinder Malhi /* End callback dump funcs */
82e3cf00d0SUpinder Malhi 
usnic_ib_dump_vf(struct usnic_ib_vf * vf,char * buf,int buf_sz)83e3cf00d0SUpinder Malhi static void usnic_ib_dump_vf(struct usnic_ib_vf *vf, char *buf, int buf_sz)
84e3cf00d0SUpinder Malhi {
85e3cf00d0SUpinder Malhi 	usnic_vnic_dump(vf->vnic, buf, buf_sz, vf,
86e3cf00d0SUpinder Malhi 			usnic_ib_dump_vf_hdr,
87e3cf00d0SUpinder Malhi 			usnic_ib_qp_grp_dump_hdr, usnic_ib_qp_grp_dump_rows);
88e3cf00d0SUpinder Malhi }
89e3cf00d0SUpinder Malhi 
usnic_ib_log_vf(struct usnic_ib_vf * vf)90e3cf00d0SUpinder Malhi void usnic_ib_log_vf(struct usnic_ib_vf *vf)
91e3cf00d0SUpinder Malhi {
922ac5a6d3SArnd Bergmann 	char *buf = kzalloc(1000, GFP_KERNEL);
932ac5a6d3SArnd Bergmann 
942ac5a6d3SArnd Bergmann 	if (!buf)
952ac5a6d3SArnd Bergmann 		return;
962ac5a6d3SArnd Bergmann 
972ac5a6d3SArnd Bergmann 	usnic_ib_dump_vf(vf, buf, 1000);
98e3cf00d0SUpinder Malhi 	usnic_dbg("%s\n", buf);
992ac5a6d3SArnd Bergmann 
1002ac5a6d3SArnd Bergmann 	kfree(buf);
101e3cf00d0SUpinder Malhi }
102e3cf00d0SUpinder Malhi 
103e3cf00d0SUpinder Malhi /* Start of netdev section */
usnic_ib_qp_grp_modify_active_to_err(struct usnic_ib_dev * us_ibdev)104e3cf00d0SUpinder Malhi static void usnic_ib_qp_grp_modify_active_to_err(struct usnic_ib_dev *us_ibdev)
105e3cf00d0SUpinder Malhi {
106e3cf00d0SUpinder Malhi 	struct usnic_ib_ucontext *ctx;
107e3cf00d0SUpinder Malhi 	struct usnic_ib_qp_grp *qp_grp;
108e3cf00d0SUpinder Malhi 	enum ib_qp_state cur_state;
109e3cf00d0SUpinder Malhi 	int status;
110e3cf00d0SUpinder Malhi 
111e3cf00d0SUpinder Malhi 	BUG_ON(!mutex_is_locked(&us_ibdev->usdev_lock));
112e3cf00d0SUpinder Malhi 
113e3cf00d0SUpinder Malhi 	list_for_each_entry(ctx, &us_ibdev->ctx_list, link) {
114e3cf00d0SUpinder Malhi 		list_for_each_entry(qp_grp, &ctx->qp_grp_list, link) {
115e3cf00d0SUpinder Malhi 			cur_state = qp_grp->state;
116e3cf00d0SUpinder Malhi 			if (cur_state == IB_QPS_INIT ||
117e3cf00d0SUpinder Malhi 				cur_state == IB_QPS_RTR ||
118e3cf00d0SUpinder Malhi 				cur_state == IB_QPS_RTS) {
119e3cf00d0SUpinder Malhi 				status = usnic_ib_qp_grp_modify(qp_grp,
120e3cf00d0SUpinder Malhi 								IB_QPS_ERR,
121e3cf00d0SUpinder Malhi 								NULL);
122e3cf00d0SUpinder Malhi 				if (status) {
123dfd022a9SColin Ian King 					usnic_err("Failed to transition qp grp %u from %s to %s\n",
124e3cf00d0SUpinder Malhi 						qp_grp->grp_id,
125e3cf00d0SUpinder Malhi 						usnic_ib_qp_grp_state_to_string
126e3cf00d0SUpinder Malhi 						(cur_state),
127e3cf00d0SUpinder Malhi 						usnic_ib_qp_grp_state_to_string
128e3cf00d0SUpinder Malhi 						(IB_QPS_ERR));
129e3cf00d0SUpinder Malhi 				}
130e3cf00d0SUpinder Malhi 			}
131e3cf00d0SUpinder Malhi 		}
132e3cf00d0SUpinder Malhi 	}
133e3cf00d0SUpinder Malhi }
134e3cf00d0SUpinder Malhi 
usnic_ib_handle_usdev_event(struct usnic_ib_dev * us_ibdev,unsigned long event)135e3cf00d0SUpinder Malhi static void usnic_ib_handle_usdev_event(struct usnic_ib_dev *us_ibdev,
136e3cf00d0SUpinder Malhi 					unsigned long event)
137e3cf00d0SUpinder Malhi {
138e3cf00d0SUpinder Malhi 	struct net_device *netdev;
139e3cf00d0SUpinder Malhi 	struct ib_event ib_event;
140e3cf00d0SUpinder Malhi 
141e3cf00d0SUpinder Malhi 	memset(&ib_event, 0, sizeof(ib_event));
142e3cf00d0SUpinder Malhi 
143e3cf00d0SUpinder Malhi 	mutex_lock(&us_ibdev->usdev_lock);
144e3cf00d0SUpinder Malhi 	netdev = us_ibdev->netdev;
145e3cf00d0SUpinder Malhi 	switch (event) {
146e3cf00d0SUpinder Malhi 	case NETDEV_REBOOT:
1479de69861SJason Gunthorpe 		usnic_info("PF Reset on %s\n", dev_name(&us_ibdev->ib_dev.dev));
148e3cf00d0SUpinder Malhi 		usnic_ib_qp_grp_modify_active_to_err(us_ibdev);
149e3cf00d0SUpinder Malhi 		ib_event.event = IB_EVENT_PORT_ERR;
150e3cf00d0SUpinder Malhi 		ib_event.device = &us_ibdev->ib_dev;
151e3cf00d0SUpinder Malhi 		ib_event.element.port_num = 1;
152e3cf00d0SUpinder Malhi 		ib_dispatch_event(&ib_event);
153e3cf00d0SUpinder Malhi 		break;
154e3cf00d0SUpinder Malhi 	case NETDEV_UP:
155e3cf00d0SUpinder Malhi 	case NETDEV_DOWN:
156e3cf00d0SUpinder Malhi 	case NETDEV_CHANGE:
1578af94ac6SUpinder Malhi 		if (!us_ibdev->ufdev->link_up &&
1588af94ac6SUpinder Malhi 				netif_carrier_ok(netdev)) {
1598af94ac6SUpinder Malhi 			usnic_fwd_carrier_up(us_ibdev->ufdev);
1609de69861SJason Gunthorpe 			usnic_info("Link UP on %s\n",
1619de69861SJason Gunthorpe 				   dev_name(&us_ibdev->ib_dev.dev));
162e3cf00d0SUpinder Malhi 			ib_event.event = IB_EVENT_PORT_ACTIVE;
163e3cf00d0SUpinder Malhi 			ib_event.device = &us_ibdev->ib_dev;
164e3cf00d0SUpinder Malhi 			ib_event.element.port_num = 1;
165e3cf00d0SUpinder Malhi 			ib_dispatch_event(&ib_event);
1668af94ac6SUpinder Malhi 		} else if (us_ibdev->ufdev->link_up &&
1678af94ac6SUpinder Malhi 				!netif_carrier_ok(netdev)) {
1688af94ac6SUpinder Malhi 			usnic_fwd_carrier_down(us_ibdev->ufdev);
1699de69861SJason Gunthorpe 			usnic_info("Link DOWN on %s\n",
1709de69861SJason Gunthorpe 				   dev_name(&us_ibdev->ib_dev.dev));
171e3cf00d0SUpinder Malhi 			usnic_ib_qp_grp_modify_active_to_err(us_ibdev);
172e3cf00d0SUpinder Malhi 			ib_event.event = IB_EVENT_PORT_ERR;
173e3cf00d0SUpinder Malhi 			ib_event.device = &us_ibdev->ib_dev;
174e3cf00d0SUpinder Malhi 			ib_event.element.port_num = 1;
175e3cf00d0SUpinder Malhi 			ib_dispatch_event(&ib_event);
176e3cf00d0SUpinder Malhi 		} else {
177c30392abSRoland Dreier 			usnic_dbg("Ignoring %s on %s\n",
1783e0c2dbfSKirill Tkhai 					netdev_cmd_to_name(event),
1799de69861SJason Gunthorpe 					dev_name(&us_ibdev->ib_dev.dev));
180e3cf00d0SUpinder Malhi 		}
181e3cf00d0SUpinder Malhi 		break;
182e3cf00d0SUpinder Malhi 	case NETDEV_CHANGEADDR:
1838af94ac6SUpinder Malhi 		if (!memcmp(us_ibdev->ufdev->mac, netdev->dev_addr,
1848af94ac6SUpinder Malhi 				sizeof(us_ibdev->ufdev->mac))) {
185c30392abSRoland Dreier 			usnic_dbg("Ignoring addr change on %s\n",
1869de69861SJason Gunthorpe 				  dev_name(&us_ibdev->ib_dev.dev));
187e3cf00d0SUpinder Malhi 		} else {
188e3cf00d0SUpinder Malhi 			usnic_info(" %s old mac: %pM new mac: %pM\n",
1899de69861SJason Gunthorpe 					dev_name(&us_ibdev->ib_dev.dev),
1908af94ac6SUpinder Malhi 					us_ibdev->ufdev->mac,
191e3cf00d0SUpinder Malhi 					netdev->dev_addr);
1928af94ac6SUpinder Malhi 			usnic_fwd_set_mac(us_ibdev->ufdev, netdev->dev_addr);
193e3cf00d0SUpinder Malhi 			usnic_ib_qp_grp_modify_active_to_err(us_ibdev);
194e3cf00d0SUpinder Malhi 			ib_event.event = IB_EVENT_GID_CHANGE;
195e3cf00d0SUpinder Malhi 			ib_event.device = &us_ibdev->ib_dev;
196e3cf00d0SUpinder Malhi 			ib_event.element.port_num = 1;
197e3cf00d0SUpinder Malhi 			ib_dispatch_event(&ib_event);
198e3cf00d0SUpinder Malhi 		}
199e3cf00d0SUpinder Malhi 
200e3cf00d0SUpinder Malhi 		break;
201e3cf00d0SUpinder Malhi 	case NETDEV_CHANGEMTU:
2028af94ac6SUpinder Malhi 		if (us_ibdev->ufdev->mtu != netdev->mtu) {
203e3cf00d0SUpinder Malhi 			usnic_info("MTU Change on %s old: %u new: %u\n",
2049de69861SJason Gunthorpe 					dev_name(&us_ibdev->ib_dev.dev),
2058af94ac6SUpinder Malhi 					us_ibdev->ufdev->mtu, netdev->mtu);
2068af94ac6SUpinder Malhi 			usnic_fwd_set_mtu(us_ibdev->ufdev, netdev->mtu);
207e3cf00d0SUpinder Malhi 			usnic_ib_qp_grp_modify_active_to_err(us_ibdev);
208e3cf00d0SUpinder Malhi 		} else {
209e3cf00d0SUpinder Malhi 			usnic_dbg("Ignoring MTU change on %s\n",
2109de69861SJason Gunthorpe 				  dev_name(&us_ibdev->ib_dev.dev));
211e3cf00d0SUpinder Malhi 		}
212e3cf00d0SUpinder Malhi 		break;
213e3cf00d0SUpinder Malhi 	default:
214c30392abSRoland Dreier 		usnic_dbg("Ignoring event %s on %s",
2153e0c2dbfSKirill Tkhai 				netdev_cmd_to_name(event),
2169de69861SJason Gunthorpe 				dev_name(&us_ibdev->ib_dev.dev));
217e3cf00d0SUpinder Malhi 	}
218e3cf00d0SUpinder Malhi 	mutex_unlock(&us_ibdev->usdev_lock);
219e3cf00d0SUpinder Malhi }
220e3cf00d0SUpinder Malhi 
usnic_ib_netdevice_event(struct notifier_block * notifier,unsigned long event,void * ptr)221e3cf00d0SUpinder Malhi static int usnic_ib_netdevice_event(struct notifier_block *notifier,
222e3cf00d0SUpinder Malhi 					unsigned long event, void *ptr)
223e3cf00d0SUpinder Malhi {
224e3cf00d0SUpinder Malhi 	struct usnic_ib_dev *us_ibdev;
2255bb3c1e9SParvi Kaustubhi 	struct ib_device *ibdev;
226e3cf00d0SUpinder Malhi 
227e3cf00d0SUpinder Malhi 	struct net_device *netdev = netdev_notifier_info_to_dev(ptr);
228e3cf00d0SUpinder Malhi 
2295bb3c1e9SParvi Kaustubhi 	ibdev = ib_device_get_by_netdev(netdev, RDMA_DRIVER_USNIC);
2305bb3c1e9SParvi Kaustubhi 	if (!ibdev)
2315bb3c1e9SParvi Kaustubhi 		return NOTIFY_DONE;
232e3cf00d0SUpinder Malhi 
2335bb3c1e9SParvi Kaustubhi 	us_ibdev = container_of(ibdev, struct usnic_ib_dev, ib_dev);
2345bb3c1e9SParvi Kaustubhi 	usnic_ib_handle_usdev_event(us_ibdev, event);
2355bb3c1e9SParvi Kaustubhi 	ib_device_put(ibdev);
236e3cf00d0SUpinder Malhi 	return NOTIFY_DONE;
237e3cf00d0SUpinder Malhi }
238e3cf00d0SUpinder Malhi 
239e3cf00d0SUpinder Malhi static struct notifier_block usnic_ib_netdevice_notifier = {
240e3cf00d0SUpinder Malhi 	.notifier_call = usnic_ib_netdevice_event
241e3cf00d0SUpinder Malhi };
242e3cf00d0SUpinder Malhi /* End of netdev section */
243e3cf00d0SUpinder Malhi 
244c7845bcaSUpinder Malhi /* Start of inet section */
usnic_ib_handle_inet_event(struct usnic_ib_dev * us_ibdev,unsigned long event,void * ptr)245c7845bcaSUpinder Malhi static int usnic_ib_handle_inet_event(struct usnic_ib_dev *us_ibdev,
246c7845bcaSUpinder Malhi 					unsigned long event, void *ptr)
247c7845bcaSUpinder Malhi {
248c7845bcaSUpinder Malhi 	struct in_ifaddr *ifa = ptr;
249c7845bcaSUpinder Malhi 	struct ib_event ib_event;
250c7845bcaSUpinder Malhi 
251c7845bcaSUpinder Malhi 	mutex_lock(&us_ibdev->usdev_lock);
252c7845bcaSUpinder Malhi 
253c7845bcaSUpinder Malhi 	switch (event) {
254c7845bcaSUpinder Malhi 	case NETDEV_DOWN:
255c7845bcaSUpinder Malhi 		usnic_info("%s via ip notifiers",
2563e0c2dbfSKirill Tkhai 				netdev_cmd_to_name(event));
257c7845bcaSUpinder Malhi 		usnic_fwd_del_ipaddr(us_ibdev->ufdev);
258c7845bcaSUpinder Malhi 		usnic_ib_qp_grp_modify_active_to_err(us_ibdev);
259c7845bcaSUpinder Malhi 		ib_event.event = IB_EVENT_GID_CHANGE;
260c7845bcaSUpinder Malhi 		ib_event.device = &us_ibdev->ib_dev;
261c7845bcaSUpinder Malhi 		ib_event.element.port_num = 1;
262c7845bcaSUpinder Malhi 		ib_dispatch_event(&ib_event);
263c7845bcaSUpinder Malhi 		break;
264c7845bcaSUpinder Malhi 	case NETDEV_UP:
265c7845bcaSUpinder Malhi 		usnic_fwd_add_ipaddr(us_ibdev->ufdev, ifa->ifa_address);
266c7845bcaSUpinder Malhi 		usnic_info("%s via ip notifiers: ip %pI4",
2673e0c2dbfSKirill Tkhai 				netdev_cmd_to_name(event),
268c7845bcaSUpinder Malhi 				&us_ibdev->ufdev->inaddr);
269c7845bcaSUpinder Malhi 		ib_event.event = IB_EVENT_GID_CHANGE;
270c7845bcaSUpinder Malhi 		ib_event.device = &us_ibdev->ib_dev;
271c7845bcaSUpinder Malhi 		ib_event.element.port_num = 1;
272c7845bcaSUpinder Malhi 		ib_dispatch_event(&ib_event);
273c7845bcaSUpinder Malhi 		break;
274c7845bcaSUpinder Malhi 	default:
275c30392abSRoland Dreier 		usnic_info("Ignoring event %s on %s",
2763e0c2dbfSKirill Tkhai 				netdev_cmd_to_name(event),
2779de69861SJason Gunthorpe 				dev_name(&us_ibdev->ib_dev.dev));
278c7845bcaSUpinder Malhi 	}
279c7845bcaSUpinder Malhi 	mutex_unlock(&us_ibdev->usdev_lock);
280c7845bcaSUpinder Malhi 
281c7845bcaSUpinder Malhi 	return NOTIFY_DONE;
282c7845bcaSUpinder Malhi }
283c7845bcaSUpinder Malhi 
usnic_ib_inetaddr_event(struct notifier_block * notifier,unsigned long event,void * ptr)284c7845bcaSUpinder Malhi static int usnic_ib_inetaddr_event(struct notifier_block *notifier,
285c7845bcaSUpinder Malhi 					unsigned long event, void *ptr)
286c7845bcaSUpinder Malhi {
287c7845bcaSUpinder Malhi 	struct usnic_ib_dev *us_ibdev;
288c7845bcaSUpinder Malhi 	struct in_ifaddr *ifa = ptr;
289c7845bcaSUpinder Malhi 	struct net_device *netdev = ifa->ifa_dev->dev;
2905bb3c1e9SParvi Kaustubhi 	struct ib_device *ibdev;
291c7845bcaSUpinder Malhi 
2925bb3c1e9SParvi Kaustubhi 	ibdev = ib_device_get_by_netdev(netdev, RDMA_DRIVER_USNIC);
2935bb3c1e9SParvi Kaustubhi 	if (!ibdev)
2945bb3c1e9SParvi Kaustubhi 		return NOTIFY_DONE;
2955bb3c1e9SParvi Kaustubhi 
2965bb3c1e9SParvi Kaustubhi 	us_ibdev = container_of(ibdev, struct usnic_ib_dev, ib_dev);
297c7845bcaSUpinder Malhi 	usnic_ib_handle_inet_event(us_ibdev, event, ptr);
2985bb3c1e9SParvi Kaustubhi 	ib_device_put(ibdev);
299c7845bcaSUpinder Malhi 	return NOTIFY_DONE;
300c7845bcaSUpinder Malhi }
301c7845bcaSUpinder Malhi static struct notifier_block usnic_ib_inetaddr_notifier = {
302c7845bcaSUpinder Malhi 	.notifier_call = usnic_ib_inetaddr_event
303c7845bcaSUpinder Malhi };
304c7845bcaSUpinder Malhi /* End of inet section*/
305c7845bcaSUpinder Malhi 
usnic_port_immutable(struct ib_device * ibdev,u32 port_num,struct ib_port_immutable * immutable)3061fb7f897SMark Bloch static int usnic_port_immutable(struct ib_device *ibdev, u32 port_num,
3077738613eSIra Weiny 			        struct ib_port_immutable *immutable)
3087738613eSIra Weiny {
3097738613eSIra Weiny 	struct ib_port_attr attr;
3107738613eSIra Weiny 	int err;
3117738613eSIra Weiny 
312c4550c63SOr Gerlitz 	immutable->core_cap_flags = RDMA_CORE_PORT_USNIC;
313c4550c63SOr Gerlitz 
314c4550c63SOr Gerlitz 	err = ib_query_port(ibdev, port_num, &attr);
3157738613eSIra Weiny 	if (err)
3167738613eSIra Weiny 		return err;
3177738613eSIra Weiny 
3187738613eSIra Weiny 	immutable->gid_tbl_len = attr.gid_tbl_len;
3197738613eSIra Weiny 
3207738613eSIra Weiny 	return 0;
3217738613eSIra Weiny }
3227738613eSIra Weiny 
usnic_get_dev_fw_str(struct ib_device * device,char * str)3239abb0d1bSLeon Romanovsky static void usnic_get_dev_fw_str(struct ib_device *device, char *str)
32415453e85SIra Weiny {
32515453e85SIra Weiny 	struct usnic_ib_dev *us_ibdev =
32615453e85SIra Weiny 		container_of(device, struct usnic_ib_dev, ib_dev);
32715453e85SIra Weiny 	struct ethtool_drvinfo info;
32815453e85SIra Weiny 
32915453e85SIra Weiny 	mutex_lock(&us_ibdev->usdev_lock);
33015453e85SIra Weiny 	us_ibdev->netdev->ethtool_ops->get_drvinfo(us_ibdev->netdev, &info);
33115453e85SIra Weiny 	mutex_unlock(&us_ibdev->usdev_lock);
33215453e85SIra Weiny 
3339abb0d1bSLeon Romanovsky 	snprintf(str, IB_FW_VERSION_NAME_MAX, "%s", info.fw_version);
33415453e85SIra Weiny }
33515453e85SIra Weiny 
336e7610581SKamal Heib static const struct ib_device_ops usnic_dev_ops = {
3377a154142SJason Gunthorpe 	.owner = THIS_MODULE,
338b9560a41SJason Gunthorpe 	.driver_id = RDMA_DRIVER_USNIC,
33972c6ec18SJason Gunthorpe 	.uverbs_abi_ver = USNIC_UVERBS_ABI_VERSION,
340b9560a41SJason Gunthorpe 
341e7610581SKamal Heib 	.alloc_pd = usnic_ib_alloc_pd,
342e7610581SKamal Heib 	.alloc_ucontext = usnic_ib_alloc_ucontext,
343e7610581SKamal Heib 	.create_cq = usnic_ib_create_cq,
344e7610581SKamal Heib 	.create_qp = usnic_ib_create_qp,
345e7610581SKamal Heib 	.dealloc_pd = usnic_ib_dealloc_pd,
346e7610581SKamal Heib 	.dealloc_ucontext = usnic_ib_dealloc_ucontext,
347e7610581SKamal Heib 	.dereg_mr = usnic_ib_dereg_mr,
348e7610581SKamal Heib 	.destroy_cq = usnic_ib_destroy_cq,
349e7610581SKamal Heib 	.destroy_qp = usnic_ib_destroy_qp,
350915e4af5SJason Gunthorpe 	.device_group = &usnic_attr_group,
351e7610581SKamal Heib 	.get_dev_fw_str = usnic_get_dev_fw_str,
352e7610581SKamal Heib 	.get_link_layer = usnic_ib_port_link_layer,
353e7610581SKamal Heib 	.get_port_immutable = usnic_port_immutable,
354e7610581SKamal Heib 	.mmap = usnic_ib_mmap,
355e7610581SKamal Heib 	.modify_qp = usnic_ib_modify_qp,
356e7610581SKamal Heib 	.query_device = usnic_ib_query_device,
357e7610581SKamal Heib 	.query_gid = usnic_ib_query_gid,
358e7610581SKamal Heib 	.query_port = usnic_ib_query_port,
359e7610581SKamal Heib 	.query_qp = usnic_ib_query_qp,
360e7610581SKamal Heib 	.reg_user_mr = usnic_ib_reg_mr,
36121a428a0SLeon Romanovsky 	INIT_RDMA_OBJ_SIZE(ib_pd, usnic_ib_pd, ibpd),
362e39afe3dSLeon Romanovsky 	INIT_RDMA_OBJ_SIZE(ib_cq, usnic_ib_cq, ibcq),
363514aee66SLeon Romanovsky 	INIT_RDMA_OBJ_SIZE(ib_qp, usnic_ib_qp_grp, ibqp),
364a2a074efSLeon Romanovsky 	INIT_RDMA_OBJ_SIZE(ib_ucontext, usnic_ib_ucontext, ibucontext),
365e7610581SKamal Heib };
366e7610581SKamal Heib 
367e3cf00d0SUpinder Malhi /* Start of PF discovery section */
usnic_ib_device_add(struct pci_dev * dev)368e3cf00d0SUpinder Malhi static void *usnic_ib_device_add(struct pci_dev *dev)
369e3cf00d0SUpinder Malhi {
370e3cf00d0SUpinder Malhi 	struct usnic_ib_dev *us_ibdev;
371e3cf00d0SUpinder Malhi 	union ib_gid gid;
3725d50f400SLeon Romanovsky 	struct in_device *ind;
373c7845bcaSUpinder Malhi 	struct net_device *netdev;
3745bb3c1e9SParvi Kaustubhi 	int ret;
375e3cf00d0SUpinder Malhi 
376e3cf00d0SUpinder Malhi 	usnic_dbg("\n");
377c7845bcaSUpinder Malhi 	netdev = pci_get_drvdata(dev);
378e3cf00d0SUpinder Malhi 
379459cc69fSLeon Romanovsky 	us_ibdev = ib_alloc_device(usnic_ib_dev, ib_dev);
3802c79dad8SInsu Yun 	if (!us_ibdev) {
381e3cf00d0SUpinder Malhi 		usnic_err("Device %s context alloc failed\n",
382e3cf00d0SUpinder Malhi 				netdev_name(pci_get_drvdata(dev)));
3832c79dad8SInsu Yun 		return ERR_PTR(-EFAULT);
384e3cf00d0SUpinder Malhi 	}
385e3cf00d0SUpinder Malhi 
386e3cf00d0SUpinder Malhi 	us_ibdev->ufdev = usnic_fwd_dev_alloc(dev);
3872c79dad8SInsu Yun 	if (!us_ibdev->ufdev) {
3882c79dad8SInsu Yun 		usnic_err("Failed to alloc ufdev for %s\n", pci_name(dev));
389e3cf00d0SUpinder Malhi 		goto err_dealloc;
390e3cf00d0SUpinder Malhi 	}
391e3cf00d0SUpinder Malhi 
392e3cf00d0SUpinder Malhi 	mutex_init(&us_ibdev->usdev_lock);
393e3cf00d0SUpinder Malhi 	INIT_LIST_HEAD(&us_ibdev->vf_dev_list);
394e3cf00d0SUpinder Malhi 	INIT_LIST_HEAD(&us_ibdev->ctx_list);
395e3cf00d0SUpinder Malhi 
396e3cf00d0SUpinder Malhi 	us_ibdev->pdev = dev;
397e3cf00d0SUpinder Malhi 	us_ibdev->netdev = pci_get_drvdata(dev);
39861f78268SUpinder Malhi 	us_ibdev->ib_dev.node_type = RDMA_NODE_USNIC_UDP;
399e3cf00d0SUpinder Malhi 	us_ibdev->ib_dev.phys_port_cnt = USNIC_IB_PORT_CNT;
400e3cf00d0SUpinder Malhi 	us_ibdev->ib_dev.num_comp_vectors = USNIC_IB_NUM_COMP_VECTORS;
4016b06d52dSBart Van Assche 	us_ibdev->ib_dev.dev.parent = &dev->dev;
402e3cf00d0SUpinder Malhi 
403e7610581SKamal Heib 	ib_set_device_ops(&us_ibdev->ib_dev, &usnic_dev_ops);
404e3cf00d0SUpinder Malhi 
4055bb3c1e9SParvi Kaustubhi 	ret = ib_device_set_netdev(&us_ibdev->ib_dev, us_ibdev->netdev, 1);
4065bb3c1e9SParvi Kaustubhi 	if (ret)
4075bb3c1e9SParvi Kaustubhi 		goto err_fwd_dealloc;
4085bb3c1e9SParvi Kaustubhi 
409e0477b34SJason Gunthorpe 	dma_set_max_seg_size(&dev->dev, SZ_2G);
410e0477b34SJason Gunthorpe 	if (ib_register_device(&us_ibdev->ib_dev, "usnic_%d", &dev->dev))
411e3cf00d0SUpinder Malhi 		goto err_fwd_dealloc;
412e3cf00d0SUpinder Malhi 
4138af94ac6SUpinder Malhi 	usnic_fwd_set_mtu(us_ibdev->ufdev, us_ibdev->netdev->mtu);
4148af94ac6SUpinder Malhi 	usnic_fwd_set_mac(us_ibdev->ufdev, us_ibdev->netdev->dev_addr);
4158af94ac6SUpinder Malhi 	if (netif_carrier_ok(us_ibdev->netdev))
4168af94ac6SUpinder Malhi 		usnic_fwd_carrier_up(us_ibdev->ufdev);
4178af94ac6SUpinder Malhi 
4182638eb8bSFlorian Westphal 	rcu_read_lock();
4192638eb8bSFlorian Westphal 	ind = __in_dev_get_rcu(netdev);
4202638eb8bSFlorian Westphal 	if (ind) {
4212638eb8bSFlorian Westphal 		const struct in_ifaddr *ifa;
4222638eb8bSFlorian Westphal 
4232638eb8bSFlorian Westphal 		ifa = rcu_dereference(ind->ifa_list);
4242638eb8bSFlorian Westphal 		if (ifa)
4252638eb8bSFlorian Westphal 			usnic_fwd_add_ipaddr(us_ibdev->ufdev, ifa->ifa_address);
4262638eb8bSFlorian Westphal 	}
4272638eb8bSFlorian Westphal 	rcu_read_unlock();
428c7845bcaSUpinder Malhi 
429c7845bcaSUpinder Malhi 	usnic_mac_ip_to_gid(us_ibdev->netdev->perm_addr,
430c7845bcaSUpinder Malhi 				us_ibdev->ufdev->inaddr, &gid.raw[0]);
431e3cf00d0SUpinder Malhi 	memcpy(&us_ibdev->ib_dev.node_guid, &gid.global.interface_id,
432e3cf00d0SUpinder Malhi 		sizeof(gid.global.interface_id));
433e3cf00d0SUpinder Malhi 	kref_init(&us_ibdev->vf_cnt);
434e3cf00d0SUpinder Malhi 
435e3cf00d0SUpinder Malhi 	usnic_info("Added ibdev: %s netdev: %s with mac %pM Link: %u MTU: %u\n",
4369de69861SJason Gunthorpe 		   dev_name(&us_ibdev->ib_dev.dev),
4379de69861SJason Gunthorpe 		   netdev_name(us_ibdev->netdev), us_ibdev->ufdev->mac,
4389de69861SJason Gunthorpe 		   us_ibdev->ufdev->link_up, us_ibdev->ufdev->mtu);
439e3cf00d0SUpinder Malhi 	return us_ibdev;
440e3cf00d0SUpinder Malhi 
441e3cf00d0SUpinder Malhi err_fwd_dealloc:
442e3cf00d0SUpinder Malhi 	usnic_fwd_dev_free(us_ibdev->ufdev);
443e3cf00d0SUpinder Malhi err_dealloc:
444e3cf00d0SUpinder Malhi 	usnic_err("failed -- deallocing device\n");
445e3cf00d0SUpinder Malhi 	ib_dealloc_device(&us_ibdev->ib_dev);
446e3cf00d0SUpinder Malhi 	return NULL;
447e3cf00d0SUpinder Malhi }
448e3cf00d0SUpinder Malhi 
usnic_ib_device_remove(struct usnic_ib_dev * us_ibdev)449e3cf00d0SUpinder Malhi static void usnic_ib_device_remove(struct usnic_ib_dev *us_ibdev)
450e3cf00d0SUpinder Malhi {
4519de69861SJason Gunthorpe 	usnic_info("Unregistering %s\n", dev_name(&us_ibdev->ib_dev.dev));
452e3cf00d0SUpinder Malhi 	usnic_ib_sysfs_unregister_usdev(us_ibdev);
453e3cf00d0SUpinder Malhi 	usnic_fwd_dev_free(us_ibdev->ufdev);
454e3cf00d0SUpinder Malhi 	ib_unregister_device(&us_ibdev->ib_dev);
455e3cf00d0SUpinder Malhi 	ib_dealloc_device(&us_ibdev->ib_dev);
456e3cf00d0SUpinder Malhi }
457e3cf00d0SUpinder Malhi 
usnic_ib_undiscover_pf(struct kref * kref)458e3cf00d0SUpinder Malhi static void usnic_ib_undiscover_pf(struct kref *kref)
459e3cf00d0SUpinder Malhi {
460e3cf00d0SUpinder Malhi 	struct usnic_ib_dev *us_ibdev, *tmp;
461e3cf00d0SUpinder Malhi 	struct pci_dev *dev;
462e3cf00d0SUpinder Malhi 	bool found = false;
463e3cf00d0SUpinder Malhi 
464e3cf00d0SUpinder Malhi 	dev = container_of(kref, struct usnic_ib_dev, vf_cnt)->pdev;
465e3cf00d0SUpinder Malhi 	mutex_lock(&usnic_ib_ibdev_list_lock);
466e3cf00d0SUpinder Malhi 	list_for_each_entry_safe(us_ibdev, tmp,
467e3cf00d0SUpinder Malhi 				&usnic_ib_ibdev_list, ib_dev_link) {
468e3cf00d0SUpinder Malhi 		if (us_ibdev->pdev == dev) {
469e3cf00d0SUpinder Malhi 			list_del(&us_ibdev->ib_dev_link);
470e3cf00d0SUpinder Malhi 			found = true;
471e3cf00d0SUpinder Malhi 			break;
472e3cf00d0SUpinder Malhi 		}
473e3cf00d0SUpinder Malhi 	}
474e3cf00d0SUpinder Malhi 
475e3cf00d0SUpinder Malhi 
476e3cf00d0SUpinder Malhi 	mutex_unlock(&usnic_ib_ibdev_list_lock);
4770c236606SParvi Kaustubhi 	if (found)
4780c236606SParvi Kaustubhi 		usnic_ib_device_remove(us_ibdev);
4790c236606SParvi Kaustubhi 	else
4800c236606SParvi Kaustubhi 		WARN(1, "Failed to remove PF %s\n", pci_name(dev));
481e3cf00d0SUpinder Malhi }
482e3cf00d0SUpinder Malhi 
usnic_ib_discover_pf(struct usnic_vnic * vnic)483e3cf00d0SUpinder Malhi static struct usnic_ib_dev *usnic_ib_discover_pf(struct usnic_vnic *vnic)
484e3cf00d0SUpinder Malhi {
485e3cf00d0SUpinder Malhi 	struct usnic_ib_dev *us_ibdev;
486e3cf00d0SUpinder Malhi 	struct pci_dev *parent_pci, *vf_pci;
487e3cf00d0SUpinder Malhi 	int err;
488e3cf00d0SUpinder Malhi 
489e3cf00d0SUpinder Malhi 	vf_pci = usnic_vnic_get_pdev(vnic);
490e3cf00d0SUpinder Malhi 	parent_pci = pci_physfn(vf_pci);
491e3cf00d0SUpinder Malhi 
492e3cf00d0SUpinder Malhi 	BUG_ON(!parent_pci);
493e3cf00d0SUpinder Malhi 
494e3cf00d0SUpinder Malhi 	mutex_lock(&usnic_ib_ibdev_list_lock);
495e3cf00d0SUpinder Malhi 	list_for_each_entry(us_ibdev, &usnic_ib_ibdev_list, ib_dev_link) {
496e3cf00d0SUpinder Malhi 		if (us_ibdev->pdev == parent_pci) {
497e3cf00d0SUpinder Malhi 			kref_get(&us_ibdev->vf_cnt);
498e3cf00d0SUpinder Malhi 			goto out;
499e3cf00d0SUpinder Malhi 		}
500e3cf00d0SUpinder Malhi 	}
501e3cf00d0SUpinder Malhi 
502e3cf00d0SUpinder Malhi 	us_ibdev = usnic_ib_device_add(parent_pci);
503e3cf00d0SUpinder Malhi 	if (IS_ERR_OR_NULL(us_ibdev)) {
5046a54d9f9SUpinder Malhi 		us_ibdev = us_ibdev ? us_ibdev : ERR_PTR(-EFAULT);
505e3cf00d0SUpinder Malhi 		goto out;
506e3cf00d0SUpinder Malhi 	}
507e3cf00d0SUpinder Malhi 
508e3cf00d0SUpinder Malhi 	err = usnic_ib_sysfs_register_usdev(us_ibdev);
509e3cf00d0SUpinder Malhi 	if (err) {
510e3cf00d0SUpinder Malhi 		usnic_ib_device_remove(us_ibdev);
511e3cf00d0SUpinder Malhi 		us_ibdev = ERR_PTR(err);
512e3cf00d0SUpinder Malhi 		goto out;
513e3cf00d0SUpinder Malhi 	}
514e3cf00d0SUpinder Malhi 
515e3cf00d0SUpinder Malhi 	list_add(&us_ibdev->ib_dev_link, &usnic_ib_ibdev_list);
516e3cf00d0SUpinder Malhi out:
517e3cf00d0SUpinder Malhi 	mutex_unlock(&usnic_ib_ibdev_list_lock);
518e3cf00d0SUpinder Malhi 	return us_ibdev;
519e3cf00d0SUpinder Malhi }
520e3cf00d0SUpinder Malhi /* End of PF discovery section */
521e3cf00d0SUpinder Malhi 
522e3cf00d0SUpinder Malhi /* Start of PCI section */
523e3cf00d0SUpinder Malhi 
5249baa3c34SBenoit Taine static const struct pci_device_id usnic_ib_pci_ids[] = {
525e3cf00d0SUpinder Malhi 	{PCI_DEVICE(PCI_VENDOR_ID_CISCO, PCI_DEVICE_ID_CISCO_VIC_USPACE_NIC)},
526e3cf00d0SUpinder Malhi 	{0,}
527e3cf00d0SUpinder Malhi };
528e3cf00d0SUpinder Malhi 
usnic_ib_pci_probe(struct pci_dev * pdev,const struct pci_device_id * id)529e3cf00d0SUpinder Malhi static int usnic_ib_pci_probe(struct pci_dev *pdev,
530e3cf00d0SUpinder Malhi 				const struct pci_device_id *id)
531e3cf00d0SUpinder Malhi {
532e3cf00d0SUpinder Malhi 	int err;
533e3cf00d0SUpinder Malhi 	struct usnic_ib_dev *pf;
534e3cf00d0SUpinder Malhi 	struct usnic_ib_vf *vf;
535e3cf00d0SUpinder Malhi 	enum usnic_vnic_res_type res_type;
536e3cf00d0SUpinder Malhi 
537*d9539fb7SRobin Murphy 	if (!device_iommu_mapped(&pdev->dev)) {
538*d9539fb7SRobin Murphy 		usnic_err("IOMMU required but not present or enabled.  USNIC QPs will not function w/o enabling IOMMU\n");
539*d9539fb7SRobin Murphy 		return -EPERM;
540*d9539fb7SRobin Murphy 	}
541*d9539fb7SRobin Murphy 
542e3cf00d0SUpinder Malhi 	vf = kzalloc(sizeof(*vf), GFP_KERNEL);
543e3cf00d0SUpinder Malhi 	if (!vf)
544e3cf00d0SUpinder Malhi 		return -ENOMEM;
545e3cf00d0SUpinder Malhi 
546e3cf00d0SUpinder Malhi 	err = pci_enable_device(pdev);
547e3cf00d0SUpinder Malhi 	if (err) {
548e3cf00d0SUpinder Malhi 		usnic_err("Failed to enable %s with err %d\n",
549e3cf00d0SUpinder Malhi 				pci_name(pdev), err);
550e3cf00d0SUpinder Malhi 		goto out_clean_vf;
551e3cf00d0SUpinder Malhi 	}
552e3cf00d0SUpinder Malhi 
553e3cf00d0SUpinder Malhi 	err = pci_request_regions(pdev, DRV_NAME);
554e3cf00d0SUpinder Malhi 	if (err) {
555e3cf00d0SUpinder Malhi 		usnic_err("Failed to request region for %s with err %d\n",
556e3cf00d0SUpinder Malhi 				pci_name(pdev), err);
557e3cf00d0SUpinder Malhi 		goto out_disable_device;
558e3cf00d0SUpinder Malhi 	}
559e3cf00d0SUpinder Malhi 
560e3cf00d0SUpinder Malhi 	pci_set_master(pdev);
561e3cf00d0SUpinder Malhi 	pci_set_drvdata(pdev, vf);
562e3cf00d0SUpinder Malhi 
563e3cf00d0SUpinder Malhi 	vf->vnic = usnic_vnic_alloc(pdev);
564e3cf00d0SUpinder Malhi 	if (IS_ERR_OR_NULL(vf->vnic)) {
5656a54d9f9SUpinder Malhi 		err = vf->vnic ? PTR_ERR(vf->vnic) : -ENOMEM;
566e3cf00d0SUpinder Malhi 		usnic_err("Failed to alloc vnic for %s with err %d\n",
567e3cf00d0SUpinder Malhi 				pci_name(pdev), err);
568e3cf00d0SUpinder Malhi 		goto out_release_regions;
569e3cf00d0SUpinder Malhi 	}
570e3cf00d0SUpinder Malhi 
571e3cf00d0SUpinder Malhi 	pf = usnic_ib_discover_pf(vf->vnic);
572e3cf00d0SUpinder Malhi 	if (IS_ERR_OR_NULL(pf)) {
573e3cf00d0SUpinder Malhi 		usnic_err("Failed to discover pf of vnic %s with err%ld\n",
574e3cf00d0SUpinder Malhi 				pci_name(pdev), PTR_ERR(pf));
5756a54d9f9SUpinder Malhi 		err = pf ? PTR_ERR(pf) : -EFAULT;
576e3cf00d0SUpinder Malhi 		goto out_clean_vnic;
577e3cf00d0SUpinder Malhi 	}
578e3cf00d0SUpinder Malhi 
579e3cf00d0SUpinder Malhi 	vf->pf = pf;
580a86cd017SLeon Romanovsky 	mutex_init(&vf->lock);
581e3cf00d0SUpinder Malhi 	mutex_lock(&pf->usdev_lock);
582e3cf00d0SUpinder Malhi 	list_add_tail(&vf->link, &pf->vf_dev_list);
583e3cf00d0SUpinder Malhi 	/*
584e3cf00d0SUpinder Malhi 	 * Save max settings (will be same for each VF, easier to re-write than
585e3cf00d0SUpinder Malhi 	 * to say "if (!set) { set_values(); set=1; }
586e3cf00d0SUpinder Malhi 	 */
587e3cf00d0SUpinder Malhi 	for (res_type = USNIC_VNIC_RES_TYPE_EOL+1;
588e3cf00d0SUpinder Malhi 			res_type < USNIC_VNIC_RES_TYPE_MAX;
589e3cf00d0SUpinder Malhi 			res_type++) {
590e3cf00d0SUpinder Malhi 		pf->vf_res_cnt[res_type] = usnic_vnic_res_cnt(vf->vnic,
591e3cf00d0SUpinder Malhi 								res_type);
592e3cf00d0SUpinder Malhi 	}
593e3cf00d0SUpinder Malhi 
594e3cf00d0SUpinder Malhi 	mutex_unlock(&pf->usdev_lock);
595e3cf00d0SUpinder Malhi 
596e3cf00d0SUpinder Malhi 	usnic_info("Registering usnic VF %s into PF %s\n", pci_name(pdev),
5979de69861SJason Gunthorpe 		   dev_name(&pf->ib_dev.dev));
598e3cf00d0SUpinder Malhi 	usnic_ib_log_vf(vf);
599e3cf00d0SUpinder Malhi 	return 0;
600e3cf00d0SUpinder Malhi 
601e3cf00d0SUpinder Malhi out_clean_vnic:
602e3cf00d0SUpinder Malhi 	usnic_vnic_free(vf->vnic);
603e3cf00d0SUpinder Malhi out_release_regions:
604e3cf00d0SUpinder Malhi 	pci_set_drvdata(pdev, NULL);
605e3cf00d0SUpinder Malhi 	pci_release_regions(pdev);
606e3cf00d0SUpinder Malhi out_disable_device:
607e3cf00d0SUpinder Malhi 	pci_disable_device(pdev);
608e3cf00d0SUpinder Malhi out_clean_vf:
609e3cf00d0SUpinder Malhi 	kfree(vf);
610e3cf00d0SUpinder Malhi 	return err;
611e3cf00d0SUpinder Malhi }
612e3cf00d0SUpinder Malhi 
usnic_ib_pci_remove(struct pci_dev * pdev)613e3cf00d0SUpinder Malhi static void usnic_ib_pci_remove(struct pci_dev *pdev)
614e3cf00d0SUpinder Malhi {
615e3cf00d0SUpinder Malhi 	struct usnic_ib_vf *vf = pci_get_drvdata(pdev);
616e3cf00d0SUpinder Malhi 	struct usnic_ib_dev *pf = vf->pf;
617e3cf00d0SUpinder Malhi 
618e3cf00d0SUpinder Malhi 	mutex_lock(&pf->usdev_lock);
619e3cf00d0SUpinder Malhi 	list_del(&vf->link);
620e3cf00d0SUpinder Malhi 	mutex_unlock(&pf->usdev_lock);
621e3cf00d0SUpinder Malhi 
622e3cf00d0SUpinder Malhi 	kref_put(&pf->vf_cnt, usnic_ib_undiscover_pf);
623e3cf00d0SUpinder Malhi 	usnic_vnic_free(vf->vnic);
624e3cf00d0SUpinder Malhi 	pci_set_drvdata(pdev, NULL);
625e3cf00d0SUpinder Malhi 	pci_release_regions(pdev);
626e3cf00d0SUpinder Malhi 	pci_disable_device(pdev);
627e3cf00d0SUpinder Malhi 	kfree(vf);
628e3cf00d0SUpinder Malhi 
629e3cf00d0SUpinder Malhi 	usnic_info("Removed VF %s\n", pci_name(pdev));
630e3cf00d0SUpinder Malhi }
631e3cf00d0SUpinder Malhi 
632e3cf00d0SUpinder Malhi /* PCI driver entry points */
633e3cf00d0SUpinder Malhi static struct pci_driver usnic_ib_pci_driver = {
634e3cf00d0SUpinder Malhi 	.name = DRV_NAME,
635e3cf00d0SUpinder Malhi 	.id_table = usnic_ib_pci_ids,
636e3cf00d0SUpinder Malhi 	.probe = usnic_ib_pci_probe,
637e3cf00d0SUpinder Malhi 	.remove = usnic_ib_pci_remove,
638e3cf00d0SUpinder Malhi };
639e3cf00d0SUpinder Malhi /* End of PCI section */
640e3cf00d0SUpinder Malhi 
641e3cf00d0SUpinder Malhi /* Start of module section */
usnic_ib_init(void)642e3cf00d0SUpinder Malhi static int __init usnic_ib_init(void)
643e3cf00d0SUpinder Malhi {
644e3cf00d0SUpinder Malhi 	int err;
645e3cf00d0SUpinder Malhi 
646e3cf00d0SUpinder Malhi 	printk_once(KERN_INFO "%s", usnic_version);
647e3cf00d0SUpinder Malhi 
64886cd747cSChristophe Jaillet 	err = pci_register_driver(&usnic_ib_pci_driver);
64986cd747cSChristophe Jaillet 	if (err) {
650e3cf00d0SUpinder Malhi 		usnic_err("Unable to register with PCI\n");
651e3cf00d0SUpinder Malhi 		goto out_umem_fini;
652e3cf00d0SUpinder Malhi 	}
653e3cf00d0SUpinder Malhi 
654e3cf00d0SUpinder Malhi 	err = register_netdevice_notifier(&usnic_ib_netdevice_notifier);
655e3cf00d0SUpinder Malhi 	if (err) {
656e3cf00d0SUpinder Malhi 		usnic_err("Failed to register netdev notifier\n");
657e3cf00d0SUpinder Malhi 		goto out_pci_unreg;
658e3cf00d0SUpinder Malhi 	}
659e3cf00d0SUpinder Malhi 
660c7845bcaSUpinder Malhi 	err = register_inetaddr_notifier(&usnic_ib_inetaddr_notifier);
661c7845bcaSUpinder Malhi 	if (err) {
662c7845bcaSUpinder Malhi 		usnic_err("Failed to register inet addr notifier\n");
663c7845bcaSUpinder Malhi 		goto out_unreg_netdev_notifier;
664c7845bcaSUpinder Malhi 	}
665c7845bcaSUpinder Malhi 
666e3cf00d0SUpinder Malhi 	err = usnic_transport_init();
667e3cf00d0SUpinder Malhi 	if (err) {
668e3cf00d0SUpinder Malhi 		usnic_err("Failed to initialize transport\n");
669c7845bcaSUpinder Malhi 		goto out_unreg_inetaddr_notifier;
670e3cf00d0SUpinder Malhi 	}
671e3cf00d0SUpinder Malhi 
672e3cf00d0SUpinder Malhi 	usnic_debugfs_init();
673e3cf00d0SUpinder Malhi 
674e3cf00d0SUpinder Malhi 	return 0;
675e3cf00d0SUpinder Malhi 
676c7845bcaSUpinder Malhi out_unreg_inetaddr_notifier:
677c7845bcaSUpinder Malhi 	unregister_inetaddr_notifier(&usnic_ib_inetaddr_notifier);
678e3cf00d0SUpinder Malhi out_unreg_netdev_notifier:
679e3cf00d0SUpinder Malhi 	unregister_netdevice_notifier(&usnic_ib_netdevice_notifier);
680e3cf00d0SUpinder Malhi out_pci_unreg:
681e3cf00d0SUpinder Malhi 	pci_unregister_driver(&usnic_ib_pci_driver);
682e3cf00d0SUpinder Malhi out_umem_fini:
683e3cf00d0SUpinder Malhi 
684e3cf00d0SUpinder Malhi 	return err;
685e3cf00d0SUpinder Malhi }
686e3cf00d0SUpinder Malhi 
usnic_ib_destroy(void)687e3cf00d0SUpinder Malhi static void __exit usnic_ib_destroy(void)
688e3cf00d0SUpinder Malhi {
689e3cf00d0SUpinder Malhi 	usnic_dbg("\n");
690e3cf00d0SUpinder Malhi 	usnic_debugfs_exit();
691e3cf00d0SUpinder Malhi 	usnic_transport_fini();
692c7845bcaSUpinder Malhi 	unregister_inetaddr_notifier(&usnic_ib_inetaddr_notifier);
693e3cf00d0SUpinder Malhi 	unregister_netdevice_notifier(&usnic_ib_netdevice_notifier);
694e3cf00d0SUpinder Malhi 	pci_unregister_driver(&usnic_ib_pci_driver);
695e3cf00d0SUpinder Malhi }
696e3cf00d0SUpinder Malhi 
697e3cf00d0SUpinder Malhi MODULE_DESCRIPTION("Cisco VIC (usNIC) Verbs Driver");
698e3cf00d0SUpinder Malhi MODULE_AUTHOR("Upinder Malhi <umalhi@cisco.com>");
699e3cf00d0SUpinder Malhi MODULE_LICENSE("Dual BSD/GPL");
700e3cf00d0SUpinder Malhi module_param(usnic_log_lvl, uint, S_IRUGO | S_IWUSR);
701e3cf00d0SUpinder Malhi module_param(usnic_ib_share_vf, uint, S_IRUGO | S_IWUSR);
702e3cf00d0SUpinder Malhi MODULE_PARM_DESC(usnic_log_lvl, " Off=0, Err=1, Info=2, Debug=3");
703e3cf00d0SUpinder Malhi MODULE_PARM_DESC(usnic_ib_share_vf, "Off=0, On=1 VF sharing amongst QPs");
704e3cf00d0SUpinder Malhi MODULE_DEVICE_TABLE(pci, usnic_ib_pci_ids);
705e3cf00d0SUpinder Malhi 
706e3cf00d0SUpinder Malhi module_init(usnic_ib_init);
707e3cf00d0SUpinder Malhi module_exit(usnic_ib_destroy);
708e3cf00d0SUpinder Malhi /* End of module section */
709