Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

dibs: Define dibs_client_ops and dibs_dev_ops

Move the device add() and remove() functions from ism_client to
dibs_client_ops and call add_dev()/del_dev() for ism devices and
dibs_loopback devices. dibs_client_ops->add_dev() = smcd_register_dev() for
the smc_dibs_client. This is the first step to handle ism and loopback
devices alike (as dibs devices) in the smc dibs client.

Define dibs_dev->ops and move smcd_ops->get_chid to
dibs_dev_ops->get_fabric_id() for ism and loopback devices. See below for
why this needs to be in the same patch as dibs_client_ops->add_dev().

The following changes contain intermediate steps, that will be obsoleted by
follow-on patches, once more functionality has been moved to dibs:

Use different smcd_ops and max_dmbs for ism and loopback. Follow-on patches
will change SMC-D to directly use dibs_ops instead of smcd_ops.

In smcd_register_dev() it is now necessary to identify a dibs_loopback
device before smcd_dev and smcd_ops->get_chid() are available. So provide
dibs_dev_ops->get_fabric_id() in this patch and evaluate it in
smc_ism_is_loopback().

Call smc_loopback_init() in smcd_register_dev() and call
smc_loopback_exit() in smcd_unregister_dev() to handle the functionality
that is still in smc_loopback. Follow-on patches will move all smc_loopback
code to dibs_loopback.

In smcd_[un]register_dev() use only ism device name, this will be replaced
by dibs device name by a follow-on patch.

End of changes with intermediate parts.

Allocate an smcd event workqueue for all dibs devices, although
dibs_loopback does not generate events.

Use kernel memory instead of devres memory for smcd_dev and smcd->conn.
Since commit a72178cfe855 ("net/smc: Fix dependency of SMC on ISM") an ism
device and its driver can have a longer lifetime than the smc module, so
smc should not rely on devres to free its resources [1]. It is now the
responsibility of the smc client to free smcd and smcd->conn for all dibs
devices, ism devices as well as loopback. Call client->ops->del_dev() for
all existing dibs devices in dibs_unregister_client(), so all device
related structures can be freed in the client.

When dibs_unregister_client() is called in the context of smc_exit() or
smc_core_reboot_event(), these functions have already called
smc_lgrs_shutdown() which calls smc_smcd_terminate_all(smcd) and sets
going_away. This is done a second time in smcd_unregister_dev(). This is
analogous to how smcr is handled in these functions, by calling first
smc_lgrs_shutdown() and then smc_ib_unregister_client() >
smc_ib_remove_dev(), so leave it that way. It may be worth investigating,
whether smc_lgrs_shutdown() is still required or useful.

Remove CONFIG_SMC_LO. CONFIG_DIBS_LO now controls whether a dibs loopback
device exists or not.

Link: https://www.kernel.org/doc/Documentation/driver-model/devres.txt [1]
Signed-off-by: Alexandra Winter <wintera@linux.ibm.com>
Reviewed-by: Mahanta Jambigi <mjambigi@linux.ibm.com>
Link: https://patch.msgid.link/20250918110500.1731261-8-wintera@linux.ibm.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>

authored by

Alexandra Winter and committed by
Paolo Abeni
69baaac9 cb990a45

+270 -193
-1
arch/s390/configs/debug_defconfig
··· 123 123 CONFIG_DIBS=y 124 124 CONFIG_DIBS_LO=y 125 125 CONFIG_SMC_DIAG=m 126 - CONFIG_SMC_LO=y 127 126 CONFIG_INET=y 128 127 CONFIG_IP_MULTICAST=y 129 128 CONFIG_IP_ADVANCED_ROUTER=y
-1
arch/s390/configs/defconfig
··· 114 114 CONFIG_DIBS=y 115 115 CONFIG_DIBS_LO=y 116 116 CONFIG_SMC_DIAG=m 117 - CONFIG_SMC_LO=y 118 117 CONFIG_INET=y 119 118 CONFIG_IP_MULTICAST=y 120 119 CONFIG_IP_ADVANCED_ROUTER=y
+11
drivers/dibs/dibs_loopback.c
··· 18 18 /* global loopback device */ 19 19 static struct dibs_lo_dev *lo_dev; 20 20 21 + static u16 dibs_lo_get_fabric_id(struct dibs_dev *dibs) 22 + { 23 + return DIBS_LOOPBACK_FABRIC; 24 + } 25 + 26 + static const struct dibs_dev_ops dibs_lo_ops = { 27 + .get_fabric_id = dibs_lo_get_fabric_id, 28 + }; 29 + 21 30 static void dibs_lo_dev_exit(struct dibs_lo_dev *ldev) 22 31 { 23 32 dibs_dev_del(ldev->dibs); ··· 49 40 } 50 41 51 42 ldev->dibs = dibs; 43 + dibs->drv_priv = ldev; 44 + dibs->ops = &dibs_lo_ops; 52 45 53 46 ret = dibs_dev_add(dibs); 54 47 if (ret)
+36
drivers/dibs/dibs_main.c
··· 36 36 37 37 int dibs_register_client(struct dibs_client *client) 38 38 { 39 + struct dibs_dev *dibs; 39 40 int i, rc = -ENOSPC; 40 41 42 + mutex_lock(&dibs_dev_list.mutex); 41 43 mutex_lock(&clients_lock); 42 44 for (i = 0; i < MAX_DIBS_CLIENTS; ++i) { 43 45 if (!clients[i]) { ··· 53 51 } 54 52 mutex_unlock(&clients_lock); 55 53 54 + if (i < MAX_DIBS_CLIENTS) { 55 + /* initialize with all devices that we got so far */ 56 + list_for_each_entry(dibs, &dibs_dev_list.list, list) { 57 + dibs->priv[i] = NULL; 58 + client->ops->add_dev(dibs); 59 + } 60 + } 61 + mutex_unlock(&dibs_dev_list.mutex); 62 + 56 63 return rc; 57 64 } 58 65 EXPORT_SYMBOL_GPL(dibs_register_client); 59 66 60 67 int dibs_unregister_client(struct dibs_client *client) 61 68 { 69 + struct dibs_dev *dibs; 62 70 int rc = 0; 71 + 72 + mutex_lock(&dibs_dev_list.mutex); 73 + list_for_each_entry(dibs, &dibs_dev_list.list, list) { 74 + clients[client->id]->ops->del_dev(dibs); 75 + dibs->priv[client->id] = NULL; 76 + } 63 77 64 78 mutex_lock(&clients_lock); 65 79 clients[client->id] = NULL; 66 80 if (client->id + 1 == max_client) 67 81 max_client--; 68 82 mutex_unlock(&clients_lock); 83 + 84 + mutex_unlock(&dibs_dev_list.mutex); 69 85 return rc; 70 86 } 71 87 EXPORT_SYMBOL_GPL(dibs_unregister_client); ··· 100 80 101 81 int dibs_dev_add(struct dibs_dev *dibs) 102 82 { 83 + int i; 84 + 103 85 mutex_lock(&dibs_dev_list.mutex); 86 + mutex_lock(&clients_lock); 87 + for (i = 0; i < max_client; ++i) { 88 + if (clients[i]) 89 + clients[i]->ops->add_dev(dibs); 90 + } 91 + mutex_unlock(&clients_lock); 104 92 list_add(&dibs->list, &dibs_dev_list.list); 105 93 mutex_unlock(&dibs_dev_list.mutex); 106 94 ··· 118 90 119 91 void dibs_dev_del(struct dibs_dev *dibs) 120 92 { 93 + int i; 94 + 121 95 mutex_lock(&dibs_dev_list.mutex); 96 + mutex_lock(&clients_lock); 97 + for (i = 0; i < max_client; ++i) { 98 + if (clients[i]) 99 + clients[i]->ops->del_dev(dibs); 100 + } 101 + mutex_unlock(&clients_lock); 122 102 list_del_init(&dibs->list); 123 103 mutex_unlock(&dibs_dev_list.mutex); 124 104 }
+19 -24
drivers/s390/net/ism_drv.c
··· 79 79 /* initialize with all devices that we got so far */ 80 80 list_for_each_entry(ism, &ism_dev_list.list, list) { 81 81 ism->priv[i] = NULL; 82 - client->add(ism); 83 82 ism_setup_forwarding(client, ism); 84 83 } 85 84 } ··· 464 465 } 465 466 EXPORT_SYMBOL_GPL(ism_move); 466 467 468 + static u16 ism_get_chid(struct dibs_dev *dibs) 469 + { 470 + struct ism_dev *ism = dibs->drv_priv; 471 + 472 + if (!ism || !ism->pdev) 473 + return 0; 474 + 475 + return to_zpci(ism->pdev)->pchid; 476 + } 477 + 467 478 static void ism_handle_event(struct ism_dev *ism) 468 479 { 469 480 struct ism_event *entry; ··· 532 523 return IRQ_HANDLED; 533 524 } 534 525 526 + static const struct dibs_dev_ops ism_ops = { 527 + .get_fabric_id = ism_get_chid, 528 + }; 529 + 535 530 static int ism_dev_init(struct ism_dev *ism) 536 531 { 537 532 struct pci_dev *pdev = ism->pdev; ··· 577 564 mutex_lock(&clients_lock); 578 565 for (i = 0; i < max_client; ++i) { 579 566 if (clients[i]) { 580 - clients[i]->add(ism); 581 567 ism_setup_forwarding(clients[i], ism); 582 568 } 583 569 } ··· 623 611 spin_unlock_irqrestore(&ism->lock, flags); 624 612 625 613 mutex_lock(&ism_dev_list.mutex); 626 - mutex_lock(&clients_lock); 627 - for (i = 0; i < max_client; ++i) { 628 - if (clients[i]) 629 - clients[i]->remove(ism); 630 - } 631 - mutex_unlock(&clients_lock); 632 614 633 615 if (ism_v2_capable) 634 616 ism_del_vlan_id(ism, ISM_RESERVED_VLANID); ··· 678 672 ret = -ENOMEM; 679 673 goto err_resource; 680 674 } 675 + /* set this up before we enable interrupts */ 681 676 ism->dibs = dibs; 677 + dibs->drv_priv = ism; 678 + dibs->ops = &ism_ops; 682 679 683 680 ret = ism_dev_init(ism); 684 681 if (ret) ··· 866 857 smcd_gid->gid_ext = 0; 867 858 } 868 859 869 - static u16 ism_get_chid(struct ism_dev *ism) 870 - { 871 - if (!ism || !ism->pdev) 872 - return 0; 873 - 874 - return to_zpci(ism->pdev)->pchid; 875 - } 876 - 877 - static u16 smcd_get_chid(struct smcd_dev *smcd) 878 - { 879 - return ism_get_chid(smcd->priv); 880 - } 881 - 882 860 static inline struct device *smcd_get_dev(struct smcd_dev *dev) 883 861 { 884 862 struct ism_dev *ism = dev->priv; ··· 873 877 return &ism->dev; 874 878 } 875 879 876 - static const struct smcd_ops ism_ops = { 880 + static const struct smcd_ops ism_smcd_ops = { 877 881 .query_remote_gid = smcd_query_rgid, 878 882 .register_dmb = smcd_register_dmb, 879 883 .unregister_dmb = smcd_unregister_dmb, ··· 885 889 .move_data = smcd_move, 886 890 .supports_v2 = smcd_supports_v2, 887 891 .get_local_gid = smcd_get_local_gid, 888 - .get_chid = smcd_get_chid, 889 892 .get_dev = smcd_get_dev, 890 893 }; 891 894 892 895 const struct smcd_ops *ism_get_smcd_ops(void) 893 896 { 894 - return &ism_ops; 897 + return &ism_smcd_ops; 895 898 } 896 899 EXPORT_SYMBOL_GPL(ism_get_smcd_ops); 897 900 #endif
+87 -2
include/linux/dibs.h
··· 34 34 * clients. 35 35 */ 36 36 37 + struct dibs_dev; 38 + 37 39 /* DIBS client 38 40 * ----------- 39 41 */ 40 42 #define MAX_DIBS_CLIENTS 8 43 + /* All dibs clients have access to all dibs devices. 44 + * A dibs client provides the following functions to be called by dibs layer or 45 + * dibs device drivers: 46 + */ 47 + struct dibs_client_ops { 48 + /** 49 + * add_dev() - add a dibs device 50 + * @dev: device that was added 51 + * 52 + * Will be called during dibs_register_client() for all existing 53 + * dibs devices and whenever a new dibs device is registered. 54 + * dev is usable until dibs_client.remove() is called. 55 + * *dev is protected by device refcounting. 56 + */ 57 + void (*add_dev)(struct dibs_dev *dev); 58 + /** 59 + * del_dev() - remove a dibs device 60 + * @dev: device to be removed 61 + * 62 + * Will be called whenever a dibs device is removed. 63 + * Will be called during dibs_unregister_client() for all existing 64 + * dibs devices and whenever a dibs device is unregistered. 65 + * The device has already stopped initiative for this client: 66 + * No new handlers will be started. 67 + * The device is no longer usable by this client after this call. 68 + */ 69 + void (*del_dev)(struct dibs_dev *dev); 70 + }; 41 71 42 72 struct dibs_client { 43 73 /* client name for logging and debugging purposes */ 44 74 const char *name; 75 + const struct dibs_client_ops *ops; 45 76 /* client index - provided and used by dibs layer */ 46 77 u8 id; 47 78 }; ··· 83 52 * dibs_register_client() - register a client with dibs layer 84 53 * @client: this client 85 54 * 55 + * Will call client->ops->add_dev() for all existing dibs devices. 86 56 * Return: zero on success. 87 57 */ 88 58 int dibs_register_client(struct dibs_client *client); ··· 91 59 * dibs_unregister_client() - unregister a client with dibs layer 92 60 * @client: this client 93 61 * 62 + * Will call client->ops->del_dev() for all existing dibs devices. 94 63 * Return: zero on success. 95 64 */ 96 65 int dibs_unregister_client(struct dibs_client *client); 97 66 67 + /* dibs clients can call dibs device ops. */ 68 + 98 69 /* DIBS devices 99 70 * ------------ 100 71 */ 72 + 73 + /* Defined fabric id / CHID for all loopback devices: 74 + * All dibs loopback devices report this fabric id. In this case devices with 75 + * the same fabric id can NOT communicate via dibs. Only loopback devices with 76 + * the same dibs device gid can communicate (=same device with itself). 77 + */ 78 + #define DIBS_LOOPBACK_FABRIC 0xFFFF 79 + 80 + /* A dibs device provides the following functions to be called by dibs clients. 81 + * They are mandatory, unless marked 'optional'. 82 + */ 83 + struct dibs_dev_ops { 84 + /** 85 + * get_fabric_id() 86 + * @dev: local dibs device 87 + * 88 + * Only devices on the same dibs fabric can communicate. Fabric_id is 89 + * unique inside the same HW system. Use fabric_id for fast negative 90 + * checks, but only query_remote_gid() can give a reliable positive 91 + * answer: 92 + * Different fabric_id: dibs is not possible 93 + * Same fabric_id: dibs may be possible or not 94 + * (e.g. different HW systems) 95 + * EXCEPTION: DIBS_LOOPBACK_FABRIC denotes an ism_loopback device 96 + * that can only communicate with itself. Use dibs_dev.gid 97 + * or query_remote_gid()to determine whether sender and 98 + * receiver use the same ism_loopback device. 99 + * Return: 2 byte dibs fabric id 100 + */ 101 + u16 (*get_fabric_id)(struct dibs_dev *dev); 102 + }; 103 + 101 104 struct dibs_dev { 102 105 struct list_head list; 106 + /* To be filled by device driver, before calling dibs_dev_add(): */ 107 + const struct dibs_dev_ops *ops; 108 + /* priv pointer for device driver */ 109 + void *drv_priv; 110 + 111 + /* priv pointer per client; for client usage only */ 112 + void *priv[MAX_DIBS_CLIENTS]; 103 113 }; 114 + 115 + static inline void dibs_set_priv(struct dibs_dev *dev, 116 + struct dibs_client *client, void *priv) 117 + { 118 + dev->priv[client->id] = priv; 119 + } 120 + 121 + static inline void *dibs_get_priv(struct dibs_dev *dev, 122 + struct dibs_client *client) 123 + { 124 + return dev->priv[client->id]; 125 + } 104 126 105 127 /* ------- End of client-only functions ----------- */ 106 128 107 - /* 108 - * Functions to be called by dibs device drivers: 129 + /* Functions to be called by dibs device drivers: 109 130 */ 110 131 /** 111 132 * dibs_dev_alloc() - allocate and reference device structure
-2
include/linux/ism.h
··· 59 59 60 60 struct ism_client { 61 61 const char *name; 62 - void (*add)(struct ism_dev *dev); 63 - void (*remove)(struct ism_dev *dev); 64 62 void (*handle_event)(struct ism_dev *dev, struct ism_event *event); 65 63 /* Parameter dmbemask contains a bit vector with updated DMBEs, if sent 66 64 * via ism_move_data(). Callback function must handle all active bits
+2 -1
include/net/smc.h
··· 15 15 #include <linux/spinlock.h> 16 16 #include <linux/types.h> 17 17 #include <linux/wait.h> 18 + #include <linux/dibs.h> 18 19 #include "linux/ism.h" 19 20 20 21 struct sock; ··· 63 62 unsigned int size); 64 63 int (*supports_v2)(void); 65 64 void (*get_local_gid)(struct smcd_dev *dev, struct smcd_gid *gid); 66 - u16 (*get_chid)(struct smcd_dev *dev); 67 65 struct device* (*get_dev)(struct smcd_dev *dev); 68 66 69 67 /* optional operations */ ··· 81 81 const struct smcd_ops *ops; 82 82 void *priv; 83 83 void *client; 84 + struct dibs_dev *dibs; 84 85 struct list_head list; 85 86 spinlock_t lock; 86 87 struct smc_connection **conn;
-13
net/smc/Kconfig
··· 20 20 smcss. 21 21 22 22 if unsure, say Y. 23 - 24 - config SMC_LO 25 - bool "SMC intra-OS shortcut with loopback-ism" 26 - depends on SMC 27 - default n 28 - help 29 - SMC_LO enables the creation of an Emulated-ISM device named 30 - loopback-ism in SMC and makes use of it for transferring data 31 - when communication occurs within the same OS. This helps in 32 - convenient testing of SMC-D since loopback-ism is independent 33 - of architecture or hardware. 34 - 35 - if unsure, say N.
+1 -1
net/smc/Makefile
··· 6 6 smc-y += smc_cdc.o smc_tx.o smc_rx.o smc_close.o smc_ism.o smc_netlink.o smc_stats.o 7 7 smc-y += smc_tracepoint.o smc_inet.o 8 8 smc-$(CONFIG_SYSCTL) += smc_sysctl.o 9 - smc-$(CONFIG_SMC_LO) += smc_loopback.o 9 + smc-y += smc_loopback.o
+1 -11
net/smc/af_smc.c
··· 57 57 #include "smc_stats.h" 58 58 #include "smc_tracepoint.h" 59 59 #include "smc_sysctl.h" 60 - #include "smc_loopback.h" 61 60 #include "smc_inet.h" 62 61 63 62 static DEFINE_MUTEX(smc_server_lgr_pending); /* serialize link group ··· 3590 3591 goto out_sock; 3591 3592 } 3592 3593 3593 - rc = smc_loopback_init(); 3594 - if (rc) { 3595 - pr_err("%s: smc_loopback_init fails with %d\n", __func__, rc); 3596 - goto out_ib; 3597 - } 3598 - 3599 3594 rc = tcp_register_ulp(&smc_ulp_ops); 3600 3595 if (rc) { 3601 3596 pr_err("%s: tcp_ulp_register fails with %d\n", __func__, rc); 3602 - goto out_lo; 3597 + goto out_ib; 3603 3598 } 3604 3599 rc = smc_inet_init(); 3605 3600 if (rc) { ··· 3604 3611 return 0; 3605 3612 out_ulp: 3606 3613 tcp_unregister_ulp(&smc_ulp_ops); 3607 - out_lo: 3608 - smc_loopback_exit(); 3609 3614 out_ib: 3610 3615 smc_ib_unregister_client(); 3611 3616 out_sock: ··· 3642 3651 tcp_unregister_ulp(&smc_ulp_ops); 3643 3652 sock_unregister(PF_SMC); 3644 3653 smc_core_exit(); 3645 - smc_loopback_exit(); 3646 3654 smc_ib_unregister_client(); 3647 3655 smc_ism_exit(); 3648 3656 destroy_workqueue(smc_close_wq);
+92 -40
net/smc/smc_ism.c
··· 15 15 #include "smc.h" 16 16 #include "smc_core.h" 17 17 #include "smc_ism.h" 18 + #include "smc_loopback.h" 18 19 #include "smc_pnet.h" 19 20 #include "smc_netlink.h" 20 21 #include "linux/ism.h" ··· 29 28 static bool smc_ism_v2_capable; 30 29 static u8 smc_ism_v2_system_eid[SMC_MAX_EID_LEN]; 31 30 31 + static void smcd_register_dev(struct dibs_dev *dibs); 32 + static void smcd_unregister_dev(struct dibs_dev *dibs); 32 33 #if IS_ENABLED(CONFIG_ISM) 33 - static void smcd_register_dev(struct ism_dev *ism); 34 - static void smcd_unregister_dev(struct ism_dev *ism); 35 34 static void smcd_handle_event(struct ism_dev *ism, struct ism_event *event); 36 35 static void smcd_handle_irq(struct ism_dev *ism, unsigned int dmbno, 37 36 u16 dmbemask); 38 37 39 38 static struct ism_client smc_ism_client = { 40 39 .name = "SMC-D", 41 - .add = smcd_register_dev, 42 - .remove = smcd_unregister_dev, 43 40 .handle_event = smcd_handle_event, 44 41 .handle_irq = smcd_handle_irq, 45 42 }; 46 43 #endif 44 + static struct dibs_client_ops smc_client_ops = { 45 + .add_dev = smcd_register_dev, 46 + .del_dev = smcd_unregister_dev, 47 + }; 48 + 47 49 static struct dibs_client smc_dibs_client = { 48 50 .name = "SMC-D", 51 + .ops = &smc_client_ops, 49 52 }; 50 53 51 54 static void smc_ism_create_system_eid(void) ··· 91 86 92 87 u16 smc_ism_get_chid(struct smcd_dev *smcd) 93 88 { 94 - return smcd->ops->get_chid(smcd); 89 + return smcd->dibs->ops->get_fabric_id(smcd->dibs); 95 90 } 96 91 97 92 /* HW supports ISM V2 and thus System EID is defined */ ··· 323 318 if (nla_put_u8(skb, SMC_NLA_DEV_IS_CRIT, use_cnt > 0)) 324 319 goto errattr; 325 320 memset(&smc_pci_dev, 0, sizeof(smc_pci_dev)); 326 - smc_set_pci_values(to_pci_dev(ism->dev.parent), &smc_pci_dev); 321 + smc_set_pci_values(ism->pdev, &smc_pci_dev); 327 322 if (nla_put_u32(skb, SMC_NLA_DEV_PCI_FID, smc_pci_dev.pci_fid)) 328 323 goto errattr; 329 324 if (nla_put_u16(skb, SMC_NLA_DEV_PCI_CHID, smc_pci_dev.pci_pchid)) ··· 373 368 list_for_each_entry(smcd, &dev_list->list, list) { 374 369 if (num < snum) 375 370 goto next; 376 - if (smc_ism_is_loopback(smcd)) 371 + if (smc_ism_is_loopback(smcd->dibs)) 377 372 goto next; 378 373 if (smc_nl_handle_smcd_dev(smcd, skb, cb)) 379 374 goto errout; ··· 458 453 } 459 454 kfree(wrk); 460 455 } 456 + #endif 461 457 462 - static struct smcd_dev *smcd_alloc_dev(struct device *parent, const char *name, 463 - const struct smcd_ops *ops, int max_dmbs) 458 + static struct smcd_dev *smcd_alloc_dev(const char *name, 459 + const struct smcd_ops *ops, 460 + int max_dmbs) 464 461 { 465 462 struct smcd_dev *smcd; 466 463 467 - smcd = devm_kzalloc(parent, sizeof(*smcd), GFP_KERNEL); 464 + smcd = kzalloc(sizeof(*smcd), GFP_KERNEL); 468 465 if (!smcd) 469 466 return NULL; 470 - smcd->conn = devm_kcalloc(parent, max_dmbs, 471 - sizeof(struct smc_connection *), GFP_KERNEL); 467 + smcd->conn = kcalloc(max_dmbs, sizeof(struct smc_connection *), 468 + GFP_KERNEL); 472 469 if (!smcd->conn) 473 - return NULL; 470 + goto free_smcd; 474 471 475 472 smcd->event_wq = alloc_ordered_workqueue("ism_evt_wq-%s)", 476 473 WQ_MEM_RECLAIM, name); 477 474 if (!smcd->event_wq) 478 - return NULL; 475 + goto free_conn; 479 476 480 477 smcd->ops = ops; 481 478 ··· 487 480 INIT_LIST_HEAD(&smcd->lgr_list); 488 481 init_waitqueue_head(&smcd->lgrs_deleted); 489 482 return smcd; 483 + 484 + free_conn: 485 + kfree(smcd->conn); 486 + free_smcd: 487 + kfree(smcd); 488 + return NULL; 490 489 } 491 490 492 - static void smcd_register_dev(struct ism_dev *ism) 491 + static void smcd_register_dev(struct dibs_dev *dibs) 493 492 { 494 - const struct smcd_ops *ops = ism_get_smcd_ops(); 495 493 struct smcd_dev *smcd, *fentry; 494 + const struct smcd_ops *ops; 495 + struct smc_lo_dev *smc_lo; 496 + struct ism_dev *ism; 496 497 497 - if (!ops) 498 - return; 498 + if (smc_ism_is_loopback(dibs)) { 499 + if (smc_loopback_init(&smc_lo)) 500 + return; 501 + } 499 502 500 - smcd = smcd_alloc_dev(&ism->pdev->dev, dev_name(&ism->pdev->dev), ops, 501 - ISM_NR_DMBS); 503 + if (smc_ism_is_loopback(dibs)) { 504 + ops = smc_lo_get_smcd_ops(); 505 + smcd = smcd_alloc_dev(dev_name(&smc_lo->dev), ops, 506 + SMC_LO_MAX_DMBS); 507 + } else { 508 + ism = dibs->drv_priv; 509 + #if IS_ENABLED(CONFIG_ISM) 510 + ops = ism_get_smcd_ops(); 511 + #endif 512 + smcd = smcd_alloc_dev(dev_name(&ism->pdev->dev), ops, 513 + ISM_NR_DMBS); 514 + } 502 515 if (!smcd) 503 516 return; 504 - smcd->priv = ism; 505 - smcd->client = &smc_ism_client; 506 - ism_set_priv(ism, &smc_ism_client, smcd); 507 - if (smc_pnetid_by_dev_port(&ism->pdev->dev, 0, smcd->pnetid)) 508 - smc_pnetid_by_table_smcd(smcd); 509 517 510 - if (smcd->ops->supports_v2()) 518 + smcd->dibs = dibs; 519 + dibs_set_priv(dibs, &smc_dibs_client, smcd); 520 + 521 + if (smc_ism_is_loopback(dibs)) { 522 + smcd->priv = smc_lo; 523 + smc_lo->smcd = smcd; 524 + } else { 525 + smcd->priv = ism; 526 + #if IS_ENABLED(CONFIG_ISM) 527 + ism_set_priv(ism, &smc_ism_client, smcd); 528 + smcd->client = &smc_ism_client; 529 + #endif 530 + if (smc_pnetid_by_dev_port(&ism->pdev->dev, 0, smcd->pnetid)) 531 + smc_pnetid_by_table_smcd(smcd); 532 + } 533 + 534 + if (smc_ism_is_loopback(dibs) || smcd->ops->supports_v2()) 511 535 smc_ism_set_v2_capable(); 512 536 mutex_lock(&smcd_dev_list.mutex); 513 537 /* sort list: ··· 548 510 if (!smcd->pnetid[0]) { 549 511 fentry = list_first_entry_or_null(&smcd_dev_list.list, 550 512 struct smcd_dev, list); 551 - if (fentry && smc_ism_is_loopback(fentry)) 513 + if (fentry && smc_ism_is_loopback(fentry->dibs)) 552 514 list_add(&smcd->list, &fentry->list); 553 515 else 554 516 list_add(&smcd->list, &smcd_dev_list.list); ··· 557 519 } 558 520 mutex_unlock(&smcd_dev_list.mutex); 559 521 560 - if (smc_pnet_is_pnetid_set(smcd->pnetid)) 561 - pr_warn_ratelimited("smc: adding smcd device %s with pnetid %.16s%s\n", 562 - dev_name(&ism->dev), smcd->pnetid, 563 - smcd->pnetid_by_user ? 564 - " (user defined)" : 565 - ""); 566 - else 567 - pr_warn_ratelimited("smc: adding smcd device %s without pnetid\n", 568 - dev_name(&ism->dev)); 522 + if (smc_ism_is_loopback(dibs)) { 523 + pr_warn_ratelimited("smc: adding smcd loopback device\n"); 524 + } else { 525 + if (smc_pnet_is_pnetid_set(smcd->pnetid)) 526 + pr_warn_ratelimited("smc: adding smcd device %s with pnetid %.16s%s\n", 527 + dev_name(&ism->dev), smcd->pnetid, 528 + smcd->pnetid_by_user ? 529 + " (user defined)" : 530 + ""); 531 + else 532 + pr_warn_ratelimited("smc: adding smcd device %s without pnetid\n", 533 + dev_name(&ism->dev)); 534 + } 569 535 return; 570 536 } 571 537 572 - static void smcd_unregister_dev(struct ism_dev *ism) 538 + static void smcd_unregister_dev(struct dibs_dev *dibs) 573 539 { 574 - struct smcd_dev *smcd = ism_get_priv(ism, &smc_ism_client); 540 + struct smcd_dev *smcd = dibs_get_priv(dibs, &smc_dibs_client); 541 + struct ism_dev *ism = dibs->drv_priv; 575 542 576 - pr_warn_ratelimited("smc: removing smcd device %s\n", 577 - dev_name(&ism->dev)); 543 + if (smc_ism_is_loopback(dibs)) { 544 + pr_warn_ratelimited("smc: removing smcd loopback device\n"); 545 + } else { 546 + pr_warn_ratelimited("smc: removing smcd device %s\n", 547 + dev_name(&ism->dev)); 548 + } 578 549 smcd->going_away = 1; 579 550 smc_smcd_terminate_all(smcd); 580 551 mutex_lock(&smcd_dev_list.mutex); 581 552 list_del_init(&smcd->list); 582 553 mutex_unlock(&smcd_dev_list.mutex); 583 554 destroy_workqueue(smcd->event_wq); 555 + if (smc_ism_is_loopback(dibs)) 556 + smc_loopback_exit(); 557 + kfree(smcd->conn); 558 + kfree(smcd); 584 559 } 585 560 561 + #if IS_ENABLED(CONFIG_ISM) 586 562 /* SMCD Device event handler. Called from ISM device interrupt handler. 587 563 * Parameters are ism device pointer, 588 564 * - event->type (0 --> DMB, 1 --> GID),
+4 -3
net/smc/smc_ism.h
··· 12 12 #include <linux/uio.h> 13 13 #include <linux/types.h> 14 14 #include <linux/mutex.h> 15 + #include <linux/dibs.h> 15 16 16 17 #include "smc.h" 17 18 ··· 86 85 87 86 static inline bool smc_ism_is_emulated(struct smcd_dev *smcd) 88 87 { 89 - u16 chid = smcd->ops->get_chid(smcd); 88 + u16 chid = smcd->dibs->ops->get_fabric_id(smcd->dibs); 90 89 91 90 return __smc_ism_is_emulated(chid); 92 91 } 93 92 94 - static inline bool smc_ism_is_loopback(struct smcd_dev *smcd) 93 + static inline bool smc_ism_is_loopback(struct dibs_dev *dibs) 95 94 { 96 - return (smcd->ops->get_chid(smcd) == 0xFFFF); 95 + return (dibs->ops->get_fabric_id(dibs) == DIBS_LOOPBACK_FABRIC); 97 96 } 98 97 99 98 #endif
+14 -80
net/smc/smc_loopback.c
··· 35 35 memcpy(&lgid->gid, &uuid, sizeof(lgid->gid)); 36 36 memcpy(&lgid->gid_ext, (u8 *)&uuid + sizeof(lgid->gid), 37 37 sizeof(lgid->gid_ext)); 38 - 39 - ldev->chid = SMC_LO_RESERVED_CHID; 40 38 } 41 39 42 40 static int smc_lo_query_rgid(struct smcd_dev *smcd, struct smcd_gid *rgid, ··· 255 257 smcd_gid->gid_ext = ldev->local_gid.gid_ext; 256 258 } 257 259 258 - static u16 smc_lo_get_chid(struct smcd_dev *smcd) 259 - { 260 - return ((struct smc_lo_dev *)smcd->priv)->chid; 261 - } 262 - 263 260 static struct device *smc_lo_get_dev(struct smcd_dev *smcd) 264 261 { 265 262 return &((struct smc_lo_dev *)smcd->priv)->dev; ··· 274 281 .signal_event = NULL, 275 282 .move_data = smc_lo_move_data, 276 283 .get_local_gid = smc_lo_get_local_gid, 277 - .get_chid = smc_lo_get_chid, 278 284 .get_dev = smc_lo_get_dev, 279 285 }; 280 286 281 - static struct smcd_dev *smcd_lo_alloc_dev(const struct smcd_ops *ops, 282 - int max_dmbs) 287 + const struct smcd_ops *smc_lo_get_smcd_ops(void) 283 288 { 284 - struct smcd_dev *smcd; 285 - 286 - smcd = kzalloc(sizeof(*smcd), GFP_KERNEL); 287 - if (!smcd) 288 - return NULL; 289 - 290 - smcd->conn = kcalloc(max_dmbs, sizeof(struct smc_connection *), 291 - GFP_KERNEL); 292 - if (!smcd->conn) 293 - goto out_smcd; 294 - 295 - smcd->ops = ops; 296 - 297 - spin_lock_init(&smcd->lock); 298 - spin_lock_init(&smcd->lgr_lock); 299 - INIT_LIST_HEAD(&smcd->vlan); 300 - INIT_LIST_HEAD(&smcd->lgr_list); 301 - init_waitqueue_head(&smcd->lgrs_deleted); 302 - return smcd; 303 - 304 - out_smcd: 305 - kfree(smcd); 306 - return NULL; 289 + return &lo_ops; 307 290 } 308 291 309 - static int smcd_lo_register_dev(struct smc_lo_dev *ldev) 310 - { 311 - struct smcd_dev *smcd; 312 - 313 - smcd = smcd_lo_alloc_dev(&lo_ops, SMC_LO_MAX_DMBS); 314 - if (!smcd) 315 - return -ENOMEM; 316 - ldev->smcd = smcd; 317 - smcd->priv = ldev; 318 - smc_ism_set_v2_capable(); 319 - mutex_lock(&smcd_dev_list.mutex); 320 - list_add(&smcd->list, &smcd_dev_list.list); 321 - mutex_unlock(&smcd_dev_list.mutex); 322 - pr_warn_ratelimited("smc: adding smcd device %s\n", 323 - dev_name(&ldev->dev)); 324 - return 0; 325 - } 326 - 327 - static void smcd_lo_unregister_dev(struct smc_lo_dev *ldev) 328 - { 329 - struct smcd_dev *smcd = ldev->smcd; 330 - 331 - pr_warn_ratelimited("smc: removing smcd device %s\n", 332 - dev_name(&ldev->dev)); 333 - smcd->going_away = 1; 334 - smc_smcd_terminate_all(smcd); 335 - mutex_lock(&smcd_dev_list.mutex); 336 - list_del_init(&smcd->list); 337 - mutex_unlock(&smcd_dev_list.mutex); 338 - kfree(smcd->conn); 339 - kfree(smcd); 340 - } 341 - 342 - static int smc_lo_dev_init(struct smc_lo_dev *ldev) 292 + static void smc_lo_dev_init(struct smc_lo_dev *ldev) 343 293 { 344 294 smc_lo_generate_ids(ldev); 345 295 rwlock_init(&ldev->dmb_ht_lock); ··· 290 354 atomic_set(&ldev->dmb_cnt, 0); 291 355 init_waitqueue_head(&ldev->ldev_release); 292 356 293 - return smcd_lo_register_dev(ldev); 357 + return; 294 358 } 295 359 296 360 static void smc_lo_dev_exit(struct smc_lo_dev *ldev) 297 361 { 298 - smcd_lo_unregister_dev(ldev); 299 362 if (atomic_read(&ldev->dmb_cnt)) 300 363 wait_event(ldev->ldev_release, !atomic_read(&ldev->dmb_cnt)); 301 364 } ··· 310 375 static int smc_lo_dev_probe(void) 311 376 { 312 377 struct smc_lo_dev *ldev; 313 - int ret; 314 378 315 379 ldev = kzalloc(sizeof(*ldev), GFP_KERNEL); 316 380 if (!ldev) ··· 319 385 ldev->dev.release = smc_lo_dev_release; 320 386 device_initialize(&ldev->dev); 321 387 dev_set_name(&ldev->dev, smc_lo_dev_name); 322 - 323 - ret = smc_lo_dev_init(ldev); 324 - if (ret) 325 - goto free_dev; 388 + smc_lo_dev_init(ldev); 326 389 327 390 lo_dev = ldev; /* global loopback device */ 328 - return 0; 329 391 330 - free_dev: 331 - put_device(&ldev->dev); 332 - return ret; 392 + return 0; 333 393 } 334 394 335 395 static void smc_lo_dev_remove(void) ··· 333 405 334 406 smc_lo_dev_exit(lo_dev); 335 407 put_device(&lo_dev->dev); /* device_initialize in smc_lo_dev_probe */ 408 + lo_dev = NULL; 336 409 } 337 410 338 - int smc_loopback_init(void) 411 + int smc_loopback_init(struct smc_lo_dev **smc_lb) 339 412 { 340 - return smc_lo_dev_probe(); 413 + int ret; 414 + 415 + ret = smc_lo_dev_probe(); 416 + if (!ret) 417 + *smc_lb = lo_dev; 418 + return ret; 341 419 } 342 420 343 421 void smc_loopback_exit(void)
+3 -14
net/smc/smc_loopback.h
··· 17 17 #include <linux/device.h> 18 18 #include <net/smc.h> 19 19 20 - #if IS_ENABLED(CONFIG_SMC_LO) 21 20 #define SMC_LO_MAX_DMBS 5000 22 21 #define SMC_LO_DMBS_HASH_BITS 12 23 - #define SMC_LO_RESERVED_CHID 0xFFFF 24 22 25 23 struct smc_lo_dmb_node { 26 24 struct hlist_node list; ··· 33 35 struct smc_lo_dev { 34 36 struct smcd_dev *smcd; 35 37 struct device dev; 36 - u16 chid; 37 38 struct smcd_gid local_gid; 38 39 atomic_t dmb_cnt; 39 40 rwlock_t dmb_ht_lock; ··· 41 44 wait_queue_head_t ldev_release; 42 45 }; 43 46 44 - int smc_loopback_init(void); 45 - void smc_loopback_exit(void); 46 - #else 47 - static inline int smc_loopback_init(void) 48 - { 49 - return 0; 50 - } 47 + const struct smcd_ops *smc_lo_get_smcd_ops(void); 51 48 52 - static inline void smc_loopback_exit(void) 53 - { 54 - } 55 - #endif 49 + int smc_loopback_init(struct smc_lo_dev **smc_lb); 50 + void smc_loopback_exit(void); 56 51 57 52 #endif /* _SMC_LOOPBACK_H */