1 // SPDX-License-Identifier: GPL-2.0
2 /* Shared Memory Communications Direct over ISM devices (SMC-D)
4 * Functions for ISM device.
6 * Copyright IBM Corp. 2018
9 #include <linux/spinlock.h>
10 #include <linux/slab.h>
18 struct smcd_dev_list smcd_dev_list
= {
19 .list
= LIST_HEAD_INIT(smcd_dev_list
.list
),
20 .lock
= __SPIN_LOCK_UNLOCKED(smcd_dev_list
.lock
)
23 /* Test if an ISM communication is possible. */
24 int smc_ism_cantalk(u64 peer_gid
, unsigned short vlan_id
, struct smcd_dev
*smcd
)
26 return smcd
->ops
->query_remote_gid(smcd
, peer_gid
, vlan_id
? 1 : 0,
30 int smc_ism_write(struct smcd_dev
*smcd
, const struct smc_ism_position
*pos
,
31 void *data
, size_t len
)
35 rc
= smcd
->ops
->move_data(smcd
, pos
->token
, pos
->index
, pos
->signal
,
36 pos
->offset
, data
, len
);
38 return rc
< 0 ? rc
: 0;
41 /* Set a connection using this DMBE. */
42 void smc_ism_set_conn(struct smc_connection
*conn
)
46 spin_lock_irqsave(&conn
->lgr
->smcd
->lock
, flags
);
47 conn
->lgr
->smcd
->conn
[conn
->rmb_desc
->sba_idx
] = conn
;
48 spin_unlock_irqrestore(&conn
->lgr
->smcd
->lock
, flags
);
51 /* Unset a connection using this DMBE. */
52 void smc_ism_unset_conn(struct smc_connection
*conn
)
59 spin_lock_irqsave(&conn
->lgr
->smcd
->lock
, flags
);
60 conn
->lgr
->smcd
->conn
[conn
->rmb_desc
->sba_idx
] = NULL
;
61 spin_unlock_irqrestore(&conn
->lgr
->smcd
->lock
, flags
);
64 /* Register a VLAN identifier with the ISM device. Use a reference count
65 * and add a VLAN identifier only when the first DMB using this VLAN is
68 int smc_ism_get_vlan(struct smcd_dev
*smcd
, unsigned short vlanid
)
70 struct smc_ism_vlanid
*new_vlan
, *vlan
;
74 if (!vlanid
) /* No valid vlan id */
77 /* create new vlan entry, in case we need it */
78 new_vlan
= kzalloc(sizeof(*new_vlan
), GFP_KERNEL
);
81 new_vlan
->vlanid
= vlanid
;
82 refcount_set(&new_vlan
->refcnt
, 1);
84 /* if there is an existing entry, increase count and return */
85 spin_lock_irqsave(&smcd
->lock
, flags
);
86 list_for_each_entry(vlan
, &smcd
->vlan
, list
) {
87 if (vlan
->vlanid
== vlanid
) {
88 refcount_inc(&vlan
->refcnt
);
94 /* no existing entry found.
95 * add new entry to device; might fail, e.g., if HW limit reached
97 if (smcd
->ops
->add_vlan_id(smcd
, vlanid
)) {
102 list_add_tail(&new_vlan
->list
, &smcd
->vlan
);
104 spin_unlock_irqrestore(&smcd
->lock
, flags
);
108 /* Unregister a VLAN identifier with the ISM device. Use a reference count
109 * and remove a VLAN identifier only when the last DMB using this VLAN is
112 int smc_ism_put_vlan(struct smcd_dev
*smcd
, unsigned short vlanid
)
114 struct smc_ism_vlanid
*vlan
;
119 if (!vlanid
) /* No valid vlan id */
122 spin_lock_irqsave(&smcd
->lock
, flags
);
123 list_for_each_entry(vlan
, &smcd
->vlan
, list
) {
124 if (vlan
->vlanid
== vlanid
) {
125 if (!refcount_dec_and_test(&vlan
->refcnt
))
133 goto out
; /* VLAN id not in table */
136 /* Found and the last reference just gone */
137 if (smcd
->ops
->del_vlan_id(smcd
, vlanid
))
139 list_del(&vlan
->list
);
142 spin_unlock_irqrestore(&smcd
->lock
, flags
);
146 int smc_ism_unregister_dmb(struct smcd_dev
*smcd
, struct smc_buf_desc
*dmb_desc
)
151 if (!dmb_desc
->dma_addr
)
154 memset(&dmb
, 0, sizeof(dmb
));
155 dmb
.dmb_tok
= dmb_desc
->token
;
156 dmb
.sba_idx
= dmb_desc
->sba_idx
;
157 dmb
.cpu_addr
= dmb_desc
->cpu_addr
;
158 dmb
.dma_addr
= dmb_desc
->dma_addr
;
159 dmb
.dmb_len
= dmb_desc
->len
;
160 rc
= smcd
->ops
->unregister_dmb(smcd
, &dmb
);
161 if (!rc
|| rc
== ISM_ERROR
) {
162 dmb_desc
->cpu_addr
= NULL
;
163 dmb_desc
->dma_addr
= 0;
169 int smc_ism_register_dmb(struct smc_link_group
*lgr
, int dmb_len
,
170 struct smc_buf_desc
*dmb_desc
)
175 memset(&dmb
, 0, sizeof(dmb
));
176 dmb
.dmb_len
= dmb_len
;
177 dmb
.sba_idx
= dmb_desc
->sba_idx
;
178 dmb
.vlan_id
= lgr
->vlan_id
;
179 dmb
.rgid
= lgr
->peer_gid
;
180 rc
= lgr
->smcd
->ops
->register_dmb(lgr
->smcd
, &dmb
);
182 dmb_desc
->sba_idx
= dmb
.sba_idx
;
183 dmb_desc
->token
= dmb
.dmb_tok
;
184 dmb_desc
->cpu_addr
= dmb
.cpu_addr
;
185 dmb_desc
->dma_addr
= dmb
.dma_addr
;
186 dmb_desc
->len
= dmb
.dmb_len
;
191 struct smc_ism_event_work
{
192 struct work_struct work
;
193 struct smcd_dev
*smcd
;
194 struct smcd_event event
;
197 #define ISM_EVENT_REQUEST 0x0001
198 #define ISM_EVENT_RESPONSE 0x0002
199 #define ISM_EVENT_REQUEST_IR 0x00000001
200 #define ISM_EVENT_CODE_SHUTDOWN 0x80
201 #define ISM_EVENT_CODE_TESTLINK 0x83
203 union smcd_sw_event_info
{
206 u8 uid
[SMC_LGR_ID_SIZE
];
207 unsigned short vlan_id
;
212 static void smcd_handle_sw_event(struct smc_ism_event_work
*wrk
)
214 union smcd_sw_event_info ev_info
;
216 ev_info
.info
= wrk
->event
.info
;
217 switch (wrk
->event
.code
) {
218 case ISM_EVENT_CODE_SHUTDOWN
: /* Peer shut down DMBs */
219 smc_smcd_terminate(wrk
->smcd
, wrk
->event
.tok
, ev_info
.vlan_id
);
221 case ISM_EVENT_CODE_TESTLINK
: /* Activity timer */
222 if (ev_info
.code
== ISM_EVENT_REQUEST
) {
223 ev_info
.code
= ISM_EVENT_RESPONSE
;
224 wrk
->smcd
->ops
->signal_event(wrk
->smcd
,
226 ISM_EVENT_REQUEST_IR
,
227 ISM_EVENT_CODE_TESTLINK
,
234 int smc_ism_signal_shutdown(struct smc_link_group
*lgr
)
237 union smcd_sw_event_info ev_info
;
239 if (lgr
->peer_shutdown
)
242 memcpy(ev_info
.uid
, lgr
->id
, SMC_LGR_ID_SIZE
);
243 ev_info
.vlan_id
= lgr
->vlan_id
;
244 ev_info
.code
= ISM_EVENT_REQUEST
;
245 rc
= lgr
->smcd
->ops
->signal_event(lgr
->smcd
, lgr
->peer_gid
,
246 ISM_EVENT_REQUEST_IR
,
247 ISM_EVENT_CODE_SHUTDOWN
,
252 /* worker for SMC-D events */
253 static void smc_ism_event_work(struct work_struct
*work
)
255 struct smc_ism_event_work
*wrk
=
256 container_of(work
, struct smc_ism_event_work
, work
);
258 switch (wrk
->event
.type
) {
259 case ISM_EVENT_GID
: /* GID event, token is peer GID */
260 smc_smcd_terminate(wrk
->smcd
, wrk
->event
.tok
, VLAN_VID_MASK
);
264 case ISM_EVENT_SWR
: /* Software defined event */
265 smcd_handle_sw_event(wrk
);
271 static void smcd_release(struct device
*dev
)
273 struct smcd_dev
*smcd
= container_of(dev
, struct smcd_dev
, dev
);
279 struct smcd_dev
*smcd_alloc_dev(struct device
*parent
, const char *name
,
280 const struct smcd_ops
*ops
, int max_dmbs
)
282 struct smcd_dev
*smcd
;
284 smcd
= kzalloc(sizeof(*smcd
), GFP_KERNEL
);
287 smcd
->conn
= kcalloc(max_dmbs
, sizeof(struct smc_connection
*),
294 smcd
->dev
.parent
= parent
;
295 smcd
->dev
.release
= smcd_release
;
296 device_initialize(&smcd
->dev
);
297 dev_set_name(&smcd
->dev
, name
);
299 smc_pnetid_by_dev_port(parent
, 0, smcd
->pnetid
);
301 spin_lock_init(&smcd
->lock
);
302 spin_lock_init(&smcd
->lgr_lock
);
303 INIT_LIST_HEAD(&smcd
->vlan
);
304 INIT_LIST_HEAD(&smcd
->lgr_list
);
305 init_waitqueue_head(&smcd
->lgrs_deleted
);
306 smcd
->event_wq
= alloc_ordered_workqueue("ism_evt_wq-%s)",
307 WQ_MEM_RECLAIM
, name
);
308 if (!smcd
->event_wq
) {
315 EXPORT_SYMBOL_GPL(smcd_alloc_dev
);
317 int smcd_register_dev(struct smcd_dev
*smcd
)
319 spin_lock(&smcd_dev_list
.lock
);
320 list_add_tail(&smcd
->list
, &smcd_dev_list
.list
);
321 spin_unlock(&smcd_dev_list
.lock
);
323 return device_add(&smcd
->dev
);
325 EXPORT_SYMBOL_GPL(smcd_register_dev
);
327 void smcd_unregister_dev(struct smcd_dev
*smcd
)
329 spin_lock(&smcd_dev_list
.lock
);
330 list_del_init(&smcd
->list
);
331 spin_unlock(&smcd_dev_list
.lock
);
332 smcd
->going_away
= 1;
333 smc_smcd_terminate_all(smcd
);
334 flush_workqueue(smcd
->event_wq
);
335 destroy_workqueue(smcd
->event_wq
);
337 device_del(&smcd
->dev
);
339 EXPORT_SYMBOL_GPL(smcd_unregister_dev
);
341 void smcd_free_dev(struct smcd_dev
*smcd
)
343 put_device(&smcd
->dev
);
345 EXPORT_SYMBOL_GPL(smcd_free_dev
);
347 /* SMCD Device event handler. Called from ISM device interrupt handler.
348 * Parameters are smcd device pointer,
349 * - event->type (0 --> DMB, 1 --> GID),
350 * - event->code (event code),
351 * - event->tok (either DMB token when event type 0, or GID when event type 1)
352 * - event->time (time of day)
353 * - event->info (debug info).
356 * - Function called in IRQ context from ISM device driver event handler.
358 void smcd_handle_event(struct smcd_dev
*smcd
, struct smcd_event
*event
)
360 struct smc_ism_event_work
*wrk
;
362 if (smcd
->going_away
)
364 /* copy event to event work queue, and let it be handled there */
365 wrk
= kmalloc(sizeof(*wrk
), GFP_ATOMIC
);
368 INIT_WORK(&wrk
->work
, smc_ism_event_work
);
371 queue_work(smcd
->event_wq
, &wrk
->work
);
373 EXPORT_SYMBOL_GPL(smcd_handle_event
);
375 /* SMCD Device interrupt handler. Called from ISM device interrupt handler.
376 * Parameters are smcd device pointer and DMB number. Find the connection and
377 * schedule the tasklet for this connection.
380 * - Function called in IRQ context from ISM device driver IRQ handler.
382 void smcd_handle_irq(struct smcd_dev
*smcd
, unsigned int dmbno
)
384 struct smc_connection
*conn
= NULL
;
387 spin_lock_irqsave(&smcd
->lock
, flags
);
388 conn
= smcd
->conn
[dmbno
];
389 if (conn
&& !conn
->killed
)
390 tasklet_schedule(&conn
->rx_tsklet
);
391 spin_unlock_irqrestore(&smcd
->lock
, flags
);
393 EXPORT_SYMBOL_GPL(smcd_handle_irq
);