*/
#include <linux/module.h>
+#include <linux/inetdevice.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/errno.h>
};
/* End of netdev section */
+/* Start of inet section */
+static int usnic_ib_handle_inet_event(struct usnic_ib_dev *us_ibdev,
+ unsigned long event, void *ptr)
+{
+ struct in_ifaddr *ifa = ptr;
+ struct ib_event ib_event;
+
+ mutex_lock(&us_ibdev->usdev_lock);
+
+ switch (event) {
+ case NETDEV_DOWN:
+ usnic_info("%s via ip notifiers",
+ usnic_ib_netdev_event_to_string(event));
+ usnic_fwd_del_ipaddr(us_ibdev->ufdev);
+ usnic_ib_qp_grp_modify_active_to_err(us_ibdev);
+ ib_event.event = IB_EVENT_GID_CHANGE;
+ ib_event.device = &us_ibdev->ib_dev;
+ ib_event.element.port_num = 1;
+ ib_dispatch_event(&ib_event);
+ break;
+ case NETDEV_UP:
+ usnic_fwd_add_ipaddr(us_ibdev->ufdev, ifa->ifa_address);
+ usnic_info("%s via ip notifiers: ip %pI4",
+ usnic_ib_netdev_event_to_string(event),
+ &us_ibdev->ufdev->inaddr);
+ ib_event.event = IB_EVENT_GID_CHANGE;
+ ib_event.device = &us_ibdev->ib_dev;
+ ib_event.element.port_num = 1;
+ ib_dispatch_event(&ib_event);
+ break;
+ default:
+ usnic_info("Ignorning event %s on %s",
+ usnic_ib_netdev_event_to_string(event),
+ us_ibdev->ib_dev.name);
+ }
+ mutex_unlock(&us_ibdev->usdev_lock);
+
+ return NOTIFY_DONE;
+}
+
+static int usnic_ib_inetaddr_event(struct notifier_block *notifier,
+ unsigned long event, void *ptr)
+{
+ struct usnic_ib_dev *us_ibdev;
+ struct in_ifaddr *ifa = ptr;
+ struct net_device *netdev = ifa->ifa_dev->dev;
+
+ mutex_lock(&usnic_ib_ibdev_list_lock);
+ list_for_each_entry(us_ibdev, &usnic_ib_ibdev_list, ib_dev_link) {
+ if (us_ibdev->netdev == netdev) {
+ usnic_ib_handle_inet_event(us_ibdev, event, ptr);
+ break;
+ }
+ }
+ mutex_unlock(&usnic_ib_ibdev_list_lock);
+
+ return NOTIFY_DONE;
+}
+static struct notifier_block usnic_ib_inetaddr_notifier = {
+ .notifier_call = usnic_ib_inetaddr_event
+};
+/* End of inet section*/
+
/* Start of PF discovery section */
static void *usnic_ib_device_add(struct pci_dev *dev)
{
struct usnic_ib_dev *us_ibdev;
union ib_gid gid;
+ struct in_ifaddr *in;
+ struct net_device *netdev;
usnic_dbg("\n");
+ netdev = pci_get_drvdata(dev);
us_ibdev = (struct usnic_ib_dev *)ib_alloc_device(sizeof(*us_ibdev));
if (IS_ERR_OR_NULL(us_ibdev)) {
if (netif_carrier_ok(us_ibdev->netdev))
usnic_fwd_carrier_up(us_ibdev->ufdev);
+ in = ((struct in_device *)(netdev->ip_ptr))->ifa_list;
+ if (in != NULL)
+ usnic_fwd_add_ipaddr(us_ibdev->ufdev, in->ifa_address);
+
+ usnic_mac_ip_to_gid(us_ibdev->netdev->perm_addr,
+ us_ibdev->ufdev->inaddr, &gid.raw[0]);
memcpy(&us_ibdev->ib_dev.node_guid, &gid.global.interface_id,
sizeof(gid.global.interface_id));
kref_init(&us_ibdev->vf_cnt);
goto out_pci_unreg;
}
+ err = register_inetaddr_notifier(&usnic_ib_inetaddr_notifier);
+ if (err) {
+ usnic_err("Failed to register inet addr notifier\n");
+ goto out_unreg_netdev_notifier;
+ }
+
err = usnic_transport_init();
if (err) {
usnic_err("Failed to initialize transport\n");
- goto out_unreg_netdev_notifier;
+ goto out_unreg_inetaddr_notifier;
}
usnic_debugfs_init();
return 0;
+out_unreg_inetaddr_notifier:
+ unregister_inetaddr_notifier(&usnic_ib_inetaddr_notifier);
out_unreg_netdev_notifier:
unregister_netdevice_notifier(&usnic_ib_netdevice_notifier);
out_pci_unreg:
usnic_dbg("\n");
usnic_debugfs_exit();
usnic_transport_fini();
+ unregister_inetaddr_notifier(&usnic_ib_inetaddr_notifier);
unregister_netdevice_notifier(&usnic_ib_netdevice_notifier);
pci_unregister_driver(&usnic_ib_pci_driver);
usnic_uiom_fini();
}
}
+static int create_qp_validate_user_data(struct usnic_ib_create_qp_cmd cmd)
+{
+ if (cmd.spec.trans_type <= USNIC_TRANSPORT_UNKNOWN ||
+ cmd.spec.trans_type >= USNIC_TRANSPORT_MAX)
+ return -EINVAL;
+
+ return 0;
+}
+
/* Start of ib callback functions */
enum rdma_link_layer usnic_ib_port_link_layer(struct ib_device *device,
us_ibdev->netdev->ethtool_ops->get_drvinfo(us_ibdev->netdev, &info);
us_ibdev->netdev->ethtool_ops->get_settings(us_ibdev->netdev, &cmd);
memset(props, 0, sizeof(*props));
- usnic_mac_to_gid(us_ibdev->ufdev->mac, &gid.raw[0]);
+ usnic_mac_ip_to_gid(us_ibdev->ufdev->mac, us_ibdev->ufdev->inaddr,
+ &gid.raw[0]);
memcpy(&props->sys_image_guid, &gid.global.interface_id,
sizeof(gid.global.interface_id));
usnic_ib_fw_string_to_u64(&info.fw_version[0], &props->fw_ver);
props->sm_lid = 0;
props->sm_sl = 0;
- if (us_ibdev->ufdev->link_up) {
- props->state = IB_PORT_ACTIVE;
- props->phys_state = 5;
- } else {
+ if (!us_ibdev->ufdev->link_up) {
props->state = IB_PORT_DOWN;
props->phys_state = 3;
+ } else if (!us_ibdev->ufdev->inaddr) {
+ props->state = IB_PORT_INIT;
+ props->phys_state = 4;
+ } else {
+ props->state = IB_PORT_ACTIVE;
+ props->phys_state = 5;
}
props->port_cap_flags = 0;
mutex_lock(&us_ibdev->usdev_lock);
memset(&(gid->raw[0]), 0, sizeof(gid->raw));
- usnic_mac_to_gid(us_ibdev->ufdev->mac, &gid->raw[0]);
+ usnic_mac_ip_to_gid(us_ibdev->ufdev->mac, us_ibdev->ufdev->inaddr,
+ &gid->raw[0]);
mutex_unlock(&us_ibdev->usdev_lock);
return 0;
struct usnic_ib_ucontext *ucontext;
int cq_cnt;
struct usnic_vnic_res_spec res_spec;
+ struct usnic_ib_create_qp_cmd cmd;
struct usnic_transport_spec trans_spec;
usnic_dbg("\n");
ucontext = to_uucontext(pd->uobject->context);
us_ibdev = to_usdev(pd->device);
+ err = ib_copy_from_udata(&cmd, udata, sizeof(cmd));
+ if (err) {
+ usnic_err("%s: cannot copy udata for create_qp\n",
+ us_ibdev->ib_dev.name);
+ return ERR_PTR(-EINVAL);
+ }
+
+ err = create_qp_validate_user_data(cmd);
+ if (err) {
+ usnic_err("%s: Failed to validate user data\n",
+ us_ibdev->ib_dev.name);
+ return ERR_PTR(-EINVAL);
+ }
+
if (init_attr->qp_type != IB_QPT_UD) {
usnic_err("%s asked to make a non-UD QP: %d\n",
us_ibdev->ib_dev.name, init_attr->qp_type);
return ERR_PTR(-EINVAL);
}
- memset(&trans_spec, 0, sizeof(trans_spec));
- trans_spec.trans_type = USNIC_TRANSPORT_ROCE_CUSTOM;
+ trans_spec = cmd.spec;
mutex_lock(&us_ibdev->usdev_lock);
cq_cnt = (init_attr->send_cq == init_attr->recv_cq) ? 1 : 2;
res_spec = min_transport_spec[trans_spec.trans_type];