Skip to content

Commit 89e7d2b

Browse files
Stefan Raspldavem330
authored andcommitted
net/ism: Add new API for client registration
Add a new API that allows other drivers to concurrently access ISM devices. To do so, we introduce a new API that allows other modules to register for ISM device usage. Furthermore, we move the GID to struct ism, where it belongs conceptually, and rename and relocate struct smcd_event to struct ism_event. This is the first part of a bigger overhaul of the interfaces between SMC and ISM. Signed-off-by: Stefan Raspl <[email protected]> Signed-off-by: Jan Karcher <[email protected]> Signed-off-by: Wenjia Zhang <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 1baedb1 commit 89e7d2b

File tree

5 files changed

+236
-36
lines changed

5 files changed

+236
-36
lines changed

drivers/s390/net/ism.h

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
*/
1717
#define ISM_DMB_WORD_OFFSET 1
1818
#define ISM_DMB_BIT_OFFSET (ISM_DMB_WORD_OFFSET * 32)
19-
#define ISM_NR_DMBS 1920
2019
#define ISM_IDENT_MASK 0x00FFFF
2120

2221
#define ISM_REG_SBA 0x1
@@ -178,7 +177,7 @@ struct ism_eq_header {
178177

179178
struct ism_eq {
180179
struct ism_eq_header header;
181-
struct smcd_event entry[15];
180+
struct ism_event entry[15];
182181
};
183182

184183
struct ism_sba {
@@ -190,21 +189,6 @@ struct ism_sba {
190189
u16 dmbe_mask[ISM_NR_DMBS];
191190
};
192191

193-
struct ism_dev {
194-
spinlock_t lock;
195-
struct pci_dev *pdev;
196-
struct smcd_dev *smcd;
197-
198-
struct ism_sba *sba;
199-
dma_addr_t sba_dma_addr;
200-
DECLARE_BITMAP(sba_bitmap, ISM_NR_DMBS);
201-
202-
struct ism_eq *ieq;
203-
dma_addr_t ieq_dma_addr;
204-
205-
int ieq_idx;
206-
};
207-
208192
#define ISM_CREATE_REQ(dmb, idx, sf, offset) \
209193
((dmb) | (idx) << 24 | (sf) << 23 | (offset))
210194

drivers/s390/net/ism_drv.c

Lines changed: 164 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,6 @@
1515
#include <linux/err.h>
1616
#include <linux/ctype.h>
1717
#include <linux/processor.h>
18-
#include <net/smc.h>
19-
20-
#include <asm/debug.h>
2118

2219
#include "ism.h"
2320

@@ -34,6 +31,84 @@ static const struct pci_device_id ism_device_table[] = {
3431
MODULE_DEVICE_TABLE(pci, ism_device_table);
3532

3633
static debug_info_t *ism_debug_info;
34+
static const struct smcd_ops ism_ops;
35+
36+
#define NO_CLIENT 0xff /* must be >= MAX_CLIENTS */
37+
static struct ism_client *clients[MAX_CLIENTS]; /* use an array rather than */
38+
/* a list for fast mapping */
39+
static u8 max_client;
40+
static DEFINE_SPINLOCK(clients_lock);
41+
struct ism_dev_list {
42+
struct list_head list;
43+
struct mutex mutex; /* protects ism device list */
44+
};
45+
46+
static struct ism_dev_list ism_dev_list = {
47+
.list = LIST_HEAD_INIT(ism_dev_list.list),
48+
.mutex = __MUTEX_INITIALIZER(ism_dev_list.mutex),
49+
};
50+
51+
int ism_register_client(struct ism_client *client)
52+
{
53+
struct ism_dev *ism;
54+
unsigned long flags;
55+
int i, rc = -ENOSPC;
56+
57+
mutex_lock(&ism_dev_list.mutex);
58+
spin_lock_irqsave(&clients_lock, flags);
59+
for (i = 0; i < MAX_CLIENTS; ++i) {
60+
if (!clients[i]) {
61+
clients[i] = client;
62+
client->id = i;
63+
if (i == max_client)
64+
max_client++;
65+
rc = 0;
66+
break;
67+
}
68+
}
69+
spin_unlock_irqrestore(&clients_lock, flags);
70+
if (i < MAX_CLIENTS) {
71+
/* initialize with all devices that we got so far */
72+
list_for_each_entry(ism, &ism_dev_list.list, list) {
73+
ism->priv[i] = NULL;
74+
client->add(ism);
75+
}
76+
}
77+
mutex_unlock(&ism_dev_list.mutex);
78+
79+
return rc;
80+
}
81+
EXPORT_SYMBOL_GPL(ism_register_client);
82+
83+
int ism_unregister_client(struct ism_client *client)
84+
{
85+
struct ism_dev *ism;
86+
unsigned long flags;
87+
int rc = 0;
88+
89+
mutex_lock(&ism_dev_list.mutex);
90+
spin_lock_irqsave(&clients_lock, flags);
91+
clients[client->id] = NULL;
92+
if (client->id + 1 == max_client)
93+
max_client--;
94+
spin_unlock_irqrestore(&clients_lock, flags);
95+
list_for_each_entry(ism, &ism_dev_list.list, list) {
96+
for (int i = 0; i < ISM_NR_DMBS; ++i) {
97+
if (ism->sba_client_arr[i] == client->id) {
98+
pr_err("%s: attempt to unregister client '%s'"
99+
"with registered dmb(s)\n", __func__,
100+
client->name);
101+
rc = -EBUSY;
102+
goto out;
103+
}
104+
}
105+
}
106+
out:
107+
mutex_unlock(&ism_dev_list.mutex);
108+
109+
return rc;
110+
}
111+
EXPORT_SYMBOL_GPL(ism_unregister_client);
37112

38113
static int ism_cmd(struct ism_dev *ism, void *cmd)
39114
{
@@ -193,7 +268,7 @@ static int ism_read_local_gid(struct ism_dev *ism)
193268
if (ret)
194269
goto out;
195270

196-
ism->smcd->local_gid = cmd.response.gid;
271+
ism->local_gid = cmd.response.gid;
197272
out:
198273
return ret;
199274
}
@@ -437,21 +512,27 @@ static u16 ism_get_chid(struct smcd_dev *smcd)
437512

438513
static void ism_handle_event(struct ism_dev *ism)
439514
{
440-
struct smcd_event *entry;
515+
struct ism_event *entry;
516+
int i;
441517

442518
while ((ism->ieq_idx + 1) != READ_ONCE(ism->ieq->header.idx)) {
443519
if (++(ism->ieq_idx) == ARRAY_SIZE(ism->ieq->entry))
444520
ism->ieq_idx = 0;
445521

446522
entry = &ism->ieq->entry[ism->ieq_idx];
447523
debug_event(ism_debug_info, 2, entry, sizeof(*entry));
448-
smcd_handle_event(ism->smcd, entry);
524+
spin_lock(&clients_lock);
525+
for (i = 0; i < max_client; ++i)
526+
if (clients[i])
527+
clients[i]->handle_event(ism, entry);
528+
spin_unlock(&clients_lock);
449529
}
450530
}
451531

452532
static irqreturn_t ism_handle_irq(int irq, void *data)
453533
{
454534
struct ism_dev *ism = data;
535+
struct ism_client *clt;
455536
unsigned long bit, end;
456537
unsigned long *bv;
457538
u16 dmbemask;
@@ -471,7 +552,8 @@ static irqreturn_t ism_handle_irq(int irq, void *data)
471552
dmbemask = ism->sba->dmbe_mask[bit + ISM_DMB_BIT_OFFSET];
472553
ism->sba->dmbe_mask[bit + ISM_DMB_BIT_OFFSET] = 0;
473554
barrier();
474-
smcd_handle_irq(ism->smcd, bit + ISM_DMB_BIT_OFFSET, dmbemask);
555+
clt = clients[ism->sba_client_arr[bit]];
556+
clt->handle_irq(ism, bit + ISM_DMB_BIT_OFFSET, dmbemask);
475557
}
476558

477559
if (ism->sba->e) {
@@ -497,10 +579,21 @@ static const struct smcd_ops ism_ops = {
497579
.get_chid = ism_get_chid,
498580
};
499581

582+
static void ism_dev_add_work_func(struct work_struct *work)
583+
{
584+
struct ism_client *client = container_of(work, struct ism_client,
585+
add_work);
586+
587+
client->add(client->tgt_ism);
588+
atomic_dec(&client->tgt_ism->add_dev_cnt);
589+
wake_up(&client->tgt_ism->waitq);
590+
}
591+
500592
static int ism_dev_init(struct ism_dev *ism)
501593
{
502594
struct pci_dev *pdev = ism->pdev;
503-
int ret;
595+
unsigned long flags;
596+
int i, ret;
504597

505598
ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSI);
506599
if (ret <= 0)
@@ -527,6 +620,28 @@ static int ism_dev_init(struct ism_dev *ism)
527620
/* hardware is V2 capable */
528621
ism_create_system_eid();
529622

623+
init_waitqueue_head(&ism->waitq);
624+
atomic_set(&ism->free_clients_cnt, 0);
625+
atomic_set(&ism->add_dev_cnt, 0);
626+
627+
wait_event(ism->waitq, !atomic_read(&ism->add_dev_cnt));
628+
spin_lock_irqsave(&clients_lock, flags);
629+
for (i = 0; i < max_client; ++i)
630+
if (clients[i]) {
631+
INIT_WORK(&clients[i]->add_work,
632+
ism_dev_add_work_func);
633+
clients[i]->tgt_ism = ism;
634+
atomic_inc(&ism->add_dev_cnt);
635+
schedule_work(&clients[i]->add_work);
636+
}
637+
spin_unlock_irqrestore(&clients_lock, flags);
638+
639+
wait_event(ism->waitq, !atomic_read(&ism->add_dev_cnt));
640+
641+
mutex_lock(&ism_dev_list.mutex);
642+
list_add(&ism->list, &ism_dev_list.list);
643+
mutex_unlock(&ism_dev_list.mutex);
644+
530645
ret = smcd_register_dev(ism->smcd);
531646
if (ret)
532647
goto unreg_ieq;
@@ -602,9 +717,36 @@ static int ism_probe(struct pci_dev *pdev, const struct pci_device_id *id)
602717
return ret;
603718
}
604719

720+
static void ism_dev_remove_work_func(struct work_struct *work)
721+
{
722+
struct ism_client *client = container_of(work, struct ism_client,
723+
remove_work);
724+
725+
client->remove(client->tgt_ism);
726+
atomic_dec(&client->tgt_ism->free_clients_cnt);
727+
wake_up(&client->tgt_ism->waitq);
728+
}
729+
730+
/* Callers must hold ism_dev_list.mutex */
605731
static void ism_dev_exit(struct ism_dev *ism)
606732
{
607733
struct pci_dev *pdev = ism->pdev;
734+
unsigned long flags;
735+
int i;
736+
737+
wait_event(ism->waitq, !atomic_read(&ism->free_clients_cnt));
738+
spin_lock_irqsave(&clients_lock, flags);
739+
for (i = 0; i < max_client; ++i)
740+
if (clients[i]) {
741+
INIT_WORK(&clients[i]->remove_work,
742+
ism_dev_remove_work_func);
743+
clients[i]->tgt_ism = ism;
744+
atomic_inc(&ism->free_clients_cnt);
745+
schedule_work(&clients[i]->remove_work);
746+
}
747+
spin_unlock_irqrestore(&clients_lock, flags);
748+
749+
wait_event(ism->waitq, !atomic_read(&ism->free_clients_cnt));
608750

609751
smcd_unregister_dev(ism->smcd);
610752
if (SYSTEM_EID.serial_number[0] != '0' ||
@@ -614,18 +756,22 @@ static void ism_dev_exit(struct ism_dev *ism)
614756
unregister_sba(ism);
615757
free_irq(pci_irq_vector(pdev, 0), ism);
616758
pci_free_irq_vectors(pdev);
759+
list_del_init(&ism->list);
617760
}
618761

619762
static void ism_remove(struct pci_dev *pdev)
620763
{
621764
struct ism_dev *ism = dev_get_drvdata(&pdev->dev);
622765

766+
mutex_lock(&ism_dev_list.mutex);
623767
ism_dev_exit(ism);
768+
mutex_unlock(&ism_dev_list.mutex);
624769

625770
smcd_free_dev(ism->smcd);
626771
pci_clear_master(pdev);
627772
pci_release_mem_regions(pdev);
628773
pci_disable_device(pdev);
774+
device_del(&ism->dev);
629775
dev_set_drvdata(&pdev->dev, NULL);
630776
kfree(ism);
631777
}
@@ -645,6 +791,8 @@ static int __init ism_init(void)
645791
if (!ism_debug_info)
646792
return -ENODEV;
647793

794+
memset(clients, 0, sizeof(clients));
795+
max_client = 0;
648796
debug_register_view(ism_debug_info, &debug_hex_ascii_view);
649797
ret = pci_register_driver(&ism_driver);
650798
if (ret)
@@ -655,6 +803,14 @@ static int __init ism_init(void)
655803

656804
static void __exit ism_exit(void)
657805
{
806+
struct ism_dev *ism;
807+
808+
mutex_lock(&ism_dev_list.mutex);
809+
list_for_each_entry(ism, &ism_dev_list.list, list) {
810+
ism_dev_exit(ism);
811+
}
812+
mutex_unlock(&ism_dev_list.mutex);
813+
658814
pci_unregister_driver(&ism_driver);
659815
debug_unregister(ism_debug_info);
660816
}

include/linux/ism.h

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
#ifndef _ISM_H
1010
#define _ISM_H
1111

12+
#include <linux/workqueue.h>
13+
1214
struct ism_dmb {
1315
u64 dmb_tok;
1416
u64 rgid;
@@ -20,4 +22,69 @@ struct ism_dmb {
2022
dma_addr_t dma_addr;
2123
};
2224

25+
/* Unless we gain unexpected popularity, this limit should hold for a while */
26+
#define MAX_CLIENTS 8
27+
#define ISM_NR_DMBS 1920
28+
29+
struct ism_dev {
30+
spinlock_t lock; /* protects the ism device */
31+
struct list_head list;
32+
struct pci_dev *pdev;
33+
struct smcd_dev *smcd;
34+
35+
struct ism_sba *sba;
36+
dma_addr_t sba_dma_addr;
37+
DECLARE_BITMAP(sba_bitmap, ISM_NR_DMBS);
38+
u8 *sba_client_arr; /* entries are indices into 'clients' array */
39+
void *priv[MAX_CLIENTS];
40+
41+
struct ism_eq *ieq;
42+
dma_addr_t ieq_dma_addr;
43+
44+
struct device dev;
45+
u64 local_gid;
46+
int ieq_idx;
47+
48+
atomic_t free_clients_cnt;
49+
atomic_t add_dev_cnt;
50+
wait_queue_head_t waitq;
51+
};
52+
53+
struct ism_event {
54+
u32 type;
55+
u32 code;
56+
u64 tok;
57+
u64 time;
58+
u64 info;
59+
};
60+
61+
struct ism_client {
62+
const char *name;
63+
void (*add)(struct ism_dev *dev);
64+
void (*remove)(struct ism_dev *dev);
65+
void (*handle_event)(struct ism_dev *dev, struct ism_event *event);
66+
/* Parameter dmbemask contains a bit vector with updated DMBEs, if sent
67+
* via ism_move_data(). Callback function must handle all active bits
68+
* indicated by dmbemask.
69+
*/
70+
void (*handle_irq)(struct ism_dev *dev, unsigned int bit, u16 dmbemask);
71+
/* Private area - don't touch! */
72+
struct work_struct remove_work;
73+
struct work_struct add_work;
74+
struct ism_dev *tgt_ism;
75+
u8 id;
76+
};
77+
78+
int ism_register_client(struct ism_client *client);
79+
int ism_unregister_client(struct ism_client *client);
80+
static inline void *ism_get_priv(struct ism_dev *dev,
81+
struct ism_client *client) {
82+
return dev->priv[client->id];
83+
}
84+
85+
static inline void ism_set_priv(struct ism_dev *dev, struct ism_client *client,
86+
void *priv) {
87+
dev->priv[client->id] = priv;
88+
}
89+
2390
#endif /* _ISM_H */

0 commit comments

Comments
 (0)