Lines Matching +full:software +full:- +full:dl

1 // SPDX-License-Identifier: GPL-2.0-or-later
5 * Copyright (c) 2008-2009 Marvell Semiconductor
53 * dsa_lag_map() - Map LAG structure to a linear LAG array
59 * driver by setting ds->num_lag_ids. It is perfectly legal to leave
61 * no-ops.
67 for (id = 1; id <= dst->lags_len; id++) { in dsa_lag_map()
69 dst->lags[id - 1] = lag; in dsa_lag_map()
70 lag->id = id; in dsa_lag_map()
78 * driver can then return -EOPNOTSUPP back to DSA, which will in dsa_lag_map()
79 * fall back to a software LAG. in dsa_lag_map()
84 * dsa_lag_unmap() - Remove a LAG ID mapping
97 dst->lags[id - 1] = NULL; in dsa_lag_unmap()
98 lag->id = 0; in dsa_lag_unmap()
109 list_for_each_entry(dp, &dst->ports, list) in dsa_tree_lag_find()
111 return dp->lag; in dsa_tree_lag_find()
121 list_for_each_entry(dp, &dst->ports, list) in dsa_tree_bridge_find()
123 return dp->bridge; in dsa_tree_bridge_find()
137 return bridge->num; in dsa_bridge_num_find()
185 if (dst->index != tree_index) in dsa_switch_find()
188 list_for_each_entry(dp, &dst->ports, list) { in dsa_switch_find()
189 if (dp->ds->index != sw_index) in dsa_switch_find()
192 return dp->ds; in dsa_switch_find()
205 if (dst->index == index) in dsa_tree_find()
219 dst->index = index; in dsa_tree_alloc()
221 INIT_LIST_HEAD(&dst->rtable); in dsa_tree_alloc()
223 INIT_LIST_HEAD(&dst->ports); in dsa_tree_alloc()
225 INIT_LIST_HEAD(&dst->list); in dsa_tree_alloc()
226 list_add_tail(&dst->list, &dsa_tree_list); in dsa_tree_alloc()
228 kref_init(&dst->refcount); in dsa_tree_alloc()
235 if (dst->tag_ops) in dsa_tree_free()
236 dsa_tag_driver_put(dst->tag_ops); in dsa_tree_free()
237 list_del(&dst->list); in dsa_tree_free()
244 kref_get(&dst->refcount); in dsa_tree_get()
272 kref_put(&dst->refcount, dsa_tree_release); in dsa_tree_put()
280 list_for_each_entry(dp, &dst->ports, list) in dsa_tree_find_port_by_node()
281 if (dp->dn == dn) in dsa_tree_find_port_by_node()
290 struct dsa_switch *ds = dp->ds; in dsa_link_touch()
292 struct dsa_link *dl; in dsa_link_touch() local
294 dst = ds->dst; in dsa_link_touch()
296 list_for_each_entry(dl, &dst->rtable, list) in dsa_link_touch()
297 if (dl->dp == dp && dl->link_dp == link_dp) in dsa_link_touch()
298 return dl; in dsa_link_touch()
300 dl = kzalloc(sizeof(*dl), GFP_KERNEL); in dsa_link_touch()
301 if (!dl) in dsa_link_touch()
304 dl->dp = dp; in dsa_link_touch()
305 dl->link_dp = link_dp; in dsa_link_touch()
307 INIT_LIST_HEAD(&dl->list); in dsa_link_touch()
308 list_add_tail(&dl->list, &dst->rtable); in dsa_link_touch()
310 return dl; in dsa_link_touch()
315 struct dsa_switch *ds = dp->ds; in dsa_port_setup_routing_table()
316 struct dsa_switch_tree *dst = ds->dst; in dsa_port_setup_routing_table()
317 struct device_node *dn = dp->dn; in dsa_port_setup_routing_table()
320 struct dsa_link *dl; in dsa_port_setup_routing_table() local
330 dl = dsa_link_touch(dp, link_dp); in dsa_port_setup_routing_table()
331 if (!dl) { in dsa_port_setup_routing_table()
345 list_for_each_entry(dp, &dst->ports, list) { in dsa_tree_setup_routing_table()
360 list_for_each_entry(dp, &dst->ports, list) in dsa_tree_find_first_cpu()
374 ethernet = of_parse_phandle(cpu_dp->dn, "ethernet", 0); in dsa_tree_find_first_conduit()
390 pr_err("DSA: tree %d has no CPU port\n", dst->index); in dsa_tree_setup_default_cpu()
391 return -EINVAL; in dsa_tree_setup_default_cpu()
394 list_for_each_entry(dp, &dst->ports, list) { in dsa_tree_setup_default_cpu()
395 if (dp->cpu_dp) in dsa_tree_setup_default_cpu()
399 dp->cpu_dp = cpu_dp; in dsa_tree_setup_default_cpu()
410 if (!ds->ops->preferred_default_local_cpu_port) in dsa_switch_preferred_default_local_cpu_port()
413 cpu_dp = ds->ops->preferred_default_local_cpu_port(ds); in dsa_switch_preferred_default_local_cpu_port()
417 if (WARN_ON(!dsa_port_is_cpu(cpu_dp) || cpu_dp->ds != ds)) in dsa_switch_preferred_default_local_cpu_port()
432 list_for_each_entry(cpu_dp, &dst->ports, list) { in dsa_tree_setup_cpu_ports()
436 preferred_cpu_dp = dsa_switch_preferred_default_local_cpu_port(cpu_dp->ds); in dsa_tree_setup_cpu_ports()
441 dsa_switch_for_each_port(dp, cpu_dp->ds) { in dsa_tree_setup_cpu_ports()
443 if (dp->cpu_dp) in dsa_tree_setup_cpu_ports()
447 dp->cpu_dp = cpu_dp; in dsa_tree_setup_cpu_ports()
458 list_for_each_entry(dp, &dst->ports, list) in dsa_tree_teardown_cpu_ports()
460 dp->cpu_dp = NULL; in dsa_tree_teardown_cpu_ports()
466 struct dsa_switch *ds = dp->ds; in dsa_port_setup()
470 if (dp->setup) in dsa_port_setup()
477 switch (dp->type) { in dsa_port_setup()
482 if (dp->dn) { in dsa_port_setup()
488 dev_warn(ds->dev, in dsa_port_setup()
490 dp->index); in dsa_port_setup()
500 if (dp->dn) { in dsa_port_setup()
506 dev_warn(ds->dev, in dsa_port_setup()
508 dp->index); in dsa_port_setup()
518 of_get_mac_address(dp->dn, dp->mac); in dsa_port_setup()
532 dp->setup = true; in dsa_port_setup()
539 if (!dp->setup) in dsa_port_teardown()
542 switch (dp->type) { in dsa_port_teardown()
547 if (dp->dn) in dsa_port_teardown()
552 if (dp->dn) in dsa_port_teardown()
556 if (dp->user) { in dsa_port_teardown()
557 dsa_user_destroy(dp->user); in dsa_port_teardown()
558 dp->user = NULL; in dsa_port_teardown()
565 dp->setup = false; in dsa_port_teardown()
570 dp->type = DSA_PORT_TYPE_UNUSED; in dsa_port_setup_as_unused()
576 const struct dsa_device_ops *tag_ops = ds->dst->tag_ops; in dsa_switch_setup_tag_protocol()
577 struct dsa_switch_tree *dst = ds->dst; in dsa_switch_setup_tag_protocol()
580 if (tag_ops->proto == dst->default_proto) in dsa_switch_setup_tag_protocol()
584 err = ds->ops->change_tag_protocol(ds, tag_ops->proto); in dsa_switch_setup_tag_protocol()
587 dev_err(ds->dev, "Unable to use tag protocol \"%s\": %pe\n", in dsa_switch_setup_tag_protocol()
588 tag_ops->name, ERR_PTR(err)); in dsa_switch_setup_tag_protocol()
593 if (tag_ops->connect) { in dsa_switch_setup_tag_protocol()
594 err = tag_ops->connect(ds); in dsa_switch_setup_tag_protocol()
599 if (ds->ops->connect_tag_protocol) { in dsa_switch_setup_tag_protocol()
600 err = ds->ops->connect_tag_protocol(ds, tag_ops->proto); in dsa_switch_setup_tag_protocol()
602 dev_err(ds->dev, in dsa_switch_setup_tag_protocol()
604 tag_ops->name, ERR_PTR(err)); in dsa_switch_setup_tag_protocol()
612 if (tag_ops->disconnect) in dsa_switch_setup_tag_protocol()
613 tag_ops->disconnect(ds); in dsa_switch_setup_tag_protocol()
620 const struct dsa_device_ops *tag_ops = ds->dst->tag_ops; in dsa_switch_teardown_tag_protocol()
622 if (tag_ops->disconnect) in dsa_switch_teardown_tag_protocol()
623 tag_ops->disconnect(ds); in dsa_switch_teardown_tag_protocol()
630 if (ds->setup) in dsa_switch_setup()
633 /* Initialize ds->phys_mii_mask before registering the user MDIO bus in dsa_switch_setup()
634 * driver and before ops->setup() has run, since the switch drivers and in dsa_switch_setup()
638 ds->phys_mii_mask |= dsa_user_ports(ds); in dsa_switch_setup()
648 ds->configure_vlan_while_not_filtering = true; in dsa_switch_setup()
650 err = ds->ops->setup(ds); in dsa_switch_setup()
658 if (!ds->user_mii_bus && ds->ops->phy_read) { in dsa_switch_setup()
659 ds->user_mii_bus = mdiobus_alloc(); in dsa_switch_setup()
660 if (!ds->user_mii_bus) { in dsa_switch_setup()
661 err = -ENOMEM; in dsa_switch_setup()
667 err = mdiobus_register(ds->user_mii_bus); in dsa_switch_setup()
674 ds->setup = true; in dsa_switch_setup()
678 if (ds->user_mii_bus && ds->ops->phy_read) in dsa_switch_setup()
679 mdiobus_free(ds->user_mii_bus); in dsa_switch_setup()
681 if (ds->ops->teardown) in dsa_switch_setup()
682 ds->ops->teardown(ds); in dsa_switch_setup()
692 if (!ds->setup) in dsa_switch_teardown()
697 if (ds->user_mii_bus && ds->ops->phy_read) { in dsa_switch_teardown()
698 mdiobus_unregister(ds->user_mii_bus); in dsa_switch_teardown()
699 mdiobus_free(ds->user_mii_bus); in dsa_switch_teardown()
700 ds->user_mii_bus = NULL; in dsa_switch_teardown()
705 if (ds->ops->teardown) in dsa_switch_teardown()
706 ds->ops->teardown(ds); in dsa_switch_teardown()
712 ds->setup = false; in dsa_switch_teardown()
715 /* First tear down the non-shared, then the shared ports. This ensures that
723 list_for_each_entry(dp, &dst->ports, list) in dsa_tree_teardown_ports()
729 list_for_each_entry(dp, &dst->ports, list) in dsa_tree_teardown_ports()
738 list_for_each_entry(dp, &dst->ports, list) in dsa_tree_teardown_switches()
739 dsa_switch_teardown(dp->ds); in dsa_tree_teardown_switches()
742 /* Bring shared ports up first, then non-shared ports */
748 list_for_each_entry(dp, &dst->ports, list) { in dsa_tree_setup_ports()
756 list_for_each_entry(dp, &dst->ports, list) { in dsa_tree_setup_ports()
780 list_for_each_entry(dp, &dst->ports, list) { in dsa_tree_setup_switches()
781 err = dsa_switch_setup(dp->ds); in dsa_tree_setup_switches()
799 struct net_device *conduit = cpu_dp->conduit; in dsa_tree_setup_conduit()
800 bool admin_up = (conduit->flags & IFF_UP) && in dsa_tree_setup_conduit()
825 struct net_device *conduit = cpu_dp->conduit; in dsa_tree_teardown_conduit()
844 list_for_each_entry(dp, &dst->ports, list) { in dsa_tree_setup_lags()
845 if (dp->ds->num_lag_ids > len) in dsa_tree_setup_lags()
846 len = dp->ds->num_lag_ids; in dsa_tree_setup_lags()
852 dst->lags = kcalloc(len, sizeof(*dst->lags), GFP_KERNEL); in dsa_tree_setup_lags()
853 if (!dst->lags) in dsa_tree_setup_lags()
854 return -ENOMEM; in dsa_tree_setup_lags()
856 dst->lags_len = len; in dsa_tree_setup_lags()
862 kfree(dst->lags); in dsa_tree_teardown_lags()
867 struct dsa_link *dl, *next; in dsa_tree_teardown_routing_table() local
869 list_for_each_entry_safe(dl, next, &dst->rtable, list) { in dsa_tree_teardown_routing_table()
870 list_del(&dl->list); in dsa_tree_teardown_routing_table()
871 kfree(dl); in dsa_tree_teardown_routing_table()
880 if (dst->setup) { in dsa_tree_setup()
882 dst->index); in dsa_tree_setup()
883 return -EEXIST; in dsa_tree_setup()
910 dst->setup = true; in dsa_tree_setup()
912 pr_info("DSA: tree %d setup\n", dst->index); in dsa_tree_setup()
932 if (!dst->setup) in dsa_tree_teardown()
947 pr_info("DSA: tree %d torn down\n", dst->index); in dsa_tree_teardown()
949 dst->setup = false; in dsa_tree_teardown()
955 const struct dsa_device_ops *old_tag_ops = dst->tag_ops; in dsa_tree_bind_tag_proto()
959 dst->tag_ops = tag_ops; in dsa_tree_bind_tag_proto()
966 if (err && err != -EOPNOTSUPP) in dsa_tree_bind_tag_proto()
978 dst->tag_ops = old_tag_ops; in dsa_tree_bind_tag_proto()
993 int err = -EBUSY; in dsa_tree_change_tag_proto()
1004 if (dsa_port_to_conduit(dp)->flags & IFF_UP) in dsa_tree_change_tag_proto()
1007 if (dp->user->flags & IFF_UP) in dsa_tree_change_tag_proto()
1037 struct dsa_port *cpu_dp = conduit->dsa_ptr; in dsa_tree_conduit_state_change()
1049 struct dsa_port *cpu_dp = conduit->dsa_ptr; in dsa_tree_conduit_admin_state_change()
1059 (up && cpu_dp->conduit_oper_up)) in dsa_tree_conduit_admin_state_change()
1062 cpu_dp->conduit_admin_up = up; in dsa_tree_conduit_admin_state_change()
1072 struct dsa_port *cpu_dp = conduit->dsa_ptr; in dsa_tree_conduit_oper_state_change()
1082 (cpu_dp->conduit_admin_up && up)) in dsa_tree_conduit_oper_state_change()
1085 cpu_dp->conduit_oper_up = up; in dsa_tree_conduit_oper_state_change()
1093 struct dsa_switch_tree *dst = ds->dst; in dsa_port_touch()
1097 if (dp->index == index) in dsa_port_touch()
1104 dp->ds = ds; in dsa_port_touch()
1105 dp->index = index; in dsa_port_touch()
1107 mutex_init(&dp->addr_lists_lock); in dsa_port_touch()
1108 mutex_init(&dp->vlans_lock); in dsa_port_touch()
1109 INIT_LIST_HEAD(&dp->fdbs); in dsa_port_touch()
1110 INIT_LIST_HEAD(&dp->mdbs); in dsa_port_touch()
1111 INIT_LIST_HEAD(&dp->vlans); /* also initializes &dp->user_vlans */ in dsa_port_touch()
1112 INIT_LIST_HEAD(&dp->list); in dsa_port_touch()
1113 list_add_tail(&dp->list, &dst->ports); in dsa_port_touch()
1120 dp->type = DSA_PORT_TYPE_USER; in dsa_port_parse_user()
1121 dp->name = name; in dsa_port_parse_user()
1128 dp->type = DSA_PORT_TYPE_DSA; in dsa_port_parse_dsa()
1137 struct dsa_switch *mds, *ds = dp->ds; in dsa_get_tag_protocol()
1147 mds = mdp->ds; in dsa_get_tag_protocol()
1148 mdp_upstream = dsa_upstream_port(mds, mdp->index); in dsa_get_tag_protocol()
1149 tag_protocol = mds->ops->get_tag_protocol(mds, mdp_upstream, in dsa_get_tag_protocol()
1156 return ds->ops->get_tag_protocol(ds, dp->index, tag_protocol); in dsa_get_tag_protocol()
1163 struct dsa_switch *ds = dp->ds; in dsa_port_parse_cpu()
1164 struct dsa_switch_tree *dst = ds->dst; in dsa_port_parse_cpu()
1169 if (dst->default_proto) { in dsa_port_parse_cpu()
1170 if (dst->default_proto != default_proto) { in dsa_port_parse_cpu()
1171 dev_err(ds->dev, in dsa_port_parse_cpu()
1173 return -EINVAL; in dsa_port_parse_cpu()
1176 dst->default_proto = default_proto; in dsa_port_parse_cpu()
1181 if (!ds->ops->change_tag_protocol) { in dsa_port_parse_cpu()
1182 dev_err(ds->dev, "Tag protocol cannot be modified\n"); in dsa_port_parse_cpu()
1183 return -EINVAL; in dsa_port_parse_cpu()
1188 dev_warn(ds->dev, in dsa_port_parse_cpu()
1199 if (PTR_ERR(tag_ops) == -ENOPROTOOPT) in dsa_port_parse_cpu()
1200 return -EPROBE_DEFER; in dsa_port_parse_cpu()
1202 dev_warn(ds->dev, "No tagger for this switch\n"); in dsa_port_parse_cpu()
1206 if (dst->tag_ops) { in dsa_port_parse_cpu()
1207 if (dst->tag_ops != tag_ops) { in dsa_port_parse_cpu()
1208 dev_err(ds->dev, in dsa_port_parse_cpu()
1212 return -EINVAL; in dsa_port_parse_cpu()
1216 * protocol is still reference-counted only per switch tree. in dsa_port_parse_cpu()
1220 dst->tag_ops = tag_ops; in dsa_port_parse_cpu()
1223 dp->conduit = conduit; in dsa_port_parse_cpu()
1224 dp->type = DSA_PORT_TYPE_CPU; in dsa_port_parse_cpu()
1225 dsa_port_set_tag_protocol(dp, dst->tag_ops); in dsa_port_parse_cpu()
1226 dp->dst = dst; in dsa_port_parse_cpu()
1250 dp->dn = dn; in dsa_port_parse_of()
1259 return -EPROBE_DEFER; in dsa_port_parse_of()
1261 user_protocol = of_get_property(dn, "dsa-tag-protocol", NULL); in dsa_port_parse_of()
1281 /* The second possibility is "ethernet-ports" */ in dsa_switch_parse_ports_of()
1282 ports = of_get_child_by_name(dn, "ethernet-ports"); in dsa_switch_parse_ports_of()
1284 dev_err(ds->dev, "no ports child node found\n"); in dsa_switch_parse_ports_of()
1285 return -EINVAL; in dsa_switch_parse_ports_of()
1296 if (reg >= ds->num_ports) { in dsa_switch_parse_ports_of()
1297 dev_err(ds->dev, "port %pOF index %u exceeds num_ports (%u)\n", in dsa_switch_parse_ports_of()
1298 port, reg, ds->num_ports); in dsa_switch_parse_ports_of()
1300 err = -EINVAL; in dsa_switch_parse_ports_of()
1326 if (sz < 0 && sz != -EINVAL) in dsa_switch_parse_member_of()
1329 ds->index = m[1]; in dsa_switch_parse_member_of()
1331 ds->dst = dsa_tree_touch(m[0]); in dsa_switch_parse_member_of()
1332 if (!ds->dst) in dsa_switch_parse_member_of()
1333 return -ENOMEM; in dsa_switch_parse_member_of()
1335 if (dsa_switch_find(ds->dst->index, ds->index)) { in dsa_switch_parse_member_of()
1336 dev_err(ds->dev, in dsa_switch_parse_member_of()
1338 ds->index, ds->dst->index); in dsa_switch_parse_member_of()
1339 return -EEXIST; in dsa_switch_parse_member_of()
1342 if (ds->dst->last_switch < ds->index) in dsa_switch_parse_member_of()
1343 ds->dst->last_switch = ds->index; in dsa_switch_parse_member_of()
1353 for (port = 0; port < ds->num_ports; port++) { in dsa_switch_touch_ports()
1356 return -ENOMEM; in dsa_switch_touch_ports()
1379 if (dev->class != NULL && !strcmp(dev->class->name, class)) in dev_is_class()
1421 return -EPROBE_DEFER; in dsa_port_parse()
1445 name = cd->port_names[i]; in dsa_switch_parse_ports()
1446 dev = cd->netdev[i]; in dsa_switch_parse_ports()
1460 return -EINVAL; in dsa_switch_parse_ports()
1469 ds->cd = cd; in dsa_switch_parse()
1474 ds->index = 0; in dsa_switch_parse()
1475 ds->dst = dsa_tree_touch(0); in dsa_switch_parse()
1476 if (!ds->dst) in dsa_switch_parse()
1477 return -ENOMEM; in dsa_switch_parse()
1498 list_for_each_entry_safe(a, tmp, &dp->fdbs, list) { in dsa_switch_release_ports()
1499 dev_info(ds->dev, in dsa_switch_release_ports()
1501 a->addr, a->vid, dp->index); in dsa_switch_release_ports()
1502 list_del(&a->list); in dsa_switch_release_ports()
1506 list_for_each_entry_safe(a, tmp, &dp->mdbs, list) { in dsa_switch_release_ports()
1507 dev_info(ds->dev, in dsa_switch_release_ports()
1509 a->addr, a->vid, dp->index); in dsa_switch_release_ports()
1510 list_del(&a->list); in dsa_switch_release_ports()
1518 list_for_each_entry_safe(v, n, &dp->vlans, list) { in dsa_switch_release_ports()
1519 dev_info(ds->dev, in dsa_switch_release_ports()
1521 v->vid, dp->index); in dsa_switch_release_ports()
1522 list_del(&v->list); in dsa_switch_release_ports()
1526 list_del(&dp->list); in dsa_switch_release_ports()
1538 if (!ds->dev) in dsa_switch_probe()
1539 return -ENODEV; in dsa_switch_probe()
1541 pdata = ds->dev->platform_data; in dsa_switch_probe()
1542 np = ds->dev->of_node; in dsa_switch_probe()
1544 if (!ds->num_ports) in dsa_switch_probe()
1545 return -EINVAL; in dsa_switch_probe()
1556 err = -ENODEV; in dsa_switch_probe()
1562 dst = ds->dst; in dsa_switch_probe()
1579 dsa_tree_put(ds->dst); in dsa_register_switch()
1588 struct dsa_switch_tree *dst = ds->dst; in dsa_switch_remove()
1616 if (!ds->setup) in dsa_switch_shutdown()
1622 list_add(&dp->conduit->close_list, &close_list); in dsa_switch_shutdown()
1628 user_dev = dp->user; in dsa_switch_shutdown()
1638 dp->conduit->dsa_ptr = NULL; in dsa_switch_shutdown()
1649 return dp->type == DSA_PORT_TYPE_USER && dp->user; in dsa_port_is_initialized()
1662 ret = dsa_user_suspend(dp->user); in dsa_switch_suspend()
1667 if (ds->ops->suspend) in dsa_switch_suspend()
1668 ret = ds->ops->suspend(ds); in dsa_switch_suspend()
1679 if (ds->ops->resume) in dsa_switch_resume()
1680 ret = ds->ops->resume(ds); in dsa_switch_resume()
1690 ret = dsa_user_resume(dp->user); in dsa_switch_resume()
1703 return ERR_PTR(-ENODEV); in dsa_port_from_netdev()
1711 if (a->type != b->type) in dsa_db_equal()
1714 switch (a->type) { in dsa_db_equal()
1716 return a->dp == b->dp; in dsa_db_equal()
1718 return a->lag.dev == b->lag.dev; in dsa_db_equal()
1720 return a->bridge.num == b->bridge.num; in dsa_db_equal()
1734 lockdep_assert_held(&dp->addr_lists_lock); in dsa_fdb_present_in_other_db()
1736 list_for_each_entry(a, &dp->fdbs, list) { in dsa_fdb_present_in_other_db()
1737 if (!ether_addr_equal(a->addr, addr) || a->vid != vid) in dsa_fdb_present_in_other_db()
1740 if (a->db.type == db.type && !dsa_db_equal(&a->db, &db)) in dsa_fdb_present_in_other_db()
1755 lockdep_assert_held(&dp->addr_lists_lock); in dsa_mdb_present_in_other_db()
1757 list_for_each_entry(a, &dp->mdbs, list) { in dsa_mdb_present_in_other_db()
1758 if (!ether_addr_equal(a->addr, mdb->addr) || a->vid != mdb->vid) in dsa_mdb_present_in_other_db()
1761 if (a->db.type == db.type && !dsa_db_equal(&a->db, &db)) in dsa_mdb_present_in_other_db()
1790 return -ENOMEM; in dsa_init_module()