xref: /f-stack/dpdk/drivers/crypto/ccp/ccp_dev.c (revision 2d9fd380)
1d30ea906Sjfb8856606 /*   SPDX-License-Identifier: BSD-3-Clause
2d30ea906Sjfb8856606  *   Copyright(c) 2018 Advanced Micro Devices, Inc. All rights reserved.
3d30ea906Sjfb8856606  */
4d30ea906Sjfb8856606 
5d30ea906Sjfb8856606 #include <dirent.h>
6d30ea906Sjfb8856606 #include <fcntl.h>
7d30ea906Sjfb8856606 #include <stdio.h>
8d30ea906Sjfb8856606 #include <string.h>
9d30ea906Sjfb8856606 #include <sys/mman.h>
10d30ea906Sjfb8856606 #include <sys/queue.h>
11d30ea906Sjfb8856606 #include <sys/types.h>
12d30ea906Sjfb8856606 #include <sys/file.h>
13d30ea906Sjfb8856606 #include <unistd.h>
14d30ea906Sjfb8856606 
15d30ea906Sjfb8856606 #include <rte_hexdump.h>
16d30ea906Sjfb8856606 #include <rte_memzone.h>
17d30ea906Sjfb8856606 #include <rte_malloc.h>
18d30ea906Sjfb8856606 #include <rte_memory.h>
19d30ea906Sjfb8856606 #include <rte_spinlock.h>
20d30ea906Sjfb8856606 #include <rte_string_fns.h>
21d30ea906Sjfb8856606 
22d30ea906Sjfb8856606 #include "ccp_dev.h"
23d30ea906Sjfb8856606 #include "ccp_pci.h"
24d30ea906Sjfb8856606 #include "ccp_pmd_private.h"
25d30ea906Sjfb8856606 
26d30ea906Sjfb8856606 struct ccp_list ccp_list = TAILQ_HEAD_INITIALIZER(ccp_list);
27d30ea906Sjfb8856606 static int ccp_dev_id;
28d30ea906Sjfb8856606 
29d30ea906Sjfb8856606 int
ccp_dev_start(struct rte_cryptodev * dev)30d30ea906Sjfb8856606 ccp_dev_start(struct rte_cryptodev *dev)
31d30ea906Sjfb8856606 {
32d30ea906Sjfb8856606 	struct ccp_private *priv = dev->data->dev_private;
33d30ea906Sjfb8856606 
34d30ea906Sjfb8856606 	priv->last_dev = TAILQ_FIRST(&ccp_list);
35d30ea906Sjfb8856606 	return 0;
36d30ea906Sjfb8856606 }
37d30ea906Sjfb8856606 
38d30ea906Sjfb8856606 struct ccp_queue *
ccp_allot_queue(struct rte_cryptodev * cdev,int slot_req)39d30ea906Sjfb8856606 ccp_allot_queue(struct rte_cryptodev *cdev, int slot_req)
40d30ea906Sjfb8856606 {
41d30ea906Sjfb8856606 	int i, ret = 0;
42d30ea906Sjfb8856606 	struct ccp_device *dev;
43d30ea906Sjfb8856606 	struct ccp_private *priv = cdev->data->dev_private;
44d30ea906Sjfb8856606 
45d30ea906Sjfb8856606 	dev = TAILQ_NEXT(priv->last_dev, next);
46d30ea906Sjfb8856606 	if (unlikely(dev == NULL))
47d30ea906Sjfb8856606 		dev = TAILQ_FIRST(&ccp_list);
48d30ea906Sjfb8856606 	priv->last_dev = dev;
49d30ea906Sjfb8856606 	if (dev->qidx >= dev->cmd_q_count)
50d30ea906Sjfb8856606 		dev->qidx = 0;
51d30ea906Sjfb8856606 	ret = rte_atomic64_read(&dev->cmd_q[dev->qidx].free_slots);
52d30ea906Sjfb8856606 	if (ret >= slot_req)
53d30ea906Sjfb8856606 		return &dev->cmd_q[dev->qidx];
54d30ea906Sjfb8856606 	for (i = 0; i < dev->cmd_q_count; i++) {
55d30ea906Sjfb8856606 		dev->qidx++;
56d30ea906Sjfb8856606 		if (dev->qidx >= dev->cmd_q_count)
57d30ea906Sjfb8856606 			dev->qidx = 0;
58d30ea906Sjfb8856606 		ret = rte_atomic64_read(&dev->cmd_q[dev->qidx].free_slots);
59d30ea906Sjfb8856606 		if (ret >= slot_req)
60d30ea906Sjfb8856606 			return &dev->cmd_q[dev->qidx];
61d30ea906Sjfb8856606 	}
62d30ea906Sjfb8856606 	return NULL;
63d30ea906Sjfb8856606 }
64d30ea906Sjfb8856606 
65d30ea906Sjfb8856606 int
ccp_read_hwrng(uint32_t * value)66d30ea906Sjfb8856606 ccp_read_hwrng(uint32_t *value)
67d30ea906Sjfb8856606 {
68d30ea906Sjfb8856606 	struct ccp_device *dev;
69d30ea906Sjfb8856606 
70d30ea906Sjfb8856606 	TAILQ_FOREACH(dev, &ccp_list, next) {
71d30ea906Sjfb8856606 		void *vaddr = (void *)(dev->pci.mem_resource[2].addr);
72d30ea906Sjfb8856606 
73d30ea906Sjfb8856606 		while (dev->hwrng_retries++ < CCP_MAX_TRNG_RETRIES) {
74d30ea906Sjfb8856606 			*value = CCP_READ_REG(vaddr, TRNG_OUT_REG);
75d30ea906Sjfb8856606 			if (*value) {
76d30ea906Sjfb8856606 				dev->hwrng_retries = 0;
77d30ea906Sjfb8856606 				return 0;
78d30ea906Sjfb8856606 			}
79d30ea906Sjfb8856606 		}
80d30ea906Sjfb8856606 		dev->hwrng_retries = 0;
81d30ea906Sjfb8856606 	}
82d30ea906Sjfb8856606 	return -1;
83d30ea906Sjfb8856606 }
84d30ea906Sjfb8856606 
85d30ea906Sjfb8856606 static const struct rte_memzone *
ccp_queue_dma_zone_reserve(const char * queue_name,uint32_t queue_size,int socket_id)86d30ea906Sjfb8856606 ccp_queue_dma_zone_reserve(const char *queue_name,
87d30ea906Sjfb8856606 			   uint32_t queue_size,
88d30ea906Sjfb8856606 			   int socket_id)
89d30ea906Sjfb8856606 {
90d30ea906Sjfb8856606 	const struct rte_memzone *mz;
91d30ea906Sjfb8856606 
92d30ea906Sjfb8856606 	mz = rte_memzone_lookup(queue_name);
93d30ea906Sjfb8856606 	if (mz != 0) {
94d30ea906Sjfb8856606 		if (((size_t)queue_size <= mz->len) &&
95d30ea906Sjfb8856606 		    ((socket_id == SOCKET_ID_ANY) ||
96d30ea906Sjfb8856606 		     (socket_id == mz->socket_id))) {
97d30ea906Sjfb8856606 			CCP_LOG_INFO("re-use memzone already "
98d30ea906Sjfb8856606 				     "allocated for %s", queue_name);
99d30ea906Sjfb8856606 			return mz;
100d30ea906Sjfb8856606 		}
101d30ea906Sjfb8856606 		CCP_LOG_ERR("Incompatible memzone already "
102d30ea906Sjfb8856606 			    "allocated %s, size %u, socket %d. "
103d30ea906Sjfb8856606 			    "Requested size %u, socket %u",
104d30ea906Sjfb8856606 			    queue_name, (uint32_t)mz->len,
105d30ea906Sjfb8856606 			    mz->socket_id, queue_size, socket_id);
106d30ea906Sjfb8856606 		return NULL;
107d30ea906Sjfb8856606 	}
108d30ea906Sjfb8856606 
109d30ea906Sjfb8856606 	CCP_LOG_INFO("Allocate memzone for %s, size %u on socket %u",
110d30ea906Sjfb8856606 		     queue_name, queue_size, socket_id);
111d30ea906Sjfb8856606 
112d30ea906Sjfb8856606 	return rte_memzone_reserve_aligned(queue_name, queue_size,
113d30ea906Sjfb8856606 			socket_id, RTE_MEMZONE_IOVA_CONTIG, queue_size);
114d30ea906Sjfb8856606 }
115d30ea906Sjfb8856606 
116d30ea906Sjfb8856606 /* bitmap support apis */
117d30ea906Sjfb8856606 static inline void
ccp_set_bit(unsigned long * bitmap,int n)118d30ea906Sjfb8856606 ccp_set_bit(unsigned long *bitmap, int n)
119d30ea906Sjfb8856606 {
120d30ea906Sjfb8856606 	__sync_fetch_and_or(&bitmap[WORD_OFFSET(n)], (1UL << BIT_OFFSET(n)));
121d30ea906Sjfb8856606 }
122d30ea906Sjfb8856606 
123d30ea906Sjfb8856606 static inline void
ccp_clear_bit(unsigned long * bitmap,int n)124d30ea906Sjfb8856606 ccp_clear_bit(unsigned long *bitmap, int n)
125d30ea906Sjfb8856606 {
126d30ea906Sjfb8856606 	__sync_fetch_and_and(&bitmap[WORD_OFFSET(n)], ~(1UL << BIT_OFFSET(n)));
127d30ea906Sjfb8856606 }
128d30ea906Sjfb8856606 
129d30ea906Sjfb8856606 static inline uint32_t
ccp_get_bit(unsigned long * bitmap,int n)130d30ea906Sjfb8856606 ccp_get_bit(unsigned long *bitmap, int n)
131d30ea906Sjfb8856606 {
132d30ea906Sjfb8856606 	return ((bitmap[WORD_OFFSET(n)] & (1 << BIT_OFFSET(n))) != 0);
133d30ea906Sjfb8856606 }
134d30ea906Sjfb8856606 
135d30ea906Sjfb8856606 
136d30ea906Sjfb8856606 static inline uint32_t
ccp_ffz(unsigned long word)137d30ea906Sjfb8856606 ccp_ffz(unsigned long word)
138d30ea906Sjfb8856606 {
139d30ea906Sjfb8856606 	unsigned long first_zero;
140d30ea906Sjfb8856606 
141d30ea906Sjfb8856606 	first_zero = __builtin_ffsl(~word);
142d30ea906Sjfb8856606 	return first_zero ? (first_zero - 1) :
143d30ea906Sjfb8856606 		BITS_PER_WORD;
144d30ea906Sjfb8856606 }
145d30ea906Sjfb8856606 
146d30ea906Sjfb8856606 static inline uint32_t
ccp_find_first_zero_bit(unsigned long * addr,uint32_t limit)147d30ea906Sjfb8856606 ccp_find_first_zero_bit(unsigned long *addr, uint32_t limit)
148d30ea906Sjfb8856606 {
149d30ea906Sjfb8856606 	uint32_t i;
150d30ea906Sjfb8856606 	uint32_t nwords = 0;
151d30ea906Sjfb8856606 
152d30ea906Sjfb8856606 	nwords = (limit - 1) / BITS_PER_WORD + 1;
153d30ea906Sjfb8856606 	for (i = 0; i < nwords; i++) {
154d30ea906Sjfb8856606 		if (addr[i] == 0UL)
155d30ea906Sjfb8856606 			return i * BITS_PER_WORD;
156d30ea906Sjfb8856606 		if (addr[i] < ~(0UL))
157d30ea906Sjfb8856606 			break;
158d30ea906Sjfb8856606 	}
159d30ea906Sjfb8856606 	return (i == nwords) ? limit : i * BITS_PER_WORD + ccp_ffz(addr[i]);
160d30ea906Sjfb8856606 }
161d30ea906Sjfb8856606 
162d30ea906Sjfb8856606 static void
ccp_bitmap_set(unsigned long * map,unsigned int start,int len)163d30ea906Sjfb8856606 ccp_bitmap_set(unsigned long *map, unsigned int start, int len)
164d30ea906Sjfb8856606 {
165d30ea906Sjfb8856606 	unsigned long *p = map + WORD_OFFSET(start);
166d30ea906Sjfb8856606 	const unsigned int size = start + len;
167d30ea906Sjfb8856606 	int bits_to_set = BITS_PER_WORD - (start % BITS_PER_WORD);
168d30ea906Sjfb8856606 	unsigned long mask_to_set = CCP_BITMAP_FIRST_WORD_MASK(start);
169d30ea906Sjfb8856606 
170d30ea906Sjfb8856606 	while (len - bits_to_set >= 0) {
171d30ea906Sjfb8856606 		*p |= mask_to_set;
172d30ea906Sjfb8856606 		len -= bits_to_set;
173d30ea906Sjfb8856606 		bits_to_set = BITS_PER_WORD;
174d30ea906Sjfb8856606 		mask_to_set = ~0UL;
175d30ea906Sjfb8856606 		p++;
176d30ea906Sjfb8856606 	}
177d30ea906Sjfb8856606 	if (len) {
178d30ea906Sjfb8856606 		mask_to_set &= CCP_BITMAP_LAST_WORD_MASK(size);
179d30ea906Sjfb8856606 		*p |= mask_to_set;
180d30ea906Sjfb8856606 	}
181d30ea906Sjfb8856606 }
182d30ea906Sjfb8856606 
183d30ea906Sjfb8856606 static void
ccp_bitmap_clear(unsigned long * map,unsigned int start,int len)184d30ea906Sjfb8856606 ccp_bitmap_clear(unsigned long *map, unsigned int start, int len)
185d30ea906Sjfb8856606 {
186d30ea906Sjfb8856606 	unsigned long *p = map + WORD_OFFSET(start);
187d30ea906Sjfb8856606 	const unsigned int size = start + len;
188d30ea906Sjfb8856606 	int bits_to_clear = BITS_PER_WORD - (start % BITS_PER_WORD);
189d30ea906Sjfb8856606 	unsigned long mask_to_clear = CCP_BITMAP_FIRST_WORD_MASK(start);
190d30ea906Sjfb8856606 
191d30ea906Sjfb8856606 	while (len - bits_to_clear >= 0) {
192d30ea906Sjfb8856606 		*p &= ~mask_to_clear;
193d30ea906Sjfb8856606 		len -= bits_to_clear;
194d30ea906Sjfb8856606 		bits_to_clear = BITS_PER_WORD;
195d30ea906Sjfb8856606 		mask_to_clear = ~0UL;
196d30ea906Sjfb8856606 		p++;
197d30ea906Sjfb8856606 	}
198d30ea906Sjfb8856606 	if (len) {
199d30ea906Sjfb8856606 		mask_to_clear &= CCP_BITMAP_LAST_WORD_MASK(size);
200d30ea906Sjfb8856606 		*p &= ~mask_to_clear;
201d30ea906Sjfb8856606 	}
202d30ea906Sjfb8856606 }
203d30ea906Sjfb8856606 
204d30ea906Sjfb8856606 
205d30ea906Sjfb8856606 static unsigned long
_ccp_find_next_bit(const unsigned long * addr,unsigned long nbits,unsigned long start,unsigned long invert)206d30ea906Sjfb8856606 _ccp_find_next_bit(const unsigned long *addr,
207d30ea906Sjfb8856606 		   unsigned long nbits,
208d30ea906Sjfb8856606 		   unsigned long start,
209d30ea906Sjfb8856606 		   unsigned long invert)
210d30ea906Sjfb8856606 {
211d30ea906Sjfb8856606 	unsigned long tmp;
212d30ea906Sjfb8856606 
213d30ea906Sjfb8856606 	if (!nbits || start >= nbits)
214d30ea906Sjfb8856606 		return nbits;
215d30ea906Sjfb8856606 
216d30ea906Sjfb8856606 	tmp = addr[start / BITS_PER_WORD] ^ invert;
217d30ea906Sjfb8856606 
218d30ea906Sjfb8856606 	/* Handle 1st word. */
219d30ea906Sjfb8856606 	tmp &= CCP_BITMAP_FIRST_WORD_MASK(start);
220d30ea906Sjfb8856606 	start = ccp_round_down(start, BITS_PER_WORD);
221d30ea906Sjfb8856606 
222d30ea906Sjfb8856606 	while (!tmp) {
223d30ea906Sjfb8856606 		start += BITS_PER_WORD;
224d30ea906Sjfb8856606 		if (start >= nbits)
225d30ea906Sjfb8856606 			return nbits;
226d30ea906Sjfb8856606 
227d30ea906Sjfb8856606 		tmp = addr[start / BITS_PER_WORD] ^ invert;
228d30ea906Sjfb8856606 	}
229d30ea906Sjfb8856606 
230d30ea906Sjfb8856606 	return RTE_MIN(start + (ffs(tmp) - 1), nbits);
231d30ea906Sjfb8856606 }
232d30ea906Sjfb8856606 
233d30ea906Sjfb8856606 static unsigned long
ccp_find_next_bit(const unsigned long * addr,unsigned long size,unsigned long offset)234d30ea906Sjfb8856606 ccp_find_next_bit(const unsigned long *addr,
235d30ea906Sjfb8856606 		  unsigned long size,
236d30ea906Sjfb8856606 		  unsigned long offset)
237d30ea906Sjfb8856606 {
238d30ea906Sjfb8856606 	return _ccp_find_next_bit(addr, size, offset, 0UL);
239d30ea906Sjfb8856606 }
240d30ea906Sjfb8856606 
241d30ea906Sjfb8856606 static unsigned long
ccp_find_next_zero_bit(const unsigned long * addr,unsigned long size,unsigned long offset)242d30ea906Sjfb8856606 ccp_find_next_zero_bit(const unsigned long *addr,
243d30ea906Sjfb8856606 		       unsigned long size,
244d30ea906Sjfb8856606 		       unsigned long offset)
245d30ea906Sjfb8856606 {
246d30ea906Sjfb8856606 	return _ccp_find_next_bit(addr, size, offset, ~0UL);
247d30ea906Sjfb8856606 }
248d30ea906Sjfb8856606 
249d30ea906Sjfb8856606 /**
250d30ea906Sjfb8856606  * bitmap_find_next_zero_area - find a contiguous aligned zero area
251d30ea906Sjfb8856606  * @map: The address to base the search on
252d30ea906Sjfb8856606  * @size: The bitmap size in bits
253d30ea906Sjfb8856606  * @start: The bitnumber to start searching at
254d30ea906Sjfb8856606  * @nr: The number of zeroed bits we're looking for
255d30ea906Sjfb8856606  */
256d30ea906Sjfb8856606 static unsigned long
ccp_bitmap_find_next_zero_area(unsigned long * map,unsigned long size,unsigned long start,unsigned int nr)257d30ea906Sjfb8856606 ccp_bitmap_find_next_zero_area(unsigned long *map,
258d30ea906Sjfb8856606 			       unsigned long size,
259d30ea906Sjfb8856606 			       unsigned long start,
260d30ea906Sjfb8856606 			       unsigned int nr)
261d30ea906Sjfb8856606 {
262d30ea906Sjfb8856606 	unsigned long index, end, i;
263d30ea906Sjfb8856606 
264d30ea906Sjfb8856606 again:
265d30ea906Sjfb8856606 	index = ccp_find_next_zero_bit(map, size, start);
266d30ea906Sjfb8856606 
267d30ea906Sjfb8856606 	end = index + nr;
268d30ea906Sjfb8856606 	if (end > size)
269d30ea906Sjfb8856606 		return end;
270d30ea906Sjfb8856606 	i = ccp_find_next_bit(map, end, index);
271d30ea906Sjfb8856606 	if (i < end) {
272d30ea906Sjfb8856606 		start = i + 1;
273d30ea906Sjfb8856606 		goto again;
274d30ea906Sjfb8856606 	}
275d30ea906Sjfb8856606 	return index;
276d30ea906Sjfb8856606 }
277d30ea906Sjfb8856606 
278d30ea906Sjfb8856606 static uint32_t
ccp_lsb_alloc(struct ccp_queue * cmd_q,unsigned int count)279d30ea906Sjfb8856606 ccp_lsb_alloc(struct ccp_queue *cmd_q, unsigned int count)
280d30ea906Sjfb8856606 {
281d30ea906Sjfb8856606 	struct ccp_device *ccp;
282d30ea906Sjfb8856606 	int start;
283d30ea906Sjfb8856606 
284d30ea906Sjfb8856606 	/* First look at the map for the queue */
285d30ea906Sjfb8856606 	if (cmd_q->lsb >= 0) {
286d30ea906Sjfb8856606 		start = (uint32_t)ccp_bitmap_find_next_zero_area(cmd_q->lsbmap,
287d30ea906Sjfb8856606 								 LSB_SIZE, 0,
288d30ea906Sjfb8856606 								 count);
289d30ea906Sjfb8856606 		if (start < LSB_SIZE) {
290d30ea906Sjfb8856606 			ccp_bitmap_set(cmd_q->lsbmap, start, count);
291d30ea906Sjfb8856606 			return start + cmd_q->lsb * LSB_SIZE;
292d30ea906Sjfb8856606 		}
293d30ea906Sjfb8856606 	}
294d30ea906Sjfb8856606 
295d30ea906Sjfb8856606 	/* try to get an entry from the shared blocks */
296d30ea906Sjfb8856606 	ccp = cmd_q->dev;
297d30ea906Sjfb8856606 
298d30ea906Sjfb8856606 	rte_spinlock_lock(&ccp->lsb_lock);
299d30ea906Sjfb8856606 
300d30ea906Sjfb8856606 	start = (uint32_t)ccp_bitmap_find_next_zero_area(ccp->lsbmap,
301d30ea906Sjfb8856606 						    MAX_LSB_CNT * LSB_SIZE,
302d30ea906Sjfb8856606 						    0, count);
303d30ea906Sjfb8856606 	if (start <= MAX_LSB_CNT * LSB_SIZE) {
304d30ea906Sjfb8856606 		ccp_bitmap_set(ccp->lsbmap, start, count);
305d30ea906Sjfb8856606 		rte_spinlock_unlock(&ccp->lsb_lock);
306d30ea906Sjfb8856606 		return start * LSB_ITEM_SIZE;
307d30ea906Sjfb8856606 	}
308d30ea906Sjfb8856606 	CCP_LOG_ERR("NO LSBs available");
309d30ea906Sjfb8856606 
310d30ea906Sjfb8856606 	rte_spinlock_unlock(&ccp->lsb_lock);
311d30ea906Sjfb8856606 
312d30ea906Sjfb8856606 	return 0;
313d30ea906Sjfb8856606 }
314d30ea906Sjfb8856606 
315d30ea906Sjfb8856606 static void __rte_unused
ccp_lsb_free(struct ccp_queue * cmd_q,unsigned int start,unsigned int count)316d30ea906Sjfb8856606 ccp_lsb_free(struct ccp_queue *cmd_q,
317d30ea906Sjfb8856606 	     unsigned int start,
318d30ea906Sjfb8856606 	     unsigned int count)
319d30ea906Sjfb8856606 {
320d30ea906Sjfb8856606 	int lsbno = start / LSB_SIZE;
321d30ea906Sjfb8856606 
322d30ea906Sjfb8856606 	if (!start)
323d30ea906Sjfb8856606 		return;
324d30ea906Sjfb8856606 
325d30ea906Sjfb8856606 	if (cmd_q->lsb == lsbno) {
326d30ea906Sjfb8856606 		/* An entry from the private LSB */
327d30ea906Sjfb8856606 		ccp_bitmap_clear(cmd_q->lsbmap, start % LSB_SIZE, count);
328d30ea906Sjfb8856606 	} else {
329d30ea906Sjfb8856606 		/* From the shared LSBs */
330d30ea906Sjfb8856606 		struct ccp_device *ccp = cmd_q->dev;
331d30ea906Sjfb8856606 
332d30ea906Sjfb8856606 		rte_spinlock_lock(&ccp->lsb_lock);
333d30ea906Sjfb8856606 		ccp_bitmap_clear(ccp->lsbmap, start, count);
334d30ea906Sjfb8856606 		rte_spinlock_unlock(&ccp->lsb_lock);
335d30ea906Sjfb8856606 	}
336d30ea906Sjfb8856606 }
337d30ea906Sjfb8856606 
338d30ea906Sjfb8856606 static int
ccp_find_lsb_regions(struct ccp_queue * cmd_q,uint64_t status)339d30ea906Sjfb8856606 ccp_find_lsb_regions(struct ccp_queue *cmd_q, uint64_t status)
340d30ea906Sjfb8856606 {
341d30ea906Sjfb8856606 	int q_mask = 1 << cmd_q->id;
342d30ea906Sjfb8856606 	int weight = 0;
343d30ea906Sjfb8856606 	int j;
344d30ea906Sjfb8856606 
345d30ea906Sjfb8856606 	/* Build a bit mask to know which LSBs
346d30ea906Sjfb8856606 	 * this queue has access to.
347d30ea906Sjfb8856606 	 * Don't bother with segment 0
348d30ea906Sjfb8856606 	 * as it has special
349d30ea906Sjfb8856606 	 * privileges.
350d30ea906Sjfb8856606 	 */
351d30ea906Sjfb8856606 	cmd_q->lsbmask = 0;
352d30ea906Sjfb8856606 	status >>= LSB_REGION_WIDTH;
353d30ea906Sjfb8856606 	for (j = 1; j < MAX_LSB_CNT; j++) {
354d30ea906Sjfb8856606 		if (status & q_mask)
355d30ea906Sjfb8856606 			ccp_set_bit(&cmd_q->lsbmask, j);
356d30ea906Sjfb8856606 
357d30ea906Sjfb8856606 		status >>= LSB_REGION_WIDTH;
358d30ea906Sjfb8856606 	}
359d30ea906Sjfb8856606 
360d30ea906Sjfb8856606 	for (j = 0; j < MAX_LSB_CNT; j++)
361d30ea906Sjfb8856606 		if (ccp_get_bit(&cmd_q->lsbmask, j))
362d30ea906Sjfb8856606 			weight++;
363d30ea906Sjfb8856606 
364d30ea906Sjfb8856606 	printf("Queue %d can access %d LSB regions  of mask  %lu\n",
365d30ea906Sjfb8856606 	       (int)cmd_q->id, weight, cmd_q->lsbmask);
366d30ea906Sjfb8856606 
367d30ea906Sjfb8856606 	return weight ? 0 : -EINVAL;
368d30ea906Sjfb8856606 }
369d30ea906Sjfb8856606 
370d30ea906Sjfb8856606 static int
ccp_find_and_assign_lsb_to_q(struct ccp_device * ccp,int lsb_cnt,int n_lsbs,unsigned long * lsb_pub)371d30ea906Sjfb8856606 ccp_find_and_assign_lsb_to_q(struct ccp_device *ccp,
372d30ea906Sjfb8856606 			     int lsb_cnt, int n_lsbs,
373d30ea906Sjfb8856606 			     unsigned long *lsb_pub)
374d30ea906Sjfb8856606 {
375d30ea906Sjfb8856606 	unsigned long qlsb = 0;
376d30ea906Sjfb8856606 	int bitno = 0;
377d30ea906Sjfb8856606 	int qlsb_wgt = 0;
378d30ea906Sjfb8856606 	int i, j;
379d30ea906Sjfb8856606 
380d30ea906Sjfb8856606 	/* For each queue:
381d30ea906Sjfb8856606 	 * If the count of potential LSBs available to a queue matches the
382d30ea906Sjfb8856606 	 * ordinal given to us in lsb_cnt:
383d30ea906Sjfb8856606 	 * Copy the mask of possible LSBs for this queue into "qlsb";
384d30ea906Sjfb8856606 	 * For each bit in qlsb, see if the corresponding bit in the
385d30ea906Sjfb8856606 	 * aggregation mask is set; if so, we have a match.
386d30ea906Sjfb8856606 	 *     If we have a match, clear the bit in the aggregation to
387d30ea906Sjfb8856606 	 *     mark it as no longer available.
388d30ea906Sjfb8856606 	 *     If there is no match, clear the bit in qlsb and keep looking.
389d30ea906Sjfb8856606 	 */
390d30ea906Sjfb8856606 	for (i = 0; i < ccp->cmd_q_count; i++) {
391d30ea906Sjfb8856606 		struct ccp_queue *cmd_q = &ccp->cmd_q[i];
392d30ea906Sjfb8856606 
393d30ea906Sjfb8856606 		qlsb_wgt = 0;
394d30ea906Sjfb8856606 		for (j = 0; j < MAX_LSB_CNT; j++)
395d30ea906Sjfb8856606 			if (ccp_get_bit(&cmd_q->lsbmask, j))
396d30ea906Sjfb8856606 				qlsb_wgt++;
397d30ea906Sjfb8856606 
398d30ea906Sjfb8856606 		if (qlsb_wgt == lsb_cnt) {
399d30ea906Sjfb8856606 			qlsb = cmd_q->lsbmask;
400d30ea906Sjfb8856606 
401d30ea906Sjfb8856606 			bitno = ffs(qlsb) - 1;
402d30ea906Sjfb8856606 			while (bitno < MAX_LSB_CNT) {
403d30ea906Sjfb8856606 				if (ccp_get_bit(lsb_pub, bitno)) {
404d30ea906Sjfb8856606 					/* We found an available LSB
405d30ea906Sjfb8856606 					 * that this queue can access
406d30ea906Sjfb8856606 					 */
407d30ea906Sjfb8856606 					cmd_q->lsb = bitno;
408d30ea906Sjfb8856606 					ccp_clear_bit(lsb_pub, bitno);
409d30ea906Sjfb8856606 					break;
410d30ea906Sjfb8856606 				}
411d30ea906Sjfb8856606 				ccp_clear_bit(&qlsb, bitno);
412d30ea906Sjfb8856606 				bitno = ffs(qlsb) - 1;
413d30ea906Sjfb8856606 			}
414d30ea906Sjfb8856606 			if (bitno >= MAX_LSB_CNT)
415d30ea906Sjfb8856606 				return -EINVAL;
416d30ea906Sjfb8856606 			n_lsbs--;
417d30ea906Sjfb8856606 		}
418d30ea906Sjfb8856606 	}
419d30ea906Sjfb8856606 	return n_lsbs;
420d30ea906Sjfb8856606 }
421d30ea906Sjfb8856606 
422d30ea906Sjfb8856606 /* For each queue, from the most- to least-constrained:
423d30ea906Sjfb8856606  * find an LSB that can be assigned to the queue. If there are N queues that
424d30ea906Sjfb8856606  * can only use M LSBs, where N > M, fail; otherwise, every queue will get a
425d30ea906Sjfb8856606  * dedicated LSB. Remaining LSB regions become a shared resource.
426d30ea906Sjfb8856606  * If we have fewer LSBs than queues, all LSB regions become shared
427d30ea906Sjfb8856606  * resources.
428d30ea906Sjfb8856606  */
429d30ea906Sjfb8856606 static int
ccp_assign_lsbs(struct ccp_device * ccp)430d30ea906Sjfb8856606 ccp_assign_lsbs(struct ccp_device *ccp)
431d30ea906Sjfb8856606 {
432d30ea906Sjfb8856606 	unsigned long lsb_pub = 0, qlsb = 0;
433d30ea906Sjfb8856606 	int n_lsbs = 0;
434d30ea906Sjfb8856606 	int bitno;
435d30ea906Sjfb8856606 	int i, lsb_cnt;
436d30ea906Sjfb8856606 	int rc = 0;
437d30ea906Sjfb8856606 
438d30ea906Sjfb8856606 	rte_spinlock_init(&ccp->lsb_lock);
439d30ea906Sjfb8856606 
440d30ea906Sjfb8856606 	/* Create an aggregate bitmap to get a total count of available LSBs */
441d30ea906Sjfb8856606 	for (i = 0; i < ccp->cmd_q_count; i++)
442d30ea906Sjfb8856606 		lsb_pub |= ccp->cmd_q[i].lsbmask;
443d30ea906Sjfb8856606 
444d30ea906Sjfb8856606 	for (i = 0; i < MAX_LSB_CNT; i++)
445d30ea906Sjfb8856606 		if (ccp_get_bit(&lsb_pub, i))
446d30ea906Sjfb8856606 			n_lsbs++;
447d30ea906Sjfb8856606 
448d30ea906Sjfb8856606 	if (n_lsbs >= ccp->cmd_q_count) {
449d30ea906Sjfb8856606 		/* We have enough LSBS to give every queue a private LSB.
450d30ea906Sjfb8856606 		 * Brute force search to start with the queues that are more
451d30ea906Sjfb8856606 		 * constrained in LSB choice. When an LSB is privately
452d30ea906Sjfb8856606 		 * assigned, it is removed from the public mask.
453d30ea906Sjfb8856606 		 * This is an ugly N squared algorithm with some optimization.
454d30ea906Sjfb8856606 		 */
455d30ea906Sjfb8856606 		for (lsb_cnt = 1; n_lsbs && (lsb_cnt <= MAX_LSB_CNT);
456d30ea906Sjfb8856606 		     lsb_cnt++) {
457d30ea906Sjfb8856606 			rc = ccp_find_and_assign_lsb_to_q(ccp, lsb_cnt, n_lsbs,
458d30ea906Sjfb8856606 							  &lsb_pub);
459d30ea906Sjfb8856606 			if (rc < 0)
460d30ea906Sjfb8856606 				return -EINVAL;
461d30ea906Sjfb8856606 			n_lsbs = rc;
462d30ea906Sjfb8856606 		}
463d30ea906Sjfb8856606 	}
464d30ea906Sjfb8856606 
465d30ea906Sjfb8856606 	rc = 0;
466d30ea906Sjfb8856606 	/* What's left of the LSBs, according to the public mask, now become
467d30ea906Sjfb8856606 	 * shared. Any zero bits in the lsb_pub mask represent an LSB region
468d30ea906Sjfb8856606 	 * that can't be used as a shared resource, so mark the LSB slots for
469d30ea906Sjfb8856606 	 * them as "in use".
470d30ea906Sjfb8856606 	 */
471d30ea906Sjfb8856606 	qlsb = lsb_pub;
472d30ea906Sjfb8856606 	bitno = ccp_find_first_zero_bit(&qlsb, MAX_LSB_CNT);
473d30ea906Sjfb8856606 	while (bitno < MAX_LSB_CNT) {
474d30ea906Sjfb8856606 		ccp_bitmap_set(ccp->lsbmap, bitno * LSB_SIZE, LSB_SIZE);
475d30ea906Sjfb8856606 		ccp_set_bit(&qlsb, bitno);
476d30ea906Sjfb8856606 		bitno = ccp_find_first_zero_bit(&qlsb, MAX_LSB_CNT);
477d30ea906Sjfb8856606 	}
478d30ea906Sjfb8856606 
479d30ea906Sjfb8856606 	return rc;
480d30ea906Sjfb8856606 }
481d30ea906Sjfb8856606 
482d30ea906Sjfb8856606 static int
ccp_add_device(struct ccp_device * dev,int type)483d30ea906Sjfb8856606 ccp_add_device(struct ccp_device *dev, int type)
484d30ea906Sjfb8856606 {
485d30ea906Sjfb8856606 	int i;
486d30ea906Sjfb8856606 	uint32_t qmr, status_lo, status_hi, dma_addr_lo, dma_addr_hi;
487d30ea906Sjfb8856606 	uint64_t status;
488d30ea906Sjfb8856606 	struct ccp_queue *cmd_q;
489d30ea906Sjfb8856606 	const struct rte_memzone *q_mz;
490d30ea906Sjfb8856606 	void *vaddr;
491d30ea906Sjfb8856606 
492d30ea906Sjfb8856606 	if (dev == NULL)
493d30ea906Sjfb8856606 		return -1;
494d30ea906Sjfb8856606 
495d30ea906Sjfb8856606 	dev->id = ccp_dev_id++;
496d30ea906Sjfb8856606 	dev->qidx = 0;
497d30ea906Sjfb8856606 	vaddr = (void *)(dev->pci.mem_resource[2].addr);
498d30ea906Sjfb8856606 
499d30ea906Sjfb8856606 	if (type == CCP_VERSION_5B) {
500d30ea906Sjfb8856606 		CCP_WRITE_REG(vaddr, CMD_TRNG_CTL_OFFSET, 0x00012D57);
501d30ea906Sjfb8856606 		CCP_WRITE_REG(vaddr, CMD_CONFIG_0_OFFSET, 0x00000003);
502d30ea906Sjfb8856606 		for (i = 0; i < 12; i++) {
503d30ea906Sjfb8856606 			CCP_WRITE_REG(vaddr, CMD_AES_MASK_OFFSET,
504d30ea906Sjfb8856606 				      CCP_READ_REG(vaddr, TRNG_OUT_REG));
505d30ea906Sjfb8856606 		}
506d30ea906Sjfb8856606 		CCP_WRITE_REG(vaddr, CMD_QUEUE_MASK_OFFSET, 0x0000001F);
507d30ea906Sjfb8856606 		CCP_WRITE_REG(vaddr, CMD_QUEUE_PRIO_OFFSET, 0x00005B6D);
508d30ea906Sjfb8856606 		CCP_WRITE_REG(vaddr, CMD_CMD_TIMEOUT_OFFSET, 0x00000000);
509d30ea906Sjfb8856606 
510d30ea906Sjfb8856606 		CCP_WRITE_REG(vaddr, LSB_PRIVATE_MASK_LO_OFFSET, 0x3FFFFFFF);
511d30ea906Sjfb8856606 		CCP_WRITE_REG(vaddr, LSB_PRIVATE_MASK_HI_OFFSET, 0x000003FF);
512d30ea906Sjfb8856606 
513d30ea906Sjfb8856606 		CCP_WRITE_REG(vaddr, CMD_CLK_GATE_CTL_OFFSET, 0x00108823);
514d30ea906Sjfb8856606 	}
515d30ea906Sjfb8856606 	CCP_WRITE_REG(vaddr, CMD_REQID_CONFIG_OFFSET, 0x00001249);
516d30ea906Sjfb8856606 
517d30ea906Sjfb8856606 	/* Copy the private LSB mask to the public registers */
518d30ea906Sjfb8856606 	status_lo = CCP_READ_REG(vaddr, LSB_PRIVATE_MASK_LO_OFFSET);
519d30ea906Sjfb8856606 	status_hi = CCP_READ_REG(vaddr, LSB_PRIVATE_MASK_HI_OFFSET);
520d30ea906Sjfb8856606 	CCP_WRITE_REG(vaddr, LSB_PUBLIC_MASK_LO_OFFSET, status_lo);
521d30ea906Sjfb8856606 	CCP_WRITE_REG(vaddr, LSB_PUBLIC_MASK_HI_OFFSET, status_hi);
522d30ea906Sjfb8856606 	status = ((uint64_t)status_hi<<30) | ((uint64_t)status_lo);
523d30ea906Sjfb8856606 
524d30ea906Sjfb8856606 	dev->cmd_q_count = 0;
525d30ea906Sjfb8856606 	/* Find available queues */
526d30ea906Sjfb8856606 	qmr = CCP_READ_REG(vaddr, Q_MASK_REG);
527d30ea906Sjfb8856606 	for (i = 0; i < MAX_HW_QUEUES; i++) {
528d30ea906Sjfb8856606 		if (!(qmr & (1 << i)))
529d30ea906Sjfb8856606 			continue;
530d30ea906Sjfb8856606 		cmd_q = &dev->cmd_q[dev->cmd_q_count++];
531d30ea906Sjfb8856606 		cmd_q->dev = dev;
532d30ea906Sjfb8856606 		cmd_q->id = i;
533d30ea906Sjfb8856606 		cmd_q->qidx = 0;
534d30ea906Sjfb8856606 		cmd_q->qsize = Q_SIZE(Q_DESC_SIZE);
535d30ea906Sjfb8856606 
536d30ea906Sjfb8856606 		cmd_q->reg_base = (uint8_t *)vaddr +
537d30ea906Sjfb8856606 			CMD_Q_STATUS_INCR * (i + 1);
538d30ea906Sjfb8856606 
539d30ea906Sjfb8856606 		/* CCP queue memory */
540d30ea906Sjfb8856606 		snprintf(cmd_q->memz_name, sizeof(cmd_q->memz_name),
541d30ea906Sjfb8856606 			 "%s_%d_%s_%d_%s",
542d30ea906Sjfb8856606 			 "ccp_dev",
543d30ea906Sjfb8856606 			 (int)dev->id, "queue",
544d30ea906Sjfb8856606 			 (int)cmd_q->id, "mem");
545d30ea906Sjfb8856606 		q_mz = ccp_queue_dma_zone_reserve(cmd_q->memz_name,
546d30ea906Sjfb8856606 						  cmd_q->qsize, SOCKET_ID_ANY);
547d30ea906Sjfb8856606 		cmd_q->qbase_addr = (void *)q_mz->addr;
548d30ea906Sjfb8856606 		cmd_q->qbase_desc = (void *)q_mz->addr;
549*2d9fd380Sjfb8856606 		cmd_q->qbase_phys_addr =  q_mz->iova;
550d30ea906Sjfb8856606 
551d30ea906Sjfb8856606 		cmd_q->qcontrol = 0;
552d30ea906Sjfb8856606 		/* init control reg to zero */
553d30ea906Sjfb8856606 		CCP_WRITE_REG(cmd_q->reg_base, CMD_Q_CONTROL_BASE,
554d30ea906Sjfb8856606 			      cmd_q->qcontrol);
555d30ea906Sjfb8856606 
556d30ea906Sjfb8856606 		/* Disable the interrupts */
557d30ea906Sjfb8856606 		CCP_WRITE_REG(cmd_q->reg_base, CMD_Q_INT_ENABLE_BASE, 0x00);
558d30ea906Sjfb8856606 		CCP_READ_REG(cmd_q->reg_base, CMD_Q_INT_STATUS_BASE);
559d30ea906Sjfb8856606 		CCP_READ_REG(cmd_q->reg_base, CMD_Q_STATUS_BASE);
560d30ea906Sjfb8856606 
561d30ea906Sjfb8856606 		/* Clear the interrupts */
562d30ea906Sjfb8856606 		CCP_WRITE_REG(cmd_q->reg_base, CMD_Q_INTERRUPT_STATUS_BASE,
563d30ea906Sjfb8856606 			      ALL_INTERRUPTS);
564d30ea906Sjfb8856606 
565d30ea906Sjfb8856606 		/* Configure size of each virtual queue accessible to host */
566d30ea906Sjfb8856606 		cmd_q->qcontrol &= ~(CMD_Q_SIZE << CMD_Q_SHIFT);
567d30ea906Sjfb8856606 		cmd_q->qcontrol |= QUEUE_SIZE_VAL << CMD_Q_SHIFT;
568d30ea906Sjfb8856606 
569d30ea906Sjfb8856606 		dma_addr_lo = low32_value(cmd_q->qbase_phys_addr);
570d30ea906Sjfb8856606 		CCP_WRITE_REG(cmd_q->reg_base, CMD_Q_TAIL_LO_BASE,
571d30ea906Sjfb8856606 			      (uint32_t)dma_addr_lo);
572d30ea906Sjfb8856606 		CCP_WRITE_REG(cmd_q->reg_base, CMD_Q_HEAD_LO_BASE,
573d30ea906Sjfb8856606 			      (uint32_t)dma_addr_lo);
574d30ea906Sjfb8856606 
575d30ea906Sjfb8856606 		dma_addr_hi = high32_value(cmd_q->qbase_phys_addr);
576d30ea906Sjfb8856606 		cmd_q->qcontrol |= (dma_addr_hi << 16);
577d30ea906Sjfb8856606 		CCP_WRITE_REG(cmd_q->reg_base, CMD_Q_CONTROL_BASE,
578d30ea906Sjfb8856606 			      cmd_q->qcontrol);
579d30ea906Sjfb8856606 
580d30ea906Sjfb8856606 		/* create LSB Mask map */
581d30ea906Sjfb8856606 		if (ccp_find_lsb_regions(cmd_q, status))
582d30ea906Sjfb8856606 			CCP_LOG_ERR("queue doesn't have lsb regions");
583d30ea906Sjfb8856606 		cmd_q->lsb = -1;
584d30ea906Sjfb8856606 
585d30ea906Sjfb8856606 		rte_atomic64_init(&cmd_q->free_slots);
586d30ea906Sjfb8856606 		rte_atomic64_set(&cmd_q->free_slots, (COMMANDS_PER_QUEUE - 1));
587d30ea906Sjfb8856606 		/* unused slot barrier b/w H&T */
588d30ea906Sjfb8856606 	}
589d30ea906Sjfb8856606 
590d30ea906Sjfb8856606 	if (ccp_assign_lsbs(dev))
591d30ea906Sjfb8856606 		CCP_LOG_ERR("Unable to assign lsb region");
592d30ea906Sjfb8856606 
593d30ea906Sjfb8856606 	/* pre-allocate LSB slots */
594d30ea906Sjfb8856606 	for (i = 0; i < dev->cmd_q_count; i++) {
595d30ea906Sjfb8856606 		dev->cmd_q[i].sb_key =
596d30ea906Sjfb8856606 			ccp_lsb_alloc(&dev->cmd_q[i], 1);
597d30ea906Sjfb8856606 		dev->cmd_q[i].sb_iv =
598d30ea906Sjfb8856606 			ccp_lsb_alloc(&dev->cmd_q[i], 1);
599d30ea906Sjfb8856606 		dev->cmd_q[i].sb_sha =
600d30ea906Sjfb8856606 			ccp_lsb_alloc(&dev->cmd_q[i], 2);
601d30ea906Sjfb8856606 		dev->cmd_q[i].sb_hmac =
602d30ea906Sjfb8856606 			ccp_lsb_alloc(&dev->cmd_q[i], 2);
603d30ea906Sjfb8856606 	}
604d30ea906Sjfb8856606 
605d30ea906Sjfb8856606 	TAILQ_INSERT_TAIL(&ccp_list, dev, next);
606d30ea906Sjfb8856606 	return 0;
607d30ea906Sjfb8856606 }
608d30ea906Sjfb8856606 
609d30ea906Sjfb8856606 static void
ccp_remove_device(struct ccp_device * dev)610d30ea906Sjfb8856606 ccp_remove_device(struct ccp_device *dev)
611d30ea906Sjfb8856606 {
612d30ea906Sjfb8856606 	if (dev == NULL)
613d30ea906Sjfb8856606 		return;
614d30ea906Sjfb8856606 
615d30ea906Sjfb8856606 	TAILQ_REMOVE(&ccp_list, dev, next);
616d30ea906Sjfb8856606 }
617d30ea906Sjfb8856606 
618d30ea906Sjfb8856606 static int
is_ccp_device(const char * dirname,const struct rte_pci_id * ccp_id,int * type)619d30ea906Sjfb8856606 is_ccp_device(const char *dirname,
620d30ea906Sjfb8856606 	      const struct rte_pci_id *ccp_id,
621d30ea906Sjfb8856606 	      int *type)
622d30ea906Sjfb8856606 {
623d30ea906Sjfb8856606 	char filename[PATH_MAX];
624d30ea906Sjfb8856606 	const struct rte_pci_id *id;
625d30ea906Sjfb8856606 	uint16_t vendor, device_id;
626d30ea906Sjfb8856606 	int i;
627d30ea906Sjfb8856606 	unsigned long tmp;
628d30ea906Sjfb8856606 
629d30ea906Sjfb8856606 	/* get vendor id */
630d30ea906Sjfb8856606 	snprintf(filename, sizeof(filename), "%s/vendor", dirname);
631d30ea906Sjfb8856606 	if (ccp_pci_parse_sysfs_value(filename, &tmp) < 0)
632d30ea906Sjfb8856606 		return 0;
633d30ea906Sjfb8856606 	vendor = (uint16_t)tmp;
634d30ea906Sjfb8856606 
635d30ea906Sjfb8856606 	/* get device id */
636d30ea906Sjfb8856606 	snprintf(filename, sizeof(filename), "%s/device", dirname);
637d30ea906Sjfb8856606 	if (ccp_pci_parse_sysfs_value(filename, &tmp) < 0)
638d30ea906Sjfb8856606 		return 0;
639d30ea906Sjfb8856606 	device_id = (uint16_t)tmp;
640d30ea906Sjfb8856606 
641d30ea906Sjfb8856606 	for (id = ccp_id, i = 0; id->vendor_id != 0; id++, i++) {
642d30ea906Sjfb8856606 		if (vendor == id->vendor_id &&
643d30ea906Sjfb8856606 		    device_id == id->device_id) {
644d30ea906Sjfb8856606 			*type = i;
645d30ea906Sjfb8856606 			return 1; /* Matched device */
646d30ea906Sjfb8856606 		}
647d30ea906Sjfb8856606 	}
648d30ea906Sjfb8856606 	return 0;
649d30ea906Sjfb8856606 }
650d30ea906Sjfb8856606 
651d30ea906Sjfb8856606 static int
ccp_probe_device(const char * dirname,uint16_t domain,uint8_t bus,uint8_t devid,uint8_t function,int ccp_type)652d30ea906Sjfb8856606 ccp_probe_device(const char *dirname, uint16_t domain,
653d30ea906Sjfb8856606 		 uint8_t bus, uint8_t devid,
654d30ea906Sjfb8856606 		 uint8_t function, int ccp_type)
655d30ea906Sjfb8856606 {
656d30ea906Sjfb8856606 	struct ccp_device *ccp_dev = NULL;
657d30ea906Sjfb8856606 	struct rte_pci_device *pci;
658d30ea906Sjfb8856606 	char filename[PATH_MAX];
659d30ea906Sjfb8856606 	unsigned long tmp;
660d30ea906Sjfb8856606 	int uio_fd = -1, i, uio_num;
661d30ea906Sjfb8856606 	char uio_devname[PATH_MAX];
662d30ea906Sjfb8856606 	void *map_addr;
663d30ea906Sjfb8856606 
664d30ea906Sjfb8856606 	ccp_dev = rte_zmalloc("ccp_device", sizeof(*ccp_dev),
665d30ea906Sjfb8856606 			      RTE_CACHE_LINE_SIZE);
666d30ea906Sjfb8856606 	if (ccp_dev == NULL)
667d30ea906Sjfb8856606 		goto fail;
668d30ea906Sjfb8856606 	pci = &(ccp_dev->pci);
669d30ea906Sjfb8856606 
670d30ea906Sjfb8856606 	pci->addr.domain = domain;
671d30ea906Sjfb8856606 	pci->addr.bus = bus;
672d30ea906Sjfb8856606 	pci->addr.devid = devid;
673d30ea906Sjfb8856606 	pci->addr.function = function;
674d30ea906Sjfb8856606 
675d30ea906Sjfb8856606 	/* get vendor id */
676d30ea906Sjfb8856606 	snprintf(filename, sizeof(filename), "%s/vendor", dirname);
677d30ea906Sjfb8856606 	if (ccp_pci_parse_sysfs_value(filename, &tmp) < 0)
678d30ea906Sjfb8856606 		goto fail;
679d30ea906Sjfb8856606 	pci->id.vendor_id = (uint16_t)tmp;
680d30ea906Sjfb8856606 
681d30ea906Sjfb8856606 	/* get device id */
682d30ea906Sjfb8856606 	snprintf(filename, sizeof(filename), "%s/device", dirname);
683d30ea906Sjfb8856606 	if (ccp_pci_parse_sysfs_value(filename, &tmp) < 0)
684d30ea906Sjfb8856606 		goto fail;
685d30ea906Sjfb8856606 	pci->id.device_id = (uint16_t)tmp;
686d30ea906Sjfb8856606 
687d30ea906Sjfb8856606 	/* get subsystem_vendor id */
688d30ea906Sjfb8856606 	snprintf(filename, sizeof(filename), "%s/subsystem_vendor",
689d30ea906Sjfb8856606 			dirname);
690d30ea906Sjfb8856606 	if (ccp_pci_parse_sysfs_value(filename, &tmp) < 0)
691d30ea906Sjfb8856606 		goto fail;
692d30ea906Sjfb8856606 	pci->id.subsystem_vendor_id = (uint16_t)tmp;
693d30ea906Sjfb8856606 
694d30ea906Sjfb8856606 	/* get subsystem_device id */
695d30ea906Sjfb8856606 	snprintf(filename, sizeof(filename), "%s/subsystem_device",
696d30ea906Sjfb8856606 			dirname);
697d30ea906Sjfb8856606 	if (ccp_pci_parse_sysfs_value(filename, &tmp) < 0)
698d30ea906Sjfb8856606 		goto fail;
699d30ea906Sjfb8856606 	pci->id.subsystem_device_id = (uint16_t)tmp;
700d30ea906Sjfb8856606 
701d30ea906Sjfb8856606 	/* get class_id */
702d30ea906Sjfb8856606 	snprintf(filename, sizeof(filename), "%s/class",
703d30ea906Sjfb8856606 			dirname);
704d30ea906Sjfb8856606 	if (ccp_pci_parse_sysfs_value(filename, &tmp) < 0)
705d30ea906Sjfb8856606 		goto fail;
706d30ea906Sjfb8856606 	/* the least 24 bits are valid: class, subclass, program interface */
707d30ea906Sjfb8856606 	pci->id.class_id = (uint32_t)tmp & RTE_CLASS_ANY_ID;
708d30ea906Sjfb8856606 
709d30ea906Sjfb8856606 	/* parse resources */
710d30ea906Sjfb8856606 	snprintf(filename, sizeof(filename), "%s/resource", dirname);
711d30ea906Sjfb8856606 	if (ccp_pci_parse_sysfs_resource(filename, pci) < 0)
712d30ea906Sjfb8856606 		goto fail;
713d30ea906Sjfb8856606 
714d30ea906Sjfb8856606 	uio_num = ccp_find_uio_devname(dirname);
715d30ea906Sjfb8856606 	if (uio_num < 0) {
716d30ea906Sjfb8856606 		/*
717d30ea906Sjfb8856606 		 * It may take time for uio device to appear,
718d30ea906Sjfb8856606 		 * wait  here and try again
719d30ea906Sjfb8856606 		 */
720d30ea906Sjfb8856606 		usleep(100000);
721d30ea906Sjfb8856606 		uio_num = ccp_find_uio_devname(dirname);
722d30ea906Sjfb8856606 		if (uio_num < 0)
723d30ea906Sjfb8856606 			goto fail;
724d30ea906Sjfb8856606 	}
725d30ea906Sjfb8856606 	snprintf(uio_devname, sizeof(uio_devname), "/dev/uio%u", uio_num);
726d30ea906Sjfb8856606 
727d30ea906Sjfb8856606 	uio_fd = open(uio_devname, O_RDWR | O_NONBLOCK);
728d30ea906Sjfb8856606 	if (uio_fd < 0)
729d30ea906Sjfb8856606 		goto fail;
730d30ea906Sjfb8856606 	if (flock(uio_fd, LOCK_EX | LOCK_NB))
731d30ea906Sjfb8856606 		goto fail;
732d30ea906Sjfb8856606 
733d30ea906Sjfb8856606 	/* Map the PCI memory resource of device */
734d30ea906Sjfb8856606 	for (i = 0; i < PCI_MAX_RESOURCE; i++) {
735d30ea906Sjfb8856606 
736d30ea906Sjfb8856606 		char devname[PATH_MAX];
737d30ea906Sjfb8856606 		int res_fd;
738d30ea906Sjfb8856606 
739d30ea906Sjfb8856606 		if (pci->mem_resource[i].phys_addr == 0)
740d30ea906Sjfb8856606 			continue;
741d30ea906Sjfb8856606 		snprintf(devname, sizeof(devname), "%s/resource%d", dirname, i);
742d30ea906Sjfb8856606 		res_fd = open(devname, O_RDWR);
743d30ea906Sjfb8856606 		if (res_fd < 0)
744d30ea906Sjfb8856606 			goto fail;
745d30ea906Sjfb8856606 		map_addr = mmap(NULL, pci->mem_resource[i].len,
746d30ea906Sjfb8856606 				PROT_READ | PROT_WRITE,
747d30ea906Sjfb8856606 				MAP_SHARED, res_fd, 0);
748d30ea906Sjfb8856606 		if (map_addr == MAP_FAILED)
749d30ea906Sjfb8856606 			goto fail;
750d30ea906Sjfb8856606 
751d30ea906Sjfb8856606 		pci->mem_resource[i].addr = map_addr;
752d30ea906Sjfb8856606 	}
753d30ea906Sjfb8856606 
754d30ea906Sjfb8856606 	/* device is valid, add in list */
755d30ea906Sjfb8856606 	if (ccp_add_device(ccp_dev, ccp_type)) {
756d30ea906Sjfb8856606 		ccp_remove_device(ccp_dev);
757d30ea906Sjfb8856606 		goto fail;
758d30ea906Sjfb8856606 	}
759d30ea906Sjfb8856606 
760d30ea906Sjfb8856606 	return 0;
761d30ea906Sjfb8856606 fail:
762d30ea906Sjfb8856606 	CCP_LOG_ERR("CCP Device probe failed");
7630c6bd470Sfengbojiang 	if (uio_fd >= 0)
764d30ea906Sjfb8856606 		close(uio_fd);
765d30ea906Sjfb8856606 	if (ccp_dev)
766d30ea906Sjfb8856606 		rte_free(ccp_dev);
767d30ea906Sjfb8856606 	return -1;
768d30ea906Sjfb8856606 }
769d30ea906Sjfb8856606 
770d30ea906Sjfb8856606 int
ccp_probe_devices(const struct rte_pci_id * ccp_id)771d30ea906Sjfb8856606 ccp_probe_devices(const struct rte_pci_id *ccp_id)
772d30ea906Sjfb8856606 {
773d30ea906Sjfb8856606 	int dev_cnt = 0;
774d30ea906Sjfb8856606 	int ccp_type = 0;
775d30ea906Sjfb8856606 	struct dirent *d;
776d30ea906Sjfb8856606 	DIR *dir;
777d30ea906Sjfb8856606 	int ret = 0;
778d30ea906Sjfb8856606 	int module_idx = 0;
779d30ea906Sjfb8856606 	uint16_t domain;
780d30ea906Sjfb8856606 	uint8_t bus, devid, function;
781d30ea906Sjfb8856606 	char dirname[PATH_MAX];
782d30ea906Sjfb8856606 
783d30ea906Sjfb8856606 	module_idx = ccp_check_pci_uio_module();
784d30ea906Sjfb8856606 	if (module_idx < 0)
785d30ea906Sjfb8856606 		return -1;
786d30ea906Sjfb8856606 
787d30ea906Sjfb8856606 	TAILQ_INIT(&ccp_list);
788d30ea906Sjfb8856606 	dir = opendir(SYSFS_PCI_DEVICES);
789d30ea906Sjfb8856606 	if (dir == NULL)
790d30ea906Sjfb8856606 		return -1;
791d30ea906Sjfb8856606 	while ((d = readdir(dir)) != NULL) {
792d30ea906Sjfb8856606 		if (d->d_name[0] == '.')
793d30ea906Sjfb8856606 			continue;
794d30ea906Sjfb8856606 		if (ccp_parse_pci_addr_format(d->d_name, sizeof(d->d_name),
795d30ea906Sjfb8856606 					&domain, &bus, &devid, &function) != 0)
796d30ea906Sjfb8856606 			continue;
797d30ea906Sjfb8856606 		snprintf(dirname, sizeof(dirname), "%s/%s",
798d30ea906Sjfb8856606 			     SYSFS_PCI_DEVICES, d->d_name);
799d30ea906Sjfb8856606 		if (is_ccp_device(dirname, ccp_id, &ccp_type)) {
800d30ea906Sjfb8856606 			printf("CCP : Detected CCP device with ID = 0x%x\n",
801d30ea906Sjfb8856606 			       ccp_id[ccp_type].device_id);
802d30ea906Sjfb8856606 			ret = ccp_probe_device(dirname, domain, bus, devid,
803d30ea906Sjfb8856606 					       function, ccp_type);
804d30ea906Sjfb8856606 			if (ret == 0)
805d30ea906Sjfb8856606 				dev_cnt++;
806d30ea906Sjfb8856606 		}
807d30ea906Sjfb8856606 	}
808d30ea906Sjfb8856606 	closedir(dir);
809d30ea906Sjfb8856606 	return dev_cnt;
810d30ea906Sjfb8856606 }
811