1 // SPDX-License-Identifier: GPL-2.0 1 // SPDX-License-Identifier: GPL-2.0 2 /* Shared Memory Communications Direct over IS 2 /* Shared Memory Communications Direct over ISM devices (SMC-D) 3 * 3 * 4 * Functions for ISM device. 4 * Functions for ISM device. 5 * 5 * 6 * Copyright IBM Corp. 2018 6 * Copyright IBM Corp. 2018 7 */ 7 */ 8 8 9 #include <linux/if_vlan.h> 9 #include <linux/if_vlan.h> 10 #include <linux/spinlock.h> 10 #include <linux/spinlock.h> 11 #include <linux/mutex.h> 11 #include <linux/mutex.h> 12 #include <linux/slab.h> 12 #include <linux/slab.h> 13 #include <asm/page.h> 13 #include <asm/page.h> 14 14 15 #include "smc.h" 15 #include "smc.h" 16 #include "smc_core.h" 16 #include "smc_core.h" 17 #include "smc_ism.h" 17 #include "smc_ism.h" 18 #include "smc_pnet.h" 18 #include "smc_pnet.h" 19 #include "smc_netlink.h" 19 #include "smc_netlink.h" 20 #include "linux/ism.h" << 21 20 22 struct smcd_dev_list smcd_dev_list = { 21 struct smcd_dev_list smcd_dev_list = { 23 .list = LIST_HEAD_INIT(smcd_dev_list.l 22 .list = LIST_HEAD_INIT(smcd_dev_list.list), 24 .mutex = __MUTEX_INITIALIZER(smcd_dev_ 23 .mutex = __MUTEX_INITIALIZER(smcd_dev_list.mutex) 25 }; 24 }; 26 25 27 static bool smc_ism_v2_capable; 26 static bool smc_ism_v2_capable; 28 static u8 smc_ism_v2_system_eid[SMC_MAX_EID_LE 27 static u8 smc_ism_v2_system_eid[SMC_MAX_EID_LEN]; 29 28 30 #if IS_ENABLED(CONFIG_ISM) << 31 static void smcd_register_dev(struct ism_dev * << 32 static void smcd_unregister_dev(struct ism_dev << 33 static void smcd_handle_event(struct ism_dev * << 34 static void smcd_handle_irq(struct ism_dev *is << 35 u16 dmbemask); << 36 << 37 static struct ism_client smc_ism_client = { << 38 .name = "SMC-D", << 39 .add = smcd_register_dev, << 40 .remove = smcd_unregister_dev, << 41 .handle_event = smcd_handle_event, << 42 .handle_irq = smcd_handle_irq, << 43 }; << 44 #endif << 45 << 46 static void smc_ism_create_system_eid(void) << 47 { << 48 struct smc_ism_seid *seid = << 49 (struct smc_ism_seid *)smc_ism << 50 #if IS_ENABLED(CONFIG_S390) << 51 struct cpuid id; << 52 u16 ident_tail; << 53 char tmp[5]; << 54 << 55 memcpy(seid->seid_string, "IBM-SYSZ-IS << 56 get_cpu_id(&id); << 57 ident_tail = (u16)(id.ident & SMC_ISM_ << 58 snprintf(tmp, 5, "%04X", ident_tail); << 59 memcpy(seid->serial_number, tmp, 4); << 60 snprintf(tmp, 5, "%04X", id.machine); << 61 memcpy(seid->type, tmp, 4); << 62 #else << 63 memset(seid, 0, SMC_MAX_EID_LEN); << 64 #endif << 65 } << 66 << 67 /* Test if an ISM communication is possible - 29 /* Test if an ISM communication is possible - same CPC */ 68 int smc_ism_cantalk(struct smcd_gid *peer_gid, !! 30 int smc_ism_cantalk(u64 peer_gid, unsigned short vlan_id, struct smcd_dev *smcd) 69 struct smcd_dev *smcd) << 70 { 31 { 71 return smcd->ops->query_remote_gid(smc 32 return smcd->ops->query_remote_gid(smcd, peer_gid, vlan_id ? 1 : 0, 72 vla 33 vlan_id); 73 } 34 } 74 35 75 void smc_ism_get_system_eid(u8 **eid) 36 void smc_ism_get_system_eid(u8 **eid) 76 { 37 { 77 if (!smc_ism_v2_capable) 38 if (!smc_ism_v2_capable) 78 *eid = NULL; 39 *eid = NULL; 79 else 40 else 80 *eid = smc_ism_v2_system_eid; 41 *eid = smc_ism_v2_system_eid; 81 } 42 } 82 43 83 u16 smc_ism_get_chid(struct smcd_dev *smcd) 44 u16 smc_ism_get_chid(struct smcd_dev *smcd) 84 { 45 { 85 return smcd->ops->get_chid(smcd); 46 return smcd->ops->get_chid(smcd); 86 } 47 } 87 48 88 /* HW supports ISM V2 and thus System EID is d 49 /* HW supports ISM V2 and thus System EID is defined */ 89 bool smc_ism_is_v2_capable(void) 50 bool smc_ism_is_v2_capable(void) 90 { 51 { 91 return smc_ism_v2_capable; 52 return smc_ism_v2_capable; 92 } 53 } 93 54 94 void smc_ism_set_v2_capable(void) << 95 { << 96 smc_ism_v2_capable = true; << 97 } << 98 << 99 /* Set a connection using this DMBE. */ 55 /* Set a connection using this DMBE. */ 100 void smc_ism_set_conn(struct smc_connection *c 56 void smc_ism_set_conn(struct smc_connection *conn) 101 { 57 { 102 unsigned long flags; 58 unsigned long flags; 103 59 104 spin_lock_irqsave(&conn->lgr->smcd->lo 60 spin_lock_irqsave(&conn->lgr->smcd->lock, flags); 105 conn->lgr->smcd->conn[conn->rmb_desc-> 61 conn->lgr->smcd->conn[conn->rmb_desc->sba_idx] = conn; 106 spin_unlock_irqrestore(&conn->lgr->smc 62 spin_unlock_irqrestore(&conn->lgr->smcd->lock, flags); 107 } 63 } 108 64 109 /* Unset a connection using this DMBE. */ 65 /* Unset a connection using this DMBE. */ 110 void smc_ism_unset_conn(struct smc_connection 66 void smc_ism_unset_conn(struct smc_connection *conn) 111 { 67 { 112 unsigned long flags; 68 unsigned long flags; 113 69 114 if (!conn->rmb_desc) 70 if (!conn->rmb_desc) 115 return; 71 return; 116 72 117 spin_lock_irqsave(&conn->lgr->smcd->lo 73 spin_lock_irqsave(&conn->lgr->smcd->lock, flags); 118 conn->lgr->smcd->conn[conn->rmb_desc-> 74 conn->lgr->smcd->conn[conn->rmb_desc->sba_idx] = NULL; 119 spin_unlock_irqrestore(&conn->lgr->smc 75 spin_unlock_irqrestore(&conn->lgr->smcd->lock, flags); 120 } 76 } 121 77 122 /* Register a VLAN identifier with the ISM dev 78 /* Register a VLAN identifier with the ISM device. Use a reference count 123 * and add a VLAN identifier only when the fir 79 * and add a VLAN identifier only when the first DMB using this VLAN is 124 * registered. 80 * registered. 125 */ 81 */ 126 int smc_ism_get_vlan(struct smcd_dev *smcd, un 82 int smc_ism_get_vlan(struct smcd_dev *smcd, unsigned short vlanid) 127 { 83 { 128 struct smc_ism_vlanid *new_vlan, *vlan 84 struct smc_ism_vlanid *new_vlan, *vlan; 129 unsigned long flags; 85 unsigned long flags; 130 int rc = 0; 86 int rc = 0; 131 87 132 if (!vlanid) /* No 88 if (!vlanid) /* No valid vlan id */ 133 return -EINVAL; 89 return -EINVAL; 134 if (!smcd->ops->add_vlan_id) << 135 return -EOPNOTSUPP; << 136 90 137 /* create new vlan entry, in case we n 91 /* create new vlan entry, in case we need it */ 138 new_vlan = kzalloc(sizeof(*new_vlan), 92 new_vlan = kzalloc(sizeof(*new_vlan), GFP_KERNEL); 139 if (!new_vlan) 93 if (!new_vlan) 140 return -ENOMEM; 94 return -ENOMEM; 141 new_vlan->vlanid = vlanid; 95 new_vlan->vlanid = vlanid; 142 refcount_set(&new_vlan->refcnt, 1); 96 refcount_set(&new_vlan->refcnt, 1); 143 97 144 /* if there is an existing entry, incr 98 /* if there is an existing entry, increase count and return */ 145 spin_lock_irqsave(&smcd->lock, flags); 99 spin_lock_irqsave(&smcd->lock, flags); 146 list_for_each_entry(vlan, &smcd->vlan, 100 list_for_each_entry(vlan, &smcd->vlan, list) { 147 if (vlan->vlanid == vlanid) { 101 if (vlan->vlanid == vlanid) { 148 refcount_inc(&vlan->re 102 refcount_inc(&vlan->refcnt); 149 kfree(new_vlan); 103 kfree(new_vlan); 150 goto out; 104 goto out; 151 } 105 } 152 } 106 } 153 107 154 /* no existing entry found. 108 /* no existing entry found. 155 * add new entry to device; might fail 109 * add new entry to device; might fail, e.g., if HW limit reached 156 */ 110 */ 157 if (smcd->ops->add_vlan_id(smcd, vlani 111 if (smcd->ops->add_vlan_id(smcd, vlanid)) { 158 kfree(new_vlan); 112 kfree(new_vlan); 159 rc = -EIO; 113 rc = -EIO; 160 goto out; 114 goto out; 161 } 115 } 162 list_add_tail(&new_vlan->list, &smcd-> 116 list_add_tail(&new_vlan->list, &smcd->vlan); 163 out: 117 out: 164 spin_unlock_irqrestore(&smcd->lock, fl 118 spin_unlock_irqrestore(&smcd->lock, flags); 165 return rc; 119 return rc; 166 } 120 } 167 121 168 /* Unregister a VLAN identifier with the ISM d 122 /* Unregister a VLAN identifier with the ISM device. Use a reference count 169 * and remove a VLAN identifier only when the 123 * and remove a VLAN identifier only when the last DMB using this VLAN is 170 * unregistered. 124 * unregistered. 171 */ 125 */ 172 int smc_ism_put_vlan(struct smcd_dev *smcd, un 126 int smc_ism_put_vlan(struct smcd_dev *smcd, unsigned short vlanid) 173 { 127 { 174 struct smc_ism_vlanid *vlan; 128 struct smc_ism_vlanid *vlan; 175 unsigned long flags; 129 unsigned long flags; 176 bool found = false; 130 bool found = false; 177 int rc = 0; 131 int rc = 0; 178 132 179 if (!vlanid) /* No 133 if (!vlanid) /* No valid vlan id */ 180 return -EINVAL; 134 return -EINVAL; 181 if (!smcd->ops->del_vlan_id) << 182 return -EOPNOTSUPP; << 183 135 184 spin_lock_irqsave(&smcd->lock, flags); 136 spin_lock_irqsave(&smcd->lock, flags); 185 list_for_each_entry(vlan, &smcd->vlan, 137 list_for_each_entry(vlan, &smcd->vlan, list) { 186 if (vlan->vlanid == vlanid) { 138 if (vlan->vlanid == vlanid) { 187 if (!refcount_dec_and_ 139 if (!refcount_dec_and_test(&vlan->refcnt)) 188 goto out; 140 goto out; 189 found = true; 141 found = true; 190 break; 142 break; 191 } 143 } 192 } 144 } 193 if (!found) { 145 if (!found) { 194 rc = -ENOENT; 146 rc = -ENOENT; 195 goto out; /* VLA 147 goto out; /* VLAN id not in table */ 196 } 148 } 197 149 198 /* Found and the last reference just g 150 /* Found and the last reference just gone */ 199 if (smcd->ops->del_vlan_id(smcd, vlani 151 if (smcd->ops->del_vlan_id(smcd, vlanid)) 200 rc = -EIO; 152 rc = -EIO; 201 list_del(&vlan->list); 153 list_del(&vlan->list); 202 kfree(vlan); 154 kfree(vlan); 203 out: 155 out: 204 spin_unlock_irqrestore(&smcd->lock, fl 156 spin_unlock_irqrestore(&smcd->lock, flags); 205 return rc; 157 return rc; 206 } 158 } 207 159 208 int smc_ism_unregister_dmb(struct smcd_dev *sm 160 int smc_ism_unregister_dmb(struct smcd_dev *smcd, struct smc_buf_desc *dmb_desc) 209 { 161 { 210 struct smcd_dmb dmb; 162 struct smcd_dmb dmb; 211 int rc = 0; 163 int rc = 0; 212 164 213 if (!dmb_desc->dma_addr) 165 if (!dmb_desc->dma_addr) 214 return rc; 166 return rc; 215 167 216 memset(&dmb, 0, sizeof(dmb)); 168 memset(&dmb, 0, sizeof(dmb)); 217 dmb.dmb_tok = dmb_desc->token; 169 dmb.dmb_tok = dmb_desc->token; 218 dmb.sba_idx = dmb_desc->sba_idx; 170 dmb.sba_idx = dmb_desc->sba_idx; 219 dmb.cpu_addr = dmb_desc->cpu_addr; 171 dmb.cpu_addr = dmb_desc->cpu_addr; 220 dmb.dma_addr = dmb_desc->dma_addr; 172 dmb.dma_addr = dmb_desc->dma_addr; 221 dmb.dmb_len = dmb_desc->len; 173 dmb.dmb_len = dmb_desc->len; 222 rc = smcd->ops->unregister_dmb(smcd, & 174 rc = smcd->ops->unregister_dmb(smcd, &dmb); 223 if (!rc || rc == ISM_ERROR) { 175 if (!rc || rc == ISM_ERROR) { 224 dmb_desc->cpu_addr = NULL; 176 dmb_desc->cpu_addr = NULL; 225 dmb_desc->dma_addr = 0; 177 dmb_desc->dma_addr = 0; 226 } 178 } 227 179 228 return rc; 180 return rc; 229 } 181 } 230 182 231 int smc_ism_register_dmb(struct smc_link_group 183 int smc_ism_register_dmb(struct smc_link_group *lgr, int dmb_len, 232 struct smc_buf_desc * 184 struct smc_buf_desc *dmb_desc) 233 { 185 { 234 struct smcd_dmb dmb; 186 struct smcd_dmb dmb; 235 int rc; 187 int rc; 236 188 237 memset(&dmb, 0, sizeof(dmb)); 189 memset(&dmb, 0, sizeof(dmb)); 238 dmb.dmb_len = dmb_len; 190 dmb.dmb_len = dmb_len; 239 dmb.sba_idx = dmb_desc->sba_idx; 191 dmb.sba_idx = dmb_desc->sba_idx; 240 dmb.vlan_id = lgr->vlan_id; 192 dmb.vlan_id = lgr->vlan_id; 241 dmb.rgid = lgr->peer_gid.gid; !! 193 dmb.rgid = lgr->peer_gid; 242 rc = lgr->smcd->ops->register_dmb(lgr- !! 194 rc = lgr->smcd->ops->register_dmb(lgr->smcd, &dmb); 243 if (!rc) { 195 if (!rc) { 244 dmb_desc->sba_idx = dmb.sba_id 196 dmb_desc->sba_idx = dmb.sba_idx; 245 dmb_desc->token = dmb.dmb_tok; 197 dmb_desc->token = dmb.dmb_tok; 246 dmb_desc->cpu_addr = dmb.cpu_a 198 dmb_desc->cpu_addr = dmb.cpu_addr; 247 dmb_desc->dma_addr = dmb.dma_a 199 dmb_desc->dma_addr = dmb.dma_addr; 248 dmb_desc->len = dmb.dmb_len; 200 dmb_desc->len = dmb.dmb_len; 249 } 201 } 250 return rc; 202 return rc; 251 } 203 } 252 204 253 bool smc_ism_support_dmb_nocopy(struct smcd_de << 254 { << 255 /* for now only loopback-ism supports << 256 * merging sndbuf with peer DMB to avo << 257 * data copies between them. << 258 */ << 259 return (smcd->ops->support_dmb_nocopy << 260 smcd->ops->support_dmb_nocopy( << 261 } << 262 << 263 int smc_ism_attach_dmb(struct smcd_dev *dev, u << 264 struct smc_buf_desc *dm << 265 { << 266 struct smcd_dmb dmb; << 267 int rc = 0; << 268 << 269 if (!dev->ops->attach_dmb) << 270 return -EINVAL; << 271 << 272 memset(&dmb, 0, sizeof(dmb)); << 273 dmb.dmb_tok = token; << 274 rc = dev->ops->attach_dmb(dev, &dmb); << 275 if (!rc) { << 276 dmb_desc->sba_idx = dmb.sba_id << 277 dmb_desc->token = dmb.dmb_tok; << 278 dmb_desc->cpu_addr = dmb.cpu_a << 279 dmb_desc->dma_addr = dmb.dma_a << 280 dmb_desc->len = dmb.dmb_len; << 281 } << 282 return rc; << 283 } << 284 << 285 int smc_ism_detach_dmb(struct smcd_dev *dev, u << 286 { << 287 if (!dev->ops->detach_dmb) << 288 return -EINVAL; << 289 << 290 return dev->ops->detach_dmb(dev, token << 291 } << 292 << 293 static int smc_nl_handle_smcd_dev(struct smcd_ 205 static int smc_nl_handle_smcd_dev(struct smcd_dev *smcd, 294 struct sk_bu 206 struct sk_buff *skb, 295 struct netli 207 struct netlink_callback *cb) 296 { 208 { 297 char smc_pnet[SMC_MAX_PNETID_LEN + 1]; 209 char smc_pnet[SMC_MAX_PNETID_LEN + 1]; 298 struct smc_pci_dev smc_pci_dev; 210 struct smc_pci_dev smc_pci_dev; 299 struct nlattr *port_attrs; 211 struct nlattr *port_attrs; 300 struct nlattr *attrs; 212 struct nlattr *attrs; 301 struct ism_dev *ism; << 302 int use_cnt = 0; 213 int use_cnt = 0; 303 void *nlh; 214 void *nlh; 304 215 305 ism = smcd->priv; << 306 nlh = genlmsg_put(skb, NETLINK_CB(cb-> 216 nlh = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, 307 &smc_gen_nl_family, 217 &smc_gen_nl_family, NLM_F_MULTI, 308 SMC_NETLINK_GET_DEV_ 218 SMC_NETLINK_GET_DEV_SMCD); 309 if (!nlh) 219 if (!nlh) 310 goto errmsg; 220 goto errmsg; 311 attrs = nla_nest_start(skb, SMC_GEN_DE 221 attrs = nla_nest_start(skb, SMC_GEN_DEV_SMCD); 312 if (!attrs) 222 if (!attrs) 313 goto errout; 223 goto errout; 314 use_cnt = atomic_read(&smcd->lgr_cnt); 224 use_cnt = atomic_read(&smcd->lgr_cnt); 315 if (nla_put_u32(skb, SMC_NLA_DEV_USE_C 225 if (nla_put_u32(skb, SMC_NLA_DEV_USE_CNT, use_cnt)) 316 goto errattr; 226 goto errattr; 317 if (nla_put_u8(skb, SMC_NLA_DEV_IS_CRI 227 if (nla_put_u8(skb, SMC_NLA_DEV_IS_CRIT, use_cnt > 0)) 318 goto errattr; 228 goto errattr; 319 memset(&smc_pci_dev, 0, sizeof(smc_pci 229 memset(&smc_pci_dev, 0, sizeof(smc_pci_dev)); 320 smc_set_pci_values(to_pci_dev(ism->dev !! 230 smc_set_pci_values(to_pci_dev(smcd->dev.parent), &smc_pci_dev); 321 if (nla_put_u32(skb, SMC_NLA_DEV_PCI_F 231 if (nla_put_u32(skb, SMC_NLA_DEV_PCI_FID, smc_pci_dev.pci_fid)) 322 goto errattr; 232 goto errattr; 323 if (nla_put_u16(skb, SMC_NLA_DEV_PCI_C 233 if (nla_put_u16(skb, SMC_NLA_DEV_PCI_CHID, smc_pci_dev.pci_pchid)) 324 goto errattr; 234 goto errattr; 325 if (nla_put_u16(skb, SMC_NLA_DEV_PCI_V 235 if (nla_put_u16(skb, SMC_NLA_DEV_PCI_VENDOR, smc_pci_dev.pci_vendor)) 326 goto errattr; 236 goto errattr; 327 if (nla_put_u16(skb, SMC_NLA_DEV_PCI_D 237 if (nla_put_u16(skb, SMC_NLA_DEV_PCI_DEVICE, smc_pci_dev.pci_device)) 328 goto errattr; 238 goto errattr; 329 if (nla_put_string(skb, SMC_NLA_DEV_PC 239 if (nla_put_string(skb, SMC_NLA_DEV_PCI_ID, smc_pci_dev.pci_id)) 330 goto errattr; 240 goto errattr; 331 241 332 port_attrs = nla_nest_start(skb, SMC_N 242 port_attrs = nla_nest_start(skb, SMC_NLA_DEV_PORT); 333 if (!port_attrs) 243 if (!port_attrs) 334 goto errattr; 244 goto errattr; 335 if (nla_put_u8(skb, SMC_NLA_DEV_PORT_P 245 if (nla_put_u8(skb, SMC_NLA_DEV_PORT_PNET_USR, smcd->pnetid_by_user)) 336 goto errportattr; 246 goto errportattr; 337 memcpy(smc_pnet, smcd->pnetid, SMC_MAX 247 memcpy(smc_pnet, smcd->pnetid, SMC_MAX_PNETID_LEN); 338 smc_pnet[SMC_MAX_PNETID_LEN] = 0; 248 smc_pnet[SMC_MAX_PNETID_LEN] = 0; 339 if (nla_put_string(skb, SMC_NLA_DEV_PO 249 if (nla_put_string(skb, SMC_NLA_DEV_PORT_PNETID, smc_pnet)) 340 goto errportattr; 250 goto errportattr; 341 251 342 nla_nest_end(skb, port_attrs); 252 nla_nest_end(skb, port_attrs); 343 nla_nest_end(skb, attrs); 253 nla_nest_end(skb, attrs); 344 genlmsg_end(skb, nlh); 254 genlmsg_end(skb, nlh); 345 return 0; 255 return 0; 346 256 347 errportattr: 257 errportattr: 348 nla_nest_cancel(skb, port_attrs); 258 nla_nest_cancel(skb, port_attrs); 349 errattr: 259 errattr: 350 nla_nest_cancel(skb, attrs); 260 nla_nest_cancel(skb, attrs); 351 errout: 261 errout: 352 nlmsg_cancel(skb, nlh); 262 nlmsg_cancel(skb, nlh); 353 errmsg: 263 errmsg: 354 return -EMSGSIZE; 264 return -EMSGSIZE; 355 } 265 } 356 266 357 static void smc_nl_prep_smcd_dev(struct smcd_d 267 static void smc_nl_prep_smcd_dev(struct smcd_dev_list *dev_list, 358 struct sk_buf 268 struct sk_buff *skb, 359 struct netlin 269 struct netlink_callback *cb) 360 { 270 { 361 struct smc_nl_dmp_ctx *cb_ctx = smc_nl 271 struct smc_nl_dmp_ctx *cb_ctx = smc_nl_dmp_ctx(cb); 362 int snum = cb_ctx->pos[0]; 272 int snum = cb_ctx->pos[0]; 363 struct smcd_dev *smcd; 273 struct smcd_dev *smcd; 364 int num = 0; 274 int num = 0; 365 275 366 mutex_lock(&dev_list->mutex); 276 mutex_lock(&dev_list->mutex); 367 list_for_each_entry(smcd, &dev_list->l 277 list_for_each_entry(smcd, &dev_list->list, list) { 368 if (num < snum) 278 if (num < snum) 369 goto next; 279 goto next; 370 if (smc_ism_is_loopback(smcd)) << 371 goto next; << 372 if (smc_nl_handle_smcd_dev(smc 280 if (smc_nl_handle_smcd_dev(smcd, skb, cb)) 373 goto errout; 281 goto errout; 374 next: 282 next: 375 num++; 283 num++; 376 } 284 } 377 errout: 285 errout: 378 mutex_unlock(&dev_list->mutex); 286 mutex_unlock(&dev_list->mutex); 379 cb_ctx->pos[0] = num; 287 cb_ctx->pos[0] = num; 380 } 288 } 381 289 382 int smcd_nl_get_device(struct sk_buff *skb, st 290 int smcd_nl_get_device(struct sk_buff *skb, struct netlink_callback *cb) 383 { 291 { 384 smc_nl_prep_smcd_dev(&smcd_dev_list, s 292 smc_nl_prep_smcd_dev(&smcd_dev_list, skb, cb); 385 return skb->len; 293 return skb->len; 386 } 294 } 387 295 388 #if IS_ENABLED(CONFIG_ISM) << 389 struct smc_ism_event_work { 296 struct smc_ism_event_work { 390 struct work_struct work; 297 struct work_struct work; 391 struct smcd_dev *smcd; 298 struct smcd_dev *smcd; 392 struct ism_event event; !! 299 struct smcd_event event; 393 }; 300 }; 394 301 395 #define ISM_EVENT_REQUEST 0x0001 302 #define ISM_EVENT_REQUEST 0x0001 396 #define ISM_EVENT_RESPONSE 0x0002 303 #define ISM_EVENT_RESPONSE 0x0002 397 #define ISM_EVENT_REQUEST_IR 0x0000 304 #define ISM_EVENT_REQUEST_IR 0x00000001 398 #define ISM_EVENT_CODE_SHUTDOWN 0x80 305 #define ISM_EVENT_CODE_SHUTDOWN 0x80 399 #define ISM_EVENT_CODE_TESTLINK 0x83 306 #define ISM_EVENT_CODE_TESTLINK 0x83 400 307 401 union smcd_sw_event_info { 308 union smcd_sw_event_info { 402 u64 info; 309 u64 info; 403 struct { 310 struct { 404 u8 uid[SMC_LGR_ID 311 u8 uid[SMC_LGR_ID_SIZE]; 405 unsigned short vlan_id; 312 unsigned short vlan_id; 406 u16 code; 313 u16 code; 407 }; 314 }; 408 }; 315 }; 409 316 410 static void smcd_handle_sw_event(struct smc_is 317 static void smcd_handle_sw_event(struct smc_ism_event_work *wrk) 411 { 318 { 412 struct smcd_gid peer_gid = { .gid = wr << 413 .gid_ext << 414 union smcd_sw_event_info ev_info; 319 union smcd_sw_event_info ev_info; 415 320 416 ev_info.info = wrk->event.info; 321 ev_info.info = wrk->event.info; 417 switch (wrk->event.code) { 322 switch (wrk->event.code) { 418 case ISM_EVENT_CODE_SHUTDOWN: /* Pee 323 case ISM_EVENT_CODE_SHUTDOWN: /* Peer shut down DMBs */ 419 smc_smcd_terminate(wrk->smcd, !! 324 smc_smcd_terminate(wrk->smcd, wrk->event.tok, ev_info.vlan_id); 420 break; 325 break; 421 case ISM_EVENT_CODE_TESTLINK: /* Act 326 case ISM_EVENT_CODE_TESTLINK: /* Activity timer */ 422 if (ev_info.code == ISM_EVENT_ !! 327 if (ev_info.code == ISM_EVENT_REQUEST) { 423 wrk->smcd->ops->signal_eve << 424 ev_info.code = ISM_EVE 328 ev_info.code = ISM_EVENT_RESPONSE; 425 wrk->smcd->ops->signal 329 wrk->smcd->ops->signal_event(wrk->smcd, 426 !! 330 wrk->event.tok, 427 331 ISM_EVENT_REQUEST_IR, 428 332 ISM_EVENT_CODE_TESTLINK, 429 333 ev_info.info); 430 } 334 } 431 break; 335 break; 432 } 336 } 433 } 337 } 434 338 >> 339 int smc_ism_signal_shutdown(struct smc_link_group *lgr) >> 340 { >> 341 int rc; >> 342 union smcd_sw_event_info ev_info; >> 343 >> 344 if (lgr->peer_shutdown) >> 345 return 0; >> 346 >> 347 memcpy(ev_info.uid, lgr->id, SMC_LGR_ID_SIZE); >> 348 ev_info.vlan_id = lgr->vlan_id; >> 349 ev_info.code = ISM_EVENT_REQUEST; >> 350 rc = lgr->smcd->ops->signal_event(lgr->smcd, lgr->peer_gid, >> 351 ISM_EVENT_REQUEST_IR, >> 352 ISM_EVENT_CODE_SHUTDOWN, >> 353 ev_info.info); >> 354 return rc; >> 355 } >> 356 435 /* worker for SMC-D events */ 357 /* worker for SMC-D events */ 436 static void smc_ism_event_work(struct work_str 358 static void smc_ism_event_work(struct work_struct *work) 437 { 359 { 438 struct smc_ism_event_work *wrk = 360 struct smc_ism_event_work *wrk = 439 container_of(work, struct smc_ 361 container_of(work, struct smc_ism_event_work, work); 440 struct smcd_gid smcd_gid = { .gid = wr << 441 .gid_ext << 442 362 443 switch (wrk->event.type) { 363 switch (wrk->event.type) { 444 case ISM_EVENT_GID: /* GID event, 364 case ISM_EVENT_GID: /* GID event, token is peer GID */ 445 smc_smcd_terminate(wrk->smcd, !! 365 smc_smcd_terminate(wrk->smcd, wrk->event.tok, VLAN_VID_MASK); 446 break; 366 break; 447 case ISM_EVENT_DMB: 367 case ISM_EVENT_DMB: 448 break; 368 break; 449 case ISM_EVENT_SWR: /* Software de 369 case ISM_EVENT_SWR: /* Software defined event */ 450 smcd_handle_sw_event(wrk); 370 smcd_handle_sw_event(wrk); 451 break; 371 break; 452 } 372 } 453 kfree(wrk); 373 kfree(wrk); 454 } 374 } 455 375 456 static struct smcd_dev *smcd_alloc_dev(struct !! 376 static void smcd_release(struct device *dev) 457 const s !! 377 { >> 378 struct smcd_dev *smcd = container_of(dev, struct smcd_dev, dev); >> 379 >> 380 kfree(smcd->conn); >> 381 kfree(smcd); >> 382 } >> 383 >> 384 struct smcd_dev *smcd_alloc_dev(struct device *parent, const char *name, >> 385 const struct smcd_ops *ops, int max_dmbs) 458 { 386 { 459 struct smcd_dev *smcd; 387 struct smcd_dev *smcd; 460 388 461 smcd = devm_kzalloc(parent, sizeof(*sm !! 389 smcd = kzalloc(sizeof(*smcd), GFP_KERNEL); 462 if (!smcd) 390 if (!smcd) 463 return NULL; 391 return NULL; 464 smcd->conn = devm_kcalloc(parent, max_ !! 392 smcd->conn = kcalloc(max_dmbs, sizeof(struct smc_connection *), 465 sizeof(struc !! 393 GFP_KERNEL); 466 if (!smcd->conn) !! 394 if (!smcd->conn) { >> 395 kfree(smcd); 467 return NULL; 396 return NULL; >> 397 } 468 398 469 smcd->event_wq = alloc_ordered_workque 399 smcd->event_wq = alloc_ordered_workqueue("ism_evt_wq-%s)", 470 400 WQ_MEM_RECLAIM, name); 471 if (!smcd->event_wq) !! 401 if (!smcd->event_wq) { >> 402 kfree(smcd->conn); >> 403 kfree(smcd); 472 return NULL; 404 return NULL; >> 405 } 473 406 >> 407 smcd->dev.parent = parent; >> 408 smcd->dev.release = smcd_release; >> 409 device_initialize(&smcd->dev); >> 410 dev_set_name(&smcd->dev, name); 474 smcd->ops = ops; 411 smcd->ops = ops; >> 412 if (smc_pnetid_by_dev_port(parent, 0, smcd->pnetid)) >> 413 smc_pnetid_by_table_smcd(smcd); 475 414 476 spin_lock_init(&smcd->lock); 415 spin_lock_init(&smcd->lock); 477 spin_lock_init(&smcd->lgr_lock); 416 spin_lock_init(&smcd->lgr_lock); 478 INIT_LIST_HEAD(&smcd->vlan); 417 INIT_LIST_HEAD(&smcd->vlan); 479 INIT_LIST_HEAD(&smcd->lgr_list); 418 INIT_LIST_HEAD(&smcd->lgr_list); 480 init_waitqueue_head(&smcd->lgrs_delete 419 init_waitqueue_head(&smcd->lgrs_deleted); 481 return smcd; 420 return smcd; 482 } 421 } >> 422 EXPORT_SYMBOL_GPL(smcd_alloc_dev); 483 423 484 static void smcd_register_dev(struct ism_dev * !! 424 int smcd_register_dev(struct smcd_dev *smcd) 485 { 425 { 486 const struct smcd_ops *ops = ism_get_s !! 426 int rc; 487 struct smcd_dev *smcd, *fentry; << 488 << 489 if (!ops) << 490 return; << 491 << 492 smcd = smcd_alloc_dev(&ism->pdev->dev, << 493 ISM_NR_DMBS); << 494 if (!smcd) << 495 return; << 496 smcd->priv = ism; << 497 smcd->client = &smc_ism_client; << 498 ism_set_priv(ism, &smc_ism_client, smc << 499 if (smc_pnetid_by_dev_port(&ism->pdev- << 500 smc_pnetid_by_table_smcd(smcd) << 501 427 502 if (smcd->ops->supports_v2()) << 503 smc_ism_set_v2_capable(); << 504 mutex_lock(&smcd_dev_list.mutex); 428 mutex_lock(&smcd_dev_list.mutex); 505 /* sort list: !! 429 if (list_empty(&smcd_dev_list.list)) { 506 * - devices without pnetid before dev !! 430 u8 *system_eid = NULL; 507 * - loopback-ism always at the very b !! 431 508 */ !! 432 system_eid = smcd->ops->get_system_eid(); 509 if (!smcd->pnetid[0]) { !! 433 if (system_eid[24] != '' || system_eid[28] != '') { 510 fentry = list_first_entry_or_n !! 434 smc_ism_v2_capable = true; 511 !! 435 memcpy(smc_ism_v2_system_eid, system_eid, 512 if (fentry && smc_ism_is_loopb !! 436 SMC_MAX_EID_LEN); 513 list_add(&smcd->list, !! 437 } 514 else << 515 list_add(&smcd->list, << 516 } else { << 517 list_add_tail(&smcd->list, &sm << 518 } 438 } >> 439 /* sort list: devices without pnetid before devices with pnetid */ >> 440 if (smcd->pnetid[0]) >> 441 list_add_tail(&smcd->list, &smcd_dev_list.list); >> 442 else >> 443 list_add(&smcd->list, &smcd_dev_list.list); 519 mutex_unlock(&smcd_dev_list.mutex); 444 mutex_unlock(&smcd_dev_list.mutex); 520 445 521 pr_warn_ratelimited("smc: adding smcd 446 pr_warn_ratelimited("smc: adding smcd device %s with pnetid %.16s%s\n", 522 dev_name(&ism->dev !! 447 dev_name(&smcd->dev), smcd->pnetid, 523 smcd->pnetid_by_us 448 smcd->pnetid_by_user ? " (user defined)" : ""); 524 449 525 return; !! 450 rc = device_add(&smcd->dev); >> 451 if (rc) { >> 452 mutex_lock(&smcd_dev_list.mutex); >> 453 list_del(&smcd->list); >> 454 mutex_unlock(&smcd_dev_list.mutex); >> 455 } >> 456 >> 457 return rc; 526 } 458 } >> 459 EXPORT_SYMBOL_GPL(smcd_register_dev); 527 460 528 static void smcd_unregister_dev(struct ism_dev !! 461 void smcd_unregister_dev(struct smcd_dev *smcd) 529 { 462 { 530 struct smcd_dev *smcd = ism_get_priv(i << 531 << 532 pr_warn_ratelimited("smc: removing smc 463 pr_warn_ratelimited("smc: removing smcd device %s\n", 533 dev_name(&ism->dev !! 464 dev_name(&smcd->dev)); 534 smcd->going_away = 1; << 535 smc_smcd_terminate_all(smcd); << 536 mutex_lock(&smcd_dev_list.mutex); 465 mutex_lock(&smcd_dev_list.mutex); 537 list_del_init(&smcd->list); 466 list_del_init(&smcd->list); 538 mutex_unlock(&smcd_dev_list.mutex); 467 mutex_unlock(&smcd_dev_list.mutex); >> 468 smcd->going_away = 1; >> 469 smc_smcd_terminate_all(smcd); 539 destroy_workqueue(smcd->event_wq); 470 destroy_workqueue(smcd->event_wq); >> 471 >> 472 device_del(&smcd->dev); >> 473 } >> 474 EXPORT_SYMBOL_GPL(smcd_unregister_dev); >> 475 >> 476 void smcd_free_dev(struct smcd_dev *smcd) >> 477 { >> 478 put_device(&smcd->dev); 540 } 479 } >> 480 EXPORT_SYMBOL_GPL(smcd_free_dev); 541 481 542 /* SMCD Device event handler. Called from ISM 482 /* SMCD Device event handler. Called from ISM device interrupt handler. 543 * Parameters are ism device pointer, !! 483 * Parameters are smcd device pointer, 544 * - event->type (0 --> DMB, 1 --> GID), 484 * - event->type (0 --> DMB, 1 --> GID), 545 * - event->code (event code), 485 * - event->code (event code), 546 * - event->tok (either DMB token when event t 486 * - event->tok (either DMB token when event type 0, or GID when event type 1) 547 * - event->time (time of day) 487 * - event->time (time of day) 548 * - event->info (debug info). 488 * - event->info (debug info). 549 * 489 * 550 * Context: 490 * Context: 551 * - Function called in IRQ context from ISM d 491 * - Function called in IRQ context from ISM device driver event handler. 552 */ 492 */ 553 static void smcd_handle_event(struct ism_dev * !! 493 void smcd_handle_event(struct smcd_dev *smcd, struct smcd_event *event) 554 { 494 { 555 struct smcd_dev *smcd = ism_get_priv(i << 556 struct smc_ism_event_work *wrk; 495 struct smc_ism_event_work *wrk; 557 496 558 if (smcd->going_away) 497 if (smcd->going_away) 559 return; 498 return; 560 /* copy event to event work queue, and 499 /* copy event to event work queue, and let it be handled there */ 561 wrk = kmalloc(sizeof(*wrk), GFP_ATOMIC 500 wrk = kmalloc(sizeof(*wrk), GFP_ATOMIC); 562 if (!wrk) 501 if (!wrk) 563 return; 502 return; 564 INIT_WORK(&wrk->work, smc_ism_event_wo 503 INIT_WORK(&wrk->work, smc_ism_event_work); 565 wrk->smcd = smcd; 504 wrk->smcd = smcd; 566 wrk->event = *event; 505 wrk->event = *event; 567 queue_work(smcd->event_wq, &wrk->work) 506 queue_work(smcd->event_wq, &wrk->work); 568 } 507 } >> 508 EXPORT_SYMBOL_GPL(smcd_handle_event); 569 509 570 /* SMCD Device interrupt handler. Called from 510 /* SMCD Device interrupt handler. Called from ISM device interrupt handler. 571 * Parameters are the ism device pointer, DMB !! 511 * Parameters are smcd device pointer, DMB number, and the DMBE bitmask. 572 * Find the connection and schedule the taskle 512 * Find the connection and schedule the tasklet for this connection. 573 * 513 * 574 * Context: 514 * Context: 575 * - Function called in IRQ context from ISM d 515 * - Function called in IRQ context from ISM device driver IRQ handler. 576 */ 516 */ 577 static void smcd_handle_irq(struct ism_dev *is !! 517 void smcd_handle_irq(struct smcd_dev *smcd, unsigned int dmbno, u16 dmbemask) 578 u16 dmbemask) << 579 { 518 { 580 struct smcd_dev *smcd = ism_get_priv(i << 581 struct smc_connection *conn = NULL; 519 struct smc_connection *conn = NULL; 582 unsigned long flags; 520 unsigned long flags; 583 521 584 spin_lock_irqsave(&smcd->lock, flags); 522 spin_lock_irqsave(&smcd->lock, flags); 585 conn = smcd->conn[dmbno]; 523 conn = smcd->conn[dmbno]; 586 if (conn && !conn->killed) 524 if (conn && !conn->killed) 587 tasklet_schedule(&conn->rx_tsk 525 tasklet_schedule(&conn->rx_tsklet); 588 spin_unlock_irqrestore(&smcd->lock, fl 526 spin_unlock_irqrestore(&smcd->lock, flags); 589 } 527 } 590 #endif !! 528 EXPORT_SYMBOL_GPL(smcd_handle_irq); 591 529 592 int smc_ism_signal_shutdown(struct smc_link_gr !! 530 void __init smc_ism_init(void) 593 { 531 { 594 int rc = 0; << 595 #if IS_ENABLED(CONFIG_ISM) << 596 union smcd_sw_event_info ev_info; << 597 << 598 if (lgr->peer_shutdown) << 599 return 0; << 600 if (!lgr->smcd->ops->signal_event) << 601 return 0; << 602 << 603 memcpy(ev_info.uid, lgr->id, SMC_LGR_I << 604 ev_info.vlan_id = lgr->vlan_id; << 605 ev_info.code = ISM_EVENT_REQUEST; << 606 rc = lgr->smcd->ops->signal_event(lgr- << 607 ISM_ << 608 ISM_ << 609 ev_i << 610 #endif << 611 return rc; << 612 } << 613 << 614 int smc_ism_init(void) << 615 { << 616 int rc = 0; << 617 << 618 smc_ism_v2_capable = false; 532 smc_ism_v2_capable = false; 619 smc_ism_create_system_eid(); !! 533 memset(smc_ism_v2_system_eid, 0, SMC_MAX_EID_LEN); 620 << 621 #if IS_ENABLED(CONFIG_ISM) << 622 rc = ism_register_client(&smc_ism_clie << 623 #endif << 624 return rc; << 625 } << 626 << 627 void smc_ism_exit(void) << 628 { << 629 #if IS_ENABLED(CONFIG_ISM) << 630 ism_unregister_client(&smc_ism_client) << 631 #endif << 632 } 534 } 633 535
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.