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
)
150 memset(&dmb
, 0, sizeof(dmb
));
151 dmb
.dmb_tok
= dmb_desc
->token
;
152 dmb
.sba_idx
= dmb_desc
->sba_idx
;
153 dmb
.cpu_addr
= dmb_desc
->cpu_addr
;
154 dmb
.dma_addr
= dmb_desc
->dma_addr
;
155 dmb
.dmb_len
= dmb_desc
->len
;
156 return smcd
->ops
->unregister_dmb(smcd
, &dmb
);
159 int smc_ism_register_dmb(struct smc_link_group
*lgr
, int dmb_len
,
160 struct smc_buf_desc
*dmb_desc
)
165 memset(&dmb
, 0, sizeof(dmb
));
166 dmb
.dmb_len
= dmb_len
;
167 dmb
.sba_idx
= dmb_desc
->sba_idx
;
168 dmb
.vlan_id
= lgr
->vlan_id
;
169 dmb
.rgid
= lgr
->peer_gid
;
170 rc
= lgr
->smcd
->ops
->register_dmb(lgr
->smcd
, &dmb
);
172 dmb_desc
->sba_idx
= dmb
.sba_idx
;
173 dmb_desc
->token
= dmb
.dmb_tok
;
174 dmb_desc
->cpu_addr
= dmb
.cpu_addr
;
175 dmb_desc
->dma_addr
= dmb
.dma_addr
;
176 dmb_desc
->len
= dmb
.dmb_len
;
181 struct smc_ism_event_work
{
182 struct work_struct work
;
183 struct smcd_dev
*smcd
;
184 struct smcd_event event
;
187 #define ISM_EVENT_REQUEST 0x0001
188 #define ISM_EVENT_RESPONSE 0x0002
189 #define ISM_EVENT_REQUEST_IR 0x00000001
190 #define ISM_EVENT_CODE_TESTLINK 0x83
192 static void smcd_handle_sw_event(struct smc_ism_event_work
*wrk
)
198 unsigned short vlanid
;
203 switch (wrk
->event
.code
) {
204 case ISM_EVENT_CODE_TESTLINK
: /* Activity timer */
205 ev_info
.info
= wrk
->event
.info
;
206 if (ev_info
.code
== ISM_EVENT_REQUEST
) {
207 ev_info
.code
= ISM_EVENT_RESPONSE
;
208 wrk
->smcd
->ops
->signal_event(wrk
->smcd
,
210 ISM_EVENT_REQUEST_IR
,
211 ISM_EVENT_CODE_TESTLINK
,
218 /* worker for SMC-D events */
219 static void smc_ism_event_work(struct work_struct
*work
)
221 struct smc_ism_event_work
*wrk
=
222 container_of(work
, struct smc_ism_event_work
, work
);
224 switch (wrk
->event
.type
) {
225 case ISM_EVENT_GID
: /* GID event, token is peer GID */
226 smc_smcd_terminate(wrk
->smcd
, wrk
->event
.tok
);
230 case ISM_EVENT_SWR
: /* Software defined event */
231 smcd_handle_sw_event(wrk
);
237 static void smcd_release(struct device
*dev
)
239 struct smcd_dev
*smcd
= container_of(dev
, struct smcd_dev
, dev
);
245 struct smcd_dev
*smcd_alloc_dev(struct device
*parent
, const char *name
,
246 const struct smcd_ops
*ops
, int max_dmbs
)
248 struct smcd_dev
*smcd
;
250 smcd
= kzalloc(sizeof(*smcd
), GFP_KERNEL
);
253 smcd
->conn
= kcalloc(max_dmbs
, sizeof(struct smc_connection
*),
260 smcd
->dev
.parent
= parent
;
261 smcd
->dev
.release
= smcd_release
;
262 device_initialize(&smcd
->dev
);
263 dev_set_name(&smcd
->dev
, name
);
265 smc_pnetid_by_dev_port(parent
, 0, smcd
->pnetid
);
267 spin_lock_init(&smcd
->lock
);
268 INIT_LIST_HEAD(&smcd
->vlan
);
269 smcd
->event_wq
= alloc_ordered_workqueue("ism_evt_wq-%s)",
270 WQ_MEM_RECLAIM
, name
);
273 EXPORT_SYMBOL_GPL(smcd_alloc_dev
);
275 int smcd_register_dev(struct smcd_dev
*smcd
)
277 spin_lock(&smcd_dev_list
.lock
);
278 list_add_tail(&smcd
->list
, &smcd_dev_list
.list
);
279 spin_unlock(&smcd_dev_list
.lock
);
281 return device_add(&smcd
->dev
);
283 EXPORT_SYMBOL_GPL(smcd_register_dev
);
285 void smcd_unregister_dev(struct smcd_dev
*smcd
)
287 spin_lock(&smcd_dev_list
.lock
);
288 list_del(&smcd
->list
);
289 spin_unlock(&smcd_dev_list
.lock
);
290 flush_workqueue(smcd
->event_wq
);
291 destroy_workqueue(smcd
->event_wq
);
292 smc_smcd_terminate(smcd
, 0);
294 device_del(&smcd
->dev
);
296 EXPORT_SYMBOL_GPL(smcd_unregister_dev
);
298 void smcd_free_dev(struct smcd_dev
*smcd
)
300 put_device(&smcd
->dev
);
302 EXPORT_SYMBOL_GPL(smcd_free_dev
);
304 /* SMCD Device event handler. Called from ISM device interrupt handler.
305 * Parameters are smcd device pointer,
306 * - event->type (0 --> DMB, 1 --> GID),
307 * - event->code (event code),
308 * - event->tok (either DMB token when event type 0, or GID when event type 1)
309 * - event->time (time of day)
310 * - event->info (debug info).
313 * - Function called in IRQ context from ISM device driver event handler.
315 void smcd_handle_event(struct smcd_dev
*smcd
, struct smcd_event
*event
)
317 struct smc_ism_event_work
*wrk
;
319 /* copy event to event work queue, and let it be handled there */
320 wrk
= kmalloc(sizeof(*wrk
), GFP_ATOMIC
);
323 INIT_WORK(&wrk
->work
, smc_ism_event_work
);
326 queue_work(smcd
->event_wq
, &wrk
->work
);
328 EXPORT_SYMBOL_GPL(smcd_handle_event
);
330 /* SMCD Device interrupt handler. Called from ISM device interrupt handler.
331 * Parameters are smcd device pointer and DMB number. Find the connection and
332 * schedule the tasklet for this connection.
335 * - Function called in IRQ context from ISM device driver IRQ handler.
337 void smcd_handle_irq(struct smcd_dev
*smcd
, unsigned int dmbno
)
339 struct smc_connection
*conn
= NULL
;
342 spin_lock_irqsave(&smcd
->lock
, flags
);
343 conn
= smcd
->conn
[dmbno
];
345 tasklet_schedule(&conn
->rx_tsklet
);
346 spin_unlock_irqrestore(&smcd
->lock
, flags
);
348 EXPORT_SYMBOL_GPL(smcd_handle_irq
);