On Mon, May 11, 2020 at 12:32:22PM +0200, Jiri Pirko wrote: [...]
> > This is RCU list. Treat it accordingly. > > > >+ spin_unlock(&sw->ports_lock); > > I don't follow, why do you need to protect the list by spinlock here? > More to that, why do you need the port_list reader-writer > protected (by rcu)? Is is possible that you add/remove port in the same > time packets are flying in? > > If yes, you need to ensure the structs are in the memory (free_rcu, > synchronize_rcu). But I believe that you should disable that from > happening in HW. > > > >+ [...] > >+ > >+static int prestera_switch_init(struct prestera_switch *sw) > >+{ > >+ int err; > >+ > >+ err = prestera_hw_switch_init(sw); > >+ if (err) { > >+ dev_err(prestera_dev(sw), "Failed to init Switch device\n"); > >+ return err; > >+ } > >+ > >+ memcpy(sw->base_mac, base_mac_addr, sizeof(sw->base_mac)); > >+ spin_lock_init(&sw->ports_lock); > >+ INIT_LIST_HEAD(&sw->port_list); > >+ > >+ err = prestera_hw_switch_mac_set(sw, sw->base_mac); > >+ if (err) > >+ return err; > >+ > >+ err = prestera_rxtx_switch_init(sw); > >+ if (err) > >+ return err; > >+ > >+ err = prestera_event_handlers_register(sw); > >+ if (err) > >+ goto err_evt_handlers; > >+ > >+ err = prestera_create_ports(sw); > >+ if (err) > >+ goto err_ports_create; > >+ > >+ return 0; > >+ > >+err_ports_create: > > You are missing prestera_event_handlers_unregister(sw); call here. > it is handled below in prestera_switch_fini(). > > >+err_evt_handlers: > >+ prestera_rxtx_switch_fini(sw); > >+ > >+ return err; > >+} > >+ > >+static void prestera_switch_fini(struct prestera_switch *sw) > >+{ > >+ prestera_destroy_ports(sw); > >+ prestera_event_handlers_unregister(sw); > >+ prestera_rxtx_switch_fini(sw); > >+} > >+ > >+int prestera_device_register(struct prestera_device *dev) > >+{ > >+ struct prestera_switch *sw; > >+ int err; > >+ > >+ sw = kzalloc(sizeof(*sw), GFP_KERNEL); > >+ if (!sw) > >+ return -ENOMEM; > >+ > >+ dev->priv = sw; > >+ sw->dev = dev; > >+ > >+ err = prestera_switch_init(sw); > >+ if (err) { > >+ kfree(sw); > >+ return err; > >+ } > >+ > >+ registered_switch = sw; > >+ return 0; > >+} > >+EXPORT_SYMBOL(prestera_device_register); > >+ > >+void prestera_device_unregister(struct prestera_device *dev) > >+{ > >+ struct prestera_switch *sw = dev->priv; > >+ > >+ registered_switch = NULL; > >+ prestera_switch_fini(sw); > >+ kfree(sw); > >+} > >+EXPORT_SYMBOL(prestera_device_unregister); > >+ > >+static int __init prestera_module_init(void) > >+{ > >+ if (!base_mac) { > >+ pr_err("[base_mac] parameter must be specified\n"); > >+ return -EINVAL; > >+ } > >+ if (!mac_pton(base_mac, base_mac_addr)) { > >+ pr_err("[base_mac] parameter has invalid format\n"); > >+ return -EINVAL; > >+ } > >+ > >+ prestera_wq = alloc_workqueue("prestera", 0, 0); > >+ if (!prestera_wq) > >+ return -ENOMEM; > >+ > >+ return 0; > >+} > >+ > >+static void __exit prestera_module_exit(void) > >+{ > >+ destroy_workqueue(prestera_wq); > >+} > >+ > >+module_init(prestera_module_init); > >+module_exit(prestera_module_exit); > >+ > >+MODULE_AUTHOR("Marvell Semi."); > >+MODULE_LICENSE("Dual BSD/GPL"); > >+MODULE_DESCRIPTION("Marvell Prestera switch driver"); > >+ > >+module_param(base_mac, charp, 0); > > No please. > > > [..] >