1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
3 * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved.
4 * Copyright (c) 2015 System Fabric Works, Inc. All rights reserved.
7 #include <linux/vmalloc.h>
10 #include "rxe_queue.h"
12 int do_mmap_info(struct rxe_dev
*rxe
, struct mminfo __user
*outbuf
,
13 struct ib_udata
*udata
, struct rxe_queue_buf
*buf
,
14 size_t buf_size
, struct rxe_mmap_info
**ip_p
)
17 struct rxe_mmap_info
*ip
= NULL
;
20 ip
= rxe_create_mmap_info(rxe
, buf_size
, udata
, buf
);
26 if (copy_to_user(outbuf
, &ip
->info
, sizeof(ip
->info
))) {
31 spin_lock_bh(&rxe
->pending_lock
);
32 list_add(&ip
->pending_mmaps
, &rxe
->pending_mmaps
);
33 spin_unlock_bh(&rxe
->pending_lock
);
46 inline void rxe_queue_reset(struct rxe_queue
*q
)
48 /* queue is comprised from header and the memory
49 * of the actual queue. See "struct rxe_queue_buf" in rxe_queue.h
50 * reset only the queue itself and not the management header
52 memset(q
->buf
->data
, 0, q
->buf_size
- sizeof(struct rxe_queue_buf
));
55 struct rxe_queue
*rxe_queue_init(struct rxe_dev
*rxe
,
57 unsigned int elem_size
)
61 unsigned int num_slots
;
63 /* num_elem == 0 is allowed, but uninteresting */
67 q
= kmalloc(sizeof(*q
), GFP_KERNEL
);
73 /* used in resize, only need to copy used part of queue */
74 q
->elem_size
= elem_size
;
76 /* pad element up to at least a cacheline and always a power of 2 */
77 if (elem_size
< cache_line_size())
78 elem_size
= cache_line_size();
79 elem_size
= roundup_pow_of_two(elem_size
);
81 q
->log2_elem_size
= order_base_2(elem_size
);
83 num_slots
= *num_elem
+ 1;
84 num_slots
= roundup_pow_of_two(num_slots
);
85 q
->index_mask
= num_slots
- 1;
87 buf_size
= sizeof(struct rxe_queue_buf
) + num_slots
* elem_size
;
89 q
->buf
= vmalloc_user(buf_size
);
93 q
->buf
->log2_elem_size
= q
->log2_elem_size
;
94 q
->buf
->index_mask
= q
->index_mask
;
96 q
->buf_size
= buf_size
;
98 *num_elem
= num_slots
- 1;
107 /* copies elements from original q to new q and then swaps the contents of the
108 * two q headers. This is so that if anyone is holding a pointer to q it will
111 static int resize_finish(struct rxe_queue
*q
, struct rxe_queue
*new_q
,
112 unsigned int num_elem
)
114 if (!queue_empty(q
) && (num_elem
< queue_count(q
)))
117 while (!queue_empty(q
)) {
118 memcpy(producer_addr(new_q
), consumer_addr(q
),
120 advance_producer(new_q
);
129 int rxe_queue_resize(struct rxe_queue
*q
, unsigned int *num_elem_p
,
130 unsigned int elem_size
, struct ib_udata
*udata
,
131 struct mminfo __user
*outbuf
, spinlock_t
*producer_lock
,
132 spinlock_t
*consumer_lock
)
134 struct rxe_queue
*new_q
;
135 unsigned int num_elem
= *num_elem_p
;
137 unsigned long flags
= 0, flags1
;
139 new_q
= rxe_queue_init(q
->rxe
, &num_elem
, elem_size
);
143 err
= do_mmap_info(new_q
->rxe
, outbuf
, udata
, new_q
->buf
,
144 new_q
->buf_size
, &new_q
->ip
);
151 spin_lock_irqsave(consumer_lock
, flags1
);
154 spin_lock_irqsave(producer_lock
, flags
);
155 err
= resize_finish(q
, new_q
, num_elem
);
156 spin_unlock_irqrestore(producer_lock
, flags
);
158 err
= resize_finish(q
, new_q
, num_elem
);
161 spin_unlock_irqrestore(consumer_lock
, flags1
);
163 rxe_queue_cleanup(new_q
); /* new/old dep on err */
167 *num_elem_p
= num_elem
;
174 void rxe_queue_cleanup(struct rxe_queue
*q
)
177 kref_put(&q
->ip
->ref
, rxe_mmap_release
);