1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60#include <linux/kernel.h>
61#include <linux/bsearch.h>
62
63#include "iwl-trans.h"
64#include "iwl-drv.h"
65#include "iwl-fh.h"
66
67struct iwl_trans *iwl_trans_alloc(unsigned int priv_size,
68 struct device *dev,
69 const struct iwl_cfg *cfg,
70 const struct iwl_trans_ops *ops)
71{
72 struct iwl_trans *trans;
73#ifdef CONFIG_LOCKDEP
74 static struct lock_class_key __key;
75#endif
76
77 trans = devm_kzalloc(dev, sizeof(*trans) + priv_size, GFP_KERNEL);
78 if (!trans)
79 return NULL;
80
81#ifdef CONFIG_LOCKDEP
82 lockdep_init_map(&trans->sync_cmd_lockdep_map, "sync_cmd_lockdep_map",
83 &__key, 0);
84#endif
85
86 trans->dev = dev;
87 trans->cfg = cfg;
88 trans->ops = ops;
89 trans->num_rx_queues = 1;
90
91 snprintf(trans->dev_cmd_pool_name, sizeof(trans->dev_cmd_pool_name),
92 "iwl_cmd_pool:%s", dev_name(trans->dev));
93 trans->dev_cmd_pool =
94 kmem_cache_create(trans->dev_cmd_pool_name,
95 sizeof(struct iwl_device_cmd),
96 sizeof(void *),
97 SLAB_HWCACHE_ALIGN,
98 NULL);
99 if (!trans->dev_cmd_pool)
100 return NULL;
101
102 WARN_ON(!ops->wait_txq_empty && !ops->wait_tx_queues_empty);
103
104 return trans;
105}
106
107void iwl_trans_free(struct iwl_trans *trans)
108{
109 kmem_cache_destroy(trans->dev_cmd_pool);
110}
111
112int iwl_trans_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
113{
114 int ret;
115
116 if (unlikely(!(cmd->flags & CMD_SEND_IN_RFKILL) &&
117 test_bit(STATUS_RFKILL_OPMODE, &trans->status)))
118 return -ERFKILL;
119
120 if (unlikely(test_bit(STATUS_FW_ERROR, &trans->status)))
121 return -EIO;
122
123 if (unlikely(trans->state != IWL_TRANS_FW_ALIVE)) {
124 IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state);
125 return -EIO;
126 }
127
128 if (WARN_ON((cmd->flags & CMD_WANT_ASYNC_CALLBACK) &&
129 !(cmd->flags & CMD_ASYNC)))
130 return -EINVAL;
131
132 if (!(cmd->flags & CMD_ASYNC))
133 lock_map_acquire_read(&trans->sync_cmd_lockdep_map);
134
135 if (trans->wide_cmd_header && !iwl_cmd_groupid(cmd->id))
136 cmd->id = DEF_ID(cmd->id);
137
138 ret = trans->ops->send_cmd(trans, cmd);
139
140 if (!(cmd->flags & CMD_ASYNC))
141 lock_map_release(&trans->sync_cmd_lockdep_map);
142
143 if (WARN_ON((cmd->flags & CMD_WANT_SKB) && !ret && !cmd->resp_pkt))
144 return -EIO;
145
146 return ret;
147}
148IWL_EXPORT_SYMBOL(iwl_trans_send_cmd);
149
150
151
152
153
154
155
156
157
158static int iwl_hcmd_names_cmp(const void *key, const void *elt)
159{
160 const struct iwl_hcmd_names *name = elt;
161 u8 cmd1 = *(u8 *)key;
162 u8 cmd2 = name->cmd_id;
163
164 return (cmd1 - cmd2);
165}
166
167const char *iwl_get_cmd_string(struct iwl_trans *trans, u32 id)
168{
169 u8 grp, cmd;
170 struct iwl_hcmd_names *ret;
171 const struct iwl_hcmd_arr *arr;
172 size_t size = sizeof(struct iwl_hcmd_names);
173
174 grp = iwl_cmd_groupid(id);
175 cmd = iwl_cmd_opcode(id);
176
177 if (!trans->command_groups || grp >= trans->command_groups_size ||
178 !trans->command_groups[grp].arr)
179 return "UNKNOWN";
180
181 arr = &trans->command_groups[grp];
182 ret = bsearch(&cmd, arr->arr, arr->size, size, iwl_hcmd_names_cmp);
183 if (!ret)
184 return "UNKNOWN";
185 return ret->cmd_name;
186}
187IWL_EXPORT_SYMBOL(iwl_get_cmd_string);
188
189int iwl_cmd_groups_verify_sorted(const struct iwl_trans_config *trans)
190{
191 int i, j;
192 const struct iwl_hcmd_arr *arr;
193
194 for (i = 0; i < trans->command_groups_size; i++) {
195 arr = &trans->command_groups[i];
196 if (!arr->arr)
197 continue;
198 for (j = 0; j < arr->size - 1; j++)
199 if (arr->arr[j].cmd_id > arr->arr[j + 1].cmd_id)
200 return -1;
201 }
202 return 0;
203}
204IWL_EXPORT_SYMBOL(iwl_cmd_groups_verify_sorted);
205
206void iwl_trans_ref(struct iwl_trans *trans)
207{
208 if (trans->ops->ref)
209 trans->ops->ref(trans);
210}
211IWL_EXPORT_SYMBOL(iwl_trans_ref);
212
213void iwl_trans_unref(struct iwl_trans *trans)
214{
215 if (trans->ops->unref)
216 trans->ops->unref(trans);
217}
218IWL_EXPORT_SYMBOL(iwl_trans_unref);
219