Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 13571
b: refs/heads/master
c: b39860c
h: refs/heads/master
i:
  13569: db08953
  13567: 033ad91
v: v3
  • Loading branch information
James Ketrenos committed Nov 7, 2005
1 parent 4a5d400 commit 7d9a868
Show file tree
Hide file tree
Showing 3 changed files with 205 additions and 78 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: e666619e232308c8ee2aba6b87f28ad26b38d905
refs/heads/master: b39860c60b135ef16c1c16a3e2a757ff8070c5ad
251 changes: 175 additions & 76 deletions trunk/drivers/net/wireless/ipw2200.c
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,7 @@ static inline void ipw_disable_interrupts(struct ipw_priv *priv)
ipw_write32(priv, IPW_INTA_MASK_R, ~IPW_INTA_MASK_ALL);
}

#ifdef CONFIG_IPW_DEBUG
static char *ipw_error_desc(u32 val)
{
switch (val) {
Expand Down Expand Up @@ -466,56 +467,35 @@ static char *ipw_error_desc(u32 val)
}
}

static void ipw_dump_nic_error_log(struct ipw_priv *priv)
static void ipw_dump_error_log(struct ipw_priv *priv,
struct ipw_fw_error *error)
{
u32 desc, time, blink1, blink2, ilink1, ilink2, idata, i, count, base;

base = ipw_read32(priv, IPWSTATUS_ERROR_LOG);
count = ipw_read_reg32(priv, base);
u32 i;

if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) {
IPW_ERROR("Start IPW Error Log Dump:\n");
IPW_ERROR("Status: 0x%08X, Config: %08X\n",
priv->status, priv->config);
if (!error) {
IPW_ERROR("Error allocating and capturing error log. "
"Nothing to dump.\n");
return;
}

for (i = ERROR_START_OFFSET;
i <= count * ERROR_ELEM_SIZE; i += ERROR_ELEM_SIZE) {
desc = ipw_read_reg32(priv, base + i);
time = ipw_read_reg32(priv, base + i + 1 * sizeof(u32));
blink1 = ipw_read_reg32(priv, base + i + 2 * sizeof(u32));
blink2 = ipw_read_reg32(priv, base + i + 3 * sizeof(u32));
ilink1 = ipw_read_reg32(priv, base + i + 4 * sizeof(u32));
ilink2 = ipw_read_reg32(priv, base + i + 5 * sizeof(u32));
idata = ipw_read_reg32(priv, base + i + 6 * sizeof(u32));
IPW_ERROR("Start IPW Error Log Dump:\n");
IPW_ERROR("Status: 0x%08X, Config: %08X\n",
error->status, error->config);

for (i = 0; i < error->elem_len; i++)
IPW_ERROR("%s %i 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",
ipw_error_desc(desc), time, blink1, blink2,
ilink1, ilink2, idata);
}
ipw_error_desc(error->elem[i].desc),
error->elem[i].time,
error->elem[i].blink1,
error->elem[i].blink2,
error->elem[i].link1,
error->elem[i].link2, error->elem[i].data);
for (i = 0; i < error->log_len; i++)
IPW_ERROR("%i\t0x%08x\t%i\n",
error->log[i].time,
error->log[i].event, error->log[i].data);
}

static void ipw_dump_nic_event_log(struct ipw_priv *priv)
{
u32 ev, time, data, i, count, base;

base = ipw_read32(priv, IPW_EVENT_LOG);
count = ipw_read_reg32(priv, base);

if (EVENT_START_OFFSET <= count * EVENT_ELEM_SIZE)
IPW_ERROR("Start IPW Event Log Dump:\n");

for (i = EVENT_START_OFFSET;
i <= count * EVENT_ELEM_SIZE; i += EVENT_ELEM_SIZE) {
ev = ipw_read_reg32(priv, base + i);
time = ipw_read_reg32(priv, base + i + 1 * sizeof(u32));
data = ipw_read_reg32(priv, base + i + 2 * sizeof(u32));

#ifdef CONFIG_IPW_DEBUG
IPW_ERROR("%i\t0x%08x\t%i\n", time, data, ev);
#endif
}
}

static inline int ipw_is_init(struct ipw_priv *priv)
{
Expand Down Expand Up @@ -1058,6 +1038,130 @@ static ssize_t store_debug_level(struct device_driver *d, const char *buf,
static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO,
show_debug_level, store_debug_level);

static inline u32 ipw_get_event_log_len(struct ipw_priv *priv)
{
return ipw_read_reg32(priv, ipw_read32(priv, IPW_EVENT_LOG));
}

static void ipw_capture_event_log(struct ipw_priv *priv,
u32 log_len, struct ipw_event *log)
{
u32 base;

if (log_len) {
base = ipw_read32(priv, IPW_EVENT_LOG);
ipw_read_indirect(priv, base + sizeof(base) + sizeof(u32),
(u8 *) log, sizeof(*log) * log_len);
}
}

static struct ipw_fw_error *ipw_alloc_error_log(struct ipw_priv *priv)
{
struct ipw_fw_error *error;
u32 log_len = ipw_get_event_log_len(priv);
u32 base = ipw_read32(priv, IPW_ERROR_LOG);
u32 elem_len = ipw_read_reg32(priv, base);

error = kmalloc(sizeof(*error) +
sizeof(*error->elem) * elem_len +
sizeof(*error->log) * log_len, GFP_ATOMIC);
if (!error) {
IPW_ERROR("Memory allocation for firmware error log "
"failed.\n");
return NULL;
}
error->status = priv->status;
error->config = priv->config;
error->elem_len = elem_len;
error->log_len = log_len;
error->elem = (struct ipw_error_elem *)error->payload;
error->log = (struct ipw_event *)(error->elem +
(sizeof(*error->elem) * elem_len));

ipw_capture_event_log(priv, log_len, error->log);

if (elem_len)
ipw_read_indirect(priv, base + sizeof(base), (u8 *) error->elem,
sizeof(*error->elem) * elem_len);

return error;
}

static void ipw_free_error_log(struct ipw_fw_error *error)
{
if (error)
kfree(error);
}

static ssize_t show_event_log(struct device *d,
struct device_attribute *attr, char *buf)
{
struct ipw_priv *priv = dev_get_drvdata(d);
u32 log_len = ipw_get_event_log_len(priv);
struct ipw_event log[log_len];
u32 len = 0, i;

ipw_capture_event_log(priv, log_len, log);

len += snprintf(buf + len, PAGE_SIZE - len, "%08X", log_len);
for (i = 0; i < log_len; i++)
len += snprintf(buf + len, PAGE_SIZE - len,
"\n%08X%08X%08X",
log[i].time, log[i].event, log[i].data);
len += snprintf(buf + len, PAGE_SIZE - len, "\n");
return len;
}

static DEVICE_ATTR(event_log, S_IRUGO, show_event_log, NULL);

static ssize_t show_error(struct device *d,
struct device_attribute *attr, char *buf)
{
struct ipw_priv *priv = dev_get_drvdata(d);
u32 len = 0, i;
if (!priv->error)
return 0;
len += snprintf(buf + len, PAGE_SIZE - len,
"%08X%08X%08X",
priv->error->status,
priv->error->config, priv->error->elem_len);
for (i = 0; i < priv->error->elem_len; i++)
len += snprintf(buf + len, PAGE_SIZE - len,
"\n%08X%08X%08X%08X%08X%08X%08X",
priv->error->elem[i].time,
priv->error->elem[i].desc,
priv->error->elem[i].blink1,
priv->error->elem[i].blink2,
priv->error->elem[i].link1,
priv->error->elem[i].link2,
priv->error->elem[i].data);

len += snprintf(buf + len, PAGE_SIZE - len,
"\n%08X", priv->error->log_len);
for (i = 0; i < priv->error->log_len; i++)
len += snprintf(buf + len, PAGE_SIZE - len,
"\n%08X%08X%08X",
priv->error->log[i].time,
priv->error->log[i].event,
priv->error->log[i].data);
len += snprintf(buf + len, PAGE_SIZE - len, "\n");
return len;
}

static ssize_t clear_error(struct device *d,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct ipw_priv *priv = dev_get_drvdata(d);
if (priv->error) {
ipw_free_error_log(priv->error);
priv->error = NULL;
}
return count;
}

static DEVICE_ATTR(error, S_IRUGO | S_IWUSR, show_error, clear_error);

static ssize_t show_scan_age(struct device *d, struct device_attribute *attr,
char *buf)
{
Expand Down Expand Up @@ -1163,34 +1267,6 @@ static ssize_t show_nic_type(struct device *d,

static DEVICE_ATTR(nic_type, S_IRUGO, show_nic_type, NULL);

static ssize_t dump_error_log(struct device *d,
struct device_attribute *attr, const char *buf,
size_t count)
{
char *p = (char *)buf;

if (p[0] == '1')
ipw_dump_nic_error_log((struct ipw_priv *)d->driver_data);

return strnlen(buf, count);
}

static DEVICE_ATTR(dump_errors, S_IWUSR, NULL, dump_error_log);

static ssize_t dump_event_log(struct device *d,
struct device_attribute *attr, const char *buf,
size_t count)
{
char *p = (char *)buf;

if (p[0] == '1')
ipw_dump_nic_event_log((struct ipw_priv *)d->driver_data);

return strnlen(buf, count);
}

static DEVICE_ATTR(dump_events, S_IWUSR, NULL, dump_event_log);

static ssize_t show_ucode_version(struct device *d,
struct device_attribute *attr, char *buf)
{
Expand Down Expand Up @@ -1614,12 +1690,30 @@ static void ipw_irq_tasklet(struct ipw_priv *priv)

if (inta & IPW_INTA_BIT_FATAL_ERROR) {
IPW_ERROR("Firmware error detected. Restarting.\n");
if (priv->error) {
IPW_ERROR("Sysfs 'error' log already exists.\n");
#ifdef CONFIG_IPW_DEBUG
if (ipw_debug_level & IPW_DL_FW_ERRORS) {
ipw_dump_nic_error_log(priv);
ipw_dump_nic_event_log(priv);
}
if (ipw_debug_level & IPW_DL_FW_ERRORS) {
struct ipw_fw_error *error =
ipw_alloc_error_log(priv);
ipw_dump_error_log(priv, error);
if (error)
ipw_free_error_log(error);
}
#endif
} else {
priv->error = ipw_alloc_error_log(priv);
if (priv->error)
IPW_ERROR("Sysfs 'error' log captured.\n");
else
IPW_ERROR("Error allocating sysfs 'error' "
"log.\n");
#ifdef CONFIG_IPW_DEBUG
if (ipw_debug_level & IPW_DL_FW_ERRORS)
ipw_dump_error_log(priv, priv->error);
#endif
}

/* XXX: If hardware encryption is for WPA/WPA2,
* we have to notify the supplicant. */
if (priv->ieee->sec.encrypt) {
Expand Down Expand Up @@ -10958,8 +11052,8 @@ static struct attribute *ipw_sysfs_entries[] = {
&dev_attr_nic_type.attr,
&dev_attr_status.attr,
&dev_attr_cfg.attr,
&dev_attr_dump_errors.attr,
&dev_attr_dump_events.attr,
&dev_attr_error.attr,
&dev_attr_event_log.attr,
&dev_attr_eeprom_delay.attr,
&dev_attr_ucode_version.attr,
&dev_attr_rtc.attr,
Expand Down Expand Up @@ -11172,6 +11266,11 @@ static void ipw_pci_remove(struct pci_dev *pdev)
}
}

if (priv->error) {
ipw_free_error_log(priv->error);
priv->error = NULL;
}

free_irq(pdev->irq, priv);
iounmap(priv->hw_base);
pci_release_regions(pdev);
Expand Down
30 changes: 29 additions & 1 deletion trunk/drivers/net/wireless/ipw2200.h
Original file line number Diff line number Diff line change
Expand Up @@ -1085,6 +1085,32 @@ struct ipw_ibss_seq {
struct list_head list;
};

struct ipw_error_elem {
u32 desc;
u32 time;
u32 blink1;
u32 blink2;
u32 link1;
u32 link2;
u32 data;
};

struct ipw_event {
u32 event;
u32 time;
u32 data;
} __attribute__ ((packed));

struct ipw_fw_error {
u32 status;
u32 config;
u32 elem_len;
u32 log_len;
struct ipw_error_elem *elem;
struct ipw_event *log;
u8 payload[0];
} __attribute__ ((packed));

struct ipw_priv {
/* ieee device used by generic ieee processing code */
struct ieee80211_device *ieee;
Expand Down Expand Up @@ -1245,6 +1271,8 @@ struct ipw_priv {
u32 pm_state[16];
#endif

struct ipw_fw_error *error;

/* network state */

/* Used to pass the current INTA value from ISR to Tasklet */
Expand Down Expand Up @@ -1803,7 +1831,7 @@ enum {
IPW_ORD_TABLE_7_LAST
};

#define IPWSTATUS_ERROR_LOG (IPW_SHARED_LOWER_BOUND + 0x410)
#define IPW_ERROR_LOG (IPW_SHARED_LOWER_BOUND + 0x410)
#define IPW_EVENT_LOG (IPW_SHARED_LOWER_BOUND + 0x414)
#define IPW_ORDINALS_TABLE_LOWER (IPW_SHARED_LOWER_BOUND + 0x500)
#define IPW_ORDINALS_TABLE_0 (IPW_SHARED_LOWER_BOUND + 0x180)
Expand Down

0 comments on commit 7d9a868

Please sign in to comment.