1 /*
2  * Copyright (c) 2015-2016 Quantenna Communications, Inc.
3  * All rights reserved.
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  */
16 
17 #include "util.h"
18 #include "qtn_hw_ids.h"
19 
20 void qtnf_sta_list_init(struct qtnf_sta_list *list)
21 {
22 	if (unlikely(!list))
23 		return;
24 
25 	INIT_LIST_HEAD(&list->head);
26 	atomic_set(&list->size, 0);
27 }
28 
29 struct qtnf_sta_node *qtnf_sta_list_lookup(struct qtnf_sta_list *list,
30 					   const u8 *mac)
31 {
32 	struct qtnf_sta_node *node;
33 
34 	if (unlikely(!mac))
35 		return NULL;
36 
37 	list_for_each_entry(node, &list->head, list) {
38 		if (ether_addr_equal(node->mac_addr, mac))
39 			return node;
40 	}
41 
42 	return NULL;
43 }
44 
45 struct qtnf_sta_node *qtnf_sta_list_lookup_index(struct qtnf_sta_list *list,
46 						 size_t index)
47 {
48 	struct qtnf_sta_node *node;
49 
50 	if (qtnf_sta_list_size(list) <= index)
51 		return NULL;
52 
53 	list_for_each_entry(node, &list->head, list) {
54 		if (index-- == 0)
55 			return node;
56 	}
57 
58 	return NULL;
59 }
60 
61 struct qtnf_sta_node *qtnf_sta_list_add(struct qtnf_vif *vif,
62 					const u8 *mac)
63 {
64 	struct qtnf_sta_list *list = &vif->sta_list;
65 	struct qtnf_sta_node *node;
66 
67 	if (unlikely(!mac))
68 		return NULL;
69 
70 	node = qtnf_sta_list_lookup(list, mac);
71 
72 	if (node)
73 		goto done;
74 
75 	node = kzalloc(sizeof(*node), GFP_KERNEL);
76 	if (unlikely(!node))
77 		goto done;
78 
79 	ether_addr_copy(node->mac_addr, mac);
80 	list_add_tail(&node->list, &list->head);
81 	atomic_inc(&list->size);
82 	++vif->generation;
83 
84 done:
85 	return node;
86 }
87 
88 bool qtnf_sta_list_del(struct qtnf_vif *vif, const u8 *mac)
89 {
90 	struct qtnf_sta_list *list = &vif->sta_list;
91 	struct qtnf_sta_node *node;
92 	bool ret = false;
93 
94 	node = qtnf_sta_list_lookup(list, mac);
95 
96 	if (node) {
97 		list_del(&node->list);
98 		atomic_dec(&list->size);
99 		kfree(node);
100 		++vif->generation;
101 		ret = true;
102 	}
103 
104 	return ret;
105 }
106 
107 void qtnf_sta_list_free(struct qtnf_sta_list *list)
108 {
109 	struct qtnf_sta_node *node, *tmp;
110 
111 	atomic_set(&list->size, 0);
112 
113 	list_for_each_entry_safe(node, tmp, &list->head, list) {
114 		list_del(&node->list);
115 		kfree(node);
116 	}
117 
118 	INIT_LIST_HEAD(&list->head);
119 }
120 
121 const char *qtnf_chipid_to_string(unsigned long chip_id)
122 {
123 	switch (chip_id) {
124 	case QTN_CHIP_ID_TOPAZ:
125 		return "Topaz";
126 	case QTN_CHIP_ID_PEARL:
127 		return "Pearl revA";
128 	case QTN_CHIP_ID_PEARL_B:
129 		return "Pearl revB";
130 	case QTN_CHIP_ID_PEARL_C:
131 		return "Pearl revC";
132 	default:
133 		return "unknown";
134 	}
135 }
136 EXPORT_SYMBOL_GPL(qtnf_chipid_to_string);
137