Commit 99db6fb0 authored by David S. Miller's avatar David S. Miller

Merge branch 's390-ism-generalized-interface'

Jan Karcher says:

====================
drivers/s390/net/ism: Add generalized interface

Previously, there was no clean separation between SMC-D code and the ISM
device driver.This patch series addresses the situation to make ISM available
for uses outside of SMC-D.
In detail: SMC-D offers an interface via struct smcd_ops, which only the
ISM module implements so far. However, there is no real separation between
the smcd and ism modules, which starts right with the ISM device
initialization, which calls directly into the SMC-D code.
This patch series introduces a new API in the ISM module, which allows
registration of arbitrary clients via include/linux/ism.h: struct ism_client.
Furthermore, it introduces a "pure" struct ism_dev (i.e. getting rid of
dependencies on SMC-D in the device structure), and adds a number of API
calls for data transfers via ISM (see ism_register_dmb() & friends).
Still, the ISM module implements the SMC-D API, and therefore has a number
of internal helper functions for that matter.
Note that the ISM API is consciously kept thin for now (as compared to the
SMC-D API calls), as a number of API calls are only used with SMC-D and
hardly have any meaningful usage beyond SMC-D, e.g. the VLAN-related calls.

v1 -> v2:
  Removed s390x dependency which broke config for other archs.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents d0671115 8c81ba20
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/ism.h>
#include <net/smc.h> #include <net/smc.h>
#include <asm/pci_insn.h> #include <asm/pci_insn.h>
...@@ -15,7 +16,6 @@ ...@@ -15,7 +16,6 @@
*/ */
#define ISM_DMB_WORD_OFFSET 1 #define ISM_DMB_WORD_OFFSET 1
#define ISM_DMB_BIT_OFFSET (ISM_DMB_WORD_OFFSET * 32) #define ISM_DMB_BIT_OFFSET (ISM_DMB_WORD_OFFSET * 32)
#define ISM_NR_DMBS 1920
#define ISM_IDENT_MASK 0x00FFFF #define ISM_IDENT_MASK 0x00FFFF
#define ISM_REG_SBA 0x1 #define ISM_REG_SBA 0x1
...@@ -177,7 +177,7 @@ struct ism_eq_header { ...@@ -177,7 +177,7 @@ struct ism_eq_header {
struct ism_eq { struct ism_eq {
struct ism_eq_header header; struct ism_eq_header header;
struct smcd_event entry[15]; struct ism_event entry[15];
}; };
struct ism_sba { struct ism_sba {
...@@ -189,21 +189,6 @@ struct ism_sba { ...@@ -189,21 +189,6 @@ struct ism_sba {
u16 dmbe_mask[ISM_NR_DMBS]; u16 dmbe_mask[ISM_NR_DMBS];
}; };
struct ism_dev {
spinlock_t lock;
struct pci_dev *pdev;
struct smcd_dev *smcd;
struct ism_sba *sba;
dma_addr_t sba_dma_addr;
DECLARE_BITMAP(sba_bitmap, ISM_NR_DMBS);
struct ism_eq *ieq;
dma_addr_t ieq_dma_addr;
int ieq_idx;
};
#define ISM_CREATE_REQ(dmb, idx, sf, offset) \ #define ISM_CREATE_REQ(dmb, idx, sf, offset) \
((dmb) | (idx) << 24 | (sf) << 23 | (offset)) ((dmb) | (idx) << 24 | (sf) << 23 | (offset))
......
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Internal Shared Memory
*
* Definitions for the ISM module
*
* Copyright IBM Corp. 2022
*/
#ifndef _ISM_H
#define _ISM_H
#include <linux/workqueue.h>
struct ism_dmb {
u64 dmb_tok;
u64 rgid;
u32 dmb_len;
u32 sba_idx;
u32 vlan_valid;
u32 vlan_id;
void *cpu_addr;
dma_addr_t dma_addr;
};
/* Unless we gain unexpected popularity, this limit should hold for a while */
#define MAX_CLIENTS 8
#define ISM_NR_DMBS 1920
struct ism_dev {
spinlock_t lock; /* protects the ism device */
struct list_head list;
struct pci_dev *pdev;
struct ism_sba *sba;
dma_addr_t sba_dma_addr;
DECLARE_BITMAP(sba_bitmap, ISM_NR_DMBS);
u8 *sba_client_arr; /* entries are indices into 'clients' array */
void *priv[MAX_CLIENTS];
struct ism_eq *ieq;
dma_addr_t ieq_dma_addr;
struct device dev;
u64 local_gid;
int ieq_idx;
atomic_t free_clients_cnt;
atomic_t add_dev_cnt;
wait_queue_head_t waitq;
};
struct ism_event {
u32 type;
u32 code;
u64 tok;
u64 time;
u64 info;
};
struct ism_client {
const char *name;
void (*add)(struct ism_dev *dev);
void (*remove)(struct ism_dev *dev);
void (*handle_event)(struct ism_dev *dev, struct ism_event *event);
/* Parameter dmbemask contains a bit vector with updated DMBEs, if sent
* via ism_move_data(). Callback function must handle all active bits
* indicated by dmbemask.
*/
void (*handle_irq)(struct ism_dev *dev, unsigned int bit, u16 dmbemask);
/* Private area - don't touch! */
struct work_struct remove_work;
struct work_struct add_work;
struct ism_dev *tgt_ism;
u8 id;
};
int ism_register_client(struct ism_client *client);
int ism_unregister_client(struct ism_client *client);
static inline void *ism_get_priv(struct ism_dev *dev,
struct ism_client *client) {
return dev->priv[client->id];
}
static inline void ism_set_priv(struct ism_dev *dev, struct ism_client *client,
void *priv) {
dev->priv[client->id] = priv;
}
int ism_register_dmb(struct ism_dev *dev, struct ism_dmb *dmb,
struct ism_client *client);
int ism_unregister_dmb(struct ism_dev *dev, struct ism_dmb *dmb);
int ism_move(struct ism_dev *dev, u64 dmb_tok, unsigned int idx, bool sf,
unsigned int offset, void *data, unsigned int size);
u8 *ism_get_seid(void);
const struct smcd_ops *ism_get_smcd_ops(void);
#endif /* _ISM_H */
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/wait.h> #include <linux/wait.h>
#include "linux/ism.h"
struct sock; struct sock;
...@@ -48,20 +49,14 @@ struct smcd_dmb { ...@@ -48,20 +49,14 @@ struct smcd_dmb {
#define ISM_ERROR 0xFFFF #define ISM_ERROR 0xFFFF
struct smcd_event {
u32 type;
u32 code;
u64 tok;
u64 time;
u64 info;
};
struct smcd_dev; struct smcd_dev;
struct ism_client;
struct smcd_ops { struct smcd_ops {
int (*query_remote_gid)(struct smcd_dev *dev, u64 rgid, u32 vid_valid, int (*query_remote_gid)(struct smcd_dev *dev, u64 rgid, u32 vid_valid,
u32 vid); u32 vid);
int (*register_dmb)(struct smcd_dev *dev, struct smcd_dmb *dmb); int (*register_dmb)(struct smcd_dev *dev, struct smcd_dmb *dmb,
struct ism_client *client);
int (*unregister_dmb)(struct smcd_dev *dev, struct smcd_dmb *dmb); int (*unregister_dmb)(struct smcd_dev *dev, struct smcd_dmb *dmb);
int (*add_vlan_id)(struct smcd_dev *dev, u64 vlan_id); int (*add_vlan_id)(struct smcd_dev *dev, u64 vlan_id);
int (*del_vlan_id)(struct smcd_dev *dev, u64 vlan_id); int (*del_vlan_id)(struct smcd_dev *dev, u64 vlan_id);
...@@ -73,14 +68,14 @@ struct smcd_ops { ...@@ -73,14 +68,14 @@ struct smcd_ops {
bool sf, unsigned int offset, void *data, bool sf, unsigned int offset, void *data,
unsigned int size); unsigned int size);
u8* (*get_system_eid)(void); u8* (*get_system_eid)(void);
u64 (*get_local_gid)(struct smcd_dev *dev);
u16 (*get_chid)(struct smcd_dev *dev); u16 (*get_chid)(struct smcd_dev *dev);
struct device* (*get_dev)(struct smcd_dev *dev);
}; };
struct smcd_dev { struct smcd_dev {
const struct smcd_ops *ops; const struct smcd_ops *ops;
struct device dev;
void *priv; void *priv;
u64 local_gid;
struct list_head list; struct list_head list;
spinlock_t lock; spinlock_t lock;
struct smc_connection **conn; struct smc_connection **conn;
...@@ -95,11 +90,4 @@ struct smcd_dev { ...@@ -95,11 +90,4 @@ struct smcd_dev {
u8 going_away : 1; u8 going_away : 1;
}; };
struct smcd_dev *smcd_alloc_dev(struct device *parent, const char *name,
const struct smcd_ops *ops, int max_dmbs);
int smcd_register_dev(struct smcd_dev *smcd);
void smcd_unregister_dev(struct smcd_dev *smcd);
void smcd_free_dev(struct smcd_dev *smcd);
void smcd_handle_event(struct smcd_dev *dev, struct smcd_event *event);
void smcd_handle_irq(struct smcd_dev *dev, unsigned int bit, u16 dmbemask);
#endif /* _SMC_H */ #endif /* _SMC_H */
...@@ -3382,12 +3382,14 @@ static int __init smc_init(void) ...@@ -3382,12 +3382,14 @@ static int __init smc_init(void)
if (rc) if (rc)
goto out_pernet_subsys; goto out_pernet_subsys;
smc_ism_init(); rc = smc_ism_init();
if (rc)
goto out_pernet_subsys_stat;
smc_clc_init(); smc_clc_init();
rc = smc_nl_init(); rc = smc_nl_init();
if (rc) if (rc)
goto out_pernet_subsys_stat; goto out_ism;
rc = smc_pnet_init(); rc = smc_pnet_init();
if (rc) if (rc)
...@@ -3480,6 +3482,8 @@ static int __init smc_init(void) ...@@ -3480,6 +3482,8 @@ static int __init smc_init(void)
smc_pnet_exit(); smc_pnet_exit();
out_nl: out_nl:
smc_nl_exit(); smc_nl_exit();
out_ism:
smc_ism_exit();
out_pernet_subsys_stat: out_pernet_subsys_stat:
unregister_pernet_subsys(&smc_net_stat_ops); unregister_pernet_subsys(&smc_net_stat_ops);
out_pernet_subsys: out_pernet_subsys:
...@@ -3495,6 +3499,7 @@ static void __exit smc_exit(void) ...@@ -3495,6 +3499,7 @@ static void __exit smc_exit(void)
sock_unregister(PF_SMC); sock_unregister(PF_SMC);
smc_core_exit(); smc_core_exit();
smc_ib_unregister_client(); smc_ib_unregister_client();
smc_ism_exit();
destroy_workqueue(smc_close_wq); destroy_workqueue(smc_close_wq);
destroy_workqueue(smc_tcp_ls_wq); destroy_workqueue(smc_tcp_ls_wq);
destroy_workqueue(smc_hs_wq); destroy_workqueue(smc_hs_wq);
......
...@@ -813,6 +813,7 @@ int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini) ...@@ -813,6 +813,7 @@ int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini)
struct smc_clc_v2_extension *v2_ext; struct smc_clc_v2_extension *v2_ext;
struct smc_clc_msg_smcd *pclc_smcd; struct smc_clc_msg_smcd *pclc_smcd;
struct smc_clc_msg_trail *trl; struct smc_clc_msg_trail *trl;
struct smcd_dev *smcd;
int len, i, plen, rc; int len, i, plen, rc;
int reason_code = 0; int reason_code = 0;
struct kvec vec[8]; struct kvec vec[8];
...@@ -868,7 +869,9 @@ int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini) ...@@ -868,7 +869,9 @@ int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini)
if (smcd_indicated(ini->smc_type_v1)) { if (smcd_indicated(ini->smc_type_v1)) {
/* add SMC-D specifics */ /* add SMC-D specifics */
if (ini->ism_dev[0]) { if (ini->ism_dev[0]) {
pclc_smcd->ism.gid = htonll(ini->ism_dev[0]->local_gid); smcd = ini->ism_dev[0];
pclc_smcd->ism.gid =
htonll(smcd->ops->get_local_gid(smcd));
pclc_smcd->ism.chid = pclc_smcd->ism.chid =
htons(smc_ism_get_chid(ini->ism_dev[0])); htons(smc_ism_get_chid(ini->ism_dev[0]));
} }
...@@ -914,8 +917,9 @@ int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini) ...@@ -914,8 +917,9 @@ int smc_clc_send_proposal(struct smc_sock *smc, struct smc_init_info *ini)
plen += sizeof(*smcd_v2_ext); plen += sizeof(*smcd_v2_ext);
if (ini->ism_offered_cnt) { if (ini->ism_offered_cnt) {
for (i = 1; i <= ini->ism_offered_cnt; i++) { for (i = 1; i <= ini->ism_offered_cnt; i++) {
smcd = ini->ism_dev[i];
gidchids[i - 1].gid = gidchids[i - 1].gid =
htonll(ini->ism_dev[i]->local_gid); htonll(smcd->ops->get_local_gid(smcd));
gidchids[i - 1].chid = gidchids[i - 1].chid =
htons(smc_ism_get_chid(ini->ism_dev[i])); htons(smc_ism_get_chid(ini->ism_dev[i]));
} }
...@@ -1000,7 +1004,8 @@ static int smc_clc_send_confirm_accept(struct smc_sock *smc, ...@@ -1000,7 +1004,8 @@ static int smc_clc_send_confirm_accept(struct smc_sock *smc,
memcpy(clc->hdr.eyecatcher, SMCD_EYECATCHER, memcpy(clc->hdr.eyecatcher, SMCD_EYECATCHER,
sizeof(SMCD_EYECATCHER)); sizeof(SMCD_EYECATCHER));
clc->hdr.typev1 = SMC_TYPE_D; clc->hdr.typev1 = SMC_TYPE_D;
clc->d0.gid = conn->lgr->smcd->local_gid; clc->d0.gid =
conn->lgr->smcd->ops->get_local_gid(conn->lgr->smcd);
clc->d0.token = conn->rmb_desc->token; clc->d0.token = conn->rmb_desc->token;
clc->d0.dmbe_size = conn->rmbe_size_short; clc->d0.dmbe_size = conn->rmbe_size_short;
clc->d0.dmbe_idx = 0; clc->d0.dmbe_idx = 0;
......
...@@ -500,6 +500,7 @@ static int smc_nl_fill_smcd_lgr(struct smc_link_group *lgr, ...@@ -500,6 +500,7 @@ static int smc_nl_fill_smcd_lgr(struct smc_link_group *lgr,
struct netlink_callback *cb) struct netlink_callback *cb)
{ {
char smc_pnet[SMC_MAX_PNETID_LEN + 1]; char smc_pnet[SMC_MAX_PNETID_LEN + 1];
struct smcd_dev *smcd = lgr->smcd;
struct nlattr *attrs; struct nlattr *attrs;
void *nlh; void *nlh;
...@@ -515,7 +516,8 @@ static int smc_nl_fill_smcd_lgr(struct smc_link_group *lgr, ...@@ -515,7 +516,8 @@ static int smc_nl_fill_smcd_lgr(struct smc_link_group *lgr,
if (nla_put_u32(skb, SMC_NLA_LGR_D_ID, *((u32 *)&lgr->id))) if (nla_put_u32(skb, SMC_NLA_LGR_D_ID, *((u32 *)&lgr->id)))
goto errattr; goto errattr;
if (nla_put_u64_64bit(skb, SMC_NLA_LGR_D_GID, lgr->smcd->local_gid, if (nla_put_u64_64bit(skb, SMC_NLA_LGR_D_GID,
smcd->ops->get_local_gid(smcd),
SMC_NLA_LGR_D_PAD)) SMC_NLA_LGR_D_PAD))
goto errattr; goto errattr;
if (nla_put_u64_64bit(skb, SMC_NLA_LGR_D_PEER_GID, lgr->peer_gid, if (nla_put_u64_64bit(skb, SMC_NLA_LGR_D_PEER_GID, lgr->peer_gid,
...@@ -820,6 +822,7 @@ static int smc_lgr_create(struct smc_sock *smc, struct smc_init_info *ini) ...@@ -820,6 +822,7 @@ static int smc_lgr_create(struct smc_sock *smc, struct smc_init_info *ini)
{ {
struct smc_link_group *lgr; struct smc_link_group *lgr;
struct list_head *lgr_list; struct list_head *lgr_list;
struct smcd_dev *smcd;
struct smc_link *lnk; struct smc_link *lnk;
spinlock_t *lgr_lock; spinlock_t *lgr_lock;
u8 link_idx; u8 link_idx;
...@@ -866,7 +869,8 @@ static int smc_lgr_create(struct smc_sock *smc, struct smc_init_info *ini) ...@@ -866,7 +869,8 @@ static int smc_lgr_create(struct smc_sock *smc, struct smc_init_info *ini)
lgr->conns_all = RB_ROOT; lgr->conns_all = RB_ROOT;
if (ini->is_smcd) { if (ini->is_smcd) {
/* SMC-D specific settings */ /* SMC-D specific settings */
get_device(&ini->ism_dev[ini->ism_selected]->dev); smcd = ini->ism_dev[ini->ism_selected];
get_device(smcd->ops->get_dev(smcd));
lgr->peer_gid = ini->ism_peer_gid[ini->ism_selected]; lgr->peer_gid = ini->ism_peer_gid[ini->ism_selected];
lgr->smcd = ini->ism_dev[ini->ism_selected]; lgr->smcd = ini->ism_dev[ini->ism_selected];
lgr_list = &ini->ism_dev[ini->ism_selected]->lgr_list; lgr_list = &ini->ism_dev[ini->ism_selected]->lgr_list;
...@@ -1385,7 +1389,7 @@ static void smc_lgr_free(struct smc_link_group *lgr) ...@@ -1385,7 +1389,7 @@ static void smc_lgr_free(struct smc_link_group *lgr)
destroy_workqueue(lgr->tx_wq); destroy_workqueue(lgr->tx_wq);
if (lgr->is_smcd) { if (lgr->is_smcd) {
smc_ism_put_vlan(lgr->smcd, lgr->vlan_id); smc_ism_put_vlan(lgr->smcd, lgr->vlan_id);
put_device(&lgr->smcd->dev); put_device(lgr->smcd->ops->get_dev(lgr->smcd));
} }
smc_lgr_put(lgr); /* theoretically last lgr_put */ smc_lgr_put(lgr); /* theoretically last lgr_put */
} }
...@@ -2595,6 +2599,7 @@ static int smc_core_reboot_event(struct notifier_block *this, ...@@ -2595,6 +2599,7 @@ static int smc_core_reboot_event(struct notifier_block *this,
{ {
smc_lgrs_shutdown(); smc_lgrs_shutdown();
smc_ib_unregister_client(); smc_ib_unregister_client();
smc_ism_exit();
return 0; return 0;
} }
......
...@@ -167,12 +167,13 @@ static int __smc_diag_dump(struct sock *sk, struct sk_buff *skb, ...@@ -167,12 +167,13 @@ static int __smc_diag_dump(struct sock *sk, struct sk_buff *skb,
!list_empty(&smc->conn.lgr->list)) { !list_empty(&smc->conn.lgr->list)) {
struct smc_connection *conn = &smc->conn; struct smc_connection *conn = &smc->conn;
struct smcd_diag_dmbinfo dinfo; struct smcd_diag_dmbinfo dinfo;
struct smcd_dev *smcd = conn->lgr->smcd;
memset(&dinfo, 0, sizeof(dinfo)); memset(&dinfo, 0, sizeof(dinfo));
dinfo.linkid = *((u32 *)conn->lgr->id); dinfo.linkid = *((u32 *)conn->lgr->id);
dinfo.peer_gid = conn->lgr->peer_gid; dinfo.peer_gid = conn->lgr->peer_gid;
dinfo.my_gid = conn->lgr->smcd->local_gid; dinfo.my_gid = smcd->ops->get_local_gid(smcd);
dinfo.token = conn->rmb_desc->token; dinfo.token = conn->rmb_desc->token;
dinfo.peer_token = conn->peer_token; dinfo.peer_token = conn->peer_token;
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include "smc_ism.h" #include "smc_ism.h"
#include "smc_pnet.h" #include "smc_pnet.h"
#include "smc_netlink.h" #include "smc_netlink.h"
#include "linux/ism.h"
struct smcd_dev_list smcd_dev_list = { struct smcd_dev_list smcd_dev_list = {
.list = LIST_HEAD_INIT(smcd_dev_list.list), .list = LIST_HEAD_INIT(smcd_dev_list.list),
...@@ -26,6 +27,22 @@ struct smcd_dev_list smcd_dev_list = { ...@@ -26,6 +27,22 @@ struct smcd_dev_list smcd_dev_list = {
static bool smc_ism_v2_capable; static bool smc_ism_v2_capable;
static u8 smc_ism_v2_system_eid[SMC_MAX_EID_LEN]; static u8 smc_ism_v2_system_eid[SMC_MAX_EID_LEN];
#if IS_ENABLED(CONFIG_ISM)
static void smcd_register_dev(struct ism_dev *ism);
static void smcd_unregister_dev(struct ism_dev *ism);
static void smcd_handle_event(struct ism_dev *ism, struct ism_event *event);
static void smcd_handle_irq(struct ism_dev *ism, unsigned int dmbno,
u16 dmbemask);
static struct ism_client smc_ism_client = {
.name = "SMC-D",
.add = smcd_register_dev,
.remove = smcd_unregister_dev,
.handle_event = smcd_handle_event,
.handle_irq = smcd_handle_irq,
};
#endif
/* Test if an ISM communication is possible - same CPC */ /* Test if an ISM communication is possible - same CPC */
int smc_ism_cantalk(u64 peer_gid, unsigned short vlan_id, struct smcd_dev *smcd) int smc_ism_cantalk(u64 peer_gid, unsigned short vlan_id, struct smcd_dev *smcd)
{ {
...@@ -183,6 +200,7 @@ int smc_ism_unregister_dmb(struct smcd_dev *smcd, struct smc_buf_desc *dmb_desc) ...@@ -183,6 +200,7 @@ int smc_ism_unregister_dmb(struct smcd_dev *smcd, struct smc_buf_desc *dmb_desc)
int smc_ism_register_dmb(struct smc_link_group *lgr, int dmb_len, int smc_ism_register_dmb(struct smc_link_group *lgr, int dmb_len,
struct smc_buf_desc *dmb_desc) struct smc_buf_desc *dmb_desc)
{ {
#if IS_ENABLED(CONFIG_ISM)
struct smcd_dmb dmb; struct smcd_dmb dmb;
int rc; int rc;
...@@ -191,7 +209,7 @@ int smc_ism_register_dmb(struct smc_link_group *lgr, int dmb_len, ...@@ -191,7 +209,7 @@ int smc_ism_register_dmb(struct smc_link_group *lgr, int dmb_len,
dmb.sba_idx = dmb_desc->sba_idx; dmb.sba_idx = dmb_desc->sba_idx;
dmb.vlan_id = lgr->vlan_id; dmb.vlan_id = lgr->vlan_id;
dmb.rgid = lgr->peer_gid; dmb.rgid = lgr->peer_gid;
rc = lgr->smcd->ops->register_dmb(lgr->smcd, &dmb); rc = lgr->smcd->ops->register_dmb(lgr->smcd, &dmb, &smc_ism_client);
if (!rc) { if (!rc) {
dmb_desc->sba_idx = dmb.sba_idx; dmb_desc->sba_idx = dmb.sba_idx;
dmb_desc->token = dmb.dmb_tok; dmb_desc->token = dmb.dmb_tok;
...@@ -200,6 +218,9 @@ int smc_ism_register_dmb(struct smc_link_group *lgr, int dmb_len, ...@@ -200,6 +218,9 @@ int smc_ism_register_dmb(struct smc_link_group *lgr, int dmb_len,
dmb_desc->len = dmb.dmb_len; dmb_desc->len = dmb.dmb_len;
} }
return rc; return rc;
#else
return 0;
#endif
} }
static int smc_nl_handle_smcd_dev(struct smcd_dev *smcd, static int smc_nl_handle_smcd_dev(struct smcd_dev *smcd,
...@@ -210,9 +231,11 @@ static int smc_nl_handle_smcd_dev(struct smcd_dev *smcd, ...@@ -210,9 +231,11 @@ static int smc_nl_handle_smcd_dev(struct smcd_dev *smcd,
struct smc_pci_dev smc_pci_dev; struct smc_pci_dev smc_pci_dev;
struct nlattr *port_attrs; struct nlattr *port_attrs;
struct nlattr *attrs; struct nlattr *attrs;
struct ism_dev *ism;
int use_cnt = 0; int use_cnt = 0;
void *nlh; void *nlh;
ism = smcd->priv;
nlh = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, nlh = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
&smc_gen_nl_family, NLM_F_MULTI, &smc_gen_nl_family, NLM_F_MULTI,
SMC_NETLINK_GET_DEV_SMCD); SMC_NETLINK_GET_DEV_SMCD);
...@@ -227,7 +250,7 @@ static int smc_nl_handle_smcd_dev(struct smcd_dev *smcd, ...@@ -227,7 +250,7 @@ static int smc_nl_handle_smcd_dev(struct smcd_dev *smcd,
if (nla_put_u8(skb, SMC_NLA_DEV_IS_CRIT, use_cnt > 0)) if (nla_put_u8(skb, SMC_NLA_DEV_IS_CRIT, use_cnt > 0))
goto errattr; goto errattr;
memset(&smc_pci_dev, 0, sizeof(smc_pci_dev)); memset(&smc_pci_dev, 0, sizeof(smc_pci_dev));
smc_set_pci_values(to_pci_dev(smcd->dev.parent), &smc_pci_dev); smc_set_pci_values(to_pci_dev(ism->dev.parent), &smc_pci_dev);
if (nla_put_u32(skb, SMC_NLA_DEV_PCI_FID, smc_pci_dev.pci_fid)) if (nla_put_u32(skb, SMC_NLA_DEV_PCI_FID, smc_pci_dev.pci_fid))
goto errattr; goto errattr;
if (nla_put_u16(skb, SMC_NLA_DEV_PCI_CHID, smc_pci_dev.pci_pchid)) if (nla_put_u16(skb, SMC_NLA_DEV_PCI_CHID, smc_pci_dev.pci_pchid))
...@@ -293,10 +316,11 @@ int smcd_nl_get_device(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -293,10 +316,11 @@ int smcd_nl_get_device(struct sk_buff *skb, struct netlink_callback *cb)
return skb->len; return skb->len;
} }
#if IS_ENABLED(CONFIG_ISM)
struct smc_ism_event_work { struct smc_ism_event_work {
struct work_struct work; struct work_struct work;
struct smcd_dev *smcd; struct smcd_dev *smcd;
struct smcd_event event; struct ism_event event;
}; };
#define ISM_EVENT_REQUEST 0x0001 #define ISM_EVENT_REQUEST 0x0001
...@@ -336,24 +360,6 @@ static void smcd_handle_sw_event(struct smc_ism_event_work *wrk) ...@@ -336,24 +360,6 @@ static void smcd_handle_sw_event(struct smc_ism_event_work *wrk)
} }
} }
int smc_ism_signal_shutdown(struct smc_link_group *lgr)
{
int rc;
union smcd_sw_event_info ev_info;
if (lgr->peer_shutdown)
return 0;
memcpy(ev_info.uid, lgr->id, SMC_LGR_ID_SIZE);
ev_info.vlan_id = lgr->vlan_id;
ev_info.code = ISM_EVENT_REQUEST;
rc = lgr->smcd->ops->signal_event(lgr->smcd, lgr->peer_gid,
ISM_EVENT_REQUEST_IR,
ISM_EVENT_CODE_SHUTDOWN,
ev_info.info);
return rc;
}
/* worker for SMC-D events */ /* worker for SMC-D events */
static void smc_ism_event_work(struct work_struct *work) static void smc_ism_event_work(struct work_struct *work)
{ {
...@@ -373,44 +379,25 @@ static void smc_ism_event_work(struct work_struct *work) ...@@ -373,44 +379,25 @@ static void smc_ism_event_work(struct work_struct *work)
kfree(wrk); kfree(wrk);
} }
static void smcd_release(struct device *dev) static struct smcd_dev *smcd_alloc_dev(struct device *parent, const char *name,
{
struct smcd_dev *smcd = container_of(dev, struct smcd_dev, dev);
kfree(smcd->conn);
kfree(smcd);
}
struct smcd_dev *smcd_alloc_dev(struct device *parent, const char *name,
const struct smcd_ops *ops, int max_dmbs) const struct smcd_ops *ops, int max_dmbs)
{ {
struct smcd_dev *smcd; struct smcd_dev *smcd;
smcd = kzalloc(sizeof(*smcd), GFP_KERNEL); smcd = devm_kzalloc(parent, sizeof(*smcd), GFP_KERNEL);
if (!smcd) if (!smcd)
return NULL; return NULL;
smcd->conn = kcalloc(max_dmbs, sizeof(struct smc_connection *), smcd->conn = devm_kcalloc(parent, max_dmbs,
GFP_KERNEL); sizeof(struct smc_connection *), GFP_KERNEL);
if (!smcd->conn) { if (!smcd->conn)
kfree(smcd);
return NULL; return NULL;
}
smcd->event_wq = alloc_ordered_workqueue("ism_evt_wq-%s)", smcd->event_wq = alloc_ordered_workqueue("ism_evt_wq-%s)",
WQ_MEM_RECLAIM, name); WQ_MEM_RECLAIM, name);
if (!smcd->event_wq) { if (!smcd->event_wq)
kfree(smcd->conn);
kfree(smcd);
return NULL; return NULL;
}
smcd->dev.parent = parent;
smcd->dev.release = smcd_release;
device_initialize(&smcd->dev);
dev_set_name(&smcd->dev, name);
smcd->ops = ops; smcd->ops = ops;
if (smc_pnetid_by_dev_port(parent, 0, smcd->pnetid))
smc_pnetid_by_table_smcd(smcd);
spin_lock_init(&smcd->lock); spin_lock_init(&smcd->lock);
spin_lock_init(&smcd->lgr_lock); spin_lock_init(&smcd->lgr_lock);
...@@ -419,11 +406,23 @@ struct smcd_dev *smcd_alloc_dev(struct device *parent, const char *name, ...@@ -419,11 +406,23 @@ struct smcd_dev *smcd_alloc_dev(struct device *parent, const char *name,
init_waitqueue_head(&smcd->lgrs_deleted); init_waitqueue_head(&smcd->lgrs_deleted);
return smcd; return smcd;
} }
EXPORT_SYMBOL_GPL(smcd_alloc_dev);
int smcd_register_dev(struct smcd_dev *smcd) static void smcd_register_dev(struct ism_dev *ism)
{ {
int rc; const struct smcd_ops *ops = ism_get_smcd_ops();
struct smcd_dev *smcd;
if (!ops)
return;
smcd = smcd_alloc_dev(&ism->pdev->dev, dev_name(&ism->pdev->dev), ops,
ISM_NR_DMBS);
if (!smcd)
return;
smcd->priv = ism;
ism_set_priv(ism, &smc_ism_client, smcd);
if (smc_pnetid_by_dev_port(&ism->pdev->dev, 0, smcd->pnetid))
smc_pnetid_by_table_smcd(smcd);
mutex_lock(&smcd_dev_list.mutex); mutex_lock(&smcd_dev_list.mutex);
if (list_empty(&smcd_dev_list.list)) { if (list_empty(&smcd_dev_list.list)) {
...@@ -444,43 +443,28 @@ int smcd_register_dev(struct smcd_dev *smcd) ...@@ -444,43 +443,28 @@ int smcd_register_dev(struct smcd_dev *smcd)
mutex_unlock(&smcd_dev_list.mutex); mutex_unlock(&smcd_dev_list.mutex);
pr_warn_ratelimited("smc: adding smcd device %s with pnetid %.16s%s\n", pr_warn_ratelimited("smc: adding smcd device %s with pnetid %.16s%s\n",
dev_name(&smcd->dev), smcd->pnetid, dev_name(&ism->dev), smcd->pnetid,
smcd->pnetid_by_user ? " (user defined)" : ""); smcd->pnetid_by_user ? " (user defined)" : "");
rc = device_add(&smcd->dev); return;
if (rc) {
mutex_lock(&smcd_dev_list.mutex);
list_del(&smcd->list);
mutex_unlock(&smcd_dev_list.mutex);
}
return rc;
} }
EXPORT_SYMBOL_GPL(smcd_register_dev);
void smcd_unregister_dev(struct smcd_dev *smcd) static void smcd_unregister_dev(struct ism_dev *ism)
{ {
struct smcd_dev *smcd = ism_get_priv(ism, &smc_ism_client);
pr_warn_ratelimited("smc: removing smcd device %s\n", pr_warn_ratelimited("smc: removing smcd device %s\n",
dev_name(&smcd->dev)); dev_name(&ism->dev));
smcd->going_away = 1;
smc_smcd_terminate_all(smcd);
mutex_lock(&smcd_dev_list.mutex); mutex_lock(&smcd_dev_list.mutex);
list_del_init(&smcd->list); list_del_init(&smcd->list);
mutex_unlock(&smcd_dev_list.mutex); mutex_unlock(&smcd_dev_list.mutex);
smcd->going_away = 1;
smc_smcd_terminate_all(smcd);
destroy_workqueue(smcd->event_wq); destroy_workqueue(smcd->event_wq);
device_del(&smcd->dev);
} }
EXPORT_SYMBOL_GPL(smcd_unregister_dev);
void smcd_free_dev(struct smcd_dev *smcd)
{
put_device(&smcd->dev);
}
EXPORT_SYMBOL_GPL(smcd_free_dev);
/* SMCD Device event handler. Called from ISM device interrupt handler. /* SMCD Device event handler. Called from ISM device interrupt handler.
* Parameters are smcd device pointer, * Parameters are ism device pointer,
* - event->type (0 --> DMB, 1 --> GID), * - event->type (0 --> DMB, 1 --> GID),
* - event->code (event code), * - event->code (event code),
* - event->tok (either DMB token when event type 0, or GID when event type 1) * - event->tok (either DMB token when event type 0, or GID when event type 1)
...@@ -490,8 +474,9 @@ EXPORT_SYMBOL_GPL(smcd_free_dev); ...@@ -490,8 +474,9 @@ EXPORT_SYMBOL_GPL(smcd_free_dev);
* Context: * Context:
* - Function called in IRQ context from ISM device driver event handler. * - Function called in IRQ context from ISM device driver event handler.
*/ */
void smcd_handle_event(struct smcd_dev *smcd, struct smcd_event *event) static void smcd_handle_event(struct ism_dev *ism, struct ism_event *event)
{ {
struct smcd_dev *smcd = ism_get_priv(ism, &smc_ism_client);
struct smc_ism_event_work *wrk; struct smc_ism_event_work *wrk;
if (smcd->going_away) if (smcd->going_away)
...@@ -505,17 +490,18 @@ void smcd_handle_event(struct smcd_dev *smcd, struct smcd_event *event) ...@@ -505,17 +490,18 @@ void smcd_handle_event(struct smcd_dev *smcd, struct smcd_event *event)
wrk->event = *event; wrk->event = *event;
queue_work(smcd->event_wq, &wrk->work); queue_work(smcd->event_wq, &wrk->work);
} }
EXPORT_SYMBOL_GPL(smcd_handle_event);
/* SMCD Device interrupt handler. Called from ISM device interrupt handler. /* SMCD Device interrupt handler. Called from ISM device interrupt handler.
* Parameters are smcd device pointer, DMB number, and the DMBE bitmask. * Parameters are the ism device pointer, DMB number, and the DMBE bitmask.
* Find the connection and schedule the tasklet for this connection. * Find the connection and schedule the tasklet for this connection.
* *
* Context: * Context:
* - Function called in IRQ context from ISM device driver IRQ handler. * - Function called in IRQ context from ISM device driver IRQ handler.
*/ */
void smcd_handle_irq(struct smcd_dev *smcd, unsigned int dmbno, u16 dmbemask) static void smcd_handle_irq(struct ism_dev *ism, unsigned int dmbno,
u16 dmbemask)
{ {
struct smcd_dev *smcd = ism_get_priv(ism, &smc_ism_client);
struct smc_connection *conn = NULL; struct smc_connection *conn = NULL;
unsigned long flags; unsigned long flags;
...@@ -525,10 +511,44 @@ void smcd_handle_irq(struct smcd_dev *smcd, unsigned int dmbno, u16 dmbemask) ...@@ -525,10 +511,44 @@ void smcd_handle_irq(struct smcd_dev *smcd, unsigned int dmbno, u16 dmbemask)
tasklet_schedule(&conn->rx_tsklet); tasklet_schedule(&conn->rx_tsklet);
spin_unlock_irqrestore(&smcd->lock, flags); spin_unlock_irqrestore(&smcd->lock, flags);
} }
EXPORT_SYMBOL_GPL(smcd_handle_irq); #endif
int smc_ism_signal_shutdown(struct smc_link_group *lgr)
{
int rc = 0;
#if IS_ENABLED(CONFIG_ISM)
union smcd_sw_event_info ev_info;
if (lgr->peer_shutdown)
return 0;
memcpy(ev_info.uid, lgr->id, SMC_LGR_ID_SIZE);
ev_info.vlan_id = lgr->vlan_id;
ev_info.code = ISM_EVENT_REQUEST;
rc = lgr->smcd->ops->signal_event(lgr->smcd, lgr->peer_gid,
ISM_EVENT_REQUEST_IR,
ISM_EVENT_CODE_SHUTDOWN,
ev_info.info);
#endif
return rc;
}
void __init smc_ism_init(void) int smc_ism_init(void)
{ {
int rc = 0;
#if IS_ENABLED(CONFIG_ISM)
smc_ism_v2_capable = false; smc_ism_v2_capable = false;
memset(smc_ism_v2_system_eid, 0, SMC_MAX_EID_LEN); memset(smc_ism_v2_system_eid, 0, SMC_MAX_EID_LEN);
rc = ism_register_client(&smc_ism_client);
#endif
return rc;
}
void smc_ism_exit(void)
{
#if IS_ENABLED(CONFIG_ISM)
ism_unregister_client(&smc_ism_client);
#endif
} }
...@@ -42,7 +42,8 @@ int smc_ism_signal_shutdown(struct smc_link_group *lgr); ...@@ -42,7 +42,8 @@ int smc_ism_signal_shutdown(struct smc_link_group *lgr);
void smc_ism_get_system_eid(u8 **eid); void smc_ism_get_system_eid(u8 **eid);
u16 smc_ism_get_chid(struct smcd_dev *dev); u16 smc_ism_get_chid(struct smcd_dev *dev);
bool smc_ism_is_v2_capable(void); bool smc_ism_is_v2_capable(void);
void smc_ism_init(void); int smc_ism_init(void);
void smc_ism_exit(void);
int smcd_nl_get_device(struct sk_buff *skb, struct netlink_callback *cb); int smcd_nl_get_device(struct sk_buff *skb, struct netlink_callback *cb);
static inline int smc_ism_write(struct smcd_dev *smcd, u64 dmb_tok, static inline int smc_ism_write(struct smcd_dev *smcd, u64 dmb_tok,
......
...@@ -103,7 +103,7 @@ static int smc_pnet_remove_by_pnetid(struct net *net, char *pnet_name) ...@@ -103,7 +103,7 @@ static int smc_pnet_remove_by_pnetid(struct net *net, char *pnet_name)
struct smc_pnetentry *pnetelem, *tmp_pe; struct smc_pnetentry *pnetelem, *tmp_pe;
struct smc_pnettable *pnettable; struct smc_pnettable *pnettable;
struct smc_ib_device *ibdev; struct smc_ib_device *ibdev;
struct smcd_dev *smcd_dev; struct smcd_dev *smcd;
struct smc_net *sn; struct smc_net *sn;
int rc = -ENOENT; int rc = -ENOENT;
int ibport; int ibport;
...@@ -162,16 +162,17 @@ static int smc_pnet_remove_by_pnetid(struct net *net, char *pnet_name) ...@@ -162,16 +162,17 @@ static int smc_pnet_remove_by_pnetid(struct net *net, char *pnet_name)
mutex_unlock(&smc_ib_devices.mutex); mutex_unlock(&smc_ib_devices.mutex);
/* remove smcd devices */ /* remove smcd devices */
mutex_lock(&smcd_dev_list.mutex); mutex_lock(&smcd_dev_list.mutex);
list_for_each_entry(smcd_dev, &smcd_dev_list.list, list) { list_for_each_entry(smcd, &smcd_dev_list.list, list) {
if (smcd_dev->pnetid_by_user && if (smcd->pnetid_by_user &&
(!pnet_name || (!pnet_name ||
smc_pnet_match(pnet_name, smcd_dev->pnetid))) { smc_pnet_match(pnet_name, smcd->pnetid))) {
pr_warn_ratelimited("smc: smcd device %s " pr_warn_ratelimited("smc: smcd device %s "
"erased user defined pnetid " "erased user defined pnetid "
"%.16s\n", dev_name(&smcd_dev->dev), "%.16s\n",
smcd_dev->pnetid); dev_name(smcd->ops->get_dev(smcd)),
memset(smcd_dev->pnetid, 0, SMC_MAX_PNETID_LEN); smcd->pnetid);
smcd_dev->pnetid_by_user = false; memset(smcd->pnetid, 0, SMC_MAX_PNETID_LEN);
smcd->pnetid_by_user = false;
rc = 0; rc = 0;
} }
} }
...@@ -331,8 +332,8 @@ static struct smcd_dev *smc_pnet_find_smcd(char *smcd_name) ...@@ -331,8 +332,8 @@ static struct smcd_dev *smc_pnet_find_smcd(char *smcd_name)
mutex_lock(&smcd_dev_list.mutex); mutex_lock(&smcd_dev_list.mutex);
list_for_each_entry(smcd_dev, &smcd_dev_list.list, list) { list_for_each_entry(smcd_dev, &smcd_dev_list.list, list) {
if (!strncmp(dev_name(&smcd_dev->dev), smcd_name, if (!strncmp(dev_name(smcd_dev->ops->get_dev(smcd_dev)),
IB_DEVICE_NAME_MAX - 1)) smcd_name, IB_DEVICE_NAME_MAX - 1))
goto out; goto out;
} }
smcd_dev = NULL; smcd_dev = NULL;
...@@ -411,7 +412,8 @@ static int smc_pnet_add_ib(struct smc_pnettable *pnettable, char *ib_name, ...@@ -411,7 +412,8 @@ static int smc_pnet_add_ib(struct smc_pnettable *pnettable, char *ib_name,
struct smc_ib_device *ib_dev; struct smc_ib_device *ib_dev;
bool smcddev_applied = true; bool smcddev_applied = true;
bool ibdev_applied = true; bool ibdev_applied = true;
struct smcd_dev *smcd_dev; struct smcd_dev *smcd;
struct device *dev;
bool new_ibdev; bool new_ibdev;
/* try to apply the pnetid to active devices */ /* try to apply the pnetid to active devices */
...@@ -425,14 +427,16 @@ static int smc_pnet_add_ib(struct smc_pnettable *pnettable, char *ib_name, ...@@ -425,14 +427,16 @@ static int smc_pnet_add_ib(struct smc_pnettable *pnettable, char *ib_name,
ib_port, ib_port,
ib_dev->pnetid[ib_port - 1]); ib_dev->pnetid[ib_port - 1]);
} }
smcd_dev = smc_pnet_find_smcd(ib_name); smcd = smc_pnet_find_smcd(ib_name);
if (smcd_dev) { if (smcd) {
smcddev_applied = smc_pnet_apply_smcd(smcd_dev, pnet_name); smcddev_applied = smc_pnet_apply_smcd(smcd, pnet_name);
if (smcddev_applied) if (smcddev_applied) {
dev = smcd->ops->get_dev(smcd);
pr_warn_ratelimited("smc: smcd device %s " pr_warn_ratelimited("smc: smcd device %s "
"applied user defined pnetid " "applied user defined pnetid "
"%.16s\n", dev_name(&smcd_dev->dev), "%.16s\n", dev_name(dev),
smcd_dev->pnetid); smcd->pnetid);
}
} }
/* Apply fails when a device has a hardware-defined pnetid set, do not /* Apply fails when a device has a hardware-defined pnetid set, do not
* add a pnet table entry in that case. * add a pnet table entry in that case.
...@@ -1181,7 +1185,7 @@ int smc_pnetid_by_table_ib(struct smc_ib_device *smcibdev, u8 ib_port) ...@@ -1181,7 +1185,7 @@ int smc_pnetid_by_table_ib(struct smc_ib_device *smcibdev, u8 ib_port)
*/ */
int smc_pnetid_by_table_smcd(struct smcd_dev *smcddev) int smc_pnetid_by_table_smcd(struct smcd_dev *smcddev)
{ {
const char *ib_name = dev_name(&smcddev->dev); const char *ib_name = dev_name(smcddev->ops->get_dev(smcddev));
struct smc_pnettable *pnettable; struct smc_pnettable *pnettable;
struct smc_pnetentry *tmp_pe; struct smc_pnetentry *tmp_pe;
struct smc_net *sn; struct smc_net *sn;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment