Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
reset.c
Go to the documentation of this file.
1 /*
2  * Ultra Wide Band
3  * UWB basic command support and radio reset
4  *
5  * Copyright (C) 2005-2006 Intel Corporation
6  * Inaky Perez-Gonzalez <[email protected]>
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License version
10  * 2 as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20  * 02110-1301, USA.
21  *
22  *
23  * FIXME:
24  *
25  * - docs
26  *
27  * - Now we are serializing (using the uwb_dev->mutex) the command
28  * execution; it should be parallelized as much as possible some
29  * day.
30  */
31 #include <linux/kernel.h>
32 #include <linux/err.h>
33 #include <linux/slab.h>
34 #include <linux/delay.h>
35 #include <linux/export.h>
36 
37 #include "uwb-internal.h"
38 
42 static
43 const char *__strerror[] = {
44  "success",
45  "failure",
46  "hardware failure",
47  "no more slots",
48  "beacon is too large",
49  "invalid parameter",
50  "unsupported power level",
51  "time out (wa) or invalid ie data (whci)",
52  "beacon size exceeded",
53  "cancelled",
54  "invalid state",
55  "invalid size",
56  "ack not received",
57  "no more asie notification",
58 };
59 
60 
62 const char *uwb_rc_strerror(unsigned code)
63 {
64  if (code == 255)
65  return "time out";
66  if (code >= ARRAY_SIZE(__strerror))
67  return "unknown error";
68  return __strerror[code];
69 }
70 
71 int uwb_rc_cmd_async(struct uwb_rc *rc, const char *cmd_name,
72  struct uwb_rccb *cmd, size_t cmd_size,
73  u8 expected_type, u16 expected_event,
74  uwb_rc_cmd_cb_f cb, void *arg)
75 {
76  struct device *dev = &rc->uwb_dev.dev;
77  struct uwb_rc_neh *neh;
78  int needtofree = 0;
79  int result;
80 
81  uwb_dev_lock(&rc->uwb_dev); /* Protect against rc->priv being removed */
82  if (rc->priv == NULL) {
83  uwb_dev_unlock(&rc->uwb_dev);
84  return -ESHUTDOWN;
85  }
86 
87  if (rc->filter_cmd) {
88  needtofree = rc->filter_cmd(rc, &cmd, &cmd_size);
89  if (needtofree < 0 && needtofree != -ENOANO) {
90  dev_err(dev, "%s: filter error: %d\n",
91  cmd_name, needtofree);
92  uwb_dev_unlock(&rc->uwb_dev);
93  return needtofree;
94  }
95  }
96 
97  neh = uwb_rc_neh_add(rc, cmd, expected_type, expected_event, cb, arg);
98  if (IS_ERR(neh)) {
99  result = PTR_ERR(neh);
100  goto out;
101  }
102 
103  result = rc->cmd(rc, cmd, cmd_size);
104  uwb_dev_unlock(&rc->uwb_dev);
105  if (result < 0)
106  uwb_rc_neh_rm(rc, neh);
107  else
108  uwb_rc_neh_arm(rc, neh);
109  uwb_rc_neh_put(neh);
110 out:
111  if (needtofree == 1)
112  kfree(cmd);
113  return result < 0 ? result : 0;
114 }
116 
119  struct uwb_rceb *reply;
121 };
122 
123 static void uwb_rc_cmd_done(struct uwb_rc *rc, void *arg,
124  struct uwb_rceb *reply, ssize_t reply_size)
125 {
126  struct uwb_rc_cmd_done_params *p = (struct uwb_rc_cmd_done_params *)arg;
127 
128  if (reply_size > 0) {
129  if (p->reply)
130  reply_size = min(p->reply_size, reply_size);
131  else
132  p->reply = kmalloc(reply_size, GFP_ATOMIC);
133 
134  if (p->reply)
135  memcpy(p->reply, reply, reply_size);
136  else
137  reply_size = -ENOMEM;
138  }
139  p->reply_size = reply_size;
140  complete(&p->completion);
141 }
142 
143 
169 static
170 ssize_t __uwb_rc_cmd(struct uwb_rc *rc, const char *cmd_name,
171  struct uwb_rccb *cmd, size_t cmd_size,
172  struct uwb_rceb *reply, size_t reply_size,
173  u8 expected_type, u16 expected_event,
174  struct uwb_rceb **preply)
175 {
176  ssize_t result = 0;
177  struct device *dev = &rc->uwb_dev.dev;
179 
180  init_completion(&params.completion);
181  params.reply = reply;
182  params.reply_size = reply_size;
183 
184  result = uwb_rc_cmd_async(rc, cmd_name, cmd, cmd_size,
185  expected_type, expected_event,
186  uwb_rc_cmd_done, &params);
187  if (result)
188  return result;
189 
190  wait_for_completion(&params.completion);
191 
192  if (preply)
193  *preply = params.reply;
194 
195  if (params.reply_size < 0)
196  dev_err(dev, "%s: confirmation event 0x%02x/%04x/%02x "
197  "reception failed: %d\n", cmd_name,
198  expected_type, expected_event, cmd->bCommandContext,
199  (int)params.reply_size);
200  return params.reply_size;
201 }
202 
203 
226 ssize_t uwb_rc_cmd(struct uwb_rc *rc, const char *cmd_name,
227  struct uwb_rccb *cmd, size_t cmd_size,
228  struct uwb_rceb *reply, size_t reply_size)
229 {
230  struct device *dev = &rc->uwb_dev.dev;
231  ssize_t result;
232 
233  result = __uwb_rc_cmd(rc, cmd_name,
234  cmd, cmd_size, reply, reply_size,
235  reply->bEventType, reply->wEvent, NULL);
236 
237  if (result > 0 && result < reply_size) {
238  dev_err(dev, "%s: not enough data returned for decoding reply "
239  "(%zu bytes received vs at least %zu needed)\n",
240  cmd_name, result, reply_size);
241  result = -EIO;
242  }
243  return result;
244 }
246 
247 
269 ssize_t uwb_rc_vcmd(struct uwb_rc *rc, const char *cmd_name,
270  struct uwb_rccb *cmd, size_t cmd_size,
271  u8 expected_type, u16 expected_event,
272  struct uwb_rceb **preply)
273 {
274  return __uwb_rc_cmd(rc, cmd_name, cmd, cmd_size, NULL, 0,
275  expected_type, expected_event, preply);
276 }
278 
279 
290 int uwb_rc_reset(struct uwb_rc *rc)
291 {
292  int result = -ENOMEM;
293  struct uwb_rc_evt_confirm reply;
294  struct uwb_rccb *cmd;
295  size_t cmd_size = sizeof(*cmd);
296 
297  mutex_lock(&rc->uwb_dev.mutex);
298  cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
299  if (cmd == NULL)
300  goto error_kzalloc;
303  reply.rceb.bEventType = UWB_RC_CET_GENERAL;
304  reply.rceb.wEvent = UWB_RC_CMD_RESET;
305  result = uwb_rc_cmd(rc, "RESET", cmd, cmd_size,
306  &reply.rceb, sizeof(reply));
307  if (result < 0)
308  goto error_cmd;
309  if (reply.bResultCode != UWB_RC_RES_SUCCESS) {
310  dev_err(&rc->uwb_dev.dev,
311  "RESET: command execution failed: %s (%d)\n",
312  uwb_rc_strerror(reply.bResultCode), reply.bResultCode);
313  result = -EIO;
314  }
315 error_cmd:
316  kfree(cmd);
317 error_kzalloc:
318  mutex_unlock(&rc->uwb_dev.mutex);
319  return result;
320 }
321 
323 {
324  struct uwb_rc *rc = evt->rc;
325  int ret;
326 
327  dev_info(&rc->uwb_dev.dev, "resetting radio controller\n");
328  ret = rc->reset(rc);
329  if (ret < 0) {
330  dev_err(&rc->uwb_dev.dev, "failed to reset hardware: %d\n", ret);
331  goto error;
332  }
333  return 0;
334 error:
335  /* Nothing can be done except try the reset again. Wait a bit
336  to avoid reset loops during probe() or remove(). */
337  msleep(1000);
338  uwb_rc_reset_all(rc);
339  return ret;
340 }
341 
349 void uwb_rc_reset_all(struct uwb_rc *rc)
350 {
351  struct uwb_event *evt;
352 
353  evt = kzalloc(sizeof(struct uwb_event), GFP_ATOMIC);
354  if (unlikely(evt == NULL))
355  return;
356 
357  evt->rc = __uwb_rc_get(rc); /* will be put by uwbd's uwbd_event_handle() */
358  evt->ts_jiffies = jiffies;
359  evt->type = UWB_EVT_TYPE_MSG;
360  evt->message = UWB_EVT_MSG_RESET;
361 
362  uwbd_event_queue(evt);
363 }
365 
366 void uwb_rc_pre_reset(struct uwb_rc *rc)
367 {
368  rc->stop(rc);
369  uwbd_flush(rc);
370 
372  uwb_rsv_remove_all(rc);
373 }
375 
376 int uwb_rc_post_reset(struct uwb_rc *rc)
377 {
378  int ret;
379 
380  ret = rc->start(rc);
381  if (ret)
382  goto out;
383  ret = uwb_rc_mac_addr_set(rc, &rc->uwb_dev.mac_addr);
384  if (ret)
385  goto out;
386  ret = uwb_rc_dev_addr_set(rc, &rc->uwb_dev.dev_addr);
387  if (ret)
388  goto out;
389 out:
390  return ret;
391 }