diff options
Diffstat (limited to 'drivers/uwb/i1480')
-rw-r--r-- | drivers/uwb/i1480/Makefile | 2 | ||||
-rw-r--r-- | drivers/uwb/i1480/dfu/Makefile | 9 | ||||
-rw-r--r-- | drivers/uwb/i1480/dfu/dfu.c | 217 | ||||
-rw-r--r-- | drivers/uwb/i1480/dfu/i1480-dfu.h | 260 | ||||
-rw-r--r-- | drivers/uwb/i1480/dfu/mac.c | 527 | ||||
-rw-r--r-- | drivers/uwb/i1480/dfu/phy.c | 203 | ||||
-rw-r--r-- | drivers/uwb/i1480/dfu/usb.c | 500 | ||||
-rw-r--r-- | drivers/uwb/i1480/i1480-est.c | 99 | ||||
-rw-r--r-- | drivers/uwb/i1480/i1480-wlp.h | 200 | ||||
-rw-r--r-- | drivers/uwb/i1480/i1480u-wlp/Makefile | 8 | ||||
-rw-r--r-- | drivers/uwb/i1480/i1480u-wlp/i1480u-wlp.h | 284 | ||||
-rw-r--r-- | drivers/uwb/i1480/i1480u-wlp/lc.c | 421 | ||||
-rw-r--r-- | drivers/uwb/i1480/i1480u-wlp/netdev.c | 368 | ||||
-rw-r--r-- | drivers/uwb/i1480/i1480u-wlp/rx.c | 486 | ||||
-rw-r--r-- | drivers/uwb/i1480/i1480u-wlp/sysfs.c | 408 | ||||
-rw-r--r-- | drivers/uwb/i1480/i1480u-wlp/tx.c | 632 |
16 files changed, 4624 insertions, 0 deletions
diff --git a/drivers/uwb/i1480/Makefile b/drivers/uwb/i1480/Makefile new file mode 100644 index 000000000000..212bbc7d4c32 --- /dev/null +++ b/drivers/uwb/i1480/Makefile | |||
@@ -0,0 +1,2 @@ | |||
1 | obj-$(CONFIG_UWB_I1480U) += dfu/ i1480-est.o | ||
2 | obj-$(CONFIG_UWB_I1480U_WLP) += i1480u-wlp/ | ||
diff --git a/drivers/uwb/i1480/dfu/Makefile b/drivers/uwb/i1480/dfu/Makefile new file mode 100644 index 000000000000..bd1b9f25424c --- /dev/null +++ b/drivers/uwb/i1480/dfu/Makefile | |||
@@ -0,0 +1,9 @@ | |||
1 | obj-$(CONFIG_UWB_I1480U) += i1480-dfu-usb.o | ||
2 | |||
3 | i1480-dfu-usb-objs := \ | ||
4 | dfu.o \ | ||
5 | mac.o \ | ||
6 | phy.o \ | ||
7 | usb.o | ||
8 | |||
9 | |||
diff --git a/drivers/uwb/i1480/dfu/dfu.c b/drivers/uwb/i1480/dfu/dfu.c new file mode 100644 index 000000000000..9097b3b30385 --- /dev/null +++ b/drivers/uwb/i1480/dfu/dfu.c | |||
@@ -0,0 +1,217 @@ | |||
1 | /* | ||
2 | * Intel Wireless UWB Link 1480 | ||
3 | * Main driver | ||
4 | * | ||
5 | * Copyright (C) 2005-2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
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 | * Common code for firmware upload used by the USB and PCI version; | ||
24 | * i1480_fw_upload() takes a device descriptor and uses the function | ||
25 | * pointers it provides to upload firmware and prepare the PHY. | ||
26 | * | ||
27 | * As well, provides common functions used by the rest of the code. | ||
28 | */ | ||
29 | #include "i1480-dfu.h" | ||
30 | #include <linux/errno.h> | ||
31 | #include <linux/delay.h> | ||
32 | #include <linux/pci.h> | ||
33 | #include <linux/device.h> | ||
34 | #include <linux/uwb.h> | ||
35 | #include <linux/random.h> | ||
36 | |||
37 | #define D_LOCAL 0 | ||
38 | #include <linux/uwb/debug.h> | ||
39 | |||
40 | /** | ||
41 | * i1480_rceb_check - Check RCEB for expected field values | ||
42 | * @i1480: pointer to device for which RCEB is being checked | ||
43 | * @rceb: RCEB being checked | ||
44 | * @cmd: which command the RCEB is related to | ||
45 | * @context: expected context | ||
46 | * @expected_type: expected event type | ||
47 | * @expected_event: expected event | ||
48 | * | ||
49 | * If @cmd is NULL, do not print error messages, but still return an error | ||
50 | * code. | ||
51 | * | ||
52 | * Return 0 if @rceb matches the expected values, -EINVAL otherwise. | ||
53 | */ | ||
54 | int i1480_rceb_check(const struct i1480 *i1480, const struct uwb_rceb *rceb, | ||
55 | const char *cmd, u8 context, u8 expected_type, | ||
56 | unsigned expected_event) | ||
57 | { | ||
58 | int result = 0; | ||
59 | struct device *dev = i1480->dev; | ||
60 | if (rceb->bEventContext != context) { | ||
61 | if (cmd) | ||
62 | dev_err(dev, "%s: unexpected context id 0x%02x " | ||
63 | "(expected 0x%02x)\n", cmd, | ||
64 | rceb->bEventContext, context); | ||
65 | result = -EINVAL; | ||
66 | } | ||
67 | if (rceb->bEventType != expected_type) { | ||
68 | if (cmd) | ||
69 | dev_err(dev, "%s: unexpected event type 0x%02x " | ||
70 | "(expected 0x%02x)\n", cmd, | ||
71 | rceb->bEventType, expected_type); | ||
72 | result = -EINVAL; | ||
73 | } | ||
74 | if (le16_to_cpu(rceb->wEvent) != expected_event) { | ||
75 | if (cmd) | ||
76 | dev_err(dev, "%s: unexpected event 0x%04x " | ||
77 | "(expected 0x%04x)\n", cmd, | ||
78 | le16_to_cpu(rceb->wEvent), expected_event); | ||
79 | result = -EINVAL; | ||
80 | } | ||
81 | return result; | ||
82 | } | ||
83 | EXPORT_SYMBOL_GPL(i1480_rceb_check); | ||
84 | |||
85 | |||
86 | /** | ||
87 | * Execute a Radio Control Command | ||
88 | * | ||
89 | * Command data has to be in i1480->cmd_buf. | ||
90 | * | ||
91 | * @returns size of the reply data filled in i1480->evt_buf or < 0 errno | ||
92 | * code on error. | ||
93 | */ | ||
94 | ssize_t i1480_cmd(struct i1480 *i1480, const char *cmd_name, size_t cmd_size, | ||
95 | size_t reply_size) | ||
96 | { | ||
97 | ssize_t result; | ||
98 | struct uwb_rceb *reply = i1480->evt_buf; | ||
99 | struct uwb_rccb *cmd = i1480->cmd_buf; | ||
100 | u16 expected_event = reply->wEvent; | ||
101 | u8 expected_type = reply->bEventType; | ||
102 | u8 context; | ||
103 | |||
104 | d_fnstart(3, i1480->dev, "(%p, %s, %zu)\n", i1480, cmd_name, cmd_size); | ||
105 | init_completion(&i1480->evt_complete); | ||
106 | i1480->evt_result = -EINPROGRESS; | ||
107 | do { | ||
108 | get_random_bytes(&context, 1); | ||
109 | } while (context == 0x00 || context == 0xff); | ||
110 | cmd->bCommandContext = context; | ||
111 | result = i1480->cmd(i1480, cmd_name, cmd_size); | ||
112 | if (result < 0) | ||
113 | goto error; | ||
114 | /* wait for the callback to report a event was received */ | ||
115 | result = wait_for_completion_interruptible_timeout( | ||
116 | &i1480->evt_complete, HZ); | ||
117 | if (result == 0) { | ||
118 | result = -ETIMEDOUT; | ||
119 | goto error; | ||
120 | } | ||
121 | if (result < 0) | ||
122 | goto error; | ||
123 | result = i1480->evt_result; | ||
124 | if (result < 0) { | ||
125 | dev_err(i1480->dev, "%s: command reply reception failed: %zd\n", | ||
126 | cmd_name, result); | ||
127 | goto error; | ||
128 | } | ||
129 | /* | ||
130 | * Firmware versions >= 1.4.12224 for IOGear GUWA100U generate a | ||
131 | * spurious notification after firmware is downloaded. So check whether | ||
132 | * the receibed RCEB is such notification before assuming that the | ||
133 | * command has failed. | ||
134 | */ | ||
135 | if (i1480_rceb_check(i1480, i1480->evt_buf, NULL, | ||
136 | 0, 0xfd, 0x0022) == 0) { | ||
137 | /* Now wait for the actual RCEB for this command. */ | ||
138 | result = i1480->wait_init_done(i1480); | ||
139 | if (result < 0) | ||
140 | goto error; | ||
141 | result = i1480->evt_result; | ||
142 | } | ||
143 | if (result != reply_size) { | ||
144 | dev_err(i1480->dev, "%s returned only %zu bytes, %zu expected\n", | ||
145 | cmd_name, result, reply_size); | ||
146 | result = -EINVAL; | ||
147 | goto error; | ||
148 | } | ||
149 | /* Verify we got the right event in response */ | ||
150 | result = i1480_rceb_check(i1480, i1480->evt_buf, cmd_name, context, | ||
151 | expected_type, expected_event); | ||
152 | error: | ||
153 | d_fnend(3, i1480->dev, "(%p, %s, %zu) = %zd\n", | ||
154 | i1480, cmd_name, cmd_size, result); | ||
155 | return result; | ||
156 | } | ||
157 | EXPORT_SYMBOL_GPL(i1480_cmd); | ||
158 | |||
159 | |||
160 | static | ||
161 | int i1480_print_state(struct i1480 *i1480) | ||
162 | { | ||
163 | int result; | ||
164 | u32 *buf = (u32 *) i1480->cmd_buf; | ||
165 | |||
166 | result = i1480->read(i1480, 0x80080000, 2 * sizeof(*buf)); | ||
167 | if (result < 0) { | ||
168 | dev_err(i1480->dev, "cannot read U & L states: %d\n", result); | ||
169 | goto error; | ||
170 | } | ||
171 | dev_info(i1480->dev, "state U 0x%08x, L 0x%08x\n", buf[0], buf[1]); | ||
172 | error: | ||
173 | return result; | ||
174 | } | ||
175 | |||
176 | |||
177 | /* | ||
178 | * PCI probe, firmware uploader | ||
179 | * | ||
180 | * _mac_fw_upload() will call rc_setup(), which needs an rc_release(). | ||
181 | */ | ||
182 | int i1480_fw_upload(struct i1480 *i1480) | ||
183 | { | ||
184 | int result; | ||
185 | |||
186 | result = i1480_pre_fw_upload(i1480); /* PHY pre fw */ | ||
187 | if (result < 0 && result != -ENOENT) { | ||
188 | i1480_print_state(i1480); | ||
189 | goto error; | ||
190 | } | ||
191 | result = i1480_mac_fw_upload(i1480); /* MAC fw */ | ||
192 | if (result < 0) { | ||
193 | if (result == -ENOENT) | ||
194 | dev_err(i1480->dev, "Cannot locate MAC FW file '%s'\n", | ||
195 | i1480->mac_fw_name); | ||
196 | else | ||
197 | i1480_print_state(i1480); | ||
198 | goto error; | ||
199 | } | ||
200 | result = i1480_phy_fw_upload(i1480); /* PHY fw */ | ||
201 | if (result < 0 && result != -ENOENT) { | ||
202 | i1480_print_state(i1480); | ||
203 | goto error_rc_release; | ||
204 | } | ||
205 | /* | ||
206 | * FIXME: find some reliable way to check whether firmware is running | ||
207 | * properly. Maybe use some standard request that has no side effects? | ||
208 | */ | ||
209 | dev_info(i1480->dev, "firmware uploaded successfully\n"); | ||
210 | error_rc_release: | ||
211 | if (i1480->rc_release) | ||
212 | i1480->rc_release(i1480); | ||
213 | result = 0; | ||
214 | error: | ||
215 | return result; | ||
216 | } | ||
217 | EXPORT_SYMBOL_GPL(i1480_fw_upload); | ||
diff --git a/drivers/uwb/i1480/dfu/i1480-dfu.h b/drivers/uwb/i1480/dfu/i1480-dfu.h new file mode 100644 index 000000000000..46f45e800f36 --- /dev/null +++ b/drivers/uwb/i1480/dfu/i1480-dfu.h | |||
@@ -0,0 +1,260 @@ | |||
1 | /* | ||
2 | * i1480 Device Firmware Upload | ||
3 | * | ||
4 | * Copyright (C) 2005-2006 Intel Corporation | ||
5 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License version | ||
9 | * 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
19 | * 02110-1301, USA. | ||
20 | * | ||
21 | * | ||
22 | * This driver is the firmware uploader for the Intel Wireless UWB | ||
23 | * Link 1480 device (both in the USB and PCI incarnations). | ||
24 | * | ||
25 | * The process is quite simple: we stop the device, write the firmware | ||
26 | * to its memory and then restart it. Wait for the device to let us | ||
27 | * know it is done booting firmware. Ready. | ||
28 | * | ||
29 | * We might have to upload before or after a phy firmware (which might | ||
30 | * be done in two methods, using a normal firmware image or through | ||
31 | * the MPI port). | ||
32 | * | ||
33 | * Because USB and PCI use common methods, we just make ops out of the | ||
34 | * common operations (read, write, wait_init_done and cmd) and | ||
35 | * implement them in usb.c and pci.c. | ||
36 | * | ||
37 | * The flow is (some parts omitted): | ||
38 | * | ||
39 | * i1480_{usb,pci}_probe() On enumerate/discovery | ||
40 | * i1480_fw_upload() | ||
41 | * i1480_pre_fw_upload() | ||
42 | * __mac_fw_upload() | ||
43 | * fw_hdrs_load() | ||
44 | * mac_fw_hdrs_push() | ||
45 | * i1480->write() [i1480_{usb,pci}_write()] | ||
46 | * i1480_fw_cmp() | ||
47 | * i1480->read() [i1480_{usb,pci}_read()] | ||
48 | * i1480_mac_fw_upload() | ||
49 | * __mac_fw_upload() | ||
50 | * i1480->setup(() | ||
51 | * i1480->wait_init_done() | ||
52 | * i1480_cmd_reset() | ||
53 | * i1480->cmd() [i1480_{usb,pci}_cmd()] | ||
54 | * ... | ||
55 | * i1480_phy_fw_upload() | ||
56 | * request_firmware() | ||
57 | * i1480_mpi_write() | ||
58 | * i1480->cmd() [i1480_{usb,pci}_cmd()] | ||
59 | * | ||
60 | * Once the probe function enumerates the device and uploads the | ||
61 | * firmware, we just exit with -ENODEV, as we don't really want to | ||
62 | * attach to the device. | ||
63 | */ | ||
64 | #ifndef __i1480_DFU_H__ | ||
65 | #define __i1480_DFU_H__ | ||
66 | |||
67 | #include <linux/uwb/spec.h> | ||
68 | #include <linux/types.h> | ||
69 | #include <linux/completion.h> | ||
70 | |||
71 | #define i1480_FW_UPLOAD_MODE_MASK (cpu_to_le32(0x00000018)) | ||
72 | |||
73 | #if i1480_FW > 0x00000302 | ||
74 | #define i1480_RCEB_EXTENDED | ||
75 | #endif | ||
76 | |||
77 | struct uwb_rccb; | ||
78 | struct uwb_rceb; | ||
79 | |||
80 | /* | ||
81 | * Common firmware upload handlers | ||
82 | * | ||
83 | * Normally you embed this struct in another one specific to your hw. | ||
84 | * | ||
85 | * @write Write to device's memory from buffer. | ||
86 | * @read Read from device's memory to i1480->evt_buf. | ||
87 | * @setup Setup device after basic firmware is uploaded | ||
88 | * @wait_init_done | ||
89 | * Wait for the device to send a notification saying init | ||
90 | * is done. | ||
91 | * @cmd FOP for issuing the command to the hardware. The | ||
92 | * command data is contained in i1480->cmd_buf and the size | ||
93 | * is supplied as an argument. The command replied is put | ||
94 | * in i1480->evt_buf and the size in i1480->evt_result (or if | ||
95 | * an error, a < 0 errno code). | ||
96 | * | ||
97 | * @cmd_buf Memory buffer used to send commands to the device. | ||
98 | * Allocated by the upper layers i1480_fw_upload(). | ||
99 | * Size has to be @buf_size. | ||
100 | * @evt_buf Memory buffer used to place the async notifications | ||
101 | * received by the hw. Allocated by the upper layers | ||
102 | * i1480_fw_upload(). | ||
103 | * Size has to be @buf_size. | ||
104 | * @cmd_complete | ||
105 | * Low level driver uses this to notify code waiting afor | ||
106 | * an event that the event has arrived and data is in | ||
107 | * i1480->evt_buf (and size/result in i1480->evt_result). | ||
108 | * @hw_rev | ||
109 | * Use this value to activate dfu code to support new revisions | ||
110 | * of hardware. i1480_init() sets this to a default value. | ||
111 | * It should be updated by the USB and PCI code. | ||
112 | */ | ||
113 | struct i1480 { | ||
114 | struct device *dev; | ||
115 | |||
116 | int (*write)(struct i1480 *, u32 addr, const void *, size_t); | ||
117 | int (*read)(struct i1480 *, u32 addr, size_t); | ||
118 | int (*rc_setup)(struct i1480 *); | ||
119 | void (*rc_release)(struct i1480 *); | ||
120 | int (*wait_init_done)(struct i1480 *); | ||
121 | int (*cmd)(struct i1480 *, const char *cmd_name, size_t cmd_size); | ||
122 | const char *pre_fw_name; | ||
123 | const char *mac_fw_name; | ||
124 | const char *mac_fw_name_deprecate; /* FIXME: Will go away */ | ||
125 | const char *phy_fw_name; | ||
126 | u8 hw_rev; | ||
127 | |||
128 | size_t buf_size; /* size of both evt_buf and cmd_buf */ | ||
129 | void *evt_buf, *cmd_buf; | ||
130 | ssize_t evt_result; | ||
131 | struct completion evt_complete; | ||
132 | }; | ||
133 | |||
134 | static inline | ||
135 | void i1480_init(struct i1480 *i1480) | ||
136 | { | ||
137 | i1480->hw_rev = 1; | ||
138 | init_completion(&i1480->evt_complete); | ||
139 | } | ||
140 | |||
141 | extern int i1480_fw_upload(struct i1480 *); | ||
142 | extern int i1480_pre_fw_upload(struct i1480 *); | ||
143 | extern int i1480_mac_fw_upload(struct i1480 *); | ||
144 | extern int i1480_phy_fw_upload(struct i1480 *); | ||
145 | extern ssize_t i1480_cmd(struct i1480 *, const char *, size_t, size_t); | ||
146 | extern int i1480_rceb_check(const struct i1480 *, | ||
147 | const struct uwb_rceb *, const char *, u8, | ||
148 | u8, unsigned); | ||
149 | |||
150 | enum { | ||
151 | /* Vendor specific command type */ | ||
152 | i1480_CET_VS1 = 0xfd, | ||
153 | /* i1480 commands */ | ||
154 | i1480_CMD_SET_IP_MAS = 0x000e, | ||
155 | i1480_CMD_GET_MAC_PHY_INFO = 0x0003, | ||
156 | i1480_CMD_MPI_WRITE = 0x000f, | ||
157 | i1480_CMD_MPI_READ = 0x0010, | ||
158 | /* i1480 events */ | ||
159 | #if i1480_FW > 0x00000302 | ||
160 | i1480_EVT_CONFIRM = 0x0002, | ||
161 | i1480_EVT_RM_INIT_DONE = 0x0101, | ||
162 | i1480_EVT_DEV_ADD = 0x0103, | ||
163 | i1480_EVT_DEV_RM = 0x0104, | ||
164 | i1480_EVT_DEV_ID_CHANGE = 0x0105, | ||
165 | i1480_EVT_GET_MAC_PHY_INFO = i1480_CMD_GET_MAC_PHY_INFO, | ||
166 | #else | ||
167 | i1480_EVT_CONFIRM = 0x0002, | ||
168 | i1480_EVT_RM_INIT_DONE = 0x0101, | ||
169 | i1480_EVT_DEV_ADD = 0x0103, | ||
170 | i1480_EVT_DEV_RM = 0x0104, | ||
171 | i1480_EVT_DEV_ID_CHANGE = 0x0105, | ||
172 | i1480_EVT_GET_MAC_PHY_INFO = i1480_EVT_CONFIRM, | ||
173 | #endif | ||
174 | }; | ||
175 | |||
176 | |||
177 | struct i1480_evt_confirm { | ||
178 | struct uwb_rceb rceb; | ||
179 | #ifdef i1480_RCEB_EXTENDED | ||
180 | __le16 wParamLength; | ||
181 | #endif | ||
182 | u8 bResultCode; | ||
183 | } __attribute__((packed)); | ||
184 | |||
185 | |||
186 | struct i1480_rceb { | ||
187 | struct uwb_rceb rceb; | ||
188 | #ifdef i1480_RCEB_EXTENDED | ||
189 | __le16 wParamLength; | ||
190 | #endif | ||
191 | } __attribute__((packed)); | ||
192 | |||
193 | |||
194 | /** | ||
195 | * Get MAC & PHY Information confirm event structure | ||
196 | * | ||
197 | * Confirm event returned by the command. | ||
198 | */ | ||
199 | struct i1480_evt_confirm_GMPI { | ||
200 | #if i1480_FW > 0x00000302 | ||
201 | struct uwb_rceb rceb; | ||
202 | __le16 wParamLength; | ||
203 | __le16 status; | ||
204 | u8 mac_addr[6]; /* EUI-64 bit IEEE address [still 8 bytes?] */ | ||
205 | u8 dev_addr[2]; | ||
206 | __le16 mac_fw_rev; /* major = v >> 8; minor = v & 0xff */ | ||
207 | u8 hw_rev; | ||
208 | u8 phy_vendor; | ||
209 | u8 phy_rev; /* major v = >> 8; minor = v & 0xff */ | ||
210 | __le16 mac_caps; | ||
211 | u8 phy_caps[3]; | ||
212 | u8 key_stores; | ||
213 | __le16 mcast_addr_stores; | ||
214 | u8 sec_mode_supported; | ||
215 | #else | ||
216 | struct uwb_rceb rceb; | ||
217 | u8 status; | ||
218 | u8 mac_addr[8]; /* EUI-64 bit IEEE address [still 8 bytes?] */ | ||
219 | u8 dev_addr[2]; | ||
220 | __le16 mac_fw_rev; /* major = v >> 8; minor = v & 0xff */ | ||
221 | __le16 phy_fw_rev; /* major v = >> 8; minor = v & 0xff */ | ||
222 | __le16 mac_caps; | ||
223 | u8 phy_caps; | ||
224 | u8 key_stores; | ||
225 | __le16 mcast_addr_stores; | ||
226 | u8 sec_mode_supported; | ||
227 | #endif | ||
228 | } __attribute__((packed)); | ||
229 | |||
230 | |||
231 | struct i1480_cmd_mpi_write { | ||
232 | struct uwb_rccb rccb; | ||
233 | __le16 size; | ||
234 | u8 data[]; | ||
235 | }; | ||
236 | |||
237 | |||
238 | struct i1480_cmd_mpi_read { | ||
239 | struct uwb_rccb rccb; | ||
240 | __le16 size; | ||
241 | struct { | ||
242 | u8 page, offset; | ||
243 | } __attribute__((packed)) data[]; | ||
244 | } __attribute__((packed)); | ||
245 | |||
246 | |||
247 | struct i1480_evt_mpi_read { | ||
248 | struct uwb_rceb rceb; | ||
249 | #ifdef i1480_RCEB_EXTENDED | ||
250 | __le16 wParamLength; | ||
251 | #endif | ||
252 | u8 bResultCode; | ||
253 | __le16 size; | ||
254 | struct { | ||
255 | u8 page, offset, value; | ||
256 | } __attribute__((packed)) data[]; | ||
257 | } __attribute__((packed)); | ||
258 | |||
259 | |||
260 | #endif /* #ifndef __i1480_DFU_H__ */ | ||
diff --git a/drivers/uwb/i1480/dfu/mac.c b/drivers/uwb/i1480/dfu/mac.c new file mode 100644 index 000000000000..2e4d8f07c165 --- /dev/null +++ b/drivers/uwb/i1480/dfu/mac.c | |||
@@ -0,0 +1,527 @@ | |||
1 | /* | ||
2 | * Intel Wireless UWB Link 1480 | ||
3 | * MAC Firmware upload implementation | ||
4 | * | ||
5 | * Copyright (C) 2005-2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
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 | * Implementation of the code for parsing the firmware file (extract | ||
24 | * the headers and binary code chunks) in the fw_*() functions. The | ||
25 | * code to upload pre and mac firmwares is the same, so it uses a | ||
26 | * common entry point in __mac_fw_upload(), which uses the i1480 | ||
27 | * function pointers to push the firmware to the device. | ||
28 | */ | ||
29 | #include <linux/delay.h> | ||
30 | #include <linux/firmware.h> | ||
31 | #include <linux/uwb.h> | ||
32 | #include "i1480-dfu.h" | ||
33 | |||
34 | #define D_LOCAL 0 | ||
35 | #include <linux/uwb/debug.h> | ||
36 | |||
37 | /* | ||
38 | * Descriptor for a continuous segment of MAC fw data | ||
39 | */ | ||
40 | struct fw_hdr { | ||
41 | unsigned long address; | ||
42 | size_t length; | ||
43 | const u32 *bin; | ||
44 | struct fw_hdr *next; | ||
45 | }; | ||
46 | |||
47 | |||
48 | /* Free a chain of firmware headers */ | ||
49 | static | ||
50 | void fw_hdrs_free(struct fw_hdr *hdr) | ||
51 | { | ||
52 | struct fw_hdr *next; | ||
53 | |||
54 | while (hdr) { | ||
55 | next = hdr->next; | ||
56 | kfree(hdr); | ||
57 | hdr = next; | ||
58 | } | ||
59 | } | ||
60 | |||
61 | |||
62 | /* Fill a firmware header descriptor from a memory buffer */ | ||
63 | static | ||
64 | int fw_hdr_load(struct i1480 *i1480, struct fw_hdr *hdr, unsigned hdr_cnt, | ||
65 | const char *_data, const u32 *data_itr, const u32 *data_top) | ||
66 | { | ||
67 | size_t hdr_offset = (const char *) data_itr - _data; | ||
68 | size_t remaining_size = (void *) data_top - (void *) data_itr; | ||
69 | if (data_itr + 2 > data_top) { | ||
70 | dev_err(i1480->dev, "fw hdr #%u/%zu: EOF reached in header at " | ||
71 | "offset %zu, limit %zu\n", | ||
72 | hdr_cnt, hdr_offset, | ||
73 | (const char *) data_itr + 2 - _data, | ||
74 | (const char *) data_top - _data); | ||
75 | return -EINVAL; | ||
76 | } | ||
77 | hdr->next = NULL; | ||
78 | hdr->address = le32_to_cpu(*data_itr++); | ||
79 | hdr->length = le32_to_cpu(*data_itr++); | ||
80 | hdr->bin = data_itr; | ||
81 | if (hdr->length > remaining_size) { | ||
82 | dev_err(i1480->dev, "fw hdr #%u/%zu: EOF reached in data; " | ||
83 | "chunk too long (%zu bytes), only %zu left\n", | ||
84 | hdr_cnt, hdr_offset, hdr->length, remaining_size); | ||
85 | return -EINVAL; | ||
86 | } | ||
87 | return 0; | ||
88 | } | ||
89 | |||
90 | |||
91 | /** | ||
92 | * Get a buffer where the firmware is supposed to be and create a | ||
93 | * chain of headers linking them together. | ||
94 | * | ||
95 | * @phdr: where to place the pointer to the first header (headers link | ||
96 | * to the next via the @hdr->next ptr); need to free the whole | ||
97 | * chain when done. | ||
98 | * | ||
99 | * @_data: Pointer to the data buffer. | ||
100 | * | ||
101 | * @_data_size: Size of the data buffer (bytes); data size has to be a | ||
102 | * multiple of 4. Function will fail if not. | ||
103 | * | ||
104 | * Goes over the whole binary blob; reads the first chunk and creates | ||
105 | * a fw hdr from it (which points to where the data is in @_data and | ||
106 | * the length of the chunk); then goes on to the next chunk until | ||
107 | * done. Each header is linked to the next. | ||
108 | */ | ||
109 | static | ||
110 | int fw_hdrs_load(struct i1480 *i1480, struct fw_hdr **phdr, | ||
111 | const char *_data, size_t data_size) | ||
112 | { | ||
113 | int result; | ||
114 | unsigned hdr_cnt = 0; | ||
115 | u32 *data = (u32 *) _data, *data_itr, *data_top; | ||
116 | struct fw_hdr *hdr, **prev_hdr = phdr; | ||
117 | |||
118 | result = -EINVAL; | ||
119 | /* Check size is ok and pointer is aligned */ | ||
120 | if (data_size % sizeof(u32) != 0) | ||
121 | goto error; | ||
122 | if ((unsigned long) _data % sizeof(u16) != 0) | ||
123 | goto error; | ||
124 | *phdr = NULL; | ||
125 | data_itr = data; | ||
126 | data_top = (u32 *) (_data + data_size); | ||
127 | while (data_itr < data_top) { | ||
128 | result = -ENOMEM; | ||
129 | hdr = kmalloc(sizeof(*hdr), GFP_KERNEL); | ||
130 | if (hdr == NULL) { | ||
131 | dev_err(i1480->dev, "Cannot allocate fw header " | ||
132 | "for chunk #%u\n", hdr_cnt); | ||
133 | goto error_alloc; | ||
134 | } | ||
135 | result = fw_hdr_load(i1480, hdr, hdr_cnt, | ||
136 | _data, data_itr, data_top); | ||
137 | if (result < 0) | ||
138 | goto error_load; | ||
139 | data_itr += 2 + hdr->length; | ||
140 | *prev_hdr = hdr; | ||
141 | prev_hdr = &hdr->next; | ||
142 | hdr_cnt++; | ||
143 | }; | ||
144 | *prev_hdr = NULL; | ||
145 | return 0; | ||
146 | |||
147 | error_load: | ||
148 | kfree(hdr); | ||
149 | error_alloc: | ||
150 | fw_hdrs_free(*phdr); | ||
151 | error: | ||
152 | return result; | ||
153 | } | ||
154 | |||
155 | |||
156 | /** | ||
157 | * Compares a chunk of fw with one in the devices's memory | ||
158 | * | ||
159 | * @i1480: Device instance | ||
160 | * @hdr: Pointer to the firmware chunk | ||
161 | * @returns: 0 if equal, < 0 errno on error. If > 0, it is the offset | ||
162 | * where the difference was found (plus one). | ||
163 | * | ||
164 | * Kind of dirty and simplistic, but does the trick in both the PCI | ||
165 | * and USB version. We do a quick[er] memcmp(), and if it fails, we do | ||
166 | * a byte-by-byte to find the offset. | ||
167 | */ | ||
168 | static | ||
169 | ssize_t i1480_fw_cmp(struct i1480 *i1480, struct fw_hdr *hdr) | ||
170 | { | ||
171 | ssize_t result = 0; | ||
172 | u32 src_itr = 0, cnt; | ||
173 | size_t size = hdr->length*sizeof(hdr->bin[0]); | ||
174 | size_t chunk_size; | ||
175 | u8 *bin = (u8 *) hdr->bin; | ||
176 | |||
177 | while (size > 0) { | ||
178 | chunk_size = size < i1480->buf_size ? size : i1480->buf_size; | ||
179 | result = i1480->read(i1480, hdr->address + src_itr, chunk_size); | ||
180 | if (result < 0) { | ||
181 | dev_err(i1480->dev, "error reading for verification: " | ||
182 | "%zd\n", result); | ||
183 | goto error; | ||
184 | } | ||
185 | if (memcmp(i1480->cmd_buf, bin + src_itr, result)) { | ||
186 | u8 *buf = i1480->cmd_buf; | ||
187 | d_printf(2, i1480->dev, | ||
188 | "original data @ %p + %u, %zu bytes\n", | ||
189 | bin, src_itr, result); | ||
190 | d_dump(4, i1480->dev, bin + src_itr, result); | ||
191 | for (cnt = 0; cnt < result; cnt++) | ||
192 | if (bin[src_itr + cnt] != buf[cnt]) { | ||
193 | dev_err(i1480->dev, "byte failed at " | ||
194 | "src_itr %u cnt %u [0x%02x " | ||
195 | "vs 0x%02x]\n", src_itr, cnt, | ||
196 | bin[src_itr + cnt], buf[cnt]); | ||
197 | result = src_itr + cnt + 1; | ||
198 | goto cmp_failed; | ||
199 | } | ||
200 | } | ||
201 | src_itr += result; | ||
202 | size -= result; | ||
203 | } | ||
204 | result = 0; | ||
205 | error: | ||
206 | cmp_failed: | ||
207 | return result; | ||
208 | } | ||
209 | |||
210 | |||
211 | /** | ||
212 | * Writes firmware headers to the device. | ||
213 | * | ||
214 | * @prd: PRD instance | ||
215 | * @hdr: Processed firmware | ||
216 | * @returns: 0 if ok, < 0 errno on error. | ||
217 | */ | ||
218 | static | ||
219 | int mac_fw_hdrs_push(struct i1480 *i1480, struct fw_hdr *hdr, | ||
220 | const char *fw_name, const char *fw_tag) | ||
221 | { | ||
222 | struct device *dev = i1480->dev; | ||
223 | ssize_t result = 0; | ||
224 | struct fw_hdr *hdr_itr; | ||
225 | int verif_retry_count; | ||
226 | |||
227 | d_fnstart(3, dev, "(%p, %p)\n", i1480, hdr); | ||
228 | /* Now, header by header, push them to the hw */ | ||
229 | for (hdr_itr = hdr; hdr_itr != NULL; hdr_itr = hdr_itr->next) { | ||
230 | verif_retry_count = 0; | ||
231 | retry: | ||
232 | dev_dbg(dev, "fw chunk (%zu @ 0x%08lx)\n", | ||
233 | hdr_itr->length * sizeof(hdr_itr->bin[0]), | ||
234 | hdr_itr->address); | ||
235 | result = i1480->write(i1480, hdr_itr->address, hdr_itr->bin, | ||
236 | hdr_itr->length*sizeof(hdr_itr->bin[0])); | ||
237 | if (result < 0) { | ||
238 | dev_err(dev, "%s fw '%s': write failed (%zuB @ 0x%lx):" | ||
239 | " %zd\n", fw_tag, fw_name, | ||
240 | hdr_itr->length * sizeof(hdr_itr->bin[0]), | ||
241 | hdr_itr->address, result); | ||
242 | break; | ||
243 | } | ||
244 | result = i1480_fw_cmp(i1480, hdr_itr); | ||
245 | if (result < 0) { | ||
246 | dev_err(dev, "%s fw '%s': verification read " | ||
247 | "failed (%zuB @ 0x%lx): %zd\n", | ||
248 | fw_tag, fw_name, | ||
249 | hdr_itr->length * sizeof(hdr_itr->bin[0]), | ||
250 | hdr_itr->address, result); | ||
251 | break; | ||
252 | } | ||
253 | if (result > 0) { /* Offset where it failed + 1 */ | ||
254 | result--; | ||
255 | dev_err(dev, "%s fw '%s': WARNING: verification " | ||
256 | "failed at 0x%lx: retrying\n", | ||
257 | fw_tag, fw_name, hdr_itr->address + result); | ||
258 | if (++verif_retry_count < 3) | ||
259 | goto retry; /* write this block again! */ | ||
260 | dev_err(dev, "%s fw '%s': verification failed at 0x%lx: " | ||
261 | "tried %d times\n", fw_tag, fw_name, | ||
262 | hdr_itr->address + result, verif_retry_count); | ||
263 | result = -EINVAL; | ||
264 | break; | ||
265 | } | ||
266 | } | ||
267 | d_fnend(3, dev, "(%zd)\n", result); | ||
268 | return result; | ||
269 | } | ||
270 | |||
271 | |||
272 | /** Puts the device in firmware upload mode.*/ | ||
273 | static | ||
274 | int mac_fw_upload_enable(struct i1480 *i1480) | ||
275 | { | ||
276 | int result; | ||
277 | u32 reg = 0x800000c0; | ||
278 | u32 *buffer = (u32 *)i1480->cmd_buf; | ||
279 | |||
280 | if (i1480->hw_rev > 1) | ||
281 | reg = 0x8000d0d4; | ||
282 | result = i1480->read(i1480, reg, sizeof(u32)); | ||
283 | if (result < 0) | ||
284 | goto error_cmd; | ||
285 | *buffer &= ~i1480_FW_UPLOAD_MODE_MASK; | ||
286 | result = i1480->write(i1480, reg, buffer, sizeof(u32)); | ||
287 | if (result < 0) | ||
288 | goto error_cmd; | ||
289 | return 0; | ||
290 | error_cmd: | ||
291 | dev_err(i1480->dev, "can't enable fw upload mode: %d\n", result); | ||
292 | return result; | ||
293 | } | ||
294 | |||
295 | |||
296 | /** Gets the device out of firmware upload mode. */ | ||
297 | static | ||
298 | int mac_fw_upload_disable(struct i1480 *i1480) | ||
299 | { | ||
300 | int result; | ||
301 | u32 reg = 0x800000c0; | ||
302 | u32 *buffer = (u32 *)i1480->cmd_buf; | ||
303 | |||
304 | if (i1480->hw_rev > 1) | ||
305 | reg = 0x8000d0d4; | ||
306 | result = i1480->read(i1480, reg, sizeof(u32)); | ||
307 | if (result < 0) | ||
308 | goto error_cmd; | ||
309 | *buffer |= i1480_FW_UPLOAD_MODE_MASK; | ||
310 | result = i1480->write(i1480, reg, buffer, sizeof(u32)); | ||
311 | if (result < 0) | ||
312 | goto error_cmd; | ||
313 | return 0; | ||
314 | error_cmd: | ||
315 | dev_err(i1480->dev, "can't disable fw upload mode: %d\n", result); | ||
316 | return result; | ||
317 | } | ||
318 | |||
319 | |||
320 | |||
321 | /** | ||
322 | * Generic function for uploading a MAC firmware. | ||
323 | * | ||
324 | * @i1480: Device instance | ||
325 | * @fw_name: Name of firmware file to upload. | ||
326 | * @fw_tag: Name of the firmware type (for messages) | ||
327 | * [eg: MAC, PRE] | ||
328 | * @do_wait: Wait for device to emit initialization done message (0 | ||
329 | * for PRE fws, 1 for MAC fws). | ||
330 | * @returns: 0 if ok, < 0 errno on error. | ||
331 | */ | ||
332 | static | ||
333 | int __mac_fw_upload(struct i1480 *i1480, const char *fw_name, | ||
334 | const char *fw_tag) | ||
335 | { | ||
336 | int result; | ||
337 | const struct firmware *fw; | ||
338 | struct fw_hdr *fw_hdrs; | ||
339 | |||
340 | d_fnstart(3, i1480->dev, "(%p, %s, %s)\n", i1480, fw_name, fw_tag); | ||
341 | result = request_firmware(&fw, fw_name, i1480->dev); | ||
342 | if (result < 0) /* Up to caller to complain on -ENOENT */ | ||
343 | goto out; | ||
344 | d_printf(3, i1480->dev, "%s fw '%s': uploading\n", fw_tag, fw_name); | ||
345 | result = fw_hdrs_load(i1480, &fw_hdrs, fw->data, fw->size); | ||
346 | if (result < 0) { | ||
347 | dev_err(i1480->dev, "%s fw '%s': failed to parse firmware " | ||
348 | "file: %d\n", fw_tag, fw_name, result); | ||
349 | goto out_release; | ||
350 | } | ||
351 | result = mac_fw_upload_enable(i1480); | ||
352 | if (result < 0) | ||
353 | goto out_hdrs_release; | ||
354 | result = mac_fw_hdrs_push(i1480, fw_hdrs, fw_name, fw_tag); | ||
355 | mac_fw_upload_disable(i1480); | ||
356 | out_hdrs_release: | ||
357 | if (result >= 0) | ||
358 | dev_info(i1480->dev, "%s fw '%s': uploaded\n", fw_tag, fw_name); | ||
359 | else | ||
360 | dev_err(i1480->dev, "%s fw '%s': failed to upload (%d), " | ||
361 | "power cycle device\n", fw_tag, fw_name, result); | ||
362 | fw_hdrs_free(fw_hdrs); | ||
363 | out_release: | ||
364 | release_firmware(fw); | ||
365 | out: | ||
366 | d_fnend(3, i1480->dev, "(%p, %s, %s) = %d\n", i1480, fw_name, fw_tag, | ||
367 | result); | ||
368 | return result; | ||
369 | } | ||
370 | |||
371 | |||
372 | /** | ||
373 | * Upload a pre-PHY firmware | ||
374 | * | ||
375 | */ | ||
376 | int i1480_pre_fw_upload(struct i1480 *i1480) | ||
377 | { | ||
378 | int result; | ||
379 | result = __mac_fw_upload(i1480, i1480->pre_fw_name, "PRE"); | ||
380 | if (result == 0) | ||
381 | msleep(400); | ||
382 | return result; | ||
383 | } | ||
384 | |||
385 | |||
386 | /** | ||
387 | * Reset a the MAC and PHY | ||
388 | * | ||
389 | * @i1480: Device's instance | ||
390 | * @returns: 0 if ok, < 0 errno code on error | ||
391 | * | ||
392 | * We put the command on kmalloc'ed memory as some arches cannot do | ||
393 | * USB from the stack. The reply event is copied from an stage buffer, | ||
394 | * so it can be in the stack. See WUSB1.0[8.6.2.4] for more details. | ||
395 | * | ||
396 | * We issue the reset to make sure the UWB controller reinits the PHY; | ||
397 | * this way we can now if the PHY init went ok. | ||
398 | */ | ||
399 | static | ||
400 | int i1480_cmd_reset(struct i1480 *i1480) | ||
401 | { | ||
402 | int result; | ||
403 | struct uwb_rccb *cmd = (void *) i1480->cmd_buf; | ||
404 | struct i1480_evt_reset { | ||
405 | struct uwb_rceb rceb; | ||
406 | u8 bResultCode; | ||
407 | } __attribute__((packed)) *reply = (void *) i1480->evt_buf; | ||
408 | |||
409 | result = -ENOMEM; | ||
410 | cmd->bCommandType = UWB_RC_CET_GENERAL; | ||
411 | cmd->wCommand = cpu_to_le16(UWB_RC_CMD_RESET); | ||
412 | reply->rceb.bEventType = UWB_RC_CET_GENERAL; | ||
413 | reply->rceb.wEvent = UWB_RC_CMD_RESET; | ||
414 | result = i1480_cmd(i1480, "RESET", sizeof(*cmd), sizeof(*reply)); | ||
415 | if (result < 0) | ||
416 | goto out; | ||
417 | if (reply->bResultCode != UWB_RC_RES_SUCCESS) { | ||
418 | dev_err(i1480->dev, "RESET: command execution failed: %u\n", | ||
419 | reply->bResultCode); | ||
420 | result = -EIO; | ||
421 | } | ||
422 | out: | ||
423 | return result; | ||
424 | |||
425 | } | ||
426 | |||
427 | |||
428 | /* Wait for the MAC FW to start running */ | ||
429 | static | ||
430 | int i1480_fw_is_running_q(struct i1480 *i1480) | ||
431 | { | ||
432 | int cnt = 0; | ||
433 | int result; | ||
434 | u32 *val = (u32 *) i1480->cmd_buf; | ||
435 | |||
436 | d_fnstart(3, i1480->dev, "(i1480 %p)\n", i1480); | ||
437 | for (cnt = 0; cnt < 10; cnt++) { | ||
438 | msleep(100); | ||
439 | result = i1480->read(i1480, 0x80080000, 4); | ||
440 | if (result < 0) { | ||
441 | dev_err(i1480->dev, "Can't read 0x8008000: %d\n", result); | ||
442 | goto out; | ||
443 | } | ||
444 | if (*val == 0x55555555UL) /* fw running? cool */ | ||
445 | goto out; | ||
446 | } | ||
447 | dev_err(i1480->dev, "Timed out waiting for fw to start\n"); | ||
448 | result = -ETIMEDOUT; | ||
449 | out: | ||
450 | d_fnend(3, i1480->dev, "(i1480 %p) = %d\n", i1480, result); | ||
451 | return result; | ||
452 | |||
453 | } | ||
454 | |||
455 | |||
456 | /** | ||
457 | * Upload MAC firmware, wait for it to start | ||
458 | * | ||
459 | * @i1480: Device instance | ||
460 | * @fw_name: Name of the file that contains the firmware | ||
461 | * | ||
462 | * This has to be called after the pre fw has been uploaded (if | ||
463 | * there is any). | ||
464 | */ | ||
465 | int i1480_mac_fw_upload(struct i1480 *i1480) | ||
466 | { | ||
467 | int result = 0, deprecated_name = 0; | ||
468 | struct i1480_rceb *rcebe = (void *) i1480->evt_buf; | ||
469 | |||
470 | d_fnstart(3, i1480->dev, "(%p)\n", i1480); | ||
471 | result = __mac_fw_upload(i1480, i1480->mac_fw_name, "MAC"); | ||
472 | if (result == -ENOENT) { | ||
473 | result = __mac_fw_upload(i1480, i1480->mac_fw_name_deprecate, | ||
474 | "MAC"); | ||
475 | deprecated_name = 1; | ||
476 | } | ||
477 | if (result < 0) | ||
478 | return result; | ||
479 | if (deprecated_name == 1) | ||
480 | dev_warn(i1480->dev, | ||
481 | "WARNING: firmware file name %s is deprecated, " | ||
482 | "please rename to %s\n", | ||
483 | i1480->mac_fw_name_deprecate, i1480->mac_fw_name); | ||
484 | result = i1480_fw_is_running_q(i1480); | ||
485 | if (result < 0) | ||
486 | goto error_fw_not_running; | ||
487 | result = i1480->rc_setup ? i1480->rc_setup(i1480) : 0; | ||
488 | if (result < 0) { | ||
489 | dev_err(i1480->dev, "Cannot setup after MAC fw upload: %d\n", | ||
490 | result); | ||
491 | goto error_setup; | ||
492 | } | ||
493 | result = i1480->wait_init_done(i1480); /* wait init'on */ | ||
494 | if (result < 0) { | ||
495 | dev_err(i1480->dev, "MAC fw '%s': Initialization timed out " | ||
496 | "(%d)\n", i1480->mac_fw_name, result); | ||
497 | goto error_init_timeout; | ||
498 | } | ||
499 | /* verify we got the right initialization done event */ | ||
500 | if (i1480->evt_result != sizeof(*rcebe)) { | ||
501 | dev_err(i1480->dev, "MAC fw '%s': initialization event returns " | ||
502 | "wrong size (%zu bytes vs %zu needed)\n", | ||
503 | i1480->mac_fw_name, i1480->evt_result, sizeof(*rcebe)); | ||
504 | dump_bytes(i1480->dev, rcebe, min(i1480->evt_result, (ssize_t)32)); | ||
505 | goto error_size; | ||
506 | } | ||
507 | result = -EIO; | ||
508 | if (i1480_rceb_check(i1480, &rcebe->rceb, NULL, 0, i1480_CET_VS1, | ||
509 | i1480_EVT_RM_INIT_DONE) < 0) { | ||
510 | dev_err(i1480->dev, "wrong initialization event 0x%02x/%04x/%02x " | ||
511 | "received; expected 0x%02x/%04x/00\n", | ||
512 | rcebe->rceb.bEventType, le16_to_cpu(rcebe->rceb.wEvent), | ||
513 | rcebe->rceb.bEventContext, i1480_CET_VS1, | ||
514 | i1480_EVT_RM_INIT_DONE); | ||
515 | goto error_init_timeout; | ||
516 | } | ||
517 | result = i1480_cmd_reset(i1480); | ||
518 | if (result < 0) | ||
519 | dev_err(i1480->dev, "MAC fw '%s': MBOA reset failed (%d)\n", | ||
520 | i1480->mac_fw_name, result); | ||
521 | error_fw_not_running: | ||
522 | error_init_timeout: | ||
523 | error_size: | ||
524 | error_setup: | ||
525 | d_fnend(3, i1480->dev, "(i1480 %p) = %d\n", i1480, result); | ||
526 | return result; | ||
527 | } | ||
diff --git a/drivers/uwb/i1480/dfu/phy.c b/drivers/uwb/i1480/dfu/phy.c new file mode 100644 index 000000000000..3b1a87de8e63 --- /dev/null +++ b/drivers/uwb/i1480/dfu/phy.c | |||
@@ -0,0 +1,203 @@ | |||
1 | /* | ||
2 | * Intel Wireless UWB Link 1480 | ||
3 | * PHY parameters upload | ||
4 | * | ||
5 | * Copyright (C) 2005-2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
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 | * Code for uploading the PHY parameters to the PHY through the UWB | ||
24 | * Radio Control interface. | ||
25 | * | ||
26 | * We just send the data through the MPI interface using HWA-like | ||
27 | * commands and then reset the PHY to make sure it is ok. | ||
28 | */ | ||
29 | #include <linux/delay.h> | ||
30 | #include <linux/device.h> | ||
31 | #include <linux/firmware.h> | ||
32 | #include <linux/usb/wusb.h> | ||
33 | #include "i1480-dfu.h" | ||
34 | |||
35 | |||
36 | /** | ||
37 | * Write a value array to an address of the MPI interface | ||
38 | * | ||
39 | * @i1480: Device descriptor | ||
40 | * @data: Data array to write | ||
41 | * @size: Size of the data array | ||
42 | * @returns: 0 if ok, < 0 errno code on error. | ||
43 | * | ||
44 | * The data array is organized into pairs: | ||
45 | * | ||
46 | * ADDRESS VALUE | ||
47 | * | ||
48 | * ADDRESS is BE 16 bit unsigned, VALUE 8 bit unsigned. Size thus has | ||
49 | * to be a multiple of three. | ||
50 | */ | ||
51 | static | ||
52 | int i1480_mpi_write(struct i1480 *i1480, const void *data, size_t size) | ||
53 | { | ||
54 | int result; | ||
55 | struct i1480_cmd_mpi_write *cmd = i1480->cmd_buf; | ||
56 | struct i1480_evt_confirm *reply = i1480->evt_buf; | ||
57 | |||
58 | BUG_ON(size > 480); | ||
59 | result = -ENOMEM; | ||
60 | cmd->rccb.bCommandType = i1480_CET_VS1; | ||
61 | cmd->rccb.wCommand = cpu_to_le16(i1480_CMD_MPI_WRITE); | ||
62 | cmd->size = cpu_to_le16(size); | ||
63 | memcpy(cmd->data, data, size); | ||
64 | reply->rceb.bEventType = i1480_CET_VS1; | ||
65 | reply->rceb.wEvent = i1480_CMD_MPI_WRITE; | ||
66 | result = i1480_cmd(i1480, "MPI-WRITE", sizeof(*cmd) + size, sizeof(*reply)); | ||
67 | if (result < 0) | ||
68 | goto out; | ||
69 | if (reply->bResultCode != UWB_RC_RES_SUCCESS) { | ||
70 | dev_err(i1480->dev, "MPI-WRITE: command execution failed: %d\n", | ||
71 | reply->bResultCode); | ||
72 | result = -EIO; | ||
73 | } | ||
74 | out: | ||
75 | return result; | ||
76 | } | ||
77 | |||
78 | |||
79 | /** | ||
80 | * Read a value array to from an address of the MPI interface | ||
81 | * | ||
82 | * @i1480: Device descriptor | ||
83 | * @data: where to place the read array | ||
84 | * @srcaddr: Where to read from | ||
85 | * @size: Size of the data read array | ||
86 | * @returns: 0 if ok, < 0 errno code on error. | ||
87 | * | ||
88 | * The command data array is organized into pairs ADDR0 ADDR1..., and | ||
89 | * the returned data in ADDR0 VALUE0 ADDR1 VALUE1... | ||
90 | * | ||
91 | * We generate the command array to be a sequential read and then | ||
92 | * rearrange the result. | ||
93 | * | ||
94 | * We use the i1480->cmd_buf for the command, i1480->evt_buf for the reply. | ||
95 | * | ||
96 | * As the reply has to fit in 512 bytes (i1480->evt_buffer), the max amount | ||
97 | * of values we can read is (512 - sizeof(*reply)) / 3 | ||
98 | */ | ||
99 | static | ||
100 | int i1480_mpi_read(struct i1480 *i1480, u8 *data, u16 srcaddr, size_t size) | ||
101 | { | ||
102 | int result; | ||
103 | struct i1480_cmd_mpi_read *cmd = i1480->cmd_buf; | ||
104 | struct i1480_evt_mpi_read *reply = i1480->evt_buf; | ||
105 | unsigned cnt; | ||
106 | |||
107 | memset(i1480->cmd_buf, 0x69, 512); | ||
108 | memset(i1480->evt_buf, 0x69, 512); | ||
109 | |||
110 | BUG_ON(size > (i1480->buf_size - sizeof(*reply)) / 3); | ||
111 | result = -ENOMEM; | ||
112 | cmd->rccb.bCommandType = i1480_CET_VS1; | ||
113 | cmd->rccb.wCommand = cpu_to_le16(i1480_CMD_MPI_READ); | ||
114 | cmd->size = cpu_to_le16(3*size); | ||
115 | for (cnt = 0; cnt < size; cnt++) { | ||
116 | cmd->data[cnt].page = (srcaddr + cnt) >> 8; | ||
117 | cmd->data[cnt].offset = (srcaddr + cnt) & 0xff; | ||
118 | } | ||
119 | reply->rceb.bEventType = i1480_CET_VS1; | ||
120 | reply->rceb.wEvent = i1480_CMD_MPI_READ; | ||
121 | result = i1480_cmd(i1480, "MPI-READ", sizeof(*cmd) + 2*size, | ||
122 | sizeof(*reply) + 3*size); | ||
123 | if (result < 0) | ||
124 | goto out; | ||
125 | if (reply->bResultCode != UWB_RC_RES_SUCCESS) { | ||
126 | dev_err(i1480->dev, "MPI-READ: command execution failed: %d\n", | ||
127 | reply->bResultCode); | ||
128 | result = -EIO; | ||
129 | } | ||
130 | for (cnt = 0; cnt < size; cnt++) { | ||
131 | if (reply->data[cnt].page != (srcaddr + cnt) >> 8) | ||
132 | dev_err(i1480->dev, "MPI-READ: page inconsistency at " | ||
133 | "index %u: expected 0x%02x, got 0x%02x\n", cnt, | ||
134 | (srcaddr + cnt) >> 8, reply->data[cnt].page); | ||
135 | if (reply->data[cnt].offset != ((srcaddr + cnt) & 0x00ff)) | ||
136 | dev_err(i1480->dev, "MPI-READ: offset inconsistency at " | ||
137 | "index %u: expected 0x%02x, got 0x%02x\n", cnt, | ||
138 | (srcaddr + cnt) & 0x00ff, | ||
139 | reply->data[cnt].offset); | ||
140 | data[cnt] = reply->data[cnt].value; | ||
141 | } | ||
142 | result = 0; | ||
143 | out: | ||
144 | return result; | ||
145 | } | ||
146 | |||
147 | |||
148 | /** | ||
149 | * Upload a PHY firmware, wait for it to start | ||
150 | * | ||
151 | * @i1480: Device instance | ||
152 | * @fw_name: Name of the file that contains the firmware | ||
153 | * | ||
154 | * We assume the MAC fw is up and running. This means we can use the | ||
155 | * MPI interface to write the PHY firmware. Once done, we issue an | ||
156 | * MBOA Reset, which will force the MAC to reset and reinitialize the | ||
157 | * PHY. If that works, we are ready to go. | ||
158 | * | ||
159 | * Max packet size for the MPI write is 512, so the max buffer is 480 | ||
160 | * (which gives us 160 byte triads of MSB, LSB and VAL for the data). | ||
161 | */ | ||
162 | int i1480_phy_fw_upload(struct i1480 *i1480) | ||
163 | { | ||
164 | int result; | ||
165 | const struct firmware *fw; | ||
166 | const char *data_itr, *data_top; | ||
167 | const size_t MAX_BLK_SIZE = 480; /* 160 triads */ | ||
168 | size_t data_size; | ||
169 | u8 phy_stat; | ||
170 | |||
171 | result = request_firmware(&fw, i1480->phy_fw_name, i1480->dev); | ||
172 | if (result < 0) | ||
173 | goto out; | ||
174 | /* Loop writing data in chunks as big as possible until done. */ | ||
175 | for (data_itr = fw->data, data_top = data_itr + fw->size; | ||
176 | data_itr < data_top; data_itr += MAX_BLK_SIZE) { | ||
177 | data_size = min(MAX_BLK_SIZE, (size_t) (data_top - data_itr)); | ||
178 | result = i1480_mpi_write(i1480, data_itr, data_size); | ||
179 | if (result < 0) | ||
180 | goto error_mpi_write; | ||
181 | } | ||
182 | /* Read MPI page 0, offset 6; if 0, PHY was initialized correctly. */ | ||
183 | result = i1480_mpi_read(i1480, &phy_stat, 0x0006, 1); | ||
184 | if (result < 0) { | ||
185 | dev_err(i1480->dev, "PHY: can't get status: %d\n", result); | ||
186 | goto error_mpi_status; | ||
187 | } | ||
188 | if (phy_stat != 0) { | ||
189 | result = -ENODEV; | ||
190 | dev_info(i1480->dev, "error, PHY not ready: %u\n", phy_stat); | ||
191 | goto error_phy_status; | ||
192 | } | ||
193 | dev_info(i1480->dev, "PHY fw '%s': uploaded\n", i1480->phy_fw_name); | ||
194 | error_phy_status: | ||
195 | error_mpi_status: | ||
196 | error_mpi_write: | ||
197 | release_firmware(fw); | ||
198 | if (result < 0) | ||
199 | dev_err(i1480->dev, "PHY fw '%s': failed to upload (%d), " | ||
200 | "power cycle device\n", i1480->phy_fw_name, result); | ||
201 | out: | ||
202 | return result; | ||
203 | } | ||
diff --git a/drivers/uwb/i1480/dfu/usb.c b/drivers/uwb/i1480/dfu/usb.c new file mode 100644 index 000000000000..98eeeff051aa --- /dev/null +++ b/drivers/uwb/i1480/dfu/usb.c | |||
@@ -0,0 +1,500 @@ | |||
1 | /* | ||
2 | * Intel Wireless UWB Link 1480 | ||
3 | * USB SKU firmware upload implementation | ||
4 | * | ||
5 | * Copyright (C) 2005-2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
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 | * This driver will prepare the i1480 device to behave as a real | ||
24 | * Wireless USB HWA adaptor by uploading the firmware. | ||
25 | * | ||
26 | * When the device is connected or driver is loaded, i1480_usb_probe() | ||
27 | * is called--this will allocate and initialize the device structure, | ||
28 | * fill in the pointers to the common functions (read, write, | ||
29 | * wait_init_done and cmd for HWA command execution) and once that is | ||
30 | * done, call the common firmware uploading routine. Then clean up and | ||
31 | * return -ENODEV, as we don't attach to the device. | ||
32 | * | ||
33 | * The rest are the basic ops we implement that the fw upload code | ||
34 | * uses to do its job. All the ops in the common code are i1480->NAME, | ||
35 | * the functions are i1480_usb_NAME(). | ||
36 | */ | ||
37 | #include <linux/module.h> | ||
38 | #include <linux/version.h> | ||
39 | #include <linux/usb.h> | ||
40 | #include <linux/interrupt.h> | ||
41 | #include <linux/delay.h> | ||
42 | #include <linux/uwb.h> | ||
43 | #include <linux/usb/wusb.h> | ||
44 | #include <linux/usb/wusb-wa.h> | ||
45 | #include "i1480-dfu.h" | ||
46 | |||
47 | #define D_LOCAL 0 | ||
48 | #include <linux/uwb/debug.h> | ||
49 | |||
50 | |||
51 | struct i1480_usb { | ||
52 | struct i1480 i1480; | ||
53 | struct usb_device *usb_dev; | ||
54 | struct usb_interface *usb_iface; | ||
55 | struct urb *neep_urb; /* URB for reading from EP1 */ | ||
56 | }; | ||
57 | |||
58 | |||
59 | static | ||
60 | void i1480_usb_init(struct i1480_usb *i1480_usb) | ||
61 | { | ||
62 | i1480_init(&i1480_usb->i1480); | ||
63 | } | ||
64 | |||
65 | |||
66 | static | ||
67 | int i1480_usb_create(struct i1480_usb *i1480_usb, struct usb_interface *iface) | ||
68 | { | ||
69 | struct usb_device *usb_dev = interface_to_usbdev(iface); | ||
70 | int result = -ENOMEM; | ||
71 | |||
72 | i1480_usb->usb_dev = usb_get_dev(usb_dev); /* bind the USB device */ | ||
73 | i1480_usb->usb_iface = usb_get_intf(iface); | ||
74 | usb_set_intfdata(iface, i1480_usb); /* Bind the driver to iface0 */ | ||
75 | i1480_usb->neep_urb = usb_alloc_urb(0, GFP_KERNEL); | ||
76 | if (i1480_usb->neep_urb == NULL) | ||
77 | goto error; | ||
78 | return 0; | ||
79 | |||
80 | error: | ||
81 | usb_set_intfdata(iface, NULL); | ||
82 | usb_put_intf(iface); | ||
83 | usb_put_dev(usb_dev); | ||
84 | return result; | ||
85 | } | ||
86 | |||
87 | |||
88 | static | ||
89 | void i1480_usb_destroy(struct i1480_usb *i1480_usb) | ||
90 | { | ||
91 | usb_kill_urb(i1480_usb->neep_urb); | ||
92 | usb_free_urb(i1480_usb->neep_urb); | ||
93 | usb_set_intfdata(i1480_usb->usb_iface, NULL); | ||
94 | usb_put_intf(i1480_usb->usb_iface); | ||
95 | usb_put_dev(i1480_usb->usb_dev); | ||
96 | } | ||
97 | |||
98 | |||
99 | /** | ||
100 | * Write a buffer to a memory address in the i1480 device | ||
101 | * | ||
102 | * @i1480: i1480 instance | ||
103 | * @memory_address: | ||
104 | * Address where to write the data buffer to. | ||
105 | * @buffer: Buffer to the data | ||
106 | * @size: Size of the buffer [has to be < 512]. | ||
107 | * @returns: 0 if ok, < 0 errno code on error. | ||
108 | * | ||
109 | * Data buffers to USB cannot be on the stack or in vmalloc'ed areas, | ||
110 | * so we copy it to the local i1480 buffer before proceeding. In any | ||
111 | * case, we have a max size we can send, soooo. | ||
112 | */ | ||
113 | static | ||
114 | int i1480_usb_write(struct i1480 *i1480, u32 memory_address, | ||
115 | const void *buffer, size_t size) | ||
116 | { | ||
117 | int result = 0; | ||
118 | struct i1480_usb *i1480_usb = container_of(i1480, struct i1480_usb, i1480); | ||
119 | size_t buffer_size, itr = 0; | ||
120 | |||
121 | d_fnstart(3, i1480->dev, "(%p, 0x%08x, %p, %zu)\n", | ||
122 | i1480, memory_address, buffer, size); | ||
123 | BUG_ON(size & 0x3); /* Needs to be a multiple of 4 */ | ||
124 | while (size > 0) { | ||
125 | buffer_size = size < i1480->buf_size ? size : i1480->buf_size; | ||
126 | memcpy(i1480->cmd_buf, buffer + itr, buffer_size); | ||
127 | result = usb_control_msg( | ||
128 | i1480_usb->usb_dev, usb_sndctrlpipe(i1480_usb->usb_dev, 0), | ||
129 | 0xf0, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
130 | cpu_to_le16(memory_address & 0xffff), | ||
131 | cpu_to_le16((memory_address >> 16) & 0xffff), | ||
132 | i1480->cmd_buf, buffer_size, 100 /* FIXME: arbitrary */); | ||
133 | if (result < 0) | ||
134 | break; | ||
135 | d_printf(3, i1480->dev, | ||
136 | "wrote @ 0x%08x %u bytes (of %zu bytes requested)\n", | ||
137 | memory_address, result, buffer_size); | ||
138 | d_dump(4, i1480->dev, i1480->cmd_buf, result); | ||
139 | itr += result; | ||
140 | memory_address += result; | ||
141 | size -= result; | ||
142 | } | ||
143 | d_fnend(3, i1480->dev, "(%p, 0x%08x, %p, %zu) = %d\n", | ||
144 | i1480, memory_address, buffer, size, result); | ||
145 | return result; | ||
146 | } | ||
147 | |||
148 | |||
149 | /** | ||
150 | * Read a block [max size 512] of the device's memory to @i1480's buffer. | ||
151 | * | ||
152 | * @i1480: i1480 instance | ||
153 | * @memory_address: | ||
154 | * Address where to read from. | ||
155 | * @size: Size to read. Smaller than or equal to 512. | ||
156 | * @returns: >= 0 number of bytes written if ok, < 0 errno code on error. | ||
157 | * | ||
158 | * NOTE: if the memory address or block is incorrect, you might get a | ||
159 | * stall or a different memory read. Caller has to verify the | ||
160 | * memory address and size passed back in the @neh structure. | ||
161 | */ | ||
162 | static | ||
163 | int i1480_usb_read(struct i1480 *i1480, u32 addr, size_t size) | ||
164 | { | ||
165 | ssize_t result = 0, bytes = 0; | ||
166 | size_t itr, read_size = i1480->buf_size; | ||
167 | struct i1480_usb *i1480_usb = container_of(i1480, struct i1480_usb, i1480); | ||
168 | |||
169 | d_fnstart(3, i1480->dev, "(%p, 0x%08x, %zu)\n", | ||
170 | i1480, addr, size); | ||
171 | BUG_ON(size > i1480->buf_size); | ||
172 | BUG_ON(size & 0x3); /* Needs to be a multiple of 4 */ | ||
173 | BUG_ON(read_size > 512); | ||
174 | |||
175 | if (addr >= 0x8000d200 && addr < 0x8000d400) /* Yeah, HW quirk */ | ||
176 | read_size = 4; | ||
177 | |||
178 | for (itr = 0; itr < size; itr += read_size) { | ||
179 | size_t itr_addr = addr + itr; | ||
180 | size_t itr_size = min(read_size, size - itr); | ||
181 | result = usb_control_msg( | ||
182 | i1480_usb->usb_dev, usb_rcvctrlpipe(i1480_usb->usb_dev, 0), | ||
183 | 0xf0, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
184 | cpu_to_le16(itr_addr & 0xffff), | ||
185 | cpu_to_le16((itr_addr >> 16) & 0xffff), | ||
186 | i1480->cmd_buf + itr, itr_size, | ||
187 | 100 /* FIXME: arbitrary */); | ||
188 | if (result < 0) { | ||
189 | dev_err(i1480->dev, "%s: USB read error: %zd\n", | ||
190 | __func__, result); | ||
191 | goto out; | ||
192 | } | ||
193 | if (result != itr_size) { | ||
194 | result = -EIO; | ||
195 | dev_err(i1480->dev, | ||
196 | "%s: partial read got only %zu bytes vs %zu expected\n", | ||
197 | __func__, result, itr_size); | ||
198 | goto out; | ||
199 | } | ||
200 | bytes += result; | ||
201 | } | ||
202 | result = bytes; | ||
203 | out: | ||
204 | d_fnend(3, i1480->dev, "(%p, 0x%08x, %zu) = %zd\n", | ||
205 | i1480, addr, size, result); | ||
206 | if (result > 0) | ||
207 | d_dump(4, i1480->dev, i1480->cmd_buf, result); | ||
208 | return result; | ||
209 | } | ||
210 | |||
211 | |||
212 | /** | ||
213 | * Callback for reads on the notification/event endpoint | ||
214 | * | ||
215 | * Just enables the completion read handler. | ||
216 | */ | ||
217 | static | ||
218 | void i1480_usb_neep_cb(struct urb *urb) | ||
219 | { | ||
220 | struct i1480 *i1480 = urb->context; | ||
221 | struct device *dev = i1480->dev; | ||
222 | |||
223 | switch (urb->status) { | ||
224 | case 0: | ||
225 | break; | ||
226 | case -ECONNRESET: /* Not an error, but a controlled situation; */ | ||
227 | case -ENOENT: /* (we killed the URB)...so, no broadcast */ | ||
228 | dev_dbg(dev, "NEEP: reset/noent %d\n", urb->status); | ||
229 | break; | ||
230 | case -ESHUTDOWN: /* going away! */ | ||
231 | dev_dbg(dev, "NEEP: down %d\n", urb->status); | ||
232 | break; | ||
233 | default: | ||
234 | dev_err(dev, "NEEP: unknown status %d\n", urb->status); | ||
235 | break; | ||
236 | } | ||
237 | i1480->evt_result = urb->actual_length; | ||
238 | complete(&i1480->evt_complete); | ||
239 | return; | ||
240 | } | ||
241 | |||
242 | |||
243 | /** | ||
244 | * Wait for the MAC FW to initialize | ||
245 | * | ||
246 | * MAC FW sends a 0xfd/0101/00 notification to EP1 when done | ||
247 | * initializing. Get that notification into i1480->evt_buf; upper layer | ||
248 | * will verify it. | ||
249 | * | ||
250 | * Set i1480->evt_result with the result of getting the event or its | ||
251 | * size (if succesful). | ||
252 | * | ||
253 | * Delivers the data directly to i1480->evt_buf | ||
254 | */ | ||
255 | static | ||
256 | int i1480_usb_wait_init_done(struct i1480 *i1480) | ||
257 | { | ||
258 | int result; | ||
259 | struct device *dev = i1480->dev; | ||
260 | struct i1480_usb *i1480_usb = container_of(i1480, struct i1480_usb, i1480); | ||
261 | struct usb_endpoint_descriptor *epd; | ||
262 | |||
263 | d_fnstart(3, dev, "(%p)\n", i1480); | ||
264 | init_completion(&i1480->evt_complete); | ||
265 | i1480->evt_result = -EINPROGRESS; | ||
266 | epd = &i1480_usb->usb_iface->cur_altsetting->endpoint[0].desc; | ||
267 | usb_fill_int_urb(i1480_usb->neep_urb, i1480_usb->usb_dev, | ||
268 | usb_rcvintpipe(i1480_usb->usb_dev, epd->bEndpointAddress), | ||
269 | i1480->evt_buf, i1480->buf_size, | ||
270 | i1480_usb_neep_cb, i1480, epd->bInterval); | ||
271 | result = usb_submit_urb(i1480_usb->neep_urb, GFP_KERNEL); | ||
272 | if (result < 0) { | ||
273 | dev_err(dev, "init done: cannot submit NEEP read: %d\n", | ||
274 | result); | ||
275 | goto error_submit; | ||
276 | } | ||
277 | /* Wait for the USB callback to get the data */ | ||
278 | result = wait_for_completion_interruptible_timeout( | ||
279 | &i1480->evt_complete, HZ); | ||
280 | if (result <= 0) { | ||
281 | result = result == 0 ? -ETIMEDOUT : result; | ||
282 | goto error_wait; | ||
283 | } | ||
284 | usb_kill_urb(i1480_usb->neep_urb); | ||
285 | d_fnend(3, dev, "(%p) = 0\n", i1480); | ||
286 | return 0; | ||
287 | |||
288 | error_wait: | ||
289 | usb_kill_urb(i1480_usb->neep_urb); | ||
290 | error_submit: | ||
291 | i1480->evt_result = result; | ||
292 | d_fnend(3, dev, "(%p) = %d\n", i1480, result); | ||
293 | return result; | ||
294 | } | ||
295 | |||
296 | |||
297 | /** | ||
298 | * Generic function for issuing commands to the i1480 | ||
299 | * | ||
300 | * @i1480: i1480 instance | ||
301 | * @cmd_name: Name of the command (for error messages) | ||
302 | * @cmd: Pointer to command buffer | ||
303 | * @cmd_size: Size of the command buffer | ||
304 | * @reply: Buffer for the reply event | ||
305 | * @reply_size: Expected size back (including RCEB); the reply buffer | ||
306 | * is assumed to be as big as this. | ||
307 | * @returns: >= 0 size of the returned event data if ok, | ||
308 | * < 0 errno code on error. | ||
309 | * | ||
310 | * Arms the NE handle, issues the command to the device and checks the | ||
311 | * basics of the reply event. | ||
312 | */ | ||
313 | static | ||
314 | int i1480_usb_cmd(struct i1480 *i1480, const char *cmd_name, size_t cmd_size) | ||
315 | { | ||
316 | int result; | ||
317 | struct device *dev = i1480->dev; | ||
318 | struct i1480_usb *i1480_usb = container_of(i1480, struct i1480_usb, i1480); | ||
319 | struct usb_endpoint_descriptor *epd; | ||
320 | struct uwb_rccb *cmd = i1480->cmd_buf; | ||
321 | u8 iface_no; | ||
322 | |||
323 | d_fnstart(3, dev, "(%p, %s, %zu)\n", i1480, cmd_name, cmd_size); | ||
324 | /* Post a read on the notification & event endpoint */ | ||
325 | iface_no = i1480_usb->usb_iface->cur_altsetting->desc.bInterfaceNumber; | ||
326 | epd = &i1480_usb->usb_iface->cur_altsetting->endpoint[0].desc; | ||
327 | usb_fill_int_urb( | ||
328 | i1480_usb->neep_urb, i1480_usb->usb_dev, | ||
329 | usb_rcvintpipe(i1480_usb->usb_dev, epd->bEndpointAddress), | ||
330 | i1480->evt_buf, i1480->buf_size, | ||
331 | i1480_usb_neep_cb, i1480, epd->bInterval); | ||
332 | result = usb_submit_urb(i1480_usb->neep_urb, GFP_KERNEL); | ||
333 | if (result < 0) { | ||
334 | dev_err(dev, "%s: cannot submit NEEP read: %d\n", | ||
335 | cmd_name, result); | ||
336 | goto error_submit_ep1; | ||
337 | } | ||
338 | /* Now post the command on EP0 */ | ||
339 | result = usb_control_msg( | ||
340 | i1480_usb->usb_dev, usb_sndctrlpipe(i1480_usb->usb_dev, 0), | ||
341 | WA_EXEC_RC_CMD, | ||
342 | USB_DIR_OUT | USB_RECIP_INTERFACE | USB_TYPE_CLASS, | ||
343 | 0, iface_no, | ||
344 | cmd, cmd_size, | ||
345 | 100 /* FIXME: this is totally arbitrary */); | ||
346 | if (result < 0) { | ||
347 | dev_err(dev, "%s: control request failed: %d\n", | ||
348 | cmd_name, result); | ||
349 | goto error_submit_ep0; | ||
350 | } | ||
351 | d_fnend(3, dev, "(%p, %s, %zu) = %d\n", | ||
352 | i1480, cmd_name, cmd_size, result); | ||
353 | return result; | ||
354 | |||
355 | error_submit_ep0: | ||
356 | usb_kill_urb(i1480_usb->neep_urb); | ||
357 | error_submit_ep1: | ||
358 | d_fnend(3, dev, "(%p, %s, %zu) = %d\n", | ||
359 | i1480, cmd_name, cmd_size, result); | ||
360 | return result; | ||
361 | } | ||
362 | |||
363 | |||
364 | /* | ||
365 | * Probe a i1480 device for uploading firmware. | ||
366 | * | ||
367 | * We attach only to interface #0, which is the radio control interface. | ||
368 | */ | ||
369 | static | ||
370 | int i1480_usb_probe(struct usb_interface *iface, const struct usb_device_id *id) | ||
371 | { | ||
372 | struct i1480_usb *i1480_usb; | ||
373 | struct i1480 *i1480; | ||
374 | struct device *dev = &iface->dev; | ||
375 | int result; | ||
376 | |||
377 | result = -ENODEV; | ||
378 | if (iface->cur_altsetting->desc.bInterfaceNumber != 0) { | ||
379 | dev_dbg(dev, "not attaching to iface %d\n", | ||
380 | iface->cur_altsetting->desc.bInterfaceNumber); | ||
381 | goto error; | ||
382 | } | ||
383 | if (iface->num_altsetting > 1 | ||
384 | && interface_to_usbdev(iface)->descriptor.idProduct == 0xbabe) { | ||
385 | /* Need altsetting #1 [HW QUIRK] or EP1 won't work */ | ||
386 | result = usb_set_interface(interface_to_usbdev(iface), 0, 1); | ||
387 | if (result < 0) | ||
388 | dev_warn(dev, | ||
389 | "can't set altsetting 1 on iface 0: %d\n", | ||
390 | result); | ||
391 | } | ||
392 | |||
393 | result = -ENOMEM; | ||
394 | i1480_usb = kzalloc(sizeof(*i1480_usb), GFP_KERNEL); | ||
395 | if (i1480_usb == NULL) { | ||
396 | dev_err(dev, "Unable to allocate instance\n"); | ||
397 | goto error; | ||
398 | } | ||
399 | i1480_usb_init(i1480_usb); | ||
400 | |||
401 | i1480 = &i1480_usb->i1480; | ||
402 | i1480->buf_size = 512; | ||
403 | i1480->cmd_buf = kmalloc(2 * i1480->buf_size, GFP_KERNEL); | ||
404 | if (i1480->cmd_buf == NULL) { | ||
405 | dev_err(dev, "Cannot allocate transfer buffers\n"); | ||
406 | result = -ENOMEM; | ||
407 | goto error_buf_alloc; | ||
408 | } | ||
409 | i1480->evt_buf = i1480->cmd_buf + i1480->buf_size; | ||
410 | |||
411 | result = i1480_usb_create(i1480_usb, iface); | ||
412 | if (result < 0) { | ||
413 | dev_err(dev, "Cannot create instance: %d\n", result); | ||
414 | goto error_create; | ||
415 | } | ||
416 | |||
417 | /* setup the fops and upload the firmare */ | ||
418 | i1480->pre_fw_name = "i1480-pre-phy-0.0.bin"; | ||
419 | i1480->mac_fw_name = "i1480-usb-0.0.bin"; | ||
420 | i1480->mac_fw_name_deprecate = "ptc-0.0.bin"; | ||
421 | i1480->phy_fw_name = "i1480-phy-0.0.bin"; | ||
422 | i1480->dev = &iface->dev; | ||
423 | i1480->write = i1480_usb_write; | ||
424 | i1480->read = i1480_usb_read; | ||
425 | i1480->rc_setup = NULL; | ||
426 | i1480->wait_init_done = i1480_usb_wait_init_done; | ||
427 | i1480->cmd = i1480_usb_cmd; | ||
428 | |||
429 | result = i1480_fw_upload(&i1480_usb->i1480); /* the real thing */ | ||
430 | if (result >= 0) { | ||
431 | usb_reset_device(i1480_usb->usb_dev); | ||
432 | result = -ENODEV; /* we don't want to bind to the iface */ | ||
433 | } | ||
434 | i1480_usb_destroy(i1480_usb); | ||
435 | error_create: | ||
436 | kfree(i1480->cmd_buf); | ||
437 | error_buf_alloc: | ||
438 | kfree(i1480_usb); | ||
439 | error: | ||
440 | return result; | ||
441 | } | ||
442 | |||
443 | #define i1480_USB_DEV(v, p) \ | ||
444 | { \ | ||
445 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE \ | ||
446 | | USB_DEVICE_ID_MATCH_DEV_INFO \ | ||
447 | | USB_DEVICE_ID_MATCH_INT_INFO, \ | ||
448 | .idVendor = (v), \ | ||
449 | .idProduct = (p), \ | ||
450 | .bDeviceClass = 0xff, \ | ||
451 | .bDeviceSubClass = 0xff, \ | ||
452 | .bDeviceProtocol = 0xff, \ | ||
453 | .bInterfaceClass = 0xff, \ | ||
454 | .bInterfaceSubClass = 0xff, \ | ||
455 | .bInterfaceProtocol = 0xff, \ | ||
456 | } | ||
457 | |||
458 | |||
459 | /** USB device ID's that we handle */ | ||
460 | static struct usb_device_id i1480_usb_id_table[] = { | ||
461 | i1480_USB_DEV(0x8086, 0xdf3b), | ||
462 | i1480_USB_DEV(0x15a9, 0x0005), | ||
463 | i1480_USB_DEV(0x07d1, 0x3802), | ||
464 | i1480_USB_DEV(0x050d, 0x305a), | ||
465 | i1480_USB_DEV(0x3495, 0x3007), | ||
466 | {}, | ||
467 | }; | ||
468 | MODULE_DEVICE_TABLE(usb, i1480_usb_id_table); | ||
469 | |||
470 | |||
471 | static struct usb_driver i1480_dfu_driver = { | ||
472 | .name = "i1480-dfu-usb", | ||
473 | .id_table = i1480_usb_id_table, | ||
474 | .probe = i1480_usb_probe, | ||
475 | .disconnect = NULL, | ||
476 | }; | ||
477 | |||
478 | |||
479 | /* | ||
480 | * Initialize the i1480 DFU driver. | ||
481 | * | ||
482 | * We also need to register our function for guessing event sizes. | ||
483 | */ | ||
484 | static int __init i1480_dfu_driver_init(void) | ||
485 | { | ||
486 | return usb_register(&i1480_dfu_driver); | ||
487 | } | ||
488 | module_init(i1480_dfu_driver_init); | ||
489 | |||
490 | |||
491 | static void __exit i1480_dfu_driver_exit(void) | ||
492 | { | ||
493 | usb_deregister(&i1480_dfu_driver); | ||
494 | } | ||
495 | module_exit(i1480_dfu_driver_exit); | ||
496 | |||
497 | |||
498 | MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>"); | ||
499 | MODULE_DESCRIPTION("Intel Wireless UWB Link 1480 firmware uploader for USB"); | ||
500 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/uwb/i1480/i1480-est.c b/drivers/uwb/i1480/i1480-est.c new file mode 100644 index 000000000000..7bf8c6febae7 --- /dev/null +++ b/drivers/uwb/i1480/i1480-est.c | |||
@@ -0,0 +1,99 @@ | |||
1 | /* | ||
2 | * Intel Wireless UWB Link 1480 | ||
3 | * Event Size tables for Wired Adaptors | ||
4 | * | ||
5 | * Copyright (C) 2005-2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
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: docs | ||
24 | */ | ||
25 | |||
26 | #include <linux/init.h> | ||
27 | #include <linux/module.h> | ||
28 | #include <linux/usb.h> | ||
29 | #include <linux/uwb.h> | ||
30 | #include "dfu/i1480-dfu.h" | ||
31 | |||
32 | |||
33 | /** Event size table for wEvents 0x00XX */ | ||
34 | static struct uwb_est_entry i1480_est_fd00[] = { | ||
35 | /* Anybody expecting this response has to use | ||
36 | * neh->extra_size to specify the real size that will | ||
37 | * come back. */ | ||
38 | [i1480_EVT_CONFIRM] = { .size = sizeof(struct i1480_evt_confirm) }, | ||
39 | [i1480_CMD_SET_IP_MAS] = { .size = sizeof(struct i1480_evt_confirm) }, | ||
40 | #ifdef i1480_RCEB_EXTENDED | ||
41 | [0x09] = { | ||
42 | .size = sizeof(struct i1480_rceb), | ||
43 | .offset = 1 + offsetof(struct i1480_rceb, wParamLength), | ||
44 | }, | ||
45 | #endif | ||
46 | }; | ||
47 | |||
48 | /** Event size table for wEvents 0x01XX */ | ||
49 | static struct uwb_est_entry i1480_est_fd01[] = { | ||
50 | [0xff & i1480_EVT_RM_INIT_DONE] = { .size = sizeof(struct i1480_rceb) }, | ||
51 | [0xff & i1480_EVT_DEV_ADD] = { .size = sizeof(struct i1480_rceb) + 9 }, | ||
52 | [0xff & i1480_EVT_DEV_RM] = { .size = sizeof(struct i1480_rceb) + 9 }, | ||
53 | [0xff & i1480_EVT_DEV_ID_CHANGE] = { | ||
54 | .size = sizeof(struct i1480_rceb) + 2 }, | ||
55 | }; | ||
56 | |||
57 | static int i1480_est_init(void) | ||
58 | { | ||
59 | int result = uwb_est_register(i1480_CET_VS1, 0x00, 0x8086, 0x0c3b, | ||
60 | i1480_est_fd00, | ||
61 | ARRAY_SIZE(i1480_est_fd00)); | ||
62 | if (result < 0) { | ||
63 | printk(KERN_ERR "Can't register EST table fd00: %d\n", result); | ||
64 | return result; | ||
65 | } | ||
66 | result = uwb_est_register(i1480_CET_VS1, 0x01, 0x8086, 0x0c3b, | ||
67 | i1480_est_fd01, ARRAY_SIZE(i1480_est_fd01)); | ||
68 | if (result < 0) { | ||
69 | printk(KERN_ERR "Can't register EST table fd01: %d\n", result); | ||
70 | return result; | ||
71 | } | ||
72 | return 0; | ||
73 | } | ||
74 | module_init(i1480_est_init); | ||
75 | |||
76 | static void i1480_est_exit(void) | ||
77 | { | ||
78 | uwb_est_unregister(i1480_CET_VS1, 0x00, 0x8086, 0x0c3b, | ||
79 | i1480_est_fd00, ARRAY_SIZE(i1480_est_fd00)); | ||
80 | uwb_est_unregister(i1480_CET_VS1, 0x01, 0x8086, 0x0c3b, | ||
81 | i1480_est_fd01, ARRAY_SIZE(i1480_est_fd01)); | ||
82 | } | ||
83 | module_exit(i1480_est_exit); | ||
84 | |||
85 | MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>"); | ||
86 | MODULE_DESCRIPTION("i1480's Vendor Specific Event Size Tables"); | ||
87 | MODULE_LICENSE("GPL"); | ||
88 | |||
89 | /** | ||
90 | * USB device ID's that we handle | ||
91 | * | ||
92 | * [so we are loaded when this kind device is connected] | ||
93 | */ | ||
94 | static struct usb_device_id i1480_est_id_table[] = { | ||
95 | { USB_DEVICE(0x8086, 0xdf3b), }, | ||
96 | { USB_DEVICE(0x8086, 0x0c3b), }, | ||
97 | { }, | ||
98 | }; | ||
99 | MODULE_DEVICE_TABLE(usb, i1480_est_id_table); | ||
diff --git a/drivers/uwb/i1480/i1480-wlp.h b/drivers/uwb/i1480/i1480-wlp.h new file mode 100644 index 000000000000..18a8b0e4567b --- /dev/null +++ b/drivers/uwb/i1480/i1480-wlp.h | |||
@@ -0,0 +1,200 @@ | |||
1 | /* | ||
2 | * Intel 1480 Wireless UWB Link | ||
3 | * WLP specific definitions | ||
4 | * | ||
5 | * | ||
6 | * Copyright (C) 2005-2006 Intel Corporation | ||
7 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License version | ||
11 | * 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
21 | * 02110-1301, USA. | ||
22 | * | ||
23 | * | ||
24 | * FIXME: docs | ||
25 | */ | ||
26 | |||
27 | #ifndef __i1480_wlp_h__ | ||
28 | #define __i1480_wlp_h__ | ||
29 | |||
30 | #include <linux/spinlock.h> | ||
31 | #include <linux/list.h> | ||
32 | #include <linux/uwb.h> | ||
33 | #include <linux/if_ether.h> | ||
34 | #include <asm/byteorder.h> | ||
35 | |||
36 | /* New simplified header format? */ | ||
37 | #undef WLP_HDR_FMT_2 /* FIXME: rename */ | ||
38 | |||
39 | /** | ||
40 | * Values of the Delivery ID & Type field when PCA or DRP | ||
41 | * | ||
42 | * The Delivery ID & Type field in the WLP TX header indicates whether | ||
43 | * the frame is PCA or DRP. This is done based on the high level bit of | ||
44 | * this field. | ||
45 | * We use this constant to test if the traffic is PCA or DRP as follows: | ||
46 | * if (wlp_tx_hdr_delivery_id_type(wlp_tx_hdr) & WLP_DRP) | ||
47 | * this is DRP traffic | ||
48 | * else | ||
49 | * this is PCA traffic | ||
50 | */ | ||
51 | enum deliver_id_type_bit { | ||
52 | WLP_DRP = 8, | ||
53 | }; | ||
54 | |||
55 | /** | ||
56 | * WLP TX header | ||
57 | * | ||
58 | * Indicates UWB/WLP-specific transmission parameters for a network | ||
59 | * packet. | ||
60 | */ | ||
61 | struct wlp_tx_hdr { | ||
62 | /* dword 0 */ | ||
63 | struct uwb_dev_addr dstaddr; | ||
64 | u8 key_index; | ||
65 | u8 mac_params; | ||
66 | /* dword 1 */ | ||
67 | u8 phy_params; | ||
68 | #ifndef WLP_HDR_FMT_2 | ||
69 | u8 reserved; | ||
70 | __le16 oui01; /* FIXME: not so sure if __le16 or u8[2] */ | ||
71 | /* dword 2 */ | ||
72 | u8 oui2; /* if all LE, it could be merged */ | ||
73 | __le16 prid; | ||
74 | #endif | ||
75 | } __attribute__((packed)); | ||
76 | |||
77 | static inline int wlp_tx_hdr_delivery_id_type(const struct wlp_tx_hdr *hdr) | ||
78 | { | ||
79 | return hdr->mac_params & 0x0f; | ||
80 | } | ||
81 | |||
82 | static inline int wlp_tx_hdr_ack_policy(const struct wlp_tx_hdr *hdr) | ||
83 | { | ||
84 | return (hdr->mac_params >> 4) & 0x07; | ||
85 | } | ||
86 | |||
87 | static inline int wlp_tx_hdr_rts_cts(const struct wlp_tx_hdr *hdr) | ||
88 | { | ||
89 | return (hdr->mac_params >> 7) & 0x01; | ||
90 | } | ||
91 | |||
92 | static inline void wlp_tx_hdr_set_delivery_id_type(struct wlp_tx_hdr *hdr, int id) | ||
93 | { | ||
94 | hdr->mac_params = (hdr->mac_params & ~0x0f) | id; | ||
95 | } | ||
96 | |||
97 | static inline void wlp_tx_hdr_set_ack_policy(struct wlp_tx_hdr *hdr, | ||
98 | enum uwb_ack_pol policy) | ||
99 | { | ||
100 | hdr->mac_params = (hdr->mac_params & ~0x70) | (policy << 4); | ||
101 | } | ||
102 | |||
103 | static inline void wlp_tx_hdr_set_rts_cts(struct wlp_tx_hdr *hdr, int rts_cts) | ||
104 | { | ||
105 | hdr->mac_params = (hdr->mac_params & ~0x80) | (rts_cts << 7); | ||
106 | } | ||
107 | |||
108 | static inline enum uwb_phy_rate wlp_tx_hdr_phy_rate(const struct wlp_tx_hdr *hdr) | ||
109 | { | ||
110 | return hdr->phy_params & 0x0f; | ||
111 | } | ||
112 | |||
113 | static inline int wlp_tx_hdr_tx_power(const struct wlp_tx_hdr *hdr) | ||
114 | { | ||
115 | return (hdr->phy_params >> 4) & 0x0f; | ||
116 | } | ||
117 | |||
118 | static inline void wlp_tx_hdr_set_phy_rate(struct wlp_tx_hdr *hdr, enum uwb_phy_rate rate) | ||
119 | { | ||
120 | hdr->phy_params = (hdr->phy_params & ~0x0f) | rate; | ||
121 | } | ||
122 | |||
123 | static inline void wlp_tx_hdr_set_tx_power(struct wlp_tx_hdr *hdr, int pwr) | ||
124 | { | ||
125 | hdr->phy_params = (hdr->phy_params & ~0xf0) | (pwr << 4); | ||
126 | } | ||
127 | |||
128 | |||
129 | /** | ||
130 | * WLP RX header | ||
131 | * | ||
132 | * Provides UWB/WLP-specific transmission data for a received | ||
133 | * network packet. | ||
134 | */ | ||
135 | struct wlp_rx_hdr { | ||
136 | /* dword 0 */ | ||
137 | struct uwb_dev_addr dstaddr; | ||
138 | struct uwb_dev_addr srcaddr; | ||
139 | /* dword 1 */ | ||
140 | u8 LQI; | ||
141 | s8 RSSI; | ||
142 | u8 reserved3; | ||
143 | #ifndef WLP_HDR_FMT_2 | ||
144 | u8 oui0; | ||
145 | /* dword 2 */ | ||
146 | __le16 oui12; | ||
147 | __le16 prid; | ||
148 | #endif | ||
149 | } __attribute__((packed)); | ||
150 | |||
151 | |||
152 | /** User configurable options for WLP */ | ||
153 | struct wlp_options { | ||
154 | struct mutex mutex; /* access to user configurable options*/ | ||
155 | struct wlp_tx_hdr def_tx_hdr; /* default tx hdr */ | ||
156 | u8 pca_base_priority; | ||
157 | u8 bw_alloc; /*index into bw_allocs[] for PCA/DRP reservations*/ | ||
158 | }; | ||
159 | |||
160 | |||
161 | static inline | ||
162 | void wlp_options_init(struct wlp_options *options) | ||
163 | { | ||
164 | mutex_init(&options->mutex); | ||
165 | wlp_tx_hdr_set_ack_policy(&options->def_tx_hdr, UWB_ACK_INM); | ||
166 | wlp_tx_hdr_set_rts_cts(&options->def_tx_hdr, 1); | ||
167 | /* FIXME: default to phy caps */ | ||
168 | wlp_tx_hdr_set_phy_rate(&options->def_tx_hdr, UWB_PHY_RATE_480); | ||
169 | #ifndef WLP_HDR_FMT_2 | ||
170 | options->def_tx_hdr.prid = cpu_to_le16(0x0000); | ||
171 | #endif | ||
172 | } | ||
173 | |||
174 | |||
175 | /* sysfs helpers */ | ||
176 | |||
177 | extern ssize_t uwb_pca_base_priority_store(struct wlp_options *, | ||
178 | const char *, size_t); | ||
179 | extern ssize_t uwb_pca_base_priority_show(const struct wlp_options *, char *); | ||
180 | extern ssize_t uwb_bw_alloc_store(struct wlp_options *, const char *, size_t); | ||
181 | extern ssize_t uwb_bw_alloc_show(const struct wlp_options *, char *); | ||
182 | extern ssize_t uwb_ack_policy_store(struct wlp_options *, | ||
183 | const char *, size_t); | ||
184 | extern ssize_t uwb_ack_policy_show(const struct wlp_options *, char *); | ||
185 | extern ssize_t uwb_rts_cts_store(struct wlp_options *, const char *, size_t); | ||
186 | extern ssize_t uwb_rts_cts_show(const struct wlp_options *, char *); | ||
187 | extern ssize_t uwb_phy_rate_store(struct wlp_options *, const char *, size_t); | ||
188 | extern ssize_t uwb_phy_rate_show(const struct wlp_options *, char *); | ||
189 | |||
190 | |||
191 | /** Simple bandwidth allocation (temporary and too simple) */ | ||
192 | struct wlp_bw_allocs { | ||
193 | const char *name; | ||
194 | struct { | ||
195 | u8 mask, stream; | ||
196 | } tx, rx; | ||
197 | }; | ||
198 | |||
199 | |||
200 | #endif /* #ifndef __i1480_wlp_h__ */ | ||
diff --git a/drivers/uwb/i1480/i1480u-wlp/Makefile b/drivers/uwb/i1480/i1480u-wlp/Makefile new file mode 100644 index 000000000000..fe6709b8e68b --- /dev/null +++ b/drivers/uwb/i1480/i1480u-wlp/Makefile | |||
@@ -0,0 +1,8 @@ | |||
1 | obj-$(CONFIG_UWB_I1480U_WLP) += i1480u-wlp.o | ||
2 | |||
3 | i1480u-wlp-objs := \ | ||
4 | lc.o \ | ||
5 | netdev.o \ | ||
6 | rx.o \ | ||
7 | sysfs.o \ | ||
8 | tx.o | ||
diff --git a/drivers/uwb/i1480/i1480u-wlp/i1480u-wlp.h b/drivers/uwb/i1480/i1480u-wlp/i1480u-wlp.h new file mode 100644 index 000000000000..5f1b2951bb83 --- /dev/null +++ b/drivers/uwb/i1480/i1480u-wlp/i1480u-wlp.h | |||
@@ -0,0 +1,284 @@ | |||
1 | /* | ||
2 | * Intel 1480 Wireless UWB Link USB | ||
3 | * Header formats, constants, general internal interfaces | ||
4 | * | ||
5 | * | ||
6 | * Copyright (C) 2005-2006 Intel Corporation | ||
7 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License version | ||
11 | * 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
21 | * 02110-1301, USA. | ||
22 | * | ||
23 | * | ||
24 | * This is not an standard interface. | ||
25 | * | ||
26 | * FIXME: docs | ||
27 | * | ||
28 | * i1480u-wlp is pretty simple: two endpoints, one for tx, one for | ||
29 | * rx. rx is polled. Network packets (ethernet, whatever) are wrapped | ||
30 | * in i1480 TX or RX headers (for sending over the air), and these | ||
31 | * packets are wrapped in UNTD headers (for sending to the WLP UWB | ||
32 | * controller). | ||
33 | * | ||
34 | * UNTD packets (UNTD hdr + i1480 hdr + network packet) packets | ||
35 | * cannot be bigger than i1480u_MAX_FRG_SIZE. When this happens, the | ||
36 | * i1480 packet is broken in chunks/packets: | ||
37 | * | ||
38 | * UNTD-1st.hdr + i1480.hdr + payload | ||
39 | * UNTD-next.hdr + payload | ||
40 | * ... | ||
41 | * UNTD-last.hdr + payload | ||
42 | * | ||
43 | * so that each packet is smaller or equal than i1480u_MAX_FRG_SIZE. | ||
44 | * | ||
45 | * All HW structures and bitmaps are little endian, so we need to play | ||
46 | * ugly tricks when defining bitfields. Hoping for the day GCC | ||
47 | * implements __attribute__((endian(1234))). | ||
48 | * | ||
49 | * FIXME: ROADMAP to the whole implementation | ||
50 | */ | ||
51 | |||
52 | #ifndef __i1480u_wlp_h__ | ||
53 | #define __i1480u_wlp_h__ | ||
54 | |||
55 | #include <linux/usb.h> | ||
56 | #include <linux/netdevice.h> | ||
57 | #include <linux/uwb.h> /* struct uwb_rc, struct uwb_notifs_handler */ | ||
58 | #include <linux/wlp.h> | ||
59 | #include "../i1480-wlp.h" | ||
60 | |||
61 | #undef i1480u_FLOW_CONTROL /* Enable flow control code */ | ||
62 | |||
63 | /** | ||
64 | * Basic flow control | ||
65 | */ | ||
66 | enum { | ||
67 | i1480u_TX_INFLIGHT_MAX = 1000, | ||
68 | i1480u_TX_INFLIGHT_THRESHOLD = 100, | ||
69 | }; | ||
70 | |||
71 | /** Maximum size of a transaction that we can tx/rx */ | ||
72 | enum { | ||
73 | /* Maximum packet size computed as follows: max UNTD header (8) + | ||
74 | * i1480 RX header (8) + max Ethernet header and payload (4096) + | ||
75 | * Padding added by skb_reserve (2) to make post Ethernet payload | ||
76 | * start on 16 byte boundary*/ | ||
77 | i1480u_MAX_RX_PKT_SIZE = 4114, | ||
78 | i1480u_MAX_FRG_SIZE = 512, | ||
79 | i1480u_RX_BUFS = 9, | ||
80 | }; | ||
81 | |||
82 | |||
83 | /** | ||
84 | * UNTD packet type | ||
85 | * | ||
86 | * We need to fragment any payload whose UNTD packet is going to be | ||
87 | * bigger than i1480u_MAX_FRG_SIZE. | ||
88 | */ | ||
89 | enum i1480u_pkt_type { | ||
90 | i1480u_PKT_FRAG_1ST = 0x1, | ||
91 | i1480u_PKT_FRAG_NXT = 0x0, | ||
92 | i1480u_PKT_FRAG_LST = 0x2, | ||
93 | i1480u_PKT_FRAG_CMP = 0x3 | ||
94 | }; | ||
95 | enum { | ||
96 | i1480u_PKT_NONE = 0x4, | ||
97 | }; | ||
98 | |||
99 | /** USB Network Transfer Descriptor - common */ | ||
100 | struct untd_hdr { | ||
101 | u8 type; | ||
102 | __le16 len; | ||
103 | } __attribute__((packed)); | ||
104 | |||
105 | static inline enum i1480u_pkt_type untd_hdr_type(const struct untd_hdr *hdr) | ||
106 | { | ||
107 | return hdr->type & 0x03; | ||
108 | } | ||
109 | |||
110 | static inline int untd_hdr_rx_tx(const struct untd_hdr *hdr) | ||
111 | { | ||
112 | return (hdr->type >> 2) & 0x01; | ||
113 | } | ||
114 | |||
115 | static inline void untd_hdr_set_type(struct untd_hdr *hdr, enum i1480u_pkt_type type) | ||
116 | { | ||
117 | hdr->type = (hdr->type & ~0x03) | type; | ||
118 | } | ||
119 | |||
120 | static inline void untd_hdr_set_rx_tx(struct untd_hdr *hdr, int rx_tx) | ||
121 | { | ||
122 | hdr->type = (hdr->type & ~0x04) | (rx_tx << 2); | ||
123 | } | ||
124 | |||
125 | |||
126 | /** | ||
127 | * USB Network Transfer Descriptor - Complete Packet | ||
128 | * | ||
129 | * This is for a packet that is smaller (header + payload) than | ||
130 | * i1480u_MAX_FRG_SIZE. | ||
131 | * | ||
132 | * @hdr.total_len is the size of the payload; the payload doesn't | ||
133 | * count this header nor the padding, but includes the size of i1480 | ||
134 | * header. | ||
135 | */ | ||
136 | struct untd_hdr_cmp { | ||
137 | struct untd_hdr hdr; | ||
138 | u8 padding; | ||
139 | } __attribute__((packed)); | ||
140 | |||
141 | |||
142 | /** | ||
143 | * USB Network Transfer Descriptor - First fragment | ||
144 | * | ||
145 | * @hdr.len is the size of the *whole packet* (excluding UNTD | ||
146 | * headers); @fragment_len is the size of the payload (excluding UNTD | ||
147 | * headers, but including i1480 headers). | ||
148 | */ | ||
149 | struct untd_hdr_1st { | ||
150 | struct untd_hdr hdr; | ||
151 | __le16 fragment_len; | ||
152 | u8 padding[3]; | ||
153 | } __attribute__((packed)); | ||
154 | |||
155 | |||
156 | /** | ||
157 | * USB Network Transfer Descriptor - Next / Last [Rest] | ||
158 | * | ||
159 | * @hdr.len is the size of the payload, not including headrs. | ||
160 | */ | ||
161 | struct untd_hdr_rst { | ||
162 | struct untd_hdr hdr; | ||
163 | u8 padding; | ||
164 | } __attribute__((packed)); | ||
165 | |||
166 | |||
167 | /** | ||
168 | * Transmission context | ||
169 | * | ||
170 | * Wraps all the stuff needed to track a pending/active tx | ||
171 | * operation. | ||
172 | */ | ||
173 | struct i1480u_tx { | ||
174 | struct list_head list_node; | ||
175 | struct i1480u *i1480u; | ||
176 | struct urb *urb; | ||
177 | |||
178 | struct sk_buff *skb; | ||
179 | struct wlp_tx_hdr *wlp_tx_hdr; | ||
180 | |||
181 | void *buf; /* if NULL, no new buf was used */ | ||
182 | size_t buf_size; | ||
183 | }; | ||
184 | |||
185 | /** | ||
186 | * Basic flow control | ||
187 | * | ||
188 | * We maintain a basic flow control counter. "count" how many TX URBs are | ||
189 | * outstanding. Only allow "max" | ||
190 | * TX URBs to be outstanding. If this value is reached the queue will be | ||
191 | * stopped. The queue will be restarted when there are | ||
192 | * "threshold" URBs outstanding. | ||
193 | * Maintain a counter of how many time the TX queue needed to be restarted | ||
194 | * due to the "max" being exceeded and the "threshold" reached again. The | ||
195 | * timestamp "restart_ts" is to keep track from when the counter was last | ||
196 | * queried (see sysfs handling of file wlp_tx_inflight). | ||
197 | */ | ||
198 | struct i1480u_tx_inflight { | ||
199 | atomic_t count; | ||
200 | unsigned long max; | ||
201 | unsigned long threshold; | ||
202 | unsigned long restart_ts; | ||
203 | atomic_t restart_count; | ||
204 | }; | ||
205 | |||
206 | /** | ||
207 | * Instance of a i1480u WLP interface | ||
208 | * | ||
209 | * Keeps references to the USB device that wraps it, as well as it's | ||
210 | * interface and associated UWB host controller. As well, it also | ||
211 | * keeps a link to the netdevice for integration into the networking | ||
212 | * stack. | ||
213 | * We maintian separate error history for the tx and rx endpoints because | ||
214 | * the implementation does not rely on locking - having one shared | ||
215 | * structure between endpoints may cause problems. Adding locking to the | ||
216 | * implementation will have higher cost than adding a separate structure. | ||
217 | */ | ||
218 | struct i1480u { | ||
219 | struct usb_device *usb_dev; | ||
220 | struct usb_interface *usb_iface; | ||
221 | struct net_device *net_dev; | ||
222 | |||
223 | spinlock_t lock; | ||
224 | struct net_device_stats stats; | ||
225 | |||
226 | /* RX context handling */ | ||
227 | struct sk_buff *rx_skb; | ||
228 | struct uwb_dev_addr rx_srcaddr; | ||
229 | size_t rx_untd_pkt_size; | ||
230 | struct i1480u_rx_buf { | ||
231 | struct i1480u *i1480u; /* back pointer */ | ||
232 | struct urb *urb; | ||
233 | struct sk_buff *data; /* i1480u_MAX_RX_PKT_SIZE each */ | ||
234 | } rx_buf[i1480u_RX_BUFS]; /* N bufs */ | ||
235 | |||
236 | spinlock_t tx_list_lock; /* TX context */ | ||
237 | struct list_head tx_list; | ||
238 | u8 tx_stream; | ||
239 | |||
240 | struct stats lqe_stats, rssi_stats; /* radio statistics */ | ||
241 | |||
242 | /* Options we can set from sysfs */ | ||
243 | struct wlp_options options; | ||
244 | struct uwb_notifs_handler uwb_notifs_handler; | ||
245 | struct edc tx_errors; | ||
246 | struct edc rx_errors; | ||
247 | struct wlp wlp; | ||
248 | #ifdef i1480u_FLOW_CONTROL | ||
249 | struct urb *notif_urb; | ||
250 | struct edc notif_edc; /* error density counter */ | ||
251 | u8 notif_buffer[1]; | ||
252 | #endif | ||
253 | struct i1480u_tx_inflight tx_inflight; | ||
254 | }; | ||
255 | |||
256 | /* Internal interfaces */ | ||
257 | extern void i1480u_rx_cb(struct urb *urb); | ||
258 | extern int i1480u_rx_setup(struct i1480u *); | ||
259 | extern void i1480u_rx_release(struct i1480u *); | ||
260 | extern void i1480u_tx_release(struct i1480u *); | ||
261 | extern int i1480u_xmit_frame(struct wlp *, struct sk_buff *, | ||
262 | struct uwb_dev_addr *); | ||
263 | extern void i1480u_stop_queue(struct wlp *); | ||
264 | extern void i1480u_start_queue(struct wlp *); | ||
265 | extern int i1480u_sysfs_setup(struct i1480u *); | ||
266 | extern void i1480u_sysfs_release(struct i1480u *); | ||
267 | |||
268 | /* netdev interface */ | ||
269 | extern int i1480u_open(struct net_device *); | ||
270 | extern int i1480u_stop(struct net_device *); | ||
271 | extern int i1480u_hard_start_xmit(struct sk_buff *, struct net_device *); | ||
272 | extern void i1480u_tx_timeout(struct net_device *); | ||
273 | extern int i1480u_set_config(struct net_device *, struct ifmap *); | ||
274 | extern struct net_device_stats *i1480u_get_stats(struct net_device *); | ||
275 | extern int i1480u_change_mtu(struct net_device *, int); | ||
276 | extern void i1480u_uwb_notifs_cb(void *, struct uwb_dev *, enum uwb_notifs); | ||
277 | |||
278 | /* bandwidth allocation callback */ | ||
279 | extern void i1480u_bw_alloc_cb(struct uwb_rsv *); | ||
280 | |||
281 | /* Sys FS */ | ||
282 | extern struct attribute_group i1480u_wlp_attr_group; | ||
283 | |||
284 | #endif /* #ifndef __i1480u_wlp_h__ */ | ||
diff --git a/drivers/uwb/i1480/i1480u-wlp/lc.c b/drivers/uwb/i1480/i1480u-wlp/lc.c new file mode 100644 index 000000000000..737d60cd5b73 --- /dev/null +++ b/drivers/uwb/i1480/i1480u-wlp/lc.c | |||
@@ -0,0 +1,421 @@ | |||
1 | /* | ||
2 | * WUSB Wire Adapter: WLP interface | ||
3 | * Driver for the Linux Network stack. | ||
4 | * | ||
5 | * Copyright (C) 2005-2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
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: docs | ||
24 | * | ||
25 | * This implements a very simple network driver for the WLP USB | ||
26 | * device that is associated to a UWB (Ultra Wide Band) host. | ||
27 | * | ||
28 | * This is seen as an interface of a composite device. Once the UWB | ||
29 | * host has an association to another WLP capable device, the | ||
30 | * networking interface (aka WLP) can start to send packets back and | ||
31 | * forth. | ||
32 | * | ||
33 | * Limitations: | ||
34 | * | ||
35 | * - Hand cranked; can't ifup the interface until there is an association | ||
36 | * | ||
37 | * - BW allocation very simplistic [see i1480u_mas_set() and callees]. | ||
38 | * | ||
39 | * | ||
40 | * ROADMAP: | ||
41 | * | ||
42 | * ENTRY POINTS (driver model): | ||
43 | * | ||
44 | * i1480u_driver_{exit,init}(): initialization of the driver. | ||
45 | * | ||
46 | * i1480u_probe(): called by the driver code when a device | ||
47 | * matching 'i1480u_id_table' is connected. | ||
48 | * | ||
49 | * This allocs a netdev instance, inits with | ||
50 | * i1480u_add(), then registers_netdev(). | ||
51 | * i1480u_init() | ||
52 | * i1480u_add() | ||
53 | * | ||
54 | * i1480u_disconnect(): device has been disconnected/module | ||
55 | * is being removed. | ||
56 | * i1480u_rm() | ||
57 | */ | ||
58 | #include <linux/version.h> | ||
59 | #include <linux/if_arp.h> | ||
60 | #include <linux/etherdevice.h> | ||
61 | #include <linux/uwb/debug.h> | ||
62 | #include "i1480u-wlp.h" | ||
63 | |||
64 | |||
65 | |||
66 | static inline | ||
67 | void i1480u_init(struct i1480u *i1480u) | ||
68 | { | ||
69 | /* nothing so far... doesn't it suck? */ | ||
70 | spin_lock_init(&i1480u->lock); | ||
71 | INIT_LIST_HEAD(&i1480u->tx_list); | ||
72 | spin_lock_init(&i1480u->tx_list_lock); | ||
73 | wlp_options_init(&i1480u->options); | ||
74 | edc_init(&i1480u->tx_errors); | ||
75 | edc_init(&i1480u->rx_errors); | ||
76 | #ifdef i1480u_FLOW_CONTROL | ||
77 | edc_init(&i1480u->notif_edc); | ||
78 | #endif | ||
79 | stats_init(&i1480u->lqe_stats); | ||
80 | stats_init(&i1480u->rssi_stats); | ||
81 | wlp_init(&i1480u->wlp); | ||
82 | } | ||
83 | |||
84 | /** | ||
85 | * Fill WLP device information structure | ||
86 | * | ||
87 | * The structure will contain a few character arrays, each ending with a | ||
88 | * null terminated string. Each string has to fit (excluding terminating | ||
89 | * character) into a specified range obtained from the WLP substack. | ||
90 | * | ||
91 | * It is still not clear exactly how this device information should be | ||
92 | * obtained. Until we find out we use the USB device descriptor as backup, some | ||
93 | * information elements have intuitive mappings, other not. | ||
94 | */ | ||
95 | static | ||
96 | void i1480u_fill_device_info(struct wlp *wlp, struct wlp_device_info *dev_info) | ||
97 | { | ||
98 | struct i1480u *i1480u = container_of(wlp, struct i1480u, wlp); | ||
99 | struct usb_device *usb_dev = i1480u->usb_dev; | ||
100 | /* Treat device name and model name the same */ | ||
101 | if (usb_dev->descriptor.iProduct) { | ||
102 | usb_string(usb_dev, usb_dev->descriptor.iProduct, | ||
103 | dev_info->name, sizeof(dev_info->name)); | ||
104 | usb_string(usb_dev, usb_dev->descriptor.iProduct, | ||
105 | dev_info->model_name, sizeof(dev_info->model_name)); | ||
106 | } | ||
107 | if (usb_dev->descriptor.iManufacturer) | ||
108 | usb_string(usb_dev, usb_dev->descriptor.iManufacturer, | ||
109 | dev_info->manufacturer, | ||
110 | sizeof(dev_info->manufacturer)); | ||
111 | scnprintf(dev_info->model_nr, sizeof(dev_info->model_nr), "%04x", | ||
112 | __le16_to_cpu(usb_dev->descriptor.bcdDevice)); | ||
113 | if (usb_dev->descriptor.iSerialNumber) | ||
114 | usb_string(usb_dev, usb_dev->descriptor.iSerialNumber, | ||
115 | dev_info->serial, sizeof(dev_info->serial)); | ||
116 | /* FIXME: where should we obtain category? */ | ||
117 | dev_info->prim_dev_type.category = cpu_to_le16(WLP_DEV_CAT_OTHER); | ||
118 | /* FIXME: Complete OUI and OUIsubdiv attributes */ | ||
119 | } | ||
120 | |||
121 | #ifdef i1480u_FLOW_CONTROL | ||
122 | /** | ||
123 | * Callback for the notification endpoint | ||
124 | * | ||
125 | * This mostly controls the xon/xoff protocol. In case of hard error, | ||
126 | * we stop the queue. If not, we always retry. | ||
127 | */ | ||
128 | static | ||
129 | void i1480u_notif_cb(struct urb *urb, struct pt_regs *regs) | ||
130 | { | ||
131 | struct i1480u *i1480u = urb->context; | ||
132 | struct usb_interface *usb_iface = i1480u->usb_iface; | ||
133 | struct device *dev = &usb_iface->dev; | ||
134 | int result; | ||
135 | |||
136 | switch (urb->status) { | ||
137 | case 0: /* Got valid data, do xon/xoff */ | ||
138 | switch (i1480u->notif_buffer[0]) { | ||
139 | case 'N': | ||
140 | dev_err(dev, "XOFF STOPPING queue at %lu\n", jiffies); | ||
141 | netif_stop_queue(i1480u->net_dev); | ||
142 | break; | ||
143 | case 'A': | ||
144 | dev_err(dev, "XON STARTING queue at %lu\n", jiffies); | ||
145 | netif_start_queue(i1480u->net_dev); | ||
146 | break; | ||
147 | default: | ||
148 | dev_err(dev, "NEP: unknown data 0x%02hhx\n", | ||
149 | i1480u->notif_buffer[0]); | ||
150 | } | ||
151 | break; | ||
152 | case -ECONNRESET: /* Controlled situation ... */ | ||
153 | case -ENOENT: /* we killed the URB... */ | ||
154 | dev_err(dev, "NEP: URB reset/noent %d\n", urb->status); | ||
155 | goto error; | ||
156 | case -ESHUTDOWN: /* going away! */ | ||
157 | dev_err(dev, "NEP: URB down %d\n", urb->status); | ||
158 | goto error; | ||
159 | default: /* Retry unless it gets ugly */ | ||
160 | if (edc_inc(&i1480u->notif_edc, EDC_MAX_ERRORS, | ||
161 | EDC_ERROR_TIMEFRAME)) { | ||
162 | dev_err(dev, "NEP: URB max acceptable errors " | ||
163 | "exceeded; resetting device\n"); | ||
164 | goto error_reset; | ||
165 | } | ||
166 | dev_err(dev, "NEP: URB error %d\n", urb->status); | ||
167 | break; | ||
168 | } | ||
169 | result = usb_submit_urb(urb, GFP_ATOMIC); | ||
170 | if (result < 0) { | ||
171 | dev_err(dev, "NEP: Can't resubmit URB: %d; resetting device\n", | ||
172 | result); | ||
173 | goto error_reset; | ||
174 | } | ||
175 | return; | ||
176 | |||
177 | error_reset: | ||
178 | wlp_reset_all(&i1480-wlp); | ||
179 | error: | ||
180 | netif_stop_queue(i1480u->net_dev); | ||
181 | return; | ||
182 | } | ||
183 | #endif | ||
184 | |||
185 | static | ||
186 | int i1480u_add(struct i1480u *i1480u, struct usb_interface *iface) | ||
187 | { | ||
188 | int result = -ENODEV; | ||
189 | struct wlp *wlp = &i1480u->wlp; | ||
190 | struct usb_device *usb_dev = interface_to_usbdev(iface); | ||
191 | struct net_device *net_dev = i1480u->net_dev; | ||
192 | struct uwb_rc *rc; | ||
193 | struct uwb_dev *uwb_dev; | ||
194 | #ifdef i1480u_FLOW_CONTROL | ||
195 | struct usb_endpoint_descriptor *epd; | ||
196 | #endif | ||
197 | |||
198 | i1480u->usb_dev = usb_get_dev(usb_dev); | ||
199 | i1480u->usb_iface = iface; | ||
200 | rc = uwb_rc_get_by_grandpa(&i1480u->usb_dev->dev); | ||
201 | if (rc == NULL) { | ||
202 | dev_err(&iface->dev, "Cannot get associated UWB Radio " | ||
203 | "Controller\n"); | ||
204 | goto out; | ||
205 | } | ||
206 | wlp->xmit_frame = i1480u_xmit_frame; | ||
207 | wlp->fill_device_info = i1480u_fill_device_info; | ||
208 | wlp->stop_queue = i1480u_stop_queue; | ||
209 | wlp->start_queue = i1480u_start_queue; | ||
210 | result = wlp_setup(wlp, rc); | ||
211 | if (result < 0) { | ||
212 | dev_err(&iface->dev, "Cannot setup WLP\n"); | ||
213 | goto error_wlp_setup; | ||
214 | } | ||
215 | result = 0; | ||
216 | ether_setup(net_dev); /* make it an etherdevice */ | ||
217 | uwb_dev = &rc->uwb_dev; | ||
218 | /* FIXME: hookup address change notifications? */ | ||
219 | |||
220 | memcpy(net_dev->dev_addr, uwb_dev->mac_addr.data, | ||
221 | sizeof(net_dev->dev_addr)); | ||
222 | |||
223 | net_dev->hard_header_len = sizeof(struct untd_hdr_cmp) | ||
224 | + sizeof(struct wlp_tx_hdr) | ||
225 | + WLP_DATA_HLEN | ||
226 | + ETH_HLEN; | ||
227 | net_dev->mtu = 3500; | ||
228 | net_dev->tx_queue_len = 20; /* FIXME: maybe use 1000? */ | ||
229 | |||
230 | /* net_dev->flags &= ~IFF_BROADCAST; FIXME: BUG in firmware */ | ||
231 | /* FIXME: multicast disabled */ | ||
232 | net_dev->flags &= ~IFF_MULTICAST; | ||
233 | net_dev->features &= ~NETIF_F_SG; | ||
234 | net_dev->features &= ~NETIF_F_FRAGLIST; | ||
235 | /* All NETIF_F_*_CSUM disabled */ | ||
236 | net_dev->features |= NETIF_F_HIGHDMA; | ||
237 | net_dev->watchdog_timeo = 5*HZ; /* FIXME: a better default? */ | ||
238 | |||
239 | net_dev->open = i1480u_open; | ||
240 | net_dev->stop = i1480u_stop; | ||
241 | net_dev->hard_start_xmit = i1480u_hard_start_xmit; | ||
242 | net_dev->tx_timeout = i1480u_tx_timeout; | ||
243 | net_dev->get_stats = i1480u_get_stats; | ||
244 | net_dev->set_config = i1480u_set_config; | ||
245 | net_dev->change_mtu = i1480u_change_mtu; | ||
246 | |||
247 | #ifdef i1480u_FLOW_CONTROL | ||
248 | /* Notification endpoint setup (submitted when we open the device) */ | ||
249 | i1480u->notif_urb = usb_alloc_urb(0, GFP_KERNEL); | ||
250 | if (i1480u->notif_urb == NULL) { | ||
251 | dev_err(&iface->dev, "Unable to allocate notification URB\n"); | ||
252 | result = -ENOMEM; | ||
253 | goto error_urb_alloc; | ||
254 | } | ||
255 | epd = &iface->cur_altsetting->endpoint[0].desc; | ||
256 | usb_fill_int_urb(i1480u->notif_urb, usb_dev, | ||
257 | usb_rcvintpipe(usb_dev, epd->bEndpointAddress), | ||
258 | i1480u->notif_buffer, sizeof(i1480u->notif_buffer), | ||
259 | i1480u_notif_cb, i1480u, epd->bInterval); | ||
260 | |||
261 | #endif | ||
262 | |||
263 | i1480u->tx_inflight.max = i1480u_TX_INFLIGHT_MAX; | ||
264 | i1480u->tx_inflight.threshold = i1480u_TX_INFLIGHT_THRESHOLD; | ||
265 | i1480u->tx_inflight.restart_ts = jiffies; | ||
266 | usb_set_intfdata(iface, i1480u); | ||
267 | return result; | ||
268 | |||
269 | #ifdef i1480u_FLOW_CONTROL | ||
270 | error_urb_alloc: | ||
271 | #endif | ||
272 | wlp_remove(wlp); | ||
273 | error_wlp_setup: | ||
274 | uwb_rc_put(rc); | ||
275 | out: | ||
276 | usb_put_dev(i1480u->usb_dev); | ||
277 | return result; | ||
278 | } | ||
279 | |||
280 | static void i1480u_rm(struct i1480u *i1480u) | ||
281 | { | ||
282 | struct uwb_rc *rc = i1480u->wlp.rc; | ||
283 | usb_set_intfdata(i1480u->usb_iface, NULL); | ||
284 | #ifdef i1480u_FLOW_CONTROL | ||
285 | usb_kill_urb(i1480u->notif_urb); | ||
286 | usb_free_urb(i1480u->notif_urb); | ||
287 | #endif | ||
288 | wlp_remove(&i1480u->wlp); | ||
289 | uwb_rc_put(rc); | ||
290 | usb_put_dev(i1480u->usb_dev); | ||
291 | } | ||
292 | |||
293 | /** Just setup @net_dev's i1480u private data */ | ||
294 | static void i1480u_netdev_setup(struct net_device *net_dev) | ||
295 | { | ||
296 | struct i1480u *i1480u = netdev_priv(net_dev); | ||
297 | /* Initialize @i1480u */ | ||
298 | memset(i1480u, 0, sizeof(*i1480u)); | ||
299 | i1480u_init(i1480u); | ||
300 | } | ||
301 | |||
302 | /** | ||
303 | * Probe a i1480u interface and register it | ||
304 | * | ||
305 | * @iface: USB interface to link to | ||
306 | * @id: USB class/subclass/protocol id | ||
307 | * @returns: 0 if ok, < 0 errno code on error. | ||
308 | * | ||
309 | * Does basic housekeeping stuff and then allocs a netdev with space | ||
310 | * for the i1480u data. Initializes, registers in i1480u, registers in | ||
311 | * netdev, ready to go. | ||
312 | */ | ||
313 | static int i1480u_probe(struct usb_interface *iface, | ||
314 | const struct usb_device_id *id) | ||
315 | { | ||
316 | int result; | ||
317 | struct net_device *net_dev; | ||
318 | struct device *dev = &iface->dev; | ||
319 | struct i1480u *i1480u; | ||
320 | |||
321 | /* Allocate instance [calls i1480u_netdev_setup() on it] */ | ||
322 | result = -ENOMEM; | ||
323 | net_dev = alloc_netdev(sizeof(*i1480u), "wlp%d", i1480u_netdev_setup); | ||
324 | if (net_dev == NULL) { | ||
325 | dev_err(dev, "no memory for network device instance\n"); | ||
326 | goto error_alloc_netdev; | ||
327 | } | ||
328 | SET_NETDEV_DEV(net_dev, dev); | ||
329 | i1480u = netdev_priv(net_dev); | ||
330 | i1480u->net_dev = net_dev; | ||
331 | result = i1480u_add(i1480u, iface); /* Now setup all the wlp stuff */ | ||
332 | if (result < 0) { | ||
333 | dev_err(dev, "cannot add i1480u device: %d\n", result); | ||
334 | goto error_i1480u_add; | ||
335 | } | ||
336 | result = register_netdev(net_dev); /* Okey dokey, bring it up */ | ||
337 | if (result < 0) { | ||
338 | dev_err(dev, "cannot register network device: %d\n", result); | ||
339 | goto error_register_netdev; | ||
340 | } | ||
341 | i1480u_sysfs_setup(i1480u); | ||
342 | if (result < 0) | ||
343 | goto error_sysfs_init; | ||
344 | return 0; | ||
345 | |||
346 | error_sysfs_init: | ||
347 | unregister_netdev(net_dev); | ||
348 | error_register_netdev: | ||
349 | i1480u_rm(i1480u); | ||
350 | error_i1480u_add: | ||
351 | free_netdev(net_dev); | ||
352 | error_alloc_netdev: | ||
353 | return result; | ||
354 | } | ||
355 | |||
356 | |||
357 | /** | ||
358 | * Disconect a i1480u from the system. | ||
359 | * | ||
360 | * i1480u_stop() has been called before, so al the rx and tx contexts | ||
361 | * have been taken down already. Make sure the queue is stopped, | ||
362 | * unregister netdev and i1480u, free and kill. | ||
363 | */ | ||
364 | static void i1480u_disconnect(struct usb_interface *iface) | ||
365 | { | ||
366 | struct i1480u *i1480u; | ||
367 | struct net_device *net_dev; | ||
368 | |||
369 | i1480u = usb_get_intfdata(iface); | ||
370 | net_dev = i1480u->net_dev; | ||
371 | netif_stop_queue(net_dev); | ||
372 | #ifdef i1480u_FLOW_CONTROL | ||
373 | usb_kill_urb(i1480u->notif_urb); | ||
374 | #endif | ||
375 | i1480u_sysfs_release(i1480u); | ||
376 | unregister_netdev(net_dev); | ||
377 | i1480u_rm(i1480u); | ||
378 | free_netdev(net_dev); | ||
379 | } | ||
380 | |||
381 | static struct usb_device_id i1480u_id_table[] = { | ||
382 | { | ||
383 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE \ | ||
384 | | USB_DEVICE_ID_MATCH_DEV_INFO \ | ||
385 | | USB_DEVICE_ID_MATCH_INT_INFO, | ||
386 | .idVendor = 0x8086, | ||
387 | .idProduct = 0x0c3b, | ||
388 | .bDeviceClass = 0xef, | ||
389 | .bDeviceSubClass = 0x02, | ||
390 | .bDeviceProtocol = 0x02, | ||
391 | .bInterfaceClass = 0xff, | ||
392 | .bInterfaceSubClass = 0xff, | ||
393 | .bInterfaceProtocol = 0xff, | ||
394 | }, | ||
395 | {}, | ||
396 | }; | ||
397 | MODULE_DEVICE_TABLE(usb, i1480u_id_table); | ||
398 | |||
399 | static struct usb_driver i1480u_driver = { | ||
400 | .name = KBUILD_MODNAME, | ||
401 | .probe = i1480u_probe, | ||
402 | .disconnect = i1480u_disconnect, | ||
403 | .id_table = i1480u_id_table, | ||
404 | }; | ||
405 | |||
406 | static int __init i1480u_driver_init(void) | ||
407 | { | ||
408 | return usb_register(&i1480u_driver); | ||
409 | } | ||
410 | module_init(i1480u_driver_init); | ||
411 | |||
412 | |||
413 | static void __exit i1480u_driver_exit(void) | ||
414 | { | ||
415 | usb_deregister(&i1480u_driver); | ||
416 | } | ||
417 | module_exit(i1480u_driver_exit); | ||
418 | |||
419 | MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>"); | ||
420 | MODULE_DESCRIPTION("i1480 Wireless UWB Link WLP networking for USB"); | ||
421 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/uwb/i1480/i1480u-wlp/netdev.c b/drivers/uwb/i1480/i1480u-wlp/netdev.c new file mode 100644 index 000000000000..8802ac43d872 --- /dev/null +++ b/drivers/uwb/i1480/i1480u-wlp/netdev.c | |||
@@ -0,0 +1,368 @@ | |||
1 | /* | ||
2 | * WUSB Wire Adapter: WLP interface | ||
3 | * Driver for the Linux Network stack. | ||
4 | * | ||
5 | * Copyright (C) 2005-2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
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: docs | ||
24 | * | ||
25 | * Implementation of the netdevice linkage (except tx and rx related stuff). | ||
26 | * | ||
27 | * ROADMAP: | ||
28 | * | ||
29 | * ENTRY POINTS (Net device): | ||
30 | * | ||
31 | * i1480u_open(): Called when we ifconfig up the interface; | ||
32 | * associates to a UWB host controller, reserves | ||
33 | * bandwidth (MAS), sets up RX USB URB and starts | ||
34 | * the queue. | ||
35 | * | ||
36 | * i1480u_stop(): Called when we ifconfig down a interface; | ||
37 | * reverses _open(). | ||
38 | * | ||
39 | * i1480u_set_config(): | ||
40 | */ | ||
41 | |||
42 | #include <linux/if_arp.h> | ||
43 | #include <linux/etherdevice.h> | ||
44 | #include <linux/uwb/debug.h> | ||
45 | #include "i1480u-wlp.h" | ||
46 | |||
47 | struct i1480u_cmd_set_ip_mas { | ||
48 | struct uwb_rccb rccb; | ||
49 | struct uwb_dev_addr addr; | ||
50 | u8 stream; | ||
51 | u8 owner; | ||
52 | u8 type; /* enum uwb_drp_type */ | ||
53 | u8 baMAS[32]; | ||
54 | } __attribute__((packed)); | ||
55 | |||
56 | |||
57 | static | ||
58 | int i1480u_set_ip_mas( | ||
59 | struct uwb_rc *rc, | ||
60 | const struct uwb_dev_addr *dstaddr, | ||
61 | u8 stream, u8 owner, u8 type, unsigned long *mas) | ||
62 | { | ||
63 | |||
64 | int result; | ||
65 | struct i1480u_cmd_set_ip_mas *cmd; | ||
66 | struct uwb_rc_evt_confirm reply; | ||
67 | |||
68 | result = -ENOMEM; | ||
69 | cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); | ||
70 | if (cmd == NULL) | ||
71 | goto error_kzalloc; | ||
72 | cmd->rccb.bCommandType = 0xfd; | ||
73 | cmd->rccb.wCommand = cpu_to_le16(0x000e); | ||
74 | cmd->addr = *dstaddr; | ||
75 | cmd->stream = stream; | ||
76 | cmd->owner = owner; | ||
77 | cmd->type = type; | ||
78 | if (mas == NULL) | ||
79 | memset(cmd->baMAS, 0x00, sizeof(cmd->baMAS)); | ||
80 | else | ||
81 | memcpy(cmd->baMAS, mas, sizeof(cmd->baMAS)); | ||
82 | reply.rceb.bEventType = 0xfd; | ||
83 | reply.rceb.wEvent = cpu_to_le16(0x000e); | ||
84 | result = uwb_rc_cmd(rc, "SET-IP-MAS", &cmd->rccb, sizeof(*cmd), | ||
85 | &reply.rceb, sizeof(reply)); | ||
86 | if (result < 0) | ||
87 | goto error_cmd; | ||
88 | if (reply.bResultCode != UWB_RC_RES_FAIL) { | ||
89 | dev_err(&rc->uwb_dev.dev, | ||
90 | "SET-IP-MAS: command execution failed: %d\n", | ||
91 | reply.bResultCode); | ||
92 | result = -EIO; | ||
93 | } | ||
94 | error_cmd: | ||
95 | kfree(cmd); | ||
96 | error_kzalloc: | ||
97 | return result; | ||
98 | } | ||
99 | |||
100 | /* | ||
101 | * Inform a WLP interface of a MAS reservation | ||
102 | * | ||
103 | * @rc is assumed refcnted. | ||
104 | */ | ||
105 | /* FIXME: detect if remote device is WLP capable? */ | ||
106 | static int i1480u_mas_set_dev(struct uwb_dev *uwb_dev, struct uwb_rc *rc, | ||
107 | u8 stream, u8 owner, u8 type, unsigned long *mas) | ||
108 | { | ||
109 | int result = 0; | ||
110 | struct device *dev = &rc->uwb_dev.dev; | ||
111 | |||
112 | result = i1480u_set_ip_mas(rc, &uwb_dev->dev_addr, stream, owner, | ||
113 | type, mas); | ||
114 | if (result < 0) { | ||
115 | char rcaddrbuf[UWB_ADDR_STRSIZE], devaddrbuf[UWB_ADDR_STRSIZE]; | ||
116 | uwb_dev_addr_print(rcaddrbuf, sizeof(rcaddrbuf), | ||
117 | &rc->uwb_dev.dev_addr); | ||
118 | uwb_dev_addr_print(devaddrbuf, sizeof(devaddrbuf), | ||
119 | &uwb_dev->dev_addr); | ||
120 | dev_err(dev, "Set IP MAS (%s to %s) failed: %d\n", | ||
121 | rcaddrbuf, devaddrbuf, result); | ||
122 | } | ||
123 | return result; | ||
124 | } | ||
125 | |||
126 | /** | ||
127 | * Called by bandwidth allocator when change occurs in reservation. | ||
128 | * | ||
129 | * @rsv: The reservation that is being established, modified, or | ||
130 | * terminated. | ||
131 | * | ||
132 | * When a reservation is established, modified, or terminated the upper layer | ||
133 | * (WLP here) needs set/update the currently available Media Access Slots | ||
134 | * that can be use for IP traffic. | ||
135 | * | ||
136 | * Our action taken during failure depends on how the reservation is being | ||
137 | * changed: | ||
138 | * - if reservation is being established we do nothing if we cannot set the | ||
139 | * new MAS to be used | ||
140 | * - if reservation is being terminated we revert back to PCA whether the | ||
141 | * SET IP MAS command succeeds or not. | ||
142 | */ | ||
143 | void i1480u_bw_alloc_cb(struct uwb_rsv *rsv) | ||
144 | { | ||
145 | int result = 0; | ||
146 | struct i1480u *i1480u = rsv->pal_priv; | ||
147 | struct device *dev = &i1480u->usb_iface->dev; | ||
148 | struct uwb_dev *target_dev = rsv->target.dev; | ||
149 | struct uwb_rc *rc = i1480u->wlp.rc; | ||
150 | u8 stream = rsv->stream; | ||
151 | int type = rsv->type; | ||
152 | int is_owner = rsv->owner == &rc->uwb_dev; | ||
153 | unsigned long *bmp = rsv->mas.bm; | ||
154 | |||
155 | dev_err(dev, "WLP callback called - sending set ip mas\n"); | ||
156 | /*user cannot change options while setting configuration*/ | ||
157 | mutex_lock(&i1480u->options.mutex); | ||
158 | switch (rsv->state) { | ||
159 | case UWB_RSV_STATE_T_ACCEPTED: | ||
160 | case UWB_RSV_STATE_O_ESTABLISHED: | ||
161 | result = i1480u_mas_set_dev(target_dev, rc, stream, is_owner, | ||
162 | type, bmp); | ||
163 | if (result < 0) { | ||
164 | dev_err(dev, "MAS reservation failed: %d\n", result); | ||
165 | goto out; | ||
166 | } | ||
167 | if (is_owner) { | ||
168 | wlp_tx_hdr_set_delivery_id_type(&i1480u->options.def_tx_hdr, | ||
169 | WLP_DRP | stream); | ||
170 | wlp_tx_hdr_set_rts_cts(&i1480u->options.def_tx_hdr, 0); | ||
171 | } | ||
172 | break; | ||
173 | case UWB_RSV_STATE_NONE: | ||
174 | /* revert back to PCA */ | ||
175 | result = i1480u_mas_set_dev(target_dev, rc, stream, is_owner, | ||
176 | type, bmp); | ||
177 | if (result < 0) | ||
178 | dev_err(dev, "MAS reservation failed: %d\n", result); | ||
179 | /* Revert to PCA even though SET IP MAS failed. */ | ||
180 | wlp_tx_hdr_set_delivery_id_type(&i1480u->options.def_tx_hdr, | ||
181 | i1480u->options.pca_base_priority); | ||
182 | wlp_tx_hdr_set_rts_cts(&i1480u->options.def_tx_hdr, 1); | ||
183 | break; | ||
184 | default: | ||
185 | dev_err(dev, "unexpected WLP reservation state: %s (%d).\n", | ||
186 | uwb_rsv_state_str(rsv->state), rsv->state); | ||
187 | break; | ||
188 | } | ||
189 | out: | ||
190 | mutex_unlock(&i1480u->options.mutex); | ||
191 | return; | ||
192 | } | ||
193 | |||
194 | /** | ||
195 | * | ||
196 | * Called on 'ifconfig up' | ||
197 | */ | ||
198 | int i1480u_open(struct net_device *net_dev) | ||
199 | { | ||
200 | int result; | ||
201 | struct i1480u *i1480u = netdev_priv(net_dev); | ||
202 | struct wlp *wlp = &i1480u->wlp; | ||
203 | struct uwb_rc *rc; | ||
204 | struct device *dev = &i1480u->usb_iface->dev; | ||
205 | |||
206 | rc = wlp->rc; | ||
207 | result = i1480u_rx_setup(i1480u); /* Alloc RX stuff */ | ||
208 | if (result < 0) | ||
209 | goto error_rx_setup; | ||
210 | netif_wake_queue(net_dev); | ||
211 | #ifdef i1480u_FLOW_CONTROL | ||
212 | result = usb_submit_urb(i1480u->notif_urb, GFP_KERNEL);; | ||
213 | if (result < 0) { | ||
214 | dev_err(dev, "Can't submit notification URB: %d\n", result); | ||
215 | goto error_notif_urb_submit; | ||
216 | } | ||
217 | #endif | ||
218 | i1480u->uwb_notifs_handler.cb = i1480u_uwb_notifs_cb; | ||
219 | i1480u->uwb_notifs_handler.data = i1480u; | ||
220 | if (uwb_bg_joined(rc)) | ||
221 | netif_carrier_on(net_dev); | ||
222 | else | ||
223 | netif_carrier_off(net_dev); | ||
224 | uwb_notifs_register(rc, &i1480u->uwb_notifs_handler); | ||
225 | /* Interface is up with an address, now we can create WSS */ | ||
226 | result = wlp_wss_setup(net_dev, &wlp->wss); | ||
227 | if (result < 0) { | ||
228 | dev_err(dev, "Can't create WSS: %d. \n", result); | ||
229 | goto error_notif_deregister; | ||
230 | } | ||
231 | return 0; | ||
232 | error_notif_deregister: | ||
233 | uwb_notifs_deregister(rc, &i1480u->uwb_notifs_handler); | ||
234 | #ifdef i1480u_FLOW_CONTROL | ||
235 | error_notif_urb_submit: | ||
236 | #endif | ||
237 | netif_stop_queue(net_dev); | ||
238 | i1480u_rx_release(i1480u); | ||
239 | error_rx_setup: | ||
240 | return result; | ||
241 | } | ||
242 | |||
243 | |||
244 | /** | ||
245 | * Called on 'ifconfig down' | ||
246 | */ | ||
247 | int i1480u_stop(struct net_device *net_dev) | ||
248 | { | ||
249 | struct i1480u *i1480u = netdev_priv(net_dev); | ||
250 | struct wlp *wlp = &i1480u->wlp; | ||
251 | struct uwb_rc *rc = wlp->rc; | ||
252 | |||
253 | BUG_ON(wlp->rc == NULL); | ||
254 | wlp_wss_remove(&wlp->wss); | ||
255 | uwb_notifs_deregister(rc, &i1480u->uwb_notifs_handler); | ||
256 | netif_carrier_off(net_dev); | ||
257 | #ifdef i1480u_FLOW_CONTROL | ||
258 | usb_kill_urb(i1480u->notif_urb); | ||
259 | #endif | ||
260 | netif_stop_queue(net_dev); | ||
261 | i1480u_rx_release(i1480u); | ||
262 | i1480u_tx_release(i1480u); | ||
263 | return 0; | ||
264 | } | ||
265 | |||
266 | |||
267 | /** Report statistics */ | ||
268 | struct net_device_stats *i1480u_get_stats(struct net_device *net_dev) | ||
269 | { | ||
270 | struct i1480u *i1480u = netdev_priv(net_dev); | ||
271 | return &i1480u->stats; | ||
272 | } | ||
273 | |||
274 | |||
275 | /** | ||
276 | * | ||
277 | * Change the interface config--we probably don't have to do anything. | ||
278 | */ | ||
279 | int i1480u_set_config(struct net_device *net_dev, struct ifmap *map) | ||
280 | { | ||
281 | int result; | ||
282 | struct i1480u *i1480u = netdev_priv(net_dev); | ||
283 | BUG_ON(i1480u->wlp.rc == NULL); | ||
284 | result = 0; | ||
285 | return result; | ||
286 | } | ||
287 | |||
288 | /** | ||
289 | * Change the MTU of the interface | ||
290 | */ | ||
291 | int i1480u_change_mtu(struct net_device *net_dev, int mtu) | ||
292 | { | ||
293 | static union { | ||
294 | struct wlp_tx_hdr tx; | ||
295 | struct wlp_rx_hdr rx; | ||
296 | } i1480u_all_hdrs; | ||
297 | |||
298 | if (mtu < ETH_HLEN) /* We encap eth frames */ | ||
299 | return -ERANGE; | ||
300 | if (mtu > 4000 - sizeof(i1480u_all_hdrs)) | ||
301 | return -ERANGE; | ||
302 | net_dev->mtu = mtu; | ||
303 | return 0; | ||
304 | } | ||
305 | |||
306 | |||
307 | /** | ||
308 | * Callback function to handle events from UWB | ||
309 | * When we see other devices we know the carrier is ok, | ||
310 | * if we are the only device in the beacon group we set the carrier | ||
311 | * state to off. | ||
312 | * */ | ||
313 | void i1480u_uwb_notifs_cb(void *data, struct uwb_dev *uwb_dev, | ||
314 | enum uwb_notifs event) | ||
315 | { | ||
316 | struct i1480u *i1480u = data; | ||
317 | struct net_device *net_dev = i1480u->net_dev; | ||
318 | struct device *dev = &i1480u->usb_iface->dev; | ||
319 | switch (event) { | ||
320 | case UWB_NOTIF_BG_JOIN: | ||
321 | netif_carrier_on(net_dev); | ||
322 | dev_info(dev, "Link is up\n"); | ||
323 | break; | ||
324 | case UWB_NOTIF_BG_LEAVE: | ||
325 | netif_carrier_off(net_dev); | ||
326 | dev_info(dev, "Link is down\n"); | ||
327 | break; | ||
328 | default: | ||
329 | dev_err(dev, "don't know how to handle event %d from uwb\n", | ||
330 | event); | ||
331 | } | ||
332 | } | ||
333 | |||
334 | /** | ||
335 | * Stop the network queue | ||
336 | * | ||
337 | * Enable WLP substack to stop network queue. We also set the flow control | ||
338 | * threshold at this time to prevent the flow control from restarting the | ||
339 | * queue. | ||
340 | * | ||
341 | * we are loosing the current threshold value here ... FIXME? | ||
342 | */ | ||
343 | void i1480u_stop_queue(struct wlp *wlp) | ||
344 | { | ||
345 | struct i1480u *i1480u = container_of(wlp, struct i1480u, wlp); | ||
346 | struct net_device *net_dev = i1480u->net_dev; | ||
347 | i1480u->tx_inflight.threshold = 0; | ||
348 | netif_stop_queue(net_dev); | ||
349 | } | ||
350 | |||
351 | /** | ||
352 | * Start the network queue | ||
353 | * | ||
354 | * Enable WLP substack to start network queue. Also re-enable the flow | ||
355 | * control to manage the queue again. | ||
356 | * | ||
357 | * We re-enable the flow control by storing the default threshold in the | ||
358 | * flow control threshold. This means that if the user modified the | ||
359 | * threshold before the queue was stopped and restarted that information | ||
360 | * will be lost. FIXME? | ||
361 | */ | ||
362 | void i1480u_start_queue(struct wlp *wlp) | ||
363 | { | ||
364 | struct i1480u *i1480u = container_of(wlp, struct i1480u, wlp); | ||
365 | struct net_device *net_dev = i1480u->net_dev; | ||
366 | i1480u->tx_inflight.threshold = i1480u_TX_INFLIGHT_THRESHOLD; | ||
367 | netif_start_queue(net_dev); | ||
368 | } | ||
diff --git a/drivers/uwb/i1480/i1480u-wlp/rx.c b/drivers/uwb/i1480/i1480u-wlp/rx.c new file mode 100644 index 000000000000..9fc035354a76 --- /dev/null +++ b/drivers/uwb/i1480/i1480u-wlp/rx.c | |||
@@ -0,0 +1,486 @@ | |||
1 | /* | ||
2 | * WUSB Wire Adapter: WLP interface | ||
3 | * Driver for the Linux Network stack. | ||
4 | * | ||
5 | * Copyright (C) 2005-2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
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 | * i1480u's RX handling is simple. i1480u will send the received | ||
24 | * network packets broken up in fragments; 1 to N fragments make a | ||
25 | * packet, we assemble them together and deliver the packet with netif_rx(). | ||
26 | * | ||
27 | * Beacuse each USB transfer is a *single* fragment (except when the | ||
28 | * transfer contains a first fragment), each URB called thus | ||
29 | * back contains one or two fragments. So we queue N URBs, each with its own | ||
30 | * fragment buffer. When a URB is done, we process it (adding to the | ||
31 | * current skb from the fragment buffer until complete). Once | ||
32 | * processed, we requeue the URB. There is always a bunch of URBs | ||
33 | * ready to take data, so the intergap should be minimal. | ||
34 | * | ||
35 | * An URB's transfer buffer is the data field of a socket buffer. This | ||
36 | * reduces copying as data can be passed directly to network layer. If a | ||
37 | * complete packet or 1st fragment is received the URB's transfer buffer is | ||
38 | * taken away from it and used to send data to the network layer. In this | ||
39 | * case a new transfer buffer is allocated to the URB before being requeued. | ||
40 | * If a "NEXT" or "LAST" fragment is received, the fragment contents is | ||
41 | * appended to the RX packet under construction and the transfer buffer | ||
42 | * is reused. To be able to use this buffer to assemble complete packets | ||
43 | * we set each buffer's size to that of the MAX ethernet packet that can | ||
44 | * be received. There is thus room for improvement in memory usage. | ||
45 | * | ||
46 | * When the max tx fragment size increases, we should be able to read | ||
47 | * data into the skbs directly with very simple code. | ||
48 | * | ||
49 | * ROADMAP: | ||
50 | * | ||
51 | * ENTRY POINTS: | ||
52 | * | ||
53 | * i1480u_rx_setup(): setup RX context [from i1480u_open()] | ||
54 | * | ||
55 | * i1480u_rx_release(): release RX context [from i1480u_stop()] | ||
56 | * | ||
57 | * i1480u_rx_cb(): called when the RX USB URB receives a | ||
58 | * packet. It removes the header and pushes it up | ||
59 | * the Linux netdev stack with netif_rx(). | ||
60 | * | ||
61 | * i1480u_rx_buffer() | ||
62 | * i1480u_drop() and i1480u_fix() | ||
63 | * i1480u_skb_deliver | ||
64 | * | ||
65 | */ | ||
66 | |||
67 | #include <linux/netdevice.h> | ||
68 | #include <linux/etherdevice.h> | ||
69 | #include "i1480u-wlp.h" | ||
70 | |||
71 | #define D_LOCAL 0 | ||
72 | #include <linux/uwb/debug.h> | ||
73 | |||
74 | |||
75 | /** | ||
76 | * Setup the RX context | ||
77 | * | ||
78 | * Each URB is provided with a transfer_buffer that is the data field | ||
79 | * of a new socket buffer. | ||
80 | */ | ||
81 | int i1480u_rx_setup(struct i1480u *i1480u) | ||
82 | { | ||
83 | int result, cnt; | ||
84 | struct device *dev = &i1480u->usb_iface->dev; | ||
85 | struct net_device *net_dev = i1480u->net_dev; | ||
86 | struct usb_endpoint_descriptor *epd; | ||
87 | struct sk_buff *skb; | ||
88 | |||
89 | /* Alloc RX stuff */ | ||
90 | i1480u->rx_skb = NULL; /* not in process of receiving packet */ | ||
91 | result = -ENOMEM; | ||
92 | epd = &i1480u->usb_iface->cur_altsetting->endpoint[1].desc; | ||
93 | for (cnt = 0; cnt < i1480u_RX_BUFS; cnt++) { | ||
94 | struct i1480u_rx_buf *rx_buf = &i1480u->rx_buf[cnt]; | ||
95 | rx_buf->i1480u = i1480u; | ||
96 | skb = dev_alloc_skb(i1480u_MAX_RX_PKT_SIZE); | ||
97 | if (!skb) { | ||
98 | dev_err(dev, | ||
99 | "RX: cannot allocate RX buffer %d\n", cnt); | ||
100 | result = -ENOMEM; | ||
101 | goto error; | ||
102 | } | ||
103 | skb->dev = net_dev; | ||
104 | skb->ip_summed = CHECKSUM_NONE; | ||
105 | skb_reserve(skb, 2); | ||
106 | rx_buf->data = skb; | ||
107 | rx_buf->urb = usb_alloc_urb(0, GFP_KERNEL); | ||
108 | if (unlikely(rx_buf->urb == NULL)) { | ||
109 | dev_err(dev, "RX: cannot allocate URB %d\n", cnt); | ||
110 | result = -ENOMEM; | ||
111 | goto error; | ||
112 | } | ||
113 | usb_fill_bulk_urb(rx_buf->urb, i1480u->usb_dev, | ||
114 | usb_rcvbulkpipe(i1480u->usb_dev, epd->bEndpointAddress), | ||
115 | rx_buf->data->data, i1480u_MAX_RX_PKT_SIZE - 2, | ||
116 | i1480u_rx_cb, rx_buf); | ||
117 | result = usb_submit_urb(rx_buf->urb, GFP_NOIO); | ||
118 | if (unlikely(result < 0)) { | ||
119 | dev_err(dev, "RX: cannot submit URB %d: %d\n", | ||
120 | cnt, result); | ||
121 | goto error; | ||
122 | } | ||
123 | } | ||
124 | return 0; | ||
125 | |||
126 | error: | ||
127 | i1480u_rx_release(i1480u); | ||
128 | return result; | ||
129 | } | ||
130 | |||
131 | |||
132 | /** Release resources associated to the rx context */ | ||
133 | void i1480u_rx_release(struct i1480u *i1480u) | ||
134 | { | ||
135 | int cnt; | ||
136 | for (cnt = 0; cnt < i1480u_RX_BUFS; cnt++) { | ||
137 | if (i1480u->rx_buf[cnt].data) | ||
138 | dev_kfree_skb(i1480u->rx_buf[cnt].data); | ||
139 | if (i1480u->rx_buf[cnt].urb) { | ||
140 | usb_kill_urb(i1480u->rx_buf[cnt].urb); | ||
141 | usb_free_urb(i1480u->rx_buf[cnt].urb); | ||
142 | } | ||
143 | } | ||
144 | if (i1480u->rx_skb != NULL) | ||
145 | dev_kfree_skb(i1480u->rx_skb); | ||
146 | } | ||
147 | |||
148 | static | ||
149 | void i1480u_rx_unlink_urbs(struct i1480u *i1480u) | ||
150 | { | ||
151 | int cnt; | ||
152 | for (cnt = 0; cnt < i1480u_RX_BUFS; cnt++) { | ||
153 | if (i1480u->rx_buf[cnt].urb) | ||
154 | usb_unlink_urb(i1480u->rx_buf[cnt].urb); | ||
155 | } | ||
156 | } | ||
157 | |||
158 | /** Fix an out-of-sequence packet */ | ||
159 | #define i1480u_fix(i1480u, msg...) \ | ||
160 | do { \ | ||
161 | if (printk_ratelimit()) \ | ||
162 | dev_err(&i1480u->usb_iface->dev, msg); \ | ||
163 | dev_kfree_skb_irq(i1480u->rx_skb); \ | ||
164 | i1480u->rx_skb = NULL; \ | ||
165 | i1480u->rx_untd_pkt_size = 0; \ | ||
166 | } while (0) | ||
167 | |||
168 | |||
169 | /** Drop an out-of-sequence packet */ | ||
170 | #define i1480u_drop(i1480u, msg...) \ | ||
171 | do { \ | ||
172 | if (printk_ratelimit()) \ | ||
173 | dev_err(&i1480u->usb_iface->dev, msg); \ | ||
174 | i1480u->stats.rx_dropped++; \ | ||
175 | } while (0) | ||
176 | |||
177 | |||
178 | |||
179 | |||
180 | /** Finalizes setting up the SKB and delivers it | ||
181 | * | ||
182 | * We first pass the incoming frame to WLP substack for verification. It | ||
183 | * may also be a WLP association frame in which case WLP will take over the | ||
184 | * processing. If WLP does not take it over it will still verify it, if the | ||
185 | * frame is invalid the skb will be freed by WLP and we will not continue | ||
186 | * parsing. | ||
187 | * */ | ||
188 | static | ||
189 | void i1480u_skb_deliver(struct i1480u *i1480u) | ||
190 | { | ||
191 | int should_parse; | ||
192 | struct net_device *net_dev = i1480u->net_dev; | ||
193 | struct device *dev = &i1480u->usb_iface->dev; | ||
194 | |||
195 | d_printf(6, dev, "RX delivered pre skb(%p), %u bytes\n", | ||
196 | i1480u->rx_skb, i1480u->rx_skb->len); | ||
197 | d_dump(7, dev, i1480u->rx_skb->data, i1480u->rx_skb->len); | ||
198 | should_parse = wlp_receive_frame(dev, &i1480u->wlp, i1480u->rx_skb, | ||
199 | &i1480u->rx_srcaddr); | ||
200 | if (!should_parse) | ||
201 | goto out; | ||
202 | i1480u->rx_skb->protocol = eth_type_trans(i1480u->rx_skb, net_dev); | ||
203 | d_printf(5, dev, "RX delivered skb(%p), %u bytes\n", | ||
204 | i1480u->rx_skb, i1480u->rx_skb->len); | ||
205 | d_dump(7, dev, i1480u->rx_skb->data, | ||
206 | i1480u->rx_skb->len > 72 ? 72 : i1480u->rx_skb->len); | ||
207 | i1480u->stats.rx_packets++; | ||
208 | i1480u->stats.rx_bytes += i1480u->rx_untd_pkt_size; | ||
209 | net_dev->last_rx = jiffies; | ||
210 | /* FIXME: flow control: check netif_rx() retval */ | ||
211 | |||
212 | netif_rx(i1480u->rx_skb); /* deliver */ | ||
213 | out: | ||
214 | i1480u->rx_skb = NULL; | ||
215 | i1480u->rx_untd_pkt_size = 0; | ||
216 | } | ||
217 | |||
218 | |||
219 | /** | ||
220 | * Process a buffer of data received from the USB RX endpoint | ||
221 | * | ||
222 | * First fragment arrives with next or last fragment. All other fragments | ||
223 | * arrive alone. | ||
224 | * | ||
225 | * /me hates long functions. | ||
226 | */ | ||
227 | static | ||
228 | void i1480u_rx_buffer(struct i1480u_rx_buf *rx_buf) | ||
229 | { | ||
230 | unsigned pkt_completed = 0; /* !0 when we got all pkt fragments */ | ||
231 | size_t untd_hdr_size, untd_frg_size; | ||
232 | size_t i1480u_hdr_size; | ||
233 | struct wlp_rx_hdr *i1480u_hdr = NULL; | ||
234 | |||
235 | struct i1480u *i1480u = rx_buf->i1480u; | ||
236 | struct sk_buff *skb = rx_buf->data; | ||
237 | int size_left = rx_buf->urb->actual_length; | ||
238 | void *ptr = rx_buf->urb->transfer_buffer; /* also rx_buf->data->data */ | ||
239 | struct untd_hdr *untd_hdr; | ||
240 | |||
241 | struct net_device *net_dev = i1480u->net_dev; | ||
242 | struct device *dev = &i1480u->usb_iface->dev; | ||
243 | struct sk_buff *new_skb; | ||
244 | |||
245 | #if 0 | ||
246 | dev_fnstart(dev, | ||
247 | "(i1480u %p ptr %p size_left %zu)\n", i1480u, ptr, size_left); | ||
248 | dev_err(dev, "RX packet, %zu bytes\n", size_left); | ||
249 | dump_bytes(dev, ptr, size_left); | ||
250 | #endif | ||
251 | i1480u_hdr_size = sizeof(struct wlp_rx_hdr); | ||
252 | |||
253 | while (size_left > 0) { | ||
254 | if (pkt_completed) { | ||
255 | i1480u_drop(i1480u, "RX: fragment follows completed" | ||
256 | "packet in same buffer. Dropping\n"); | ||
257 | break; | ||
258 | } | ||
259 | untd_hdr = ptr; | ||
260 | if (size_left < sizeof(*untd_hdr)) { /* Check the UNTD header */ | ||
261 | i1480u_drop(i1480u, "RX: short UNTD header! Dropping\n"); | ||
262 | goto out; | ||
263 | } | ||
264 | if (unlikely(untd_hdr_rx_tx(untd_hdr) == 0)) { /* Paranoia: TX set? */ | ||
265 | i1480u_drop(i1480u, "RX: TX bit set! Dropping\n"); | ||
266 | goto out; | ||
267 | } | ||
268 | switch (untd_hdr_type(untd_hdr)) { /* Check the UNTD header type */ | ||
269 | case i1480u_PKT_FRAG_1ST: { | ||
270 | struct untd_hdr_1st *untd_hdr_1st = (void *) untd_hdr; | ||
271 | dev_dbg(dev, "1st fragment\n"); | ||
272 | untd_hdr_size = sizeof(struct untd_hdr_1st); | ||
273 | if (i1480u->rx_skb != NULL) | ||
274 | i1480u_fix(i1480u, "RX: 1st fragment out of " | ||
275 | "sequence! Fixing\n"); | ||
276 | if (size_left < untd_hdr_size + i1480u_hdr_size) { | ||
277 | i1480u_drop(i1480u, "RX: short 1st fragment! " | ||
278 | "Dropping\n"); | ||
279 | goto out; | ||
280 | } | ||
281 | i1480u->rx_untd_pkt_size = le16_to_cpu(untd_hdr->len) | ||
282 | - i1480u_hdr_size; | ||
283 | untd_frg_size = le16_to_cpu(untd_hdr_1st->fragment_len); | ||
284 | if (size_left < untd_hdr_size + untd_frg_size) { | ||
285 | i1480u_drop(i1480u, | ||
286 | "RX: short payload! Dropping\n"); | ||
287 | goto out; | ||
288 | } | ||
289 | i1480u->rx_skb = skb; | ||
290 | i1480u_hdr = (void *) untd_hdr_1st + untd_hdr_size; | ||
291 | i1480u->rx_srcaddr = i1480u_hdr->srcaddr; | ||
292 | skb_put(i1480u->rx_skb, untd_hdr_size + untd_frg_size); | ||
293 | skb_pull(i1480u->rx_skb, untd_hdr_size + i1480u_hdr_size); | ||
294 | stats_add_sample(&i1480u->lqe_stats, (s8) i1480u_hdr->LQI - 7); | ||
295 | stats_add_sample(&i1480u->rssi_stats, i1480u_hdr->RSSI + 18); | ||
296 | rx_buf->data = NULL; /* need to create new buffer */ | ||
297 | break; | ||
298 | } | ||
299 | case i1480u_PKT_FRAG_NXT: { | ||
300 | dev_dbg(dev, "nxt fragment\n"); | ||
301 | untd_hdr_size = sizeof(struct untd_hdr_rst); | ||
302 | if (i1480u->rx_skb == NULL) { | ||
303 | i1480u_drop(i1480u, "RX: next fragment out of " | ||
304 | "sequence! Dropping\n"); | ||
305 | goto out; | ||
306 | } | ||
307 | if (size_left < untd_hdr_size) { | ||
308 | i1480u_drop(i1480u, "RX: short NXT fragment! " | ||
309 | "Dropping\n"); | ||
310 | goto out; | ||
311 | } | ||
312 | untd_frg_size = le16_to_cpu(untd_hdr->len); | ||
313 | if (size_left < untd_hdr_size + untd_frg_size) { | ||
314 | i1480u_drop(i1480u, | ||
315 | "RX: short payload! Dropping\n"); | ||
316 | goto out; | ||
317 | } | ||
318 | memmove(skb_put(i1480u->rx_skb, untd_frg_size), | ||
319 | ptr + untd_hdr_size, untd_frg_size); | ||
320 | break; | ||
321 | } | ||
322 | case i1480u_PKT_FRAG_LST: { | ||
323 | dev_dbg(dev, "Lst fragment\n"); | ||
324 | untd_hdr_size = sizeof(struct untd_hdr_rst); | ||
325 | if (i1480u->rx_skb == NULL) { | ||
326 | i1480u_drop(i1480u, "RX: last fragment out of " | ||
327 | "sequence! Dropping\n"); | ||
328 | goto out; | ||
329 | } | ||
330 | if (size_left < untd_hdr_size) { | ||
331 | i1480u_drop(i1480u, "RX: short LST fragment! " | ||
332 | "Dropping\n"); | ||
333 | goto out; | ||
334 | } | ||
335 | untd_frg_size = le16_to_cpu(untd_hdr->len); | ||
336 | if (size_left < untd_frg_size + untd_hdr_size) { | ||
337 | i1480u_drop(i1480u, | ||
338 | "RX: short payload! Dropping\n"); | ||
339 | goto out; | ||
340 | } | ||
341 | memmove(skb_put(i1480u->rx_skb, untd_frg_size), | ||
342 | ptr + untd_hdr_size, untd_frg_size); | ||
343 | pkt_completed = 1; | ||
344 | break; | ||
345 | } | ||
346 | case i1480u_PKT_FRAG_CMP: { | ||
347 | dev_dbg(dev, "cmp fragment\n"); | ||
348 | untd_hdr_size = sizeof(struct untd_hdr_cmp); | ||
349 | if (i1480u->rx_skb != NULL) | ||
350 | i1480u_fix(i1480u, "RX: fix out-of-sequence CMP" | ||
351 | " fragment!\n"); | ||
352 | if (size_left < untd_hdr_size + i1480u_hdr_size) { | ||
353 | i1480u_drop(i1480u, "RX: short CMP fragment! " | ||
354 | "Dropping\n"); | ||
355 | goto out; | ||
356 | } | ||
357 | i1480u->rx_untd_pkt_size = le16_to_cpu(untd_hdr->len); | ||
358 | untd_frg_size = i1480u->rx_untd_pkt_size; | ||
359 | if (size_left < i1480u->rx_untd_pkt_size + untd_hdr_size) { | ||
360 | i1480u_drop(i1480u, | ||
361 | "RX: short payload! Dropping\n"); | ||
362 | goto out; | ||
363 | } | ||
364 | i1480u->rx_skb = skb; | ||
365 | i1480u_hdr = (void *) untd_hdr + untd_hdr_size; | ||
366 | i1480u->rx_srcaddr = i1480u_hdr->srcaddr; | ||
367 | stats_add_sample(&i1480u->lqe_stats, (s8) i1480u_hdr->LQI - 7); | ||
368 | stats_add_sample(&i1480u->rssi_stats, i1480u_hdr->RSSI + 18); | ||
369 | skb_put(i1480u->rx_skb, untd_hdr_size + i1480u->rx_untd_pkt_size); | ||
370 | skb_pull(i1480u->rx_skb, untd_hdr_size + i1480u_hdr_size); | ||
371 | rx_buf->data = NULL; /* for hand off skb to network stack */ | ||
372 | pkt_completed = 1; | ||
373 | i1480u->rx_untd_pkt_size -= i1480u_hdr_size; /* accurate stat */ | ||
374 | break; | ||
375 | } | ||
376 | default: | ||
377 | i1480u_drop(i1480u, "RX: unknown packet type %u! " | ||
378 | "Dropping\n", untd_hdr_type(untd_hdr)); | ||
379 | goto out; | ||
380 | } | ||
381 | size_left -= untd_hdr_size + untd_frg_size; | ||
382 | if (size_left > 0) | ||
383 | ptr += untd_hdr_size + untd_frg_size; | ||
384 | } | ||
385 | if (pkt_completed) | ||
386 | i1480u_skb_deliver(i1480u); | ||
387 | out: | ||
388 | /* recreate needed RX buffers*/ | ||
389 | if (rx_buf->data == NULL) { | ||
390 | /* buffer is being used to receive packet, create new */ | ||
391 | new_skb = dev_alloc_skb(i1480u_MAX_RX_PKT_SIZE); | ||
392 | if (!new_skb) { | ||
393 | if (printk_ratelimit()) | ||
394 | dev_err(dev, | ||
395 | "RX: cannot allocate RX buffer\n"); | ||
396 | } else { | ||
397 | new_skb->dev = net_dev; | ||
398 | new_skb->ip_summed = CHECKSUM_NONE; | ||
399 | skb_reserve(new_skb, 2); | ||
400 | rx_buf->data = new_skb; | ||
401 | } | ||
402 | } | ||
403 | return; | ||
404 | } | ||
405 | |||
406 | |||
407 | /** | ||
408 | * Called when an RX URB has finished receiving or has found some kind | ||
409 | * of error condition. | ||
410 | * | ||
411 | * LIMITATIONS: | ||
412 | * | ||
413 | * - We read USB-transfers, each transfer contains a SINGLE fragment | ||
414 | * (can contain a complete packet, or a 1st, next, or last fragment | ||
415 | * of a packet). | ||
416 | * Looks like a transfer can contain more than one fragment (07/18/06) | ||
417 | * | ||
418 | * - Each transfer buffer is the size of the maximum packet size (minus | ||
419 | * headroom), i1480u_MAX_PKT_SIZE - 2 | ||
420 | * | ||
421 | * - We always read the full USB-transfer, no partials. | ||
422 | * | ||
423 | * - Each transfer is read directly into a skb. This skb will be used to | ||
424 | * send data to the upper layers if it is the first fragment or a complete | ||
425 | * packet. In the other cases the data will be copied from the skb to | ||
426 | * another skb that is being prepared for the upper layers from a prev | ||
427 | * first fragment. | ||
428 | * | ||
429 | * It is simply too much of a pain. Gosh, there should be a unified | ||
430 | * SG infrastructure for *everything* [so that I could declare a SG | ||
431 | * buffer, pass it to USB for receiving, append some space to it if | ||
432 | * I wish, receive more until I have the whole chunk, adapt | ||
433 | * pointers on each fragment to remove hardware headers and then | ||
434 | * attach that to an skbuff and netif_rx()]. | ||
435 | */ | ||
436 | void i1480u_rx_cb(struct urb *urb) | ||
437 | { | ||
438 | int result; | ||
439 | int do_parse_buffer = 1; | ||
440 | struct i1480u_rx_buf *rx_buf = urb->context; | ||
441 | struct i1480u *i1480u = rx_buf->i1480u; | ||
442 | struct device *dev = &i1480u->usb_iface->dev; | ||
443 | unsigned long flags; | ||
444 | u8 rx_buf_idx = rx_buf - i1480u->rx_buf; | ||
445 | |||
446 | switch (urb->status) { | ||
447 | case 0: | ||
448 | break; | ||
449 | case -ECONNRESET: /* Not an error, but a controlled situation; */ | ||
450 | case -ENOENT: /* (we killed the URB)...so, no broadcast */ | ||
451 | case -ESHUTDOWN: /* going away! */ | ||
452 | dev_err(dev, "RX URB[%u]: goind down %d\n", | ||
453 | rx_buf_idx, urb->status); | ||
454 | goto error; | ||
455 | default: | ||
456 | dev_err(dev, "RX URB[%u]: unknown status %d\n", | ||
457 | rx_buf_idx, urb->status); | ||
458 | if (edc_inc(&i1480u->rx_errors, EDC_MAX_ERRORS, | ||
459 | EDC_ERROR_TIMEFRAME)) { | ||
460 | dev_err(dev, "RX: max acceptable errors exceeded," | ||
461 | " resetting device.\n"); | ||
462 | i1480u_rx_unlink_urbs(i1480u); | ||
463 | wlp_reset_all(&i1480u->wlp); | ||
464 | goto error; | ||
465 | } | ||
466 | do_parse_buffer = 0; | ||
467 | break; | ||
468 | } | ||
469 | spin_lock_irqsave(&i1480u->lock, flags); | ||
470 | /* chew the data fragments, extract network packets */ | ||
471 | if (do_parse_buffer) { | ||
472 | i1480u_rx_buffer(rx_buf); | ||
473 | if (rx_buf->data) { | ||
474 | rx_buf->urb->transfer_buffer = rx_buf->data->data; | ||
475 | result = usb_submit_urb(rx_buf->urb, GFP_ATOMIC); | ||
476 | if (result < 0) { | ||
477 | dev_err(dev, "RX URB[%u]: cannot submit %d\n", | ||
478 | rx_buf_idx, result); | ||
479 | } | ||
480 | } | ||
481 | } | ||
482 | spin_unlock_irqrestore(&i1480u->lock, flags); | ||
483 | error: | ||
484 | return; | ||
485 | } | ||
486 | |||
diff --git a/drivers/uwb/i1480/i1480u-wlp/sysfs.c b/drivers/uwb/i1480/i1480u-wlp/sysfs.c new file mode 100644 index 000000000000..a1d8ca6ac935 --- /dev/null +++ b/drivers/uwb/i1480/i1480u-wlp/sysfs.c | |||
@@ -0,0 +1,408 @@ | |||
1 | /* | ||
2 | * WUSB Wire Adapter: WLP interface | ||
3 | * Sysfs interfaces | ||
4 | * | ||
5 | * Copyright (C) 2005-2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
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: docs | ||
24 | */ | ||
25 | |||
26 | #include <linux/netdevice.h> | ||
27 | #include <linux/etherdevice.h> | ||
28 | #include <linux/uwb/debug.h> | ||
29 | #include <linux/device.h> | ||
30 | #include "i1480u-wlp.h" | ||
31 | |||
32 | |||
33 | /** | ||
34 | * | ||
35 | * @dev: Class device from the net_device; assumed refcnted. | ||
36 | * | ||
37 | * Yes, I don't lock--we assume it is refcounted and I am getting a | ||
38 | * single byte value that is kind of atomic to read. | ||
39 | */ | ||
40 | ssize_t uwb_phy_rate_show(const struct wlp_options *options, char *buf) | ||
41 | { | ||
42 | return sprintf(buf, "%u\n", | ||
43 | wlp_tx_hdr_phy_rate(&options->def_tx_hdr)); | ||
44 | } | ||
45 | EXPORT_SYMBOL_GPL(uwb_phy_rate_show); | ||
46 | |||
47 | |||
48 | ssize_t uwb_phy_rate_store(struct wlp_options *options, | ||
49 | const char *buf, size_t size) | ||
50 | { | ||
51 | ssize_t result; | ||
52 | unsigned rate; | ||
53 | |||
54 | result = sscanf(buf, "%u\n", &rate); | ||
55 | if (result != 1) { | ||
56 | result = -EINVAL; | ||
57 | goto out; | ||
58 | } | ||
59 | result = -EINVAL; | ||
60 | if (rate >= UWB_PHY_RATE_INVALID) | ||
61 | goto out; | ||
62 | wlp_tx_hdr_set_phy_rate(&options->def_tx_hdr, rate); | ||
63 | result = 0; | ||
64 | out: | ||
65 | return result < 0 ? result : size; | ||
66 | } | ||
67 | EXPORT_SYMBOL_GPL(uwb_phy_rate_store); | ||
68 | |||
69 | |||
70 | ssize_t uwb_rts_cts_show(const struct wlp_options *options, char *buf) | ||
71 | { | ||
72 | return sprintf(buf, "%u\n", | ||
73 | wlp_tx_hdr_rts_cts(&options->def_tx_hdr)); | ||
74 | } | ||
75 | EXPORT_SYMBOL_GPL(uwb_rts_cts_show); | ||
76 | |||
77 | |||
78 | ssize_t uwb_rts_cts_store(struct wlp_options *options, | ||
79 | const char *buf, size_t size) | ||
80 | { | ||
81 | ssize_t result; | ||
82 | unsigned value; | ||
83 | |||
84 | result = sscanf(buf, "%u\n", &value); | ||
85 | if (result != 1) { | ||
86 | result = -EINVAL; | ||
87 | goto out; | ||
88 | } | ||
89 | result = -EINVAL; | ||
90 | wlp_tx_hdr_set_rts_cts(&options->def_tx_hdr, !!value); | ||
91 | result = 0; | ||
92 | out: | ||
93 | return result < 0 ? result : size; | ||
94 | } | ||
95 | EXPORT_SYMBOL_GPL(uwb_rts_cts_store); | ||
96 | |||
97 | |||
98 | ssize_t uwb_ack_policy_show(const struct wlp_options *options, char *buf) | ||
99 | { | ||
100 | return sprintf(buf, "%u\n", | ||
101 | wlp_tx_hdr_ack_policy(&options->def_tx_hdr)); | ||
102 | } | ||
103 | EXPORT_SYMBOL_GPL(uwb_ack_policy_show); | ||
104 | |||
105 | |||
106 | ssize_t uwb_ack_policy_store(struct wlp_options *options, | ||
107 | const char *buf, size_t size) | ||
108 | { | ||
109 | ssize_t result; | ||
110 | unsigned value; | ||
111 | |||
112 | result = sscanf(buf, "%u\n", &value); | ||
113 | if (result != 1 || value > UWB_ACK_B_REQ) { | ||
114 | result = -EINVAL; | ||
115 | goto out; | ||
116 | } | ||
117 | wlp_tx_hdr_set_ack_policy(&options->def_tx_hdr, value); | ||
118 | result = 0; | ||
119 | out: | ||
120 | return result < 0 ? result : size; | ||
121 | } | ||
122 | EXPORT_SYMBOL_GPL(uwb_ack_policy_store); | ||
123 | |||
124 | |||
125 | /** | ||
126 | * Show the PCA base priority. | ||
127 | * | ||
128 | * We can access without locking, as the value is (for now) orthogonal | ||
129 | * to other values. | ||
130 | */ | ||
131 | ssize_t uwb_pca_base_priority_show(const struct wlp_options *options, | ||
132 | char *buf) | ||
133 | { | ||
134 | return sprintf(buf, "%u\n", | ||
135 | options->pca_base_priority); | ||
136 | } | ||
137 | EXPORT_SYMBOL_GPL(uwb_pca_base_priority_show); | ||
138 | |||
139 | |||
140 | /** | ||
141 | * Set the PCA base priority. | ||
142 | * | ||
143 | * We can access without locking, as the value is (for now) orthogonal | ||
144 | * to other values. | ||
145 | */ | ||
146 | ssize_t uwb_pca_base_priority_store(struct wlp_options *options, | ||
147 | const char *buf, size_t size) | ||
148 | { | ||
149 | ssize_t result = -EINVAL; | ||
150 | u8 pca_base_priority; | ||
151 | |||
152 | result = sscanf(buf, "%hhu\n", &pca_base_priority); | ||
153 | if (result != 1) { | ||
154 | result = -EINVAL; | ||
155 | goto out; | ||
156 | } | ||
157 | result = -EINVAL; | ||
158 | if (pca_base_priority >= 8) | ||
159 | goto out; | ||
160 | options->pca_base_priority = pca_base_priority; | ||
161 | /* Update TX header if we are currently using PCA. */ | ||
162 | if (result >= 0 && (wlp_tx_hdr_delivery_id_type(&options->def_tx_hdr) & WLP_DRP) == 0) | ||
163 | wlp_tx_hdr_set_delivery_id_type(&options->def_tx_hdr, options->pca_base_priority); | ||
164 | result = 0; | ||
165 | out: | ||
166 | return result < 0 ? result : size; | ||
167 | } | ||
168 | EXPORT_SYMBOL_GPL(uwb_pca_base_priority_store); | ||
169 | |||
170 | /** | ||
171 | * Show current inflight values | ||
172 | * | ||
173 | * Will print the current MAX and THRESHOLD values for the basic flow | ||
174 | * control. In addition it will report how many times the TX queue needed | ||
175 | * to be restarted since the last time this query was made. | ||
176 | */ | ||
177 | static ssize_t wlp_tx_inflight_show(struct i1480u_tx_inflight *inflight, | ||
178 | char *buf) | ||
179 | { | ||
180 | ssize_t result; | ||
181 | unsigned long sec_elapsed = (jiffies - inflight->restart_ts)/HZ; | ||
182 | unsigned long restart_count = atomic_read(&inflight->restart_count); | ||
183 | |||
184 | result = scnprintf(buf, PAGE_SIZE, "%lu %lu %d %lu %lu %lu\n" | ||
185 | "#read: threshold max inflight_count restarts " | ||
186 | "seconds restarts/sec\n" | ||
187 | "#write: threshold max\n", | ||
188 | inflight->threshold, inflight->max, | ||
189 | atomic_read(&inflight->count), | ||
190 | restart_count, sec_elapsed, | ||
191 | sec_elapsed == 0 ? 0 : restart_count/sec_elapsed); | ||
192 | inflight->restart_ts = jiffies; | ||
193 | atomic_set(&inflight->restart_count, 0); | ||
194 | return result; | ||
195 | } | ||
196 | |||
197 | static | ||
198 | ssize_t wlp_tx_inflight_store(struct i1480u_tx_inflight *inflight, | ||
199 | const char *buf, size_t size) | ||
200 | { | ||
201 | unsigned long in_threshold, in_max; | ||
202 | ssize_t result; | ||
203 | result = sscanf(buf, "%lu %lu", &in_threshold, &in_max); | ||
204 | if (result != 2) | ||
205 | return -EINVAL; | ||
206 | if (in_max <= in_threshold) | ||
207 | return -EINVAL; | ||
208 | inflight->max = in_max; | ||
209 | inflight->threshold = in_threshold; | ||
210 | return size; | ||
211 | } | ||
212 | /* | ||
213 | * Glue (or function adaptors) for accesing info on sysfs | ||
214 | * | ||
215 | * [we need this indirection because the PCI driver does almost the | ||
216 | * same] | ||
217 | * | ||
218 | * Linux 2.6.21 changed how 'struct netdevice' does attributes (from | ||
219 | * having a 'struct class_dev' to having a 'struct device'). That is | ||
220 | * quite of a pain. | ||
221 | * | ||
222 | * So we try to abstract that here. i1480u_SHOW() and i1480u_STORE() | ||
223 | * create adaptors for extracting the 'struct i1480u' from a 'struct | ||
224 | * dev' and calling a function for doing a sysfs operation (as we have | ||
225 | * them factorized already). i1480u_ATTR creates the attribute file | ||
226 | * (CLASS_DEVICE_ATTR or DEVICE_ATTR) and i1480u_ATTR_NAME produces a | ||
227 | * class_device_attr_NAME or device_attr_NAME (for group registration). | ||
228 | */ | ||
229 | #include <linux/version.h> | ||
230 | |||
231 | #define i1480u_SHOW(name, fn, param) \ | ||
232 | static ssize_t i1480u_show_##name(struct device *dev, \ | ||
233 | struct device_attribute *attr,\ | ||
234 | char *buf) \ | ||
235 | { \ | ||
236 | struct i1480u *i1480u = netdev_priv(to_net_dev(dev)); \ | ||
237 | return fn(&i1480u->param, buf); \ | ||
238 | } | ||
239 | |||
240 | #define i1480u_STORE(name, fn, param) \ | ||
241 | static ssize_t i1480u_store_##name(struct device *dev, \ | ||
242 | struct device_attribute *attr,\ | ||
243 | const char *buf, size_t size)\ | ||
244 | { \ | ||
245 | struct i1480u *i1480u = netdev_priv(to_net_dev(dev)); \ | ||
246 | return fn(&i1480u->param, buf, size); \ | ||
247 | } | ||
248 | |||
249 | #define i1480u_ATTR(name, perm) static DEVICE_ATTR(name, perm, \ | ||
250 | i1480u_show_##name,\ | ||
251 | i1480u_store_##name) | ||
252 | |||
253 | #define i1480u_ATTR_SHOW(name) static DEVICE_ATTR(name, \ | ||
254 | S_IRUGO, \ | ||
255 | i1480u_show_##name, NULL) | ||
256 | |||
257 | #define i1480u_ATTR_NAME(a) (dev_attr_##a) | ||
258 | |||
259 | |||
260 | /* | ||
261 | * Sysfs adaptors | ||
262 | */ | ||
263 | i1480u_SHOW(uwb_phy_rate, uwb_phy_rate_show, options); | ||
264 | i1480u_STORE(uwb_phy_rate, uwb_phy_rate_store, options); | ||
265 | i1480u_ATTR(uwb_phy_rate, S_IRUGO | S_IWUSR); | ||
266 | |||
267 | i1480u_SHOW(uwb_rts_cts, uwb_rts_cts_show, options); | ||
268 | i1480u_STORE(uwb_rts_cts, uwb_rts_cts_store, options); | ||
269 | i1480u_ATTR(uwb_rts_cts, S_IRUGO | S_IWUSR); | ||
270 | |||
271 | i1480u_SHOW(uwb_ack_policy, uwb_ack_policy_show, options); | ||
272 | i1480u_STORE(uwb_ack_policy, uwb_ack_policy_store, options); | ||
273 | i1480u_ATTR(uwb_ack_policy, S_IRUGO | S_IWUSR); | ||
274 | |||
275 | i1480u_SHOW(uwb_pca_base_priority, uwb_pca_base_priority_show, options); | ||
276 | i1480u_STORE(uwb_pca_base_priority, uwb_pca_base_priority_store, options); | ||
277 | i1480u_ATTR(uwb_pca_base_priority, S_IRUGO | S_IWUSR); | ||
278 | |||
279 | i1480u_SHOW(wlp_eda, wlp_eda_show, wlp); | ||
280 | i1480u_STORE(wlp_eda, wlp_eda_store, wlp); | ||
281 | i1480u_ATTR(wlp_eda, S_IRUGO | S_IWUSR); | ||
282 | |||
283 | i1480u_SHOW(wlp_uuid, wlp_uuid_show, wlp); | ||
284 | i1480u_STORE(wlp_uuid, wlp_uuid_store, wlp); | ||
285 | i1480u_ATTR(wlp_uuid, S_IRUGO | S_IWUSR); | ||
286 | |||
287 | i1480u_SHOW(wlp_dev_name, wlp_dev_name_show, wlp); | ||
288 | i1480u_STORE(wlp_dev_name, wlp_dev_name_store, wlp); | ||
289 | i1480u_ATTR(wlp_dev_name, S_IRUGO | S_IWUSR); | ||
290 | |||
291 | i1480u_SHOW(wlp_dev_manufacturer, wlp_dev_manufacturer_show, wlp); | ||
292 | i1480u_STORE(wlp_dev_manufacturer, wlp_dev_manufacturer_store, wlp); | ||
293 | i1480u_ATTR(wlp_dev_manufacturer, S_IRUGO | S_IWUSR); | ||
294 | |||
295 | i1480u_SHOW(wlp_dev_model_name, wlp_dev_model_name_show, wlp); | ||
296 | i1480u_STORE(wlp_dev_model_name, wlp_dev_model_name_store, wlp); | ||
297 | i1480u_ATTR(wlp_dev_model_name, S_IRUGO | S_IWUSR); | ||
298 | |||
299 | i1480u_SHOW(wlp_dev_model_nr, wlp_dev_model_nr_show, wlp); | ||
300 | i1480u_STORE(wlp_dev_model_nr, wlp_dev_model_nr_store, wlp); | ||
301 | i1480u_ATTR(wlp_dev_model_nr, S_IRUGO | S_IWUSR); | ||
302 | |||
303 | i1480u_SHOW(wlp_dev_serial, wlp_dev_serial_show, wlp); | ||
304 | i1480u_STORE(wlp_dev_serial, wlp_dev_serial_store, wlp); | ||
305 | i1480u_ATTR(wlp_dev_serial, S_IRUGO | S_IWUSR); | ||
306 | |||
307 | i1480u_SHOW(wlp_dev_prim_category, wlp_dev_prim_category_show, wlp); | ||
308 | i1480u_STORE(wlp_dev_prim_category, wlp_dev_prim_category_store, wlp); | ||
309 | i1480u_ATTR(wlp_dev_prim_category, S_IRUGO | S_IWUSR); | ||
310 | |||
311 | i1480u_SHOW(wlp_dev_prim_OUI, wlp_dev_prim_OUI_show, wlp); | ||
312 | i1480u_STORE(wlp_dev_prim_OUI, wlp_dev_prim_OUI_store, wlp); | ||
313 | i1480u_ATTR(wlp_dev_prim_OUI, S_IRUGO | S_IWUSR); | ||
314 | |||
315 | i1480u_SHOW(wlp_dev_prim_OUI_sub, wlp_dev_prim_OUI_sub_show, wlp); | ||
316 | i1480u_STORE(wlp_dev_prim_OUI_sub, wlp_dev_prim_OUI_sub_store, wlp); | ||
317 | i1480u_ATTR(wlp_dev_prim_OUI_sub, S_IRUGO | S_IWUSR); | ||
318 | |||
319 | i1480u_SHOW(wlp_dev_prim_subcat, wlp_dev_prim_subcat_show, wlp); | ||
320 | i1480u_STORE(wlp_dev_prim_subcat, wlp_dev_prim_subcat_store, wlp); | ||
321 | i1480u_ATTR(wlp_dev_prim_subcat, S_IRUGO | S_IWUSR); | ||
322 | |||
323 | i1480u_SHOW(wlp_neighborhood, wlp_neighborhood_show, wlp); | ||
324 | i1480u_ATTR_SHOW(wlp_neighborhood); | ||
325 | |||
326 | i1480u_SHOW(wss_activate, wlp_wss_activate_show, wlp.wss); | ||
327 | i1480u_STORE(wss_activate, wlp_wss_activate_store, wlp.wss); | ||
328 | i1480u_ATTR(wss_activate, S_IRUGO | S_IWUSR); | ||
329 | |||
330 | /* | ||
331 | * Show the (min, max, avg) Line Quality Estimate (LQE, in dB) as over | ||
332 | * the last 256 received WLP frames (ECMA-368 13.3). | ||
333 | * | ||
334 | * [the -7dB that have to be substracted from the LQI to make the LQE | ||
335 | * are already taken into account]. | ||
336 | */ | ||
337 | i1480u_SHOW(wlp_lqe, stats_show, lqe_stats); | ||
338 | i1480u_STORE(wlp_lqe, stats_store, lqe_stats); | ||
339 | i1480u_ATTR(wlp_lqe, S_IRUGO | S_IWUSR); | ||
340 | |||
341 | /* | ||
342 | * Show the Receive Signal Strength Indicator averaged over all the | ||
343 | * received WLP frames (ECMA-368 13.3). Still is not clear what | ||
344 | * this value is, but is kind of a percentage of the signal strength | ||
345 | * at the antenna. | ||
346 | */ | ||
347 | i1480u_SHOW(wlp_rssi, stats_show, rssi_stats); | ||
348 | i1480u_STORE(wlp_rssi, stats_store, rssi_stats); | ||
349 | i1480u_ATTR(wlp_rssi, S_IRUGO | S_IWUSR); | ||
350 | |||
351 | /** | ||
352 | * We maintain a basic flow control counter. "count" how many TX URBs are | ||
353 | * outstanding. Only allow "max" | ||
354 | * TX URBs to be outstanding. If this value is reached the queue will be | ||
355 | * stopped. The queue will be restarted when there are | ||
356 | * "threshold" URBs outstanding. | ||
357 | */ | ||
358 | i1480u_SHOW(wlp_tx_inflight, wlp_tx_inflight_show, tx_inflight); | ||
359 | i1480u_STORE(wlp_tx_inflight, wlp_tx_inflight_store, tx_inflight); | ||
360 | i1480u_ATTR(wlp_tx_inflight, S_IRUGO | S_IWUSR); | ||
361 | |||
362 | static struct attribute *i1480u_attrs[] = { | ||
363 | &i1480u_ATTR_NAME(uwb_phy_rate).attr, | ||
364 | &i1480u_ATTR_NAME(uwb_rts_cts).attr, | ||
365 | &i1480u_ATTR_NAME(uwb_ack_policy).attr, | ||
366 | &i1480u_ATTR_NAME(uwb_pca_base_priority).attr, | ||
367 | &i1480u_ATTR_NAME(wlp_lqe).attr, | ||
368 | &i1480u_ATTR_NAME(wlp_rssi).attr, | ||
369 | &i1480u_ATTR_NAME(wlp_eda).attr, | ||
370 | &i1480u_ATTR_NAME(wlp_uuid).attr, | ||
371 | &i1480u_ATTR_NAME(wlp_dev_name).attr, | ||
372 | &i1480u_ATTR_NAME(wlp_dev_manufacturer).attr, | ||
373 | &i1480u_ATTR_NAME(wlp_dev_model_name).attr, | ||
374 | &i1480u_ATTR_NAME(wlp_dev_model_nr).attr, | ||
375 | &i1480u_ATTR_NAME(wlp_dev_serial).attr, | ||
376 | &i1480u_ATTR_NAME(wlp_dev_prim_category).attr, | ||
377 | &i1480u_ATTR_NAME(wlp_dev_prim_OUI).attr, | ||
378 | &i1480u_ATTR_NAME(wlp_dev_prim_OUI_sub).attr, | ||
379 | &i1480u_ATTR_NAME(wlp_dev_prim_subcat).attr, | ||
380 | &i1480u_ATTR_NAME(wlp_neighborhood).attr, | ||
381 | &i1480u_ATTR_NAME(wss_activate).attr, | ||
382 | &i1480u_ATTR_NAME(wlp_tx_inflight).attr, | ||
383 | NULL, | ||
384 | }; | ||
385 | |||
386 | static struct attribute_group i1480u_attr_group = { | ||
387 | .name = NULL, /* we want them in the same directory */ | ||
388 | .attrs = i1480u_attrs, | ||
389 | }; | ||
390 | |||
391 | int i1480u_sysfs_setup(struct i1480u *i1480u) | ||
392 | { | ||
393 | int result; | ||
394 | struct device *dev = &i1480u->usb_iface->dev; | ||
395 | result = sysfs_create_group(&i1480u->net_dev->dev.kobj, | ||
396 | &i1480u_attr_group); | ||
397 | if (result < 0) | ||
398 | dev_err(dev, "cannot initialize sysfs attributes: %d\n", | ||
399 | result); | ||
400 | return result; | ||
401 | } | ||
402 | |||
403 | |||
404 | void i1480u_sysfs_release(struct i1480u *i1480u) | ||
405 | { | ||
406 | sysfs_remove_group(&i1480u->net_dev->dev.kobj, | ||
407 | &i1480u_attr_group); | ||
408 | } | ||
diff --git a/drivers/uwb/i1480/i1480u-wlp/tx.c b/drivers/uwb/i1480/i1480u-wlp/tx.c new file mode 100644 index 000000000000..3426bfb68240 --- /dev/null +++ b/drivers/uwb/i1480/i1480u-wlp/tx.c | |||
@@ -0,0 +1,632 @@ | |||
1 | /* | ||
2 | * WUSB Wire Adapter: WLP interface | ||
3 | * Deal with TX (massaging data to transmit, handling it) | ||
4 | * | ||
5 | * Copyright (C) 2005-2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
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 | * Transmission engine. Get an skb, create from that a WLP transmit | ||
24 | * context, add a WLP TX header (which we keep prefilled in the | ||
25 | * device's instance), fill out the target-specific fields and | ||
26 | * fire it. | ||
27 | * | ||
28 | * ROADMAP: | ||
29 | * | ||
30 | * Entry points: | ||
31 | * | ||
32 | * i1480u_tx_release(): called by i1480u_disconnect() to release | ||
33 | * pending tx contexts. | ||
34 | * | ||
35 | * i1480u_tx_cb(): callback for TX contexts (USB URBs) | ||
36 | * i1480u_tx_destroy(): | ||
37 | * | ||
38 | * i1480u_tx_timeout(): called for timeout handling from the | ||
39 | * network stack. | ||
40 | * | ||
41 | * i1480u_hard_start_xmit(): called for transmitting an skb from | ||
42 | * the network stack. Will interact with WLP | ||
43 | * substack to verify and prepare frame. | ||
44 | * i1480u_xmit_frame(): actual transmission on hardware | ||
45 | * | ||
46 | * i1480u_tx_create() Creates TX context | ||
47 | * i1480u_tx_create_1() For packets in 1 fragment | ||
48 | * i1480u_tx_create_n() For packets in >1 fragments | ||
49 | * | ||
50 | * TODO: | ||
51 | * | ||
52 | * - FIXME: rewrite using usb_sg_*(), add asynch support to | ||
53 | * usb_sg_*(). It might not make too much sense as most of | ||
54 | * the times the MTU will be smaller than one page... | ||
55 | */ | ||
56 | |||
57 | #include "i1480u-wlp.h" | ||
58 | #define D_LOCAL 5 | ||
59 | #include <linux/uwb/debug.h> | ||
60 | |||
61 | enum { | ||
62 | /* This is only for Next and Last TX packets */ | ||
63 | i1480u_MAX_PL_SIZE = i1480u_MAX_FRG_SIZE | ||
64 | - sizeof(struct untd_hdr_rst), | ||
65 | }; | ||
66 | |||
67 | /** Free resources allocated to a i1480u tx context. */ | ||
68 | static | ||
69 | void i1480u_tx_free(struct i1480u_tx *wtx) | ||
70 | { | ||
71 | kfree(wtx->buf); | ||
72 | if (wtx->skb) | ||
73 | dev_kfree_skb_irq(wtx->skb); | ||
74 | usb_free_urb(wtx->urb); | ||
75 | kfree(wtx); | ||
76 | } | ||
77 | |||
78 | static | ||
79 | void i1480u_tx_destroy(struct i1480u *i1480u, struct i1480u_tx *wtx) | ||
80 | { | ||
81 | unsigned long flags; | ||
82 | spin_lock_irqsave(&i1480u->tx_list_lock, flags); /* not active any more */ | ||
83 | list_del(&wtx->list_node); | ||
84 | i1480u_tx_free(wtx); | ||
85 | spin_unlock_irqrestore(&i1480u->tx_list_lock, flags); | ||
86 | } | ||
87 | |||
88 | static | ||
89 | void i1480u_tx_unlink_urbs(struct i1480u *i1480u) | ||
90 | { | ||
91 | unsigned long flags; | ||
92 | struct i1480u_tx *wtx, *next; | ||
93 | |||
94 | spin_lock_irqsave(&i1480u->tx_list_lock, flags); | ||
95 | list_for_each_entry_safe(wtx, next, &i1480u->tx_list, list_node) { | ||
96 | usb_unlink_urb(wtx->urb); | ||
97 | } | ||
98 | spin_unlock_irqrestore(&i1480u->tx_list_lock, flags); | ||
99 | } | ||
100 | |||
101 | |||
102 | /** | ||
103 | * Callback for a completed tx USB URB. | ||
104 | * | ||
105 | * TODO: | ||
106 | * | ||
107 | * - FIXME: recover errors more gracefully | ||
108 | * - FIXME: handle NAKs (I dont think they come here) for flow ctl | ||
109 | */ | ||
110 | static | ||
111 | void i1480u_tx_cb(struct urb *urb) | ||
112 | { | ||
113 | struct i1480u_tx *wtx = urb->context; | ||
114 | struct i1480u *i1480u = wtx->i1480u; | ||
115 | struct net_device *net_dev = i1480u->net_dev; | ||
116 | struct device *dev = &i1480u->usb_iface->dev; | ||
117 | unsigned long flags; | ||
118 | |||
119 | switch (urb->status) { | ||
120 | case 0: | ||
121 | spin_lock_irqsave(&i1480u->lock, flags); | ||
122 | i1480u->stats.tx_packets++; | ||
123 | i1480u->stats.tx_bytes += urb->actual_length; | ||
124 | spin_unlock_irqrestore(&i1480u->lock, flags); | ||
125 | break; | ||
126 | case -ECONNRESET: /* Not an error, but a controlled situation; */ | ||
127 | case -ENOENT: /* (we killed the URB)...so, no broadcast */ | ||
128 | dev_dbg(dev, "notif endp: reset/noent %d\n", urb->status); | ||
129 | netif_stop_queue(net_dev); | ||
130 | break; | ||
131 | case -ESHUTDOWN: /* going away! */ | ||
132 | dev_dbg(dev, "notif endp: down %d\n", urb->status); | ||
133 | netif_stop_queue(net_dev); | ||
134 | break; | ||
135 | default: | ||
136 | dev_err(dev, "TX: unknown URB status %d\n", urb->status); | ||
137 | if (edc_inc(&i1480u->tx_errors, EDC_MAX_ERRORS, | ||
138 | EDC_ERROR_TIMEFRAME)) { | ||
139 | dev_err(dev, "TX: max acceptable errors exceeded." | ||
140 | "Reset device.\n"); | ||
141 | netif_stop_queue(net_dev); | ||
142 | i1480u_tx_unlink_urbs(i1480u); | ||
143 | wlp_reset_all(&i1480u->wlp); | ||
144 | } | ||
145 | break; | ||
146 | } | ||
147 | i1480u_tx_destroy(i1480u, wtx); | ||
148 | if (atomic_dec_return(&i1480u->tx_inflight.count) | ||
149 | <= i1480u->tx_inflight.threshold | ||
150 | && netif_queue_stopped(net_dev) | ||
151 | && i1480u->tx_inflight.threshold != 0) { | ||
152 | if (d_test(2) && printk_ratelimit()) | ||
153 | d_printf(2, dev, "Restart queue. \n"); | ||
154 | netif_start_queue(net_dev); | ||
155 | atomic_inc(&i1480u->tx_inflight.restart_count); | ||
156 | } | ||
157 | return; | ||
158 | } | ||
159 | |||
160 | |||
161 | /** | ||
162 | * Given a buffer that doesn't fit in a single fragment, create an | ||
163 | * scatter/gather structure for delivery to the USB pipe. | ||
164 | * | ||
165 | * Implements functionality of i1480u_tx_create(). | ||
166 | * | ||
167 | * @wtx: tx descriptor | ||
168 | * @skb: skb to send | ||
169 | * @gfp_mask: gfp allocation mask | ||
170 | * @returns: Pointer to @wtx if ok, NULL on error. | ||
171 | * | ||
172 | * Sorry, TOO LONG a function, but breaking it up is kind of hard | ||
173 | * | ||
174 | * This will break the buffer in chunks smaller than | ||
175 | * i1480u_MAX_FRG_SIZE (including the header) and add proper headers | ||
176 | * to each: | ||
177 | * | ||
178 | * 1st header \ | ||
179 | * i1480 tx header | fragment 1 | ||
180 | * fragment data / | ||
181 | * nxt header \ fragment 2 | ||
182 | * fragment data / | ||
183 | * .. | ||
184 | * .. | ||
185 | * last header \ fragment 3 | ||
186 | * last fragment data / | ||
187 | * | ||
188 | * This does not fill the i1480 TX header, it is left up to the | ||
189 | * caller to do that; you can get it from @wtx->wlp_tx_hdr. | ||
190 | * | ||
191 | * This function consumes the skb unless there is an error. | ||
192 | */ | ||
193 | static | ||
194 | int i1480u_tx_create_n(struct i1480u_tx *wtx, struct sk_buff *skb, | ||
195 | gfp_t gfp_mask) | ||
196 | { | ||
197 | int result; | ||
198 | void *pl; | ||
199 | size_t pl_size; | ||
200 | |||
201 | void *pl_itr, *buf_itr; | ||
202 | size_t pl_size_left, frgs, pl_size_1st, frg_pl_size = 0; | ||
203 | struct untd_hdr_1st *untd_hdr_1st; | ||
204 | struct wlp_tx_hdr *wlp_tx_hdr; | ||
205 | struct untd_hdr_rst *untd_hdr_rst; | ||
206 | |||
207 | wtx->skb = NULL; | ||
208 | pl = skb->data; | ||
209 | pl_itr = pl; | ||
210 | pl_size = skb->len; | ||
211 | pl_size_left = pl_size; /* payload size */ | ||
212 | /* First fragment; fits as much as i1480u_MAX_FRG_SIZE minus | ||
213 | * the headers */ | ||
214 | pl_size_1st = i1480u_MAX_FRG_SIZE | ||
215 | - sizeof(struct untd_hdr_1st) - sizeof(struct wlp_tx_hdr); | ||
216 | BUG_ON(pl_size_1st > pl_size); | ||
217 | pl_size_left -= pl_size_1st; | ||
218 | /* The rest have an smaller header (no i1480 TX header). We | ||
219 | * need to break up the payload in blocks smaller than | ||
220 | * i1480u_MAX_PL_SIZE (payload excluding header). */ | ||
221 | frgs = (pl_size_left + i1480u_MAX_PL_SIZE - 1) / i1480u_MAX_PL_SIZE; | ||
222 | /* Allocate space for the new buffer. In this new buffer we'll | ||
223 | * place the headers followed by the data fragment, headers, | ||
224 | * data fragments, etc.. | ||
225 | */ | ||
226 | result = -ENOMEM; | ||
227 | wtx->buf_size = sizeof(*untd_hdr_1st) | ||
228 | + sizeof(*wlp_tx_hdr) | ||
229 | + frgs * sizeof(*untd_hdr_rst) | ||
230 | + pl_size; | ||
231 | wtx->buf = kmalloc(wtx->buf_size, gfp_mask); | ||
232 | if (wtx->buf == NULL) | ||
233 | goto error_buf_alloc; | ||
234 | |||
235 | buf_itr = wtx->buf; /* We got the space, let's fill it up */ | ||
236 | /* Fill 1st fragment */ | ||
237 | untd_hdr_1st = buf_itr; | ||
238 | buf_itr += sizeof(*untd_hdr_1st); | ||
239 | untd_hdr_set_type(&untd_hdr_1st->hdr, i1480u_PKT_FRAG_1ST); | ||
240 | untd_hdr_set_rx_tx(&untd_hdr_1st->hdr, 0); | ||
241 | untd_hdr_1st->hdr.len = cpu_to_le16(pl_size + sizeof(*wlp_tx_hdr)); | ||
242 | untd_hdr_1st->fragment_len = | ||
243 | cpu_to_le16(pl_size_1st + sizeof(*wlp_tx_hdr)); | ||
244 | memset(untd_hdr_1st->padding, 0, sizeof(untd_hdr_1st->padding)); | ||
245 | /* Set up i1480 header info */ | ||
246 | wlp_tx_hdr = wtx->wlp_tx_hdr = buf_itr; | ||
247 | buf_itr += sizeof(*wlp_tx_hdr); | ||
248 | /* Copy the first fragment */ | ||
249 | memcpy(buf_itr, pl_itr, pl_size_1st); | ||
250 | pl_itr += pl_size_1st; | ||
251 | buf_itr += pl_size_1st; | ||
252 | |||
253 | /* Now do each remaining fragment */ | ||
254 | result = -EINVAL; | ||
255 | while (pl_size_left > 0) { | ||
256 | d_printf(5, NULL, "ITR HDR: pl_size_left %zu buf_itr %zu\n", | ||
257 | pl_size_left, buf_itr - wtx->buf); | ||
258 | if (buf_itr + sizeof(*untd_hdr_rst) - wtx->buf | ||
259 | > wtx->buf_size) { | ||
260 | printk(KERN_ERR "BUG: no space for header\n"); | ||
261 | goto error_bug; | ||
262 | } | ||
263 | d_printf(5, NULL, "ITR HDR 2: pl_size_left %zu buf_itr %zu\n", | ||
264 | pl_size_left, buf_itr - wtx->buf); | ||
265 | untd_hdr_rst = buf_itr; | ||
266 | buf_itr += sizeof(*untd_hdr_rst); | ||
267 | if (pl_size_left > i1480u_MAX_PL_SIZE) { | ||
268 | frg_pl_size = i1480u_MAX_PL_SIZE; | ||
269 | untd_hdr_set_type(&untd_hdr_rst->hdr, i1480u_PKT_FRAG_NXT); | ||
270 | } else { | ||
271 | frg_pl_size = pl_size_left; | ||
272 | untd_hdr_set_type(&untd_hdr_rst->hdr, i1480u_PKT_FRAG_LST); | ||
273 | } | ||
274 | d_printf(5, NULL, | ||
275 | "ITR PL: pl_size_left %zu buf_itr %zu frg_pl_size %zu\n", | ||
276 | pl_size_left, buf_itr - wtx->buf, frg_pl_size); | ||
277 | untd_hdr_set_rx_tx(&untd_hdr_rst->hdr, 0); | ||
278 | untd_hdr_rst->hdr.len = cpu_to_le16(frg_pl_size); | ||
279 | untd_hdr_rst->padding = 0; | ||
280 | if (buf_itr + frg_pl_size - wtx->buf | ||
281 | > wtx->buf_size) { | ||
282 | printk(KERN_ERR "BUG: no space for payload\n"); | ||
283 | goto error_bug; | ||
284 | } | ||
285 | memcpy(buf_itr, pl_itr, frg_pl_size); | ||
286 | buf_itr += frg_pl_size; | ||
287 | pl_itr += frg_pl_size; | ||
288 | pl_size_left -= frg_pl_size; | ||
289 | d_printf(5, NULL, | ||
290 | "ITR PL 2: pl_size_left %zu buf_itr %zu frg_pl_size %zu\n", | ||
291 | pl_size_left, buf_itr - wtx->buf, frg_pl_size); | ||
292 | } | ||
293 | dev_kfree_skb_irq(skb); | ||
294 | return 0; | ||
295 | |||
296 | error_bug: | ||
297 | printk(KERN_ERR | ||
298 | "BUG: skb %u bytes\n" | ||
299 | "BUG: frg_pl_size %zd i1480u_MAX_FRG_SIZE %u\n" | ||
300 | "BUG: buf_itr %zu buf_size %zu pl_size_left %zu\n", | ||
301 | skb->len, | ||
302 | frg_pl_size, i1480u_MAX_FRG_SIZE, | ||
303 | buf_itr - wtx->buf, wtx->buf_size, pl_size_left); | ||
304 | |||
305 | kfree(wtx->buf); | ||
306 | error_buf_alloc: | ||
307 | return result; | ||
308 | } | ||
309 | |||
310 | |||
311 | /** | ||
312 | * Given a buffer that fits in a single fragment, fill out a @wtx | ||
313 | * struct for transmitting it down the USB pipe. | ||
314 | * | ||
315 | * Uses the fact that we have space reserved in front of the skbuff | ||
316 | * for hardware headers :] | ||
317 | * | ||
318 | * This does not fill the i1480 TX header, it is left up to the | ||
319 | * caller to do that; you can get it from @wtx->wlp_tx_hdr. | ||
320 | * | ||
321 | * @pl: pointer to payload data | ||
322 | * @pl_size: size of the payuload | ||
323 | * | ||
324 | * This function does not consume the @skb. | ||
325 | */ | ||
326 | static | ||
327 | int i1480u_tx_create_1(struct i1480u_tx *wtx, struct sk_buff *skb, | ||
328 | gfp_t gfp_mask) | ||
329 | { | ||
330 | struct untd_hdr_cmp *untd_hdr_cmp; | ||
331 | struct wlp_tx_hdr *wlp_tx_hdr; | ||
332 | |||
333 | wtx->buf = NULL; | ||
334 | wtx->skb = skb; | ||
335 | BUG_ON(skb_headroom(skb) < sizeof(*wlp_tx_hdr)); | ||
336 | wlp_tx_hdr = (void *) __skb_push(skb, sizeof(*wlp_tx_hdr)); | ||
337 | wtx->wlp_tx_hdr = wlp_tx_hdr; | ||
338 | BUG_ON(skb_headroom(skb) < sizeof(*untd_hdr_cmp)); | ||
339 | untd_hdr_cmp = (void *) __skb_push(skb, sizeof(*untd_hdr_cmp)); | ||
340 | |||
341 | untd_hdr_set_type(&untd_hdr_cmp->hdr, i1480u_PKT_FRAG_CMP); | ||
342 | untd_hdr_set_rx_tx(&untd_hdr_cmp->hdr, 0); | ||
343 | untd_hdr_cmp->hdr.len = cpu_to_le16(skb->len - sizeof(*untd_hdr_cmp)); | ||
344 | untd_hdr_cmp->padding = 0; | ||
345 | return 0; | ||
346 | } | ||
347 | |||
348 | |||
349 | /** | ||
350 | * Given a skb to transmit, massage it to become palatable for the TX pipe | ||
351 | * | ||
352 | * This will break the buffer in chunks smaller than | ||
353 | * i1480u_MAX_FRG_SIZE and add proper headers to each. | ||
354 | * | ||
355 | * 1st header \ | ||
356 | * i1480 tx header | fragment 1 | ||
357 | * fragment data / | ||
358 | * nxt header \ fragment 2 | ||
359 | * fragment data / | ||
360 | * .. | ||
361 | * .. | ||
362 | * last header \ fragment 3 | ||
363 | * last fragment data / | ||
364 | * | ||
365 | * Each fragment will be always smaller or equal to i1480u_MAX_FRG_SIZE. | ||
366 | * | ||
367 | * If the first fragment is smaller than i1480u_MAX_FRG_SIZE, then the | ||
368 | * following is composed: | ||
369 | * | ||
370 | * complete header \ | ||
371 | * i1480 tx header | single fragment | ||
372 | * packet data / | ||
373 | * | ||
374 | * We were going to use s/g support, but because the interface is | ||
375 | * synch and at the end there is plenty of overhead to do it, it | ||
376 | * didn't seem that worth for data that is going to be smaller than | ||
377 | * one page. | ||
378 | */ | ||
379 | static | ||
380 | struct i1480u_tx *i1480u_tx_create(struct i1480u *i1480u, | ||
381 | struct sk_buff *skb, gfp_t gfp_mask) | ||
382 | { | ||
383 | int result; | ||
384 | struct usb_endpoint_descriptor *epd; | ||
385 | int usb_pipe; | ||
386 | unsigned long flags; | ||
387 | |||
388 | struct i1480u_tx *wtx; | ||
389 | const size_t pl_max_size = | ||
390 | i1480u_MAX_FRG_SIZE - sizeof(struct untd_hdr_cmp) | ||
391 | - sizeof(struct wlp_tx_hdr); | ||
392 | |||
393 | wtx = kmalloc(sizeof(*wtx), gfp_mask); | ||
394 | if (wtx == NULL) | ||
395 | goto error_wtx_alloc; | ||
396 | wtx->urb = usb_alloc_urb(0, gfp_mask); | ||
397 | if (wtx->urb == NULL) | ||
398 | goto error_urb_alloc; | ||
399 | epd = &i1480u->usb_iface->cur_altsetting->endpoint[2].desc; | ||
400 | usb_pipe = usb_sndbulkpipe(i1480u->usb_dev, epd->bEndpointAddress); | ||
401 | /* Fits in a single complete packet or need to split? */ | ||
402 | if (skb->len > pl_max_size) { | ||
403 | result = i1480u_tx_create_n(wtx, skb, gfp_mask); | ||
404 | if (result < 0) | ||
405 | goto error_create; | ||
406 | usb_fill_bulk_urb(wtx->urb, i1480u->usb_dev, usb_pipe, | ||
407 | wtx->buf, wtx->buf_size, i1480u_tx_cb, wtx); | ||
408 | } else { | ||
409 | result = i1480u_tx_create_1(wtx, skb, gfp_mask); | ||
410 | if (result < 0) | ||
411 | goto error_create; | ||
412 | usb_fill_bulk_urb(wtx->urb, i1480u->usb_dev, usb_pipe, | ||
413 | skb->data, skb->len, i1480u_tx_cb, wtx); | ||
414 | } | ||
415 | spin_lock_irqsave(&i1480u->tx_list_lock, flags); | ||
416 | list_add(&wtx->list_node, &i1480u->tx_list); | ||
417 | spin_unlock_irqrestore(&i1480u->tx_list_lock, flags); | ||
418 | return wtx; | ||
419 | |||
420 | error_create: | ||
421 | kfree(wtx->urb); | ||
422 | error_urb_alloc: | ||
423 | kfree(wtx); | ||
424 | error_wtx_alloc: | ||
425 | return NULL; | ||
426 | } | ||
427 | |||
428 | /** | ||
429 | * Actual fragmentation and transmission of frame | ||
430 | * | ||
431 | * @wlp: WLP substack data structure | ||
432 | * @skb: To be transmitted | ||
433 | * @dst: Device address of destination | ||
434 | * @returns: 0 on success, <0 on failure | ||
435 | * | ||
436 | * This function can also be called directly (not just from | ||
437 | * hard_start_xmit), so we also check here if the interface is up before | ||
438 | * taking sending anything. | ||
439 | */ | ||
440 | int i1480u_xmit_frame(struct wlp *wlp, struct sk_buff *skb, | ||
441 | struct uwb_dev_addr *dst) | ||
442 | { | ||
443 | int result = -ENXIO; | ||
444 | struct i1480u *i1480u = container_of(wlp, struct i1480u, wlp); | ||
445 | struct device *dev = &i1480u->usb_iface->dev; | ||
446 | struct net_device *net_dev = i1480u->net_dev; | ||
447 | struct i1480u_tx *wtx; | ||
448 | struct wlp_tx_hdr *wlp_tx_hdr; | ||
449 | static unsigned char dev_bcast[2] = { 0xff, 0xff }; | ||
450 | #if 0 | ||
451 | int lockup = 50; | ||
452 | #endif | ||
453 | |||
454 | d_fnstart(6, dev, "(skb %p (%u), net_dev %p)\n", skb, skb->len, | ||
455 | net_dev); | ||
456 | BUG_ON(i1480u->wlp.rc == NULL); | ||
457 | if ((net_dev->flags & IFF_UP) == 0) | ||
458 | goto out; | ||
459 | result = -EBUSY; | ||
460 | if (atomic_read(&i1480u->tx_inflight.count) >= i1480u->tx_inflight.max) { | ||
461 | if (d_test(2) && printk_ratelimit()) | ||
462 | d_printf(2, dev, "Max frames in flight " | ||
463 | "stopping queue.\n"); | ||
464 | netif_stop_queue(net_dev); | ||
465 | goto error_max_inflight; | ||
466 | } | ||
467 | result = -ENOMEM; | ||
468 | wtx = i1480u_tx_create(i1480u, skb, GFP_ATOMIC); | ||
469 | if (unlikely(wtx == NULL)) { | ||
470 | if (printk_ratelimit()) | ||
471 | dev_err(dev, "TX: no memory for WLP TX URB," | ||
472 | "dropping packet (in flight %d)\n", | ||
473 | atomic_read(&i1480u->tx_inflight.count)); | ||
474 | netif_stop_queue(net_dev); | ||
475 | goto error_wtx_alloc; | ||
476 | } | ||
477 | wtx->i1480u = i1480u; | ||
478 | /* Fill out the i1480 header; @i1480u->def_tx_hdr read without | ||
479 | * locking. We do so because they are kind of orthogonal to | ||
480 | * each other (and thus not changed in an atomic batch). | ||
481 | * The ETH header is right after the WLP TX header. */ | ||
482 | wlp_tx_hdr = wtx->wlp_tx_hdr; | ||
483 | *wlp_tx_hdr = i1480u->options.def_tx_hdr; | ||
484 | wlp_tx_hdr->dstaddr = *dst; | ||
485 | if (!memcmp(&wlp_tx_hdr->dstaddr, dev_bcast, sizeof(dev_bcast)) | ||
486 | && (wlp_tx_hdr_delivery_id_type(wlp_tx_hdr) & WLP_DRP)) { | ||
487 | /*Broadcast message directed to DRP host. Send as best effort | ||
488 | * on PCA. */ | ||
489 | wlp_tx_hdr_set_delivery_id_type(wlp_tx_hdr, i1480u->options.pca_base_priority); | ||
490 | } | ||
491 | |||
492 | #if 0 | ||
493 | dev_info(dev, "TX delivering skb -> USB, %zu bytes\n", skb->len); | ||
494 | dump_bytes(dev, skb->data, skb->len > 72 ? 72 : skb->len); | ||
495 | #endif | ||
496 | #if 0 | ||
497 | /* simulates a device lockup after every lockup# packets */ | ||
498 | if (lockup && ((i1480u->stats.tx_packets + 1) % lockup) == 0) { | ||
499 | /* Simulate a dropped transmit interrupt */ | ||
500 | net_dev->trans_start = jiffies; | ||
501 | netif_stop_queue(net_dev); | ||
502 | dev_err(dev, "Simulate lockup at %ld\n", jiffies); | ||
503 | return result; | ||
504 | } | ||
505 | #endif | ||
506 | |||
507 | result = usb_submit_urb(wtx->urb, GFP_ATOMIC); /* Go baby */ | ||
508 | if (result < 0) { | ||
509 | dev_err(dev, "TX: cannot submit URB: %d\n", result); | ||
510 | /* We leave the freeing of skb to calling function */ | ||
511 | wtx->skb = NULL; | ||
512 | goto error_tx_urb_submit; | ||
513 | } | ||
514 | atomic_inc(&i1480u->tx_inflight.count); | ||
515 | net_dev->trans_start = jiffies; | ||
516 | d_fnend(6, dev, "(skb %p (%u), net_dev %p) = %d\n", skb, skb->len, | ||
517 | net_dev, result); | ||
518 | return result; | ||
519 | |||
520 | error_tx_urb_submit: | ||
521 | i1480u_tx_destroy(i1480u, wtx); | ||
522 | error_wtx_alloc: | ||
523 | error_max_inflight: | ||
524 | out: | ||
525 | d_fnend(6, dev, "(skb %p (%u), net_dev %p) = %d\n", skb, skb->len, | ||
526 | net_dev, result); | ||
527 | return result; | ||
528 | } | ||
529 | |||
530 | |||
531 | /** | ||
532 | * Transmit an skb Called when an skbuf has to be transmitted | ||
533 | * | ||
534 | * The skb is first passed to WLP substack to ensure this is a valid | ||
535 | * frame. If valid the device address of destination will be filled and | ||
536 | * the WLP header prepended to the skb. If this step fails we fake sending | ||
537 | * the frame, if we return an error the network stack will just keep trying. | ||
538 | * | ||
539 | * Broadcast frames inside a WSS needs to be treated special as multicast is | ||
540 | * not supported. A broadcast frame is sent as unicast to each member of the | ||
541 | * WSS - this is done by the WLP substack when it finds a broadcast frame. | ||
542 | * So, we test if the WLP substack took over the skb and only transmit it | ||
543 | * if it has not (been taken over). | ||
544 | * | ||
545 | * @net_dev->xmit_lock is held | ||
546 | */ | ||
547 | int i1480u_hard_start_xmit(struct sk_buff *skb, struct net_device *net_dev) | ||
548 | { | ||
549 | int result; | ||
550 | struct i1480u *i1480u = netdev_priv(net_dev); | ||
551 | struct device *dev = &i1480u->usb_iface->dev; | ||
552 | struct uwb_dev_addr dst; | ||
553 | |||
554 | d_fnstart(6, dev, "(skb %p (%u), net_dev %p)\n", skb, skb->len, | ||
555 | net_dev); | ||
556 | BUG_ON(i1480u->wlp.rc == NULL); | ||
557 | if ((net_dev->flags & IFF_UP) == 0) | ||
558 | goto error; | ||
559 | result = wlp_prepare_tx_frame(dev, &i1480u->wlp, skb, &dst); | ||
560 | if (result < 0) { | ||
561 | dev_err(dev, "WLP verification of TX frame failed (%d). " | ||
562 | "Dropping packet.\n", result); | ||
563 | goto error; | ||
564 | } else if (result == 1) { | ||
565 | d_printf(6, dev, "WLP will transmit frame. \n"); | ||
566 | /* trans_start time will be set when WLP actually transmits | ||
567 | * the frame */ | ||
568 | goto out; | ||
569 | } | ||
570 | d_printf(6, dev, "Transmitting frame. \n"); | ||
571 | result = i1480u_xmit_frame(&i1480u->wlp, skb, &dst); | ||
572 | if (result < 0) { | ||
573 | dev_err(dev, "Frame TX failed (%d).\n", result); | ||
574 | goto error; | ||
575 | } | ||
576 | d_fnend(6, dev, "(skb %p (%u), net_dev %p) = %d\n", skb, skb->len, | ||
577 | net_dev, result); | ||
578 | return NETDEV_TX_OK; | ||
579 | error: | ||
580 | dev_kfree_skb_any(skb); | ||
581 | i1480u->stats.tx_dropped++; | ||
582 | out: | ||
583 | d_fnend(6, dev, "(skb %p (%u), net_dev %p) = %d\n", skb, skb->len, | ||
584 | net_dev, result); | ||
585 | return NETDEV_TX_OK; | ||
586 | } | ||
587 | |||
588 | |||
589 | /** | ||
590 | * Called when a pkt transmission doesn't complete in a reasonable period | ||
591 | * Device reset may sleep - do it outside of interrupt context (delayed) | ||
592 | */ | ||
593 | void i1480u_tx_timeout(struct net_device *net_dev) | ||
594 | { | ||
595 | struct i1480u *i1480u = netdev_priv(net_dev); | ||
596 | |||
597 | wlp_reset_all(&i1480u->wlp); | ||
598 | } | ||
599 | |||
600 | |||
601 | void i1480u_tx_release(struct i1480u *i1480u) | ||
602 | { | ||
603 | unsigned long flags; | ||
604 | struct i1480u_tx *wtx, *next; | ||
605 | int count = 0, empty; | ||
606 | |||
607 | spin_lock_irqsave(&i1480u->tx_list_lock, flags); | ||
608 | list_for_each_entry_safe(wtx, next, &i1480u->tx_list, list_node) { | ||
609 | count++; | ||
610 | usb_unlink_urb(wtx->urb); | ||
611 | } | ||
612 | spin_unlock_irqrestore(&i1480u->tx_list_lock, flags); | ||
613 | count = count*10; /* i1480ut 200ms per unlinked urb (intervals of 20ms) */ | ||
614 | /* | ||
615 | * We don't like this sollution too much (dirty as it is), but | ||
616 | * it is cheaper than putting a refcount on each i1480u_tx and | ||
617 | * i1480uting for all of them to go away... | ||
618 | * | ||
619 | * Called when no more packets can be added to tx_list | ||
620 | * so can i1480ut for it to be empty. | ||
621 | */ | ||
622 | while (1) { | ||
623 | spin_lock_irqsave(&i1480u->tx_list_lock, flags); | ||
624 | empty = list_empty(&i1480u->tx_list); | ||
625 | spin_unlock_irqrestore(&i1480u->tx_list_lock, flags); | ||
626 | if (empty) | ||
627 | break; | ||
628 | count--; | ||
629 | BUG_ON(count == 0); | ||
630 | msleep(20); | ||
631 | } | ||
632 | } | ||