On Thu, Jan 16, 2020 at 12:10:42PM +0800, Weihang Li wrote: > From: Lang Cheng <chenglang@xxxxxxxxxx> > > For the process of handling the link event of the net device, the driver > of each provider is similar, so it can be integrated into the ib_core for > unified processing. > > Signed-off-by: Lang Cheng <chenglang@xxxxxxxxxx> > Signed-off-by: Weihang Li <liweihang@xxxxxxxxxx> > drivers/infiniband/core/cache.c | 21 ++++++- > drivers/infiniband/core/device.c | 123 +++++++++++++++++++++++++++++++++++++++ > include/rdma/ib_cache.h | 13 +++++ > include/rdma/ib_verbs.h | 8 +++ > 4 files changed, 164 insertions(+), 1 deletion(-) > > diff --git a/drivers/infiniband/core/cache.c b/drivers/infiniband/core/cache.c > index 17bfedd..791e965 100644 > +++ b/drivers/infiniband/core/cache.c > @@ -1174,6 +1174,23 @@ int ib_get_cached_port_state(struct ib_device *device, > } > EXPORT_SYMBOL(ib_get_cached_port_state); > > +int ib_get_cached_port_event_flags(struct ib_device *device, > + u8 port_num, > + enum ib_port_flags *event_flags) > +{ > + unsigned long flags; > + > + if (!rdma_is_port_valid(device, port_num)) > + return -EINVAL; > + > + read_lock_irqsave(&device->cache_lock, flags); > + *event_flags = device->port_data[port_num].cache.port_event_flags; > + read_unlock_irqrestore(&device->cache_lock, flags); > + > + return 0; > +} > +EXPORT_SYMBOL(ib_get_cached_port_event_flags); > + > /** > * rdma_get_gid_attr - Returns GID attributes for a port of a device > * at a requested gid_index, if a valid GID entry exists. > @@ -1391,7 +1408,7 @@ ib_cache_update(struct ib_device *device, u8 port, bool enforce_security) > if (!rdma_is_port_valid(device, port)) > return -EINVAL; > > - tprops = kmalloc(sizeof *tprops, GFP_KERNEL); > + tprops = kzalloc(sizeof(*tprops), GFP_KERNEL); > if (!tprops) > return -ENOMEM; > > @@ -1435,6 +1452,8 @@ ib_cache_update(struct ib_device *device, u8 port, bool enforce_security) > device->port_data[port].cache.pkey = pkey_cache; > device->port_data[port].cache.lmc = tprops->lmc; > device->port_data[port].cache.port_state = tprops->state; > + device->port_data[port].cache.port_event_flags = > + tprops->port_event_flags; > > device->port_data[port].cache.subnet_prefix = tprops->subnet_prefix; > write_unlock_irq(&device->cache_lock); > diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c > index f6c2552..f03d6ce 100644 > +++ b/drivers/infiniband/core/device.c > @@ -1325,6 +1325,77 @@ static int enable_device_and_get(struct ib_device *device) > return ret; > } > > +unsigned int ib_query_ndev_port_num(struct ib_device *device, > + struct net_device *netdev) > +{ > + unsigned int port_num; > + > + rdma_for_each_port(device, port_num) > + if (netdev == device->port_data[port_num].netdev) > + break; > + > + return port_num; > +} > +EXPORT_SYMBOL(ib_query_ndev_port_num); This returns garbage if the netdev isn't found > + > +static inline enum ib_port_state get_port_state(struct net_device *netdev) > +{ > + return (netif_running(netdev) && netif_carrier_ok(netdev)) ? > + IB_PORT_ACTIVE : IB_PORT_DOWN; > +} > + > +static int ib_netdev_event(struct notifier_block *this, > + unsigned long event, void *ptr) > +{ > + struct ib_device *device = container_of(this, struct ib_device, nb); > + struct net_device *netdev = netdev_notifier_info_to_dev(ptr); > + > + switch (event) { > + case NETDEV_CHANGE: > + case NETDEV_UP: > + case NETDEV_DOWN: { > + unsigned int port_num = ib_query_ndev_port_num(device, netdev); > + enum ib_port_state last_state; > + enum ib_port_state curr_state; > + struct ib_event ibev; > + enum ib_port_flags flags; > + > + if (ib_get_cached_port_event_flags(device, port_num, &flags)) > + return NOTIFY_DONE; > + > + if (flags & IB_PORT_BONDING_SLAVE) > + goto done; > + > + if (ib_get_cached_port_state(device, port_num, &last_state)) > + return NOTIFY_DONE; > + > + curr_state = get_port_state(netdev); > + > + if (last_state == curr_state) > + goto done; > + > + ibev.device = device; > + if (curr_state == IB_PORT_DOWN) > + ibev.event = IB_EVENT_PORT_ERR; > + else if (curr_state == IB_PORT_ACTIVE) > + ibev.event = IB_EVENT_PORT_ACTIVE; > + else > + goto done; > + > + ibev.element.port_num = port_num; > + ib_dispatch_event(&ibev); > + dev_dbg(&device->dev, > + "core send %s\n", ib_event_msg(ibev.event)); > + break; > + } > + > + default: > + break; > + } > +done: > + return NOTIFY_DONE; > +} > + > /** > * ib_register_device - Register an IB device with IB core > * @device: Device to register > @@ -1342,6 +1413,7 @@ static int enable_device_and_get(struct ib_device *device) > */ > int ib_register_device(struct ib_device *device, const char *name) > { > + unsigned int port; > int ret; > > ret = assign_name(device, name); > @@ -1406,6 +1478,34 @@ int ib_register_device(struct ib_device *device, const char *name) > } > ib_device_put(device); > > + device->nb.notifier_call = ib_netdev_event; > + ret = register_netdevice_notifier(&device->nb); Lets not register a notifer for every device please, we already have ib_device_get_by_netdev() for this purpose, and we already have global notifiers in this module. Jason