aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ipw2200.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/ipw2200.c')
-rw-r--r--drivers/net/wireless/ipw2200.c120
1 files changed, 106 insertions, 14 deletions
diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c
index ef1007785030..bcb5993b68bd 100644
--- a/drivers/net/wireless/ipw2200.c
+++ b/drivers/net/wireless/ipw2200.c
@@ -44,6 +44,7 @@ MODULE_VERSION(DRV_VERSION);
44MODULE_AUTHOR(DRV_COPYRIGHT); 44MODULE_AUTHOR(DRV_COPYRIGHT);
45MODULE_LICENSE("GPL"); 45MODULE_LICENSE("GPL");
46 46
47static int cmdlog = 0;
47static int debug = 0; 48static int debug = 0;
48static int channel = 0; 49static int channel = 0;
49static int mode = 0; 50static int mode = 0;
@@ -148,8 +149,8 @@ static int init_supported_rates(struct ipw_priv *priv,
148static void ipw_set_hwcrypto_keys(struct ipw_priv *); 149static void ipw_set_hwcrypto_keys(struct ipw_priv *);
149static void ipw_send_wep_keys(struct ipw_priv *, int); 150static void ipw_send_wep_keys(struct ipw_priv *, int);
150 151
151static char *snprint_line(char *buf, size_t count, 152static int snprint_line(char *buf, size_t count,
152 const u8 * data, u32 len, u32 ofs) 153 const u8 * data, u32 len, u32 ofs)
153{ 154{
154 int out, i, j, l; 155 int out, i, j, l;
155 char c; 156 char c;
@@ -180,7 +181,7 @@ static char *snprint_line(char *buf, size_t count,
180 out += snprintf(buf + out, count - out, " "); 181 out += snprintf(buf + out, count - out, " ");
181 } 182 }
182 183
183 return buf; 184 return out;
184} 185}
185 186
186static void printk_buf(int level, const u8 * data, u32 len) 187static void printk_buf(int level, const u8 * data, u32 len)
@@ -191,14 +192,33 @@ static void printk_buf(int level, const u8 * data, u32 len)
191 return; 192 return;
192 193
193 while (len) { 194 while (len) {
194 printk(KERN_DEBUG "%s\n", 195 snprint_line(line, sizeof(line), &data[ofs],
195 snprint_line(line, sizeof(line), &data[ofs], 196 min(len, 16U), ofs);
196 min(len, 16U), ofs)); 197 printk(KERN_DEBUG "%s\n", line);
197 ofs += 16; 198 ofs += 16;
198 len -= min(len, 16U); 199 len -= min(len, 16U);
199 } 200 }
200} 201}
201 202
203static int snprintk_buf(u8 * output, size_t size, const u8 * data, size_t len)
204{
205 size_t out = size;
206 u32 ofs = 0;
207 int total = 0;
208
209 while (size && len) {
210 out = snprint_line(output, size, &data[ofs],
211 min_t(size_t, len, 16U), ofs);
212
213 ofs += 16;
214 output += out;
215 size -= out;
216 len -= min_t(size_t, len, 16U);
217 total += out;
218 }
219 return total;
220}
221
202static u32 _ipw_read_reg32(struct ipw_priv *priv, u32 reg); 222static u32 _ipw_read_reg32(struct ipw_priv *priv, u32 reg);
203#define ipw_read_reg32(a, b) _ipw_read_reg32(a, b) 223#define ipw_read_reg32(a, b) _ipw_read_reg32(a, b)
204 224
@@ -272,9 +292,15 @@ static inline u32 __ipw_read32(char *f, u32 l, struct ipw_priv *ipw, u32 ofs)
272#define ipw_read32(ipw, ofs) __ipw_read32(__FILE__, __LINE__, ipw, ofs) 292#define ipw_read32(ipw, ofs) __ipw_read32(__FILE__, __LINE__, ipw, ofs)
273 293
274static void _ipw_read_indirect(struct ipw_priv *, u32, u8 *, int); 294static void _ipw_read_indirect(struct ipw_priv *, u32, u8 *, int);
275#define ipw_read_indirect(a, b, c, d) \ 295static inline void __ipw_read_indirect(const char *f, int l,
276 IPW_DEBUG_IO("%s %d: read_indirect(0x%08X) %d bytes\n", __FILE__, __LINE__, (u32)(b), d); \ 296 struct ipw_priv *a, u32 b, u8 * c, int d)
277 _ipw_read_indirect(a, b, c, d) 297{
298 IPW_DEBUG_IO("%s %d: read_indirect(0x%08X) %d bytes\n", f, l, (u32) (b),
299 d);
300 _ipw_read_indirect(a, b, c, d);
301}
302
303#define ipw_read_indirect(a, b, c, d) __ipw_read_indirect(__FILE__, __LINE__, a, b, c, d)
278 304
279static void _ipw_write_indirect(struct ipw_priv *priv, u32 addr, u8 * data, 305static void _ipw_write_indirect(struct ipw_priv *priv, u32 addr, u8 * data,
280 int num); 306 int num);
@@ -1070,6 +1096,7 @@ static struct ipw_fw_error *ipw_alloc_error_log(struct ipw_priv *priv)
1070 "failed.\n"); 1096 "failed.\n");
1071 return NULL; 1097 return NULL;
1072 } 1098 }
1099 error->jiffies = jiffies;
1073 error->status = priv->status; 1100 error->status = priv->status;
1074 error->config = priv->config; 1101 error->config = priv->config;
1075 error->elem_len = elem_len; 1102 error->elem_len = elem_len;
@@ -1122,7 +1149,8 @@ static ssize_t show_error(struct device *d,
1122 if (!priv->error) 1149 if (!priv->error)
1123 return 0; 1150 return 0;
1124 len += snprintf(buf + len, PAGE_SIZE - len, 1151 len += snprintf(buf + len, PAGE_SIZE - len,
1125 "%08X%08X%08X", 1152 "%08lX%08X%08X%08X",
1153 priv->error->jiffies,
1126 priv->error->status, 1154 priv->error->status,
1127 priv->error->config, priv->error->elem_len); 1155 priv->error->config, priv->error->elem_len);
1128 for (i = 0; i < priv->error->elem_len; i++) 1156 for (i = 0; i < priv->error->elem_len; i++)
@@ -1162,6 +1190,33 @@ static ssize_t clear_error(struct device *d,
1162 1190
1163static DEVICE_ATTR(error, S_IRUGO | S_IWUSR, show_error, clear_error); 1191static DEVICE_ATTR(error, S_IRUGO | S_IWUSR, show_error, clear_error);
1164 1192
1193static ssize_t show_cmd_log(struct device *d,
1194 struct device_attribute *attr, char *buf)
1195{
1196 struct ipw_priv *priv = dev_get_drvdata(d);
1197 u32 len = 0, i;
1198 if (!priv->cmdlog)
1199 return 0;
1200 for (i = (priv->cmdlog_pos + 1) % priv->cmdlog_len;
1201 (i != priv->cmdlog_pos) && (PAGE_SIZE - len);
1202 i = (i + 1) % priv->cmdlog_len) {
1203 len +=
1204 snprintf(buf + len, PAGE_SIZE - len,
1205 "\n%08lX%08X%08X%08X\n", priv->cmdlog[i].jiffies,
1206 priv->cmdlog[i].retcode, priv->cmdlog[i].cmd.cmd,
1207 priv->cmdlog[i].cmd.len);
1208 len +=
1209 snprintk_buf(buf + len, PAGE_SIZE - len,
1210 (u8 *) priv->cmdlog[i].cmd.param,
1211 priv->cmdlog[i].cmd.len);
1212 len += snprintf(buf + len, PAGE_SIZE - len, "\n");
1213 }
1214 len += snprintf(buf + len, PAGE_SIZE - len, "\n");
1215 return len;
1216}
1217
1218static DEVICE_ATTR(cmd_log, S_IRUGO, show_cmd_log, NULL);
1219
1165static ssize_t show_scan_age(struct device *d, struct device_attribute *attr, 1220static ssize_t show_scan_age(struct device *d, struct device_attribute *attr,
1166 char *buf) 1221 char *buf)
1167{ 1222{
@@ -1825,6 +1880,15 @@ static int ipw_send_cmd(struct ipw_priv *priv, struct host_cmd *cmd)
1825 1880
1826 priv->status |= STATUS_HCMD_ACTIVE; 1881 priv->status |= STATUS_HCMD_ACTIVE;
1827 1882
1883 if (priv->cmdlog) {
1884 priv->cmdlog[priv->cmdlog_pos].jiffies = jiffies;
1885 priv->cmdlog[priv->cmdlog_pos].cmd.cmd = cmd->cmd;
1886 priv->cmdlog[priv->cmdlog_pos].cmd.len = cmd->len;
1887 memcpy(priv->cmdlog[priv->cmdlog_pos].cmd.param, cmd->param,
1888 cmd->len);
1889 priv->cmdlog[priv->cmdlog_pos].retcode = -1;
1890 }
1891
1828 IPW_DEBUG_HC("%s command (#%d) %d bytes: 0x%08X\n", 1892 IPW_DEBUG_HC("%s command (#%d) %d bytes: 0x%08X\n",
1829 get_cmd_string(cmd->cmd), cmd->cmd, cmd->len, 1893 get_cmd_string(cmd->cmd), cmd->cmd, cmd->len,
1830 priv->status); 1894 priv->status);
@@ -1836,7 +1900,7 @@ static int ipw_send_cmd(struct ipw_priv *priv, struct host_cmd *cmd)
1836 IPW_ERROR("Failed to send %s: Reason %d\n", 1900 IPW_ERROR("Failed to send %s: Reason %d\n",
1837 get_cmd_string(cmd->cmd), rc); 1901 get_cmd_string(cmd->cmd), rc);
1838 spin_unlock_irqrestore(&priv->lock, flags); 1902 spin_unlock_irqrestore(&priv->lock, flags);
1839 return rc; 1903 goto exit;
1840 } 1904 }
1841 spin_unlock_irqrestore(&priv->lock, flags); 1905 spin_unlock_irqrestore(&priv->lock, flags);
1842 1906
@@ -1851,7 +1915,8 @@ static int ipw_send_cmd(struct ipw_priv *priv, struct host_cmd *cmd)
1851 get_cmd_string(cmd->cmd)); 1915 get_cmd_string(cmd->cmd));
1852 priv->status &= ~STATUS_HCMD_ACTIVE; 1916 priv->status &= ~STATUS_HCMD_ACTIVE;
1853 spin_unlock_irqrestore(&priv->lock, flags); 1917 spin_unlock_irqrestore(&priv->lock, flags);
1854 return -EIO; 1918 rc = -EIO;
1919 goto exit;
1855 } 1920 }
1856 spin_unlock_irqrestore(&priv->lock, flags); 1921 spin_unlock_irqrestore(&priv->lock, flags);
1857 } 1922 }
@@ -1859,10 +1924,16 @@ static int ipw_send_cmd(struct ipw_priv *priv, struct host_cmd *cmd)
1859 if (priv->status & STATUS_RF_KILL_HW) { 1924 if (priv->status & STATUS_RF_KILL_HW) {
1860 IPW_ERROR("Failed to send %s: Aborted due to RF kill switch.\n", 1925 IPW_ERROR("Failed to send %s: Aborted due to RF kill switch.\n",
1861 get_cmd_string(cmd->cmd)); 1926 get_cmd_string(cmd->cmd));
1862 return -EIO; 1927 rc = -EIO;
1928 goto exit;
1863 } 1929 }
1864 1930
1865 return 0; 1931 exit:
1932 if (priv->cmdlog) {
1933 priv->cmdlog[priv->cmdlog_pos++].retcode = rc;
1934 priv->cmdlog_pos %= priv->cmdlog_len;
1935 }
1936 return rc;
1866} 1937}
1867 1938
1868static int ipw_send_host_complete(struct ipw_priv *priv) 1939static int ipw_send_host_complete(struct ipw_priv *priv)
@@ -10712,6 +10783,18 @@ static int ipw_up(struct ipw_priv *priv)
10712 if (priv->status & STATUS_EXIT_PENDING) 10783 if (priv->status & STATUS_EXIT_PENDING)
10713 return -EIO; 10784 return -EIO;
10714 10785
10786 if (cmdlog && !priv->cmdlog) {
10787 priv->cmdlog = kmalloc(sizeof(*priv->cmdlog) * cmdlog,
10788 GFP_KERNEL);
10789 if (priv->cmdlog == NULL) {
10790 IPW_ERROR("Error allocating %d command log entries.\n",
10791 cmdlog);
10792 } else {
10793 memset(priv->cmdlog, 0, sizeof(*priv->cmdlog) * cmdlog);
10794 priv->cmdlog_len = cmdlog;
10795 }
10796 }
10797
10715 for (i = 0; i < MAX_HW_RESTARTS; i++) { 10798 for (i = 0; i < MAX_HW_RESTARTS; i++) {
10716 /* Load the microcode, firmware, and eeprom. 10799 /* Load the microcode, firmware, and eeprom.
10717 * Also start the clocks. */ 10800 * Also start the clocks. */
@@ -10935,6 +11018,7 @@ static struct attribute *ipw_sysfs_entries[] = {
10935 &dev_attr_cfg.attr, 11018 &dev_attr_cfg.attr,
10936 &dev_attr_error.attr, 11019 &dev_attr_error.attr,
10937 &dev_attr_event_log.attr, 11020 &dev_attr_event_log.attr,
11021 &dev_attr_cmd_log.attr,
10938 &dev_attr_eeprom_delay.attr, 11022 &dev_attr_eeprom_delay.attr,
10939 &dev_attr_ucode_version.attr, 11023 &dev_attr_ucode_version.attr,
10940 &dev_attr_rtc.attr, 11024 &dev_attr_rtc.attr,
@@ -11129,6 +11213,10 @@ static void ipw_pci_remove(struct pci_dev *pdev)
11129 } 11213 }
11130 ipw_tx_queue_free(priv); 11214 ipw_tx_queue_free(priv);
11131 11215
11216 if (priv->cmdlog) {
11217 kfree(priv->cmdlog);
11218 priv->cmdlog = NULL;
11219 }
11132 /* ipw_down will ensure that there is no more pending work 11220 /* ipw_down will ensure that there is no more pending work
11133 * in the workqueue's, so we can safely remove them now. */ 11221 * in the workqueue's, so we can safely remove them now. */
11134 cancel_delayed_work(&priv->adhoc_check); 11222 cancel_delayed_work(&priv->adhoc_check);
@@ -11302,5 +11390,9 @@ MODULE_PARM_DESC(mode, "network mode (0=BSS,1=IBSS)");
11302module_param(hwcrypto, int, 0444); 11390module_param(hwcrypto, int, 0444);
11303MODULE_PARM_DESC(hwcrypto, "enable hardware crypto (default on)"); 11391MODULE_PARM_DESC(hwcrypto, "enable hardware crypto (default on)");
11304 11392
11393module_param(cmdlog, int, 0444);
11394MODULE_PARM_DESC(cmdlog,
11395 "allocate a ring buffer for logging firmware commands");
11396
11305module_exit(ipw_exit); 11397module_exit(ipw_exit);
11306module_init(ipw_init); 11398module_init(ipw_init);